[phpBB Debug] PHP Warning: in file [ROOT]/includes/bbcode.php on line 483: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead
[phpBB Debug] PHP Warning: in file [ROOT]/includes/bbcode.php on line 483: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead
[phpBB Debug] PHP Warning: in file [ROOT]/includes/bbcode.php on line 483: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead
[phpBB Debug] PHP Warning: in file [ROOT]/includes/bbcode.php on line 483: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead
[phpBB Debug] PHP Warning: in file [ROOT]/includes/bbcode.php on line 483: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead
[phpBB Debug] PHP Warning: in file [ROOT]/includes/bbcode.php on line 483: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead
[phpBB Debug] PHP Warning: in file [ROOT]/includes/bbcode.php on line 483: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead
[phpBB Debug] PHP Warning: in file [ROOT]/includes/bbcode.php on line 483: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead
[phpBB Debug] PHP Warning: in file [ROOT]/includes/bbcode.php on line 483: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead
[phpBB Debug] PHP Warning: in file [ROOT]/includes/bbcode.php on line 483: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead
[phpBB Debug] PHP Warning: in file [ROOT]/includes/bbcode.php on line 483: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead
[phpBB Debug] PHP Warning: in file [ROOT]/includes/bbcode.php on line 483: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead
[phpBB Debug] PHP Warning: in file [ROOT]/includes/bbcode.php on line 483: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead
[phpBB Debug] PHP Warning: in file [ROOT]/includes/bbcode.php on line 483: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead
[phpBB Debug] PHP Warning: in file [ROOT]/includes/bbcode.php on line 483: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead
[phpBB Debug] PHP Warning: in file [ROOT]/includes/bbcode.php on line 483: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead
[phpBB Debug] PHP Warning: in file [ROOT]/includes/bbcode.php on line 483: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead
[phpBB Debug] PHP Warning: in file [ROOT]/includes/bbcode.php on line 483: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead
[phpBB Debug] PHP Warning: in file [ROOT]/includes/bbcode.php on line 483: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead
[phpBB Debug] PHP Warning: in file [ROOT]/includes/bbcode.php on line 483: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead
[phpBB Debug] PHP Warning: in file [ROOT]/includes/bbcode.php on line 483: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead
[phpBB Debug] PHP Warning: in file [ROOT]/includes/bbcode.php on line 483: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead
[phpBB Debug] PHP Warning: in file [ROOT]/includes/bbcode.php on line 483: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead
[phpBB Debug] PHP Warning: in file [ROOT]/includes/bbcode.php on line 483: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead
[phpBB Debug] PHP Warning: in file [ROOT]/includes/bbcode.php on line 483: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead
[phpBB Debug] PHP Warning: in file [ROOT]/includes/bbcode.php on line 483: preg_replace(): The /e modifier is no longer supported, use preg_replace_callback instead
[phpBB Debug] PHP Warning: in file [ROOT]/includes/functions.php on line 4752: Cannot modify header information - headers already sent by (output started at [ROOT]/includes/functions.php:3887)
[phpBB Debug] PHP Warning: in file [ROOT]/includes/functions.php on line 4754: Cannot modify header information - headers already sent by (output started at [ROOT]/includes/functions.php:3887)
[phpBB Debug] PHP Warning: in file [ROOT]/includes/functions.php on line 4755: Cannot modify header information - headers already sent by (output started at [ROOT]/includes/functions.php:3887)
[phpBB Debug] PHP Warning: in file [ROOT]/includes/functions.php on line 4756: Cannot modify header information - headers already sent by (output started at [ROOT]/includes/functions.php:3887)
FMS Forum • View topic - I programmed a virtual joystick for parallel port - RC transmitter to joystick conversion

I programmed a virtual joystick for parallel port - RC transmitter to joystick conversion

Postby Koen » Thu Oct 02, 2003 8:48 am

Hello,

About a year ago I made a cable to connect my TX to the parallel port for use under FMS.
Since I also wanted to use the TX as a joystick in other programs, I started looking for suitable drivers. I didn't found a solution, so I used what I found to create a bridge between the IOCTL PPJoy virtual joystick driver and the parallel port.
For the case that I ever might switch to winXP I programmed the parallel port using a dll found at

I tested the program and it works fine under win98 (not tested on win2000 / xp but should work)
There seem to be some issues with the PPJoy channel assignment, therefore I rearranged channel mapping so that all four channels are available under windows.
Since I have a 5 channel TX, I hardcoded the channels in the code, with channel 5 configured as a switch. (you need at least 1 switch to calibrate your joystick under windows).

I'll attach the code here (I used BCC32 free compiler since I don't have an IDE on my PC since I havn't programmed in 5 years) so maybe someone else might want to use it.

The rest of the instructions you'll find in the code comments.

If someone makes a better version, integrates an installer or compiles this into the PPJoy driver, please send me the result.

greets,

Koen

PS: this should also solve the issue that FMS can not use the parallel port interface under win2000 / xp

#include <conio.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <windows.h>

#include <winioctl.h>
#include "ppjioctl.h"

#define NUM_ANALOG 8 /* Number of analog values which we will provide */
#define NUM_DIGITAL 1 /* Number of digital values which we will provide */

/* Definitions in the build of inpout32.dll are: */
/* short _stdcall Inp32(short PortAddress); */
/* void _stdcall Out32(short PortAddress, short data); */

/* prototype (function typedef) for DLL function Inp32: */
typedef short _stdcall (*inpfuncPtr)(short portaddr);
typedef void _stdcall (*oupfuncPtr)(short portaddr, short datum);

#pragma pack(push,1) /* All fields in structure must be byte aligned. */
typedef struct
{
unsigned long Signature; /* Signature to identify packet to PPJoy IOCTL */
char NumAnalog; /* Num of analog values we pass */
long Analog[NUM_ANALOG]; /* Analog values */
char NumDigital; /* Num of digital values we pass */
char Digital[NUM_DIGITAL]; /* Digital values */
} JOYSTICK_STATE;
#pragma pack(pop)


int main (int argc, char **argv)
{
HANDLE h;
char ch;
JOYSTICK_STATE JoyState;

DWORD RetSize;
DWORD rc;

long *Analog;
char *Digital;

char *DevName;

HINSTANCE hLib;
inpfuncPtr inp32;
oupfuncPtr oup32;

// following variables are not used in neither the io dll or the ioctl joystick interface
// they just beloing to the PPM demodulation routine
short current_data;
short glitches_in_a_row;
short previous_data;
short current_channel_number =0;
short still_waiting_for_last_pulse;
short max_channel_number_needed;
long channel_value[10]; // provide some headroom to not have to start from 0
LARGE_INTEGER Frequency;
LARGE_INTEGER PerformanceCount;
LARGE_INTEGER Startingtime;
long Pulseduration;
long three_milliseconds;
long one_millisecond;


// this is the standard name on installation, if you chose something else, change it
DevName= "\\\\.\\PPJoyIOCTL1";
/* Load the library for parallel communications*/
hLib = LoadLibrary("inpout32.dll");
if (hLib == NULL) {
printf("LoadLibrary Failed.
");
return -1;
}
/* get the address of the function for parallel input communication*/
inp32 = (inpfuncPtr) GetProcAddress(hLib, "Inp32");
if (inp32 == NULL) {
printf("GetProcAddress for Inp32 Failed.
");
return -1;
}
oup32 = (oupfuncPtr) GetProcAddress(hLib, "Out32");
if (oup32 == NULL) {
printf("GetProcAddress for Oup32 Failed.
");
return -1;
}

/* Open a handle to the control device for the first virtual joystick. */
/* Virtual joystick devices are names PPJoyIOCTL1 to PPJoyIOCTL16. */
h= CreateFile(DevName,GENERIC_WRITE,FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);
/* Make sure we could open the device! */
if (h==INVALID_HANDLE_VALUE)
{
printf ("CreateFile failed with error code %d trying to open %s device
",GetLastError(),DevName);
return 1;
}
/* Initialise the IOCTL data structure for joystick communication*/
JoyState.Signature= JOYSTICK_STATE_V1;
JoyState.NumAnalog= NUM_ANALOG; /* Number of analog values */
Analog= JoyState.Analog; /* Keep a pointer to the analog array for easy updating */
JoyState.NumDigital= NUM_DIGITAL; /* Number of digital values */
Digital= JoyState.Digital; /* Digital array */





// purpose of this program:
//
// Using the inpout32.dll and the PPJoy virtual joystick driver with IOCTL control,
// this program allows to connect a RC transmitter to the parallel port and model
// the transmitter's channels towards windows as a joystick
// Connect the TX ground to pin 10 and the TX PPM signal via a resistor and a
// zener diode to pin 18 (I used this since I already made the cable for FMS)
//
// installation notes:
//
// install PPJoy virtual joystick driver (important note for win98 users: don't perform
// all of the "post win98 steps" mentioned in the PPJoy instructions, only add to the
// control panel the "Parallel port joystick bus and forget about the other ones for LPTx)
// after installing the inpout32.dll and a compiled and linkes version of this program
// in a directory, start the program and you can configure your virtual joystick

// PPM signal spec (free interpretation):
//
// we'll see a number of active HIGH pulses
// pulse duration 1ms means channel position is 0%
// pulse duration 2ms means channel position is 100%
// 1st pulse is channel1, 2nd channel2 and so on
// max number of pulses allowed is 9
// after last pulse, min. 2ms LOW functions as reset signal,
// indicating pulse 1 will follow again

// tell the routines how many channels you want to monitor
// don't make this bigger then 9, actually 8 is the max. number for
// this routine to work reliable. Also don't make it higher then
// the actual number of channels your TX supports or it won't work
// the lower the number, the more time the routine has to call the joystick driver,
// the less chance we have for glitches in the PPM decoding
max_channel_number_needed = 6;
//check just how fast our internal HW timer is in units per second
QueryPerformanceFrequency (&Frequency);
// do some calculation before we start
one_millisecond = Frequency.QuadPart / 1000;
three_milliseconds = one_millisecond * 3;
// run the program forever. You can always terminate by pressing Ctrl + C :)
while (1!=2)
{
// read stuff from the parallel port (this allows for the simplest adaptor to the TX)
// On my win98 machine I could call the hardware directly, but since the
// library is fast enough I used that to benefit from win 2000 / win xp compatibility
current_data = (inp32)(0x379);
if (previous_data != current_data)
{
// make variable ready for next check;
previous_data = current_data;
// check if pin 18 is pulled low by the TX,
// assume other pins are high, better would be to mask them out
// if your TX is giving a active low signal, change "!=" to "==" below
if (current_data != 104)
{
// so it's a PPM HIGH
// check our watch to see what time it is
QueryPerformanceCounter(&PerformanceCount);
// calculate the pulse duration
Pulseduration = PerformanceCount.QuadPart - Startingtime.QuadPart;
// reinitialise for next measurement
Startingtime = PerformanceCount;
// see if it was the reset pulse that just ended
// if there are more then 3 ms between two highs
// assume we just ended the reset pulse.
// note: this deviates from the spec but works ok
// if TX is not sending more then 8 channels in the frame
// and it allows us to get away without checking on low signals
if (Pulseduration > three_milliseconds)
{
// yess, we have a winner: the reset pulse just ended
current_channel_number = 1;
still_waiting_for_last_pulse = 1;
}
else
{
// quess what: the pulse for the next channel is starting
// let's assume this is also the end of the previous pulse
// put the value found in the array
// if this is not the last channel, just continue to the next one
if ( max_channel_number_needed > current_channel_number)
{
channel_value[current_channel_number] = Pulseduration;
// indicate we now wait for the next channel
current_channel_number++;
}
else
{
if (still_waiting_for_last_pulse == 1)
{
// the still_waiting part is to avoid that in case we look for e.g. 6
// pulses and the signal contains 8 that we will write signals 7&8 in channel6
still_waiting_for_last_pulse = 0;
channel_value[current_channel_number]= Pulseduration;
// at this moment in the PPM signal, possibly more pulses need
// to follow but they don't interest us anymore. After them,
// the reset pulse will follow. Since we are now at the least
// time-critical period in the signal do the time-consuming joystick stuff now.
// joystick driver starts counting from 0, not 1 like I prefer
// figure out the mathwork yourselves: pulse is between 1 and 2 ms +
// about 100 us of the pause between two pulses
Analog[0]= PPJOY_AXIS_MIN +
((PPJOY_AXIS_MAX - PPJOY_AXIS_MIN) *
(channel_value[1] - one_millisecond
- (one_millisecond/10) ) /
one_millisecond);
Analog[1]= PPJOY_AXIS_MIN +
((PPJOY_AXIS_MAX - PPJOY_AXIS_MIN) *
(channel_value[2] - one_millisecond
- (one_millisecond/10) ) /
one_millisecond);
Analog[3]= PPJOY_AXIS_MIN +
((PPJOY_AXIS_MAX - PPJOY_AXIS_MIN) *
(channel_value[3] - one_millisecond
- (one_millisecond/10) ) /
one_millisecond);
Analog[4]= PPJOY_AXIS_MIN +
((PPJOY_AXIS_MAX - PPJOY_AXIS_MIN) *
(channel_value[4] - one_millisecond
- (one_millisecond/10) ) /
one_millisecond);
if (((channel_value[6] - one_millisecond
- (one_millisecond/10) ) / one_millisecond) > 0.5 )
Digital[0]= 1;
else
Digital[0]= 0;
// now write all joystick values back to the driver
DeviceIoControl(h,IOCTL_PPORTJOY_SET_STATE,&JoyState,
sizeof(JoyState),NULL,0,&RetSize,NULL);
}
}
}
}
else
{
// so it's a PPM LOW
// let's do nothing on low signals
// this saves us some calls to the timer routines,
// maybe resulting in less chances on glitches
}
}
}
// although we never arive here due to the endless loop, the code below could provide a clean exit
//CloseHandle(h);
//FreeLibrary(hLib);
//return 0;
}
Koen
 
Posts: 5
Joined: Thu Oct 02, 2003 8:33 am

Postby Koen » Thu Oct 02, 2003 4:52 pm

I can now confirm that my program works under win2000 and is giving full support for FMS (and others) to use a TX through the parallel port. (at last...)

I noticed however that not all parallel ports are created equal and that on line 160 I had to change (current_data != 104) to (current_data!=120).
Best would be to build in a small test routine that detects the 2 values appearing on the port.

PS: the mapping of the channels I did is unnecessary, since I just discovered that PPJoy has a full GUI to arrange the channel mapping. This means that the program can be made generic, independent of the number of channels your tx has.
Koen
 
Posts: 5
Joined: Thu Oct 02, 2003 8:33 am

Postby Ion » Fri Oct 03, 2003 7:46 am

Hello Koen

I'm interested in your driver, but I don't Know what to do whith the source code. Could you please put the compiled program or a link where I can find it ?. If not posible, could you send it to me to: eladiomf@hotmail.com

Thank you very much
Ion
 
Posts: 2
Joined: Fri Oct 03, 2003 7:30 am

Postby JrSnike » Tue Oct 07, 2003 6:21 pm

I compiled the program.

If somebody needs it orders me an e-mail.

:D jrsnike@bol.com.br
User avatar
JrSnike
 
Posts: 20
Joined: Wed Apr 10, 2002 1:55 pm

Postby Koen » Wed Oct 08, 2003 5:29 am

I will try to find some time during the weekend to:

- make the program parallel-port "brand" independent
- provide compatibility with positive & negative PPM TX's
- provide automatic detection for number of channels the TX has
- remove built in mapping of channels and use those of PPJoy instead
- provide some textual output to the console window about what the program is doing
- put up the final result together with instructions on a webpage

That's about as far as I want to go with this. The authors from FMS can feel free to integrate the code in FMS, the authors from PPJoy can do the same if they want to.
Koen
 
Posts: 5
Joined: Thu Oct 02, 2003 8:33 am

Postby Eric Brouwer » Wed Oct 08, 2003 9:36 am

JRSnike, have a look on my , I have created a small C++ program that can be used with a standard FMS Serial PIC Interface. The program Fms2PPJoy reads the serial data from the FMS PIC interface, and sends it to the PPJoy Virtual Joystick driver. My program makes provision for FMS interfaces on COM1 to COM4, but only supports the 19200 baud interface. The 9600 baud interfaces will not work with this program.

For the latest PPJoy version, I have also placed a link to Deon van der Westhuysen's web where you can download the PPJoy software. According to Deon (creator of PPJoy), he is looking into the possibility of including direct PPM signal scanning using his driver and a standard printer port.
Some mistakes are too much fun to only make once.

Vanderbijlpark
South Africa
Homepage: http://myweb.absa.co.za/eric.brouwer
Eric Brouwer
 
Posts: 252
Joined: Mon Apr 22, 2002 7:53 am
Location: Vanderbijlpark, South Africa


Return to Parallelport-PPM-Interface

Who is online

Users browsing this forum: No registered users and 3 guests