Solved

How to convert incoming COM1 baud 38400 to outgoing COM2 at 9600.

Posted on 2004-08-05
17
1,223 Views
Last Modified: 2012-05-05
Ok here is the situation.  I have a wire feed coming from a satellite reciever which outputs data to my computer at 38400.  The problem is that the software I need to read this data is only capable of recieving the data at 9600.  My thought was that I could put a computer in between these systems which will listen on com1 at 38400 and then output that data on com2 at 9600 which I can then plug directly into the other system.  Can this be done, and if so can someone tell me what I need to do to get it working?  Thanks in advance!

ED7
0
Comment
Question by:electricd7
  • 4
  • 3
  • 3
  • +4
17 Comments
 
LVL 55

Expert Comment

by:Jaime Olivares
ID: 11726127
I think it will be a cleaner solution to install a $3 microcontroller ($10 with all materials) to convert data rate. Could be a PIC 16F628.
0
 

Author Comment

by:electricd7
ID: 11726150
jaime olivares, probably so, but Im not a hardware guy.  Can you explain more or possibly draw up a schematic?
0
 
LVL 5

Expert Comment

by:Didier Vally
ID: 11726278
Let's assume that you'd put a computer between the two devices :


Output@38400<--->(Input@38400)Computer(Output@9600)<--->Input@9600

You need 2 COM ports on "Computer" : COM1 for Input@38400 and COM2 for Output@9600

Then you take Visual C++ 6.0 and you must code 2 COM ports handlers :
- One for Input@38400 that reads data and put these in a buffer
- One for Output@9600 that reads the buffer and send the data through COM2 to the (Input@9600) on the other side...

0
 

Author Comment

by:electricd7
ID: 11726309
right, but I have no idea how to program this.  I was hoping it was an easy thing someone could help me do for 500 pts?

Chad
0
 
LVL 55

Expert Comment

by:Jaime Olivares
ID: 11726341
I see, but is a little cheap and safer than put a PC between both. Just need the minimum:

01 PIC 16F628 microcontroller (16 pins)
01 MAX-233 RS-232 driver (16 pins)
01 Crystal 20 Mhz
02 Capacitors 0.1 uF
01 5V5C regulator LM7805 (3 pins)
01 Solder board (at least 2" x 3")

Some solder, and solder iron (30 Watts)
01 9-15 VDC Transformer (any)

You can find all in www.jameco.com

I think it can be harder to you to build it all and program the micro, but an electronics student can do it in a couple of days.
Good luck,
Jaime.
0
 

Author Comment

by:electricd7
ID: 11726390
i can physically build it and program the processor, but i don't have any idea how to write the program that would reside on the chip.  I don't have any problem building the part itself, but I am lost on how to actually write a program for a PIC that will do what I want.

ED7
0
 
LVL 11

Expert Comment

by:griessh
ID: 11726401
Hi electricd7,

I haven't seen a off the shelf software to do that.
On a PC it should be relative easy to do that job, the PIC version might need some more knowledge. Which way to go depends on your resources. If you go PC somebody could write a small VB program to read COM1 and write to COM2, quick and dirty :-)
Make sure the amount of data you get from your 38400bd receiver is not more than your 9600bd device can handle.

======
Werner
0
 
LVL 11

Expert Comment

by:griessh
ID: 11726546
... sorry, just saw that you are looking for somebody to write the program :-(
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 55

Expert Comment

by:Jaime Olivares
ID: 11726556
That's the part where an electronics student can help. Also you can buy an excecelent book at Jameco: "Serial PIC'n", there is all you need to program serial applications but it is a little expensiver ($49 aprox.)
0
 

Expert Comment

by:pcjose2002
ID: 11739613
I am familiar with both hardware and software options.

I would say..... HARDWARE OPTION is out
- it cannot deal with buffer overflow  
  Remember, you are downsizing the speed. 38.4 K to 9.6 K
  thousands of bytes will be lost per second..

Your original idea of having a PC in between will help - atleast you can buffer up, and can have the option of writing to a file in case of emergency shutdown, and later retreive the file and start sending again..

Exception::: Does the incoming wirefeed support the TRON and TROFF? if so, hardware option may work.. but still, it may not be as reliable.. Mostly, you might have to stop the satallite receiver by sending a TROFF from your hardware, for almost every BYTE you receive from the wirefeedand then startup the wirefeed reception again by sending TRON again, and after you send it out through the other end at 9.6K

General recommendation is not to use hardware, since, it may still lose one or two bytes, even before it could send out the TROFF.

There is another issue..
since you are trying to downsize the speed, other than practical problems, there is also a theoretical fact that you cannot ignore..
THEORETICALLY THIS IS IMPOSSIBLE, BY HARDWARE OR SOFTWARE OR BY ANY MEANS, IF YOU HAVE CONTINUOS DATA FLOWING AT DIFFERENT SPEEDS. unless there is no breathing time space, it is not possible. you might need to do some Math, before you invest any further time on this. HINT: look out for the average bytes transfered per hour or so.. and see whether the intervels (if any) from the wire feed is enough to take care of transfering the pending Bytes at the slower end.

if you have a windows based software taking up only 9.6K, it is something unimaginable. Mostly, the same company would have some upgrades.

Or is this a Dos based application? if it is DOS, sometimes, tampering might work. I have done this tampering on a DOS application long before.. long back, I was using Debug.com to look into the .exe and .com files. Basically, it would use the BIOS interrupt 14H and the speed initialization is through one of the values pushed to registers, BX, etc before the interrupt call. So, id you could locate that point in the DOS application and do a hexadecimal edit on the value pushed to the registers, it could make it to initialize to 38.4K even if you select 9.6K from your application. this could help.

if you would like to add a PC in between, then adding a linux box and writing some perl scripts to read from one com port and write to another com port using pipes might help, as linux have excellent piping mechanisms, where data loss is not much likely. (Thorough testing is recommended though)
Even windows perl scripts may help to get the piping.


Regards,
Jose




0
 
LVL 55

Expert Comment

by:Jaime Olivares
ID: 11739790
>I would say..... HARDWARE OPTION is out
>- it cannot deal with buffer overflow  
>  Remember, you are downsizing the speed. 38.4 K to 9.6 K
>  thousands of bytes will be lost per second

>General recommendation is not to use hardware, since, it may still lose one or two bytes, even before it could send out
> the TROFF.

I totally disagree with your comment, although using a PC is a good alternative, you can't say that "hardware is not reliable".
Besides the fact that PC is a hardware too, there are hundreds of serial interfaces in the market, like in www.blackbox.com (not so cheap), there are many techniques to avoid byte loss, including hardware handshacking (CTS/RTS) and XON/XOFF.
Also, you have to consider traffic, the fact that a connection goes to 38.4K doesn't means inmediatly that will overflow a 9.6K line, depending on specific data flow: Transmition line rate it is not equal to information rate.
Even with temporay transmition high rate, you can use buffering techniques.

PS. Please explain use what is TRON/TROFF, as far as I know them are old Basic commands, and some command related to UNIX.
0
 
LVL 8

Expert Comment

by:adg080898
ID: 11742932
It would be somewhat simple to write a Win32 program that would act as a "serial bridge". It would consist of two threads. One thread would wait for recv on COM1, and send on COM2 - and another thread would wait for recv on COM2 and send on COM1. (OR, if it really is a ONE-WAY data stream as your question says, it becomes even easier: one thread).

Will it run on windows XP? Win 9x has some bugs in its hardware flow control implementation that make it more difficult to target win9x/me.

Are the two com ports interchangable? It makes it easier to write the program if I don't need to add configurability.

How many wire is the 9600 baud serial interface? Is it full hardware handshaking (RTS/CTS)? If the data actually comes in at 38400 then you will NEED hardware flow control to slow the data down enough for the slow device. I need to know whether each port will use hardware flow control.

How long is the data stream? Assuming the data comes in at more than 9600, and you don't have flow control, is there enough idle time for the 9600 stream to "catch up" between data transfers?
0
 
LVL 8

Accepted Solution

by:
adg080898 earned 500 total points
ID: 11744243
I wrote a simple bridge, using Win32 COMM API. Uses a pair of worker threads as I described. I have no way of testing it completely, but it works as far as I can get it. Try it out and let me know if it works. It has extensive error checking and shows an error message for every possible failure, so it should be fast to work out any bugs. It's 582 lines long, so I hope there aren't any bugs! The program:

-----

// sbridge.c

// Serial bridge program
// Creates a transparent pass-thru between 2 COM
// ports with possibly different settings

#include <windows.h>
#include <process.h>
#include <stdio.h>
#include <conio.h>

// Which ports to use?
#define SB_COM1_NAME            "COM1"
#define SB_COM2_NAME            "COM2"
// Which port is the fast one?
#define SB_COM1_BAUD            38400
#define SB_COM2_BAUD            9600
// You may need to tune the buffer size if the data is bursty
// If a delay is acceptable (the fast one can get ahead),
// try huge sizes, like 65536, or, even 1048576 (1 megabyte)
// This depends. Is it ok for the sender to get way ahead?
// Or would the sender rather be slowed down by flow control?
#define SB_OSSNDBUF                  2048
#define SB_OSRCVBUF                  2048

// Buffer size to use in this program
// If this is small, the reaction time is quick
#define BUFFERSIZE                  256

HANDLE hCom1, hCom2;
OVERLAPPED ovCom1S, ovCom1R, ovCom2S, ovCom2R;

UINT idThread1, idThread2;
HANDLE hThread1, hThread2;

void UTIL_Msg(char *pFormat, ...)
{
      char buf[256];
      int nLen;

      va_list ap;
      va_start(ap, pFormat);
      nLen = _vsnprintf(buf, sizeof(buf), pFormat, ap);
      va_end(ap);

      if (nLen > 0) {
            fwrite(buf, 1, nLen, stdout);
            OutputDebugString(buf);
      } else {
            // Ack, huge message
            OutputDebugString("\n****MESSAGE TOO LONG****\n");
            vprintf(pFormat, ap);
      }
}

HANDLE PrepareComPort(char *pPortName, int nBaud,
            OVERLAPPED *pOvSend, OVERLAPPED *pOvRecv)
{
      DCB dcb;
      COMMTIMEOUTS ct;
      COMSTAT comstat;
      DWORD nErr;

      HANDLE hPort;

      ZeroMemory(pOvSend, sizeof(*pOvSend));
      ZeroMemory(pOvRecv, sizeof(*pOvRecv));

      // Create overlapped events
      pOvSend->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
      if (!pOvSend->hEvent) {
            nErr = GetLastError();
            UTIL_Msg("\nCreateEvent failed (error %08x)\n", nErr);
            goto failOvSend;
      }
      pOvRecv->hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
      if (!pOvRecv->hEvent) {
            nErr = GetLastError();
            UTIL_Msg("\nCreateEvent failed (error %08x)\n", nErr);
            goto failOvRecv;
      }

      // Open port
      hPort = CreateFile(pPortName, GENERIC_READ | GENERIC_WRITE, 0, 0,
                  OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);
      if (hPort == INVALID_HANDLE_VALUE) {
            nErr = GetLastError();
            UTIL_Msg("\nCreateFile failed opening comm port (CreateFile error %08x)\n", nErr);
            goto failPortOpen;
      }

      // Destructive reinitialization of communications device
      // 2K buffer for recv and 2K buffer for send
      if (!SetupComm(hPort, SB_OSRCVBUF, SB_OSSNDBUF)) {
            nErr = GetLastError();
            UTIL_Msg("\nSetupComm failed (error %08x)\n", nErr);
            goto failSetupComm;
      }

      // Set device control block
      ZeroMemory(&dcb, sizeof(dcb));
      dcb.DCBlength = sizeof(dcb);
      if (!GetCommState(hPort, &dcb)) {
            nErr = GetLastError();
            UTIL_Msg("\nGetCommState failed (error %08x)\n", nErr);
            goto failGetCommState;
      }

      dcb.DCBlength           = sizeof(dcb);          // sizeof(DCB)
      dcb.BaudRate            = nBaud;                // current baud rate
      dcb.fBinary             = TRUE;                 // binary mode, no EOF check
      dcb.fParity             = FALSE;                // enable parity checking
      dcb.fOutxCtsFlow        = TRUE;                 // CTS output flow control
      dcb.fOutxDsrFlow        = FALSE;                // DSR output flow control
      dcb.fDtrControl         = FALSE;                // DTR flow control type
      dcb.fDsrSensitivity     = FALSE;                // DSR sensitivity
      dcb.fTXContinueOnXoff   = FALSE;                // XOFF continues Tx
      dcb.fOutX               = FALSE;                // XON/XOFF out flow control
      dcb.fInX                = FALSE;                // XON/XOFF in flow control
      dcb.fErrorChar          = FALSE;                // enable error replacement
      dcb.fNull               = FALSE;                // enable null stripping
      dcb.fRtsControl         = RTS_CONTROL_HANDSHAKE;// RTS flow control
      dcb.fAbortOnError       = TRUE;                 // abort reads/writes on error
      dcb.XonLim              = 0;                    // transmit XON threshold
      dcb.XoffLim             = 0;                    // transmit XOFF threshold
      dcb.ByteSize            = 8;                    // number of bits/byte, 4-8
      dcb.Parity              = NOPARITY;             // 0-4=no,odd,even,mark,space
      dcb.StopBits            = ONESTOPBIT;           // 0,1,2 = 1, 1.5, 2
      dcb.XonChar             = 0;                    // Tx and Rx XON character
      dcb.XoffChar            = 0;                    // Tx and Rx XOFF character
      dcb.ErrorChar           = 0;                    // error replacement character
      dcb.EofChar             = 0;                    // end of input character
      dcb.EvtChar             = 0;                    // received event character

      if (!SetCommState(hPort, &dcb)) {
            nErr = GetLastError();
            UTIL_Msg("\nSetCommState failed (error %08x)\n", nErr);
            goto failSetCommState;
      }

      // Initialize communication timeouts
      ct.ReadIntervalTimeout                  = 0;
      ct.ReadTotalTimeoutMultiplier      = 0;
      ct.ReadTotalTimeoutConstant            = 0;
      ct.WriteTotalTimeoutMultiplier      = 0;
      ct.WriteTotalTimeoutConstant      = 0;
      if (!SetCommTimeouts(hPort, &ct)) {
            nErr = GetLastError();
            UTIL_Msg("\nSetCommTimeouts failed (error %08x)\n", nErr);
            goto failSetCommTimeouts;
      }

      // EV_BREAK | EV_ERR | EV_RLSD | EV_RXCHAR | EV_TXEMPTY
      if (!SetCommMask(hPort, EV_ERR | EV_RXCHAR)) {
            nErr = GetLastError();
            UTIL_Msg("\nSetCommMask failed (error %08x)\n", nErr);
            goto failSetCommMask;
      }

      if (!ClearCommError(hPort, &nErr, &comstat)) {
            nErr = GetLastError();
            UTIL_Msg("\nClearCommError failed (error %08x)\n", nErr);
            goto failClearCommError;
      }

      return hPort;

failClearCommError:
failSetCommMask:
failSetCommTimeouts:
failSetCommState:
failGetCommState:
failSetupComm:
      CloseHandle(hPort);
      hPort = 0;
failPortOpen:
      CloseHandle(pOvRecv->hEvent);
      pOvRecv->hEvent = 0;
failOvRecv:
      CloseHandle(pOvSend->hEvent);
      pOvSend->hEvent = 0;
failOvSend:

      return 0;
}

// Parameter structure for worker threads
typedef struct {
      HANDLE hSrc;                  // The handle from which to recv
      OVERLAPPED *pOvSrc;
      HANDLE hDst;                  // The handle to which to send
      OVERLAPPED *pOvDst;

      char aBuffer[BUFFERSIZE];
      int nBufferLevel;

      CRITICAL_SECTION csTotals;
      unsigned __int64 nTotalRcv;
      unsigned __int64 nTotalSnt;
} ThreadParam;

// Sift through thread messages ignoring all but WM_QUIT
// Returns TRUE to request quit
BOOL ShouldQuit()
{
      MSG msg;

      while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
            if (msg.message == WM_QUIT)
                  return TRUE;
      }
      return FALSE;
}

// Returns FALSE on a bad error
BOOL CheckForCommError(HANDLE hPort, char *pCausedBy)
{
      BOOL bBad;
      COMSTAT comstat;
      DWORD nEvent;

      ClearCommError(hPort, &nEvent, &comstat);

      bBad = FALSE;
      if (nEvent & CE_BREAK) {
            printf("\nBreak received! Sender trying to resync?\n");
      }
      if (nEvent & CE_FRAME) {
            printf("\nFraming error! Line noise!\n");
            bBad = TRUE;
      }
      if (nEvent & CE_IOE) {
            printf("\nSerial device error!\n");
            bBad = TRUE;
      }
      if (nEvent & CE_MODE) {
            printf("\nSerial device mode not supported error!\n");
            bBad = TRUE;
      }
      if (nEvent & CE_OVERRUN) {
            printf("\nSerial overrun error! Serial driver can't keep up!\n");
            bBad = TRUE;
      }
      if (nEvent & CE_RXOVER) {
            printf("\nReceive buffer overrun! I can't keep up!\n");
            bBad = TRUE;
      }
      if (nEvent & CE_RXPARITY) {
            printf("\nParity error! Line noise!\n");
            bBad = TRUE;
      }
      if (nEvent & CE_TXFULL) {
            printf("\nTransmit buffer overflow! This is not possible!\n");
            bBad = TRUE;
      }

      if (bBad) {
            printf("Bad error, caused by \"%s\"!\n", pCausedBy);
            return FALSE;
      }

      return TRUE;
}

unsigned WorkerThread(void *pThreadParam)
{
      ThreadParam *o = (ThreadParam *)pThreadParam;
      HANDLE aWait[2];
      BOOL ok, bRdBlock, bWrBlock;
      DWORD nDidRd, nDidWr, nErr, n;

      // Touch message queue
      if (ShouldQuit())
            return 0;

      aWait[0] = o->pOvSrc->hEvent;
      aWait[1] = o->pOvDst->hEvent;

      nDidRd = 0;
      nDidWr = 0;
      n = 0;
      nErr = 0;
      ok = 0;

      bRdBlock = FALSE;
      bWrBlock = FALSE;

      // This loop mainly tries to write,
      // and waits to read when there is nothing to write.
      // If it has has any data to write:
      //  - It writes it
      //  - If it cannot write, it waits for the ability to write.
      // If there is no data to write:
      //  - Try to fill the buffer
      //  - If I can't fill the buffer, wait

      do {
            if (o->nBufferLevel > 0) {
                  //
                  // There is outgoing data
                  //

                  if (bWrBlock) {
                        //
                        // I have data to send, but I can't, so wait
                        //

                        n = MsgWaitForMultipleObjects(1, &o->pOvDst->hEvent, FALSE,
                                    INFINITE, QS_ALLINPUT);
                        switch (n) {
                        case WAIT_OBJECT_0:
                              // Object signalled
                              if (GetOverlappedResult(o->hDst, o->pOvDst, &nDidWr, FALSE)) {
                                    // Success
                                    memmove(o->aBuffer, o->aBuffer + nDidWr,
                                                o->nBufferLevel - nDidWr);
                                    o->nBufferLevel -= nDidWr;
                                    bWrBlock = FALSE;

                                    EnterCriticalSection(&o->csTotals);
                                    o->nTotalSnt += nDidWr;
                                    LeaveCriticalSection(&o->csTotals);
                              } else {
                                    nErr = GetLastError();
                                    UTIL_Msg("\nDied trying to send! "
                                                "(GetOverlappedResult error %08x)\n", nErr);
                                    return 0;
                              }
                              break;
                        case WAIT_OBJECT_0+1:
                              // Message received
                              if (ShouldQuit())
                                    return 0;
                              break;
                        case WAIT_FAILED:
                              nErr = GetLastError();
                              UTIL_Msg("\nDied trying to send! "
                                          "(MsgWaitForMultipleObjects error %08x)\n", nErr);
                              return 0;
                        }
                  } else {
                        //
                        // Send some data
                        //
                        ok = WriteFile(o->hDst, o->aBuffer,
                                    o->nBufferLevel, &nDidWr, o->pOvDst);
                        if (!ok) {
                              nErr = GetLastError();
                              if (nErr == ERROR_IO_PENDING) {
                                    bWrBlock = TRUE;
                              } else {
                                    UTIL_Msg("\nDied trying to send! "
                                                "(WriteFile error %08x)\n", nErr);
                                    return 0;
                              }
                        } else {
                              // Success
                              memmove(o->aBuffer, o->aBuffer + nDidWr,
                                          o->nBufferLevel - nDidWr);
                              o->nBufferLevel -= nDidWr;
                              bWrBlock = FALSE;

                              EnterCriticalSection(&o->csTotals);
                              o->nTotalSnt += nDidWr;
                              LeaveCriticalSection(&o->csTotals);
                        }
                  }
            } else {
                  //
                  // There is nothing to send, so receive, and wait if necessary
                  //

                  if (bRdBlock) {
                        n = MsgWaitForMultipleObjects(1, &o->pOvSrc->hEvent, FALSE,
                                    INFINITE, QS_ALLINPUT);
                        switch (n) {
                        case WAIT_OBJECT_0:
                              // Object signalled
                              if (GetOverlappedResult(o->hSrc, o->pOvSrc, &nDidRd, FALSE)) {
                                    // Success. Data received, update buffer level
                                    o->nBufferLevel += nDidRd;

                                    EnterCriticalSection(&o->csTotals);
                                    o->nTotalRcv += nDidRd;
                                    LeaveCriticalSection(&o->csTotals);

                                    bRdBlock = FALSE;
                              } else {
                                    nErr = GetLastError();
                                    UTIL_Msg("\nDied trying to receive! "
                                                "(GetOverlappedResult error %08x)\n", nErr);
                                    return 0;
                              }
                              break;
                        case WAIT_OBJECT_0+1:
                              // Message received
                              if (ShouldQuit())
                                    return 0;
                              break;
                        case WAIT_FAILED:
                              nErr = GetLastError();
                              UTIL_Msg("\nDied trying to receive! "
                                          "(MsgWaitForMultipleObjects error %08x)\n", nErr);
                              return 0;
                        }
                  } else {
                        //
                        // Receive some data
                        //
                        ok = ReadFile(o->hSrc, o->aBuffer,
                                    BUFFERSIZE, &nDidRd, o->pOvSrc);
                        if (!ok) {
                              nErr = GetLastError();
                              if (nErr == ERROR_IO_PENDING) {
                                    bRdBlock = TRUE;
                              } else {
                                    UTIL_Msg("\nDied trying to receive! "
                                                "(ReadFile error %08x)\n", nErr);
                                    return 0;
                              }
                        } else {
                              // Success

                              if (nDidRd > 0) {
                                    o->nBufferLevel += nDidRd;

                                    EnterCriticalSection(&o->csTotals);
                                    o->nTotalRcv += nDidRd;
                                    LeaveCriticalSection(&o->csTotals);
                              }
                        }
                  }
            }

            // Look for an error
            if (!CheckForCommError(o->hSrc, "RCV"))
                  return 0;
            if (!CheckForCommError(o->hDst, "SND"))
                  return 0;
      } while (1);

      return 0;
}

unsigned __stdcall Worker(void *pThreadParam)
{
      unsigned n = WorkerThread(pThreadParam);
      UTIL_Msg("\nWorker exited\n");
      return n;
}

ThreadParam tp1, tp2;

int main()
{
      BOOL bDone;
      HANDLE aWait[2];

      unsigned __int64 nTmpRcv1, nTmpSnt1, nTmpRcv2, nTmpSnt2;

      printf("Serial bridge - virtually connects two COM ports, passes data both ways\n");
      printf("\nBridging:\n");
      printf("%s: %6u baud\n", SB_COM1_NAME, SB_COM1_BAUD);
      printf("%s: %6u baud\n\n", SB_COM2_NAME, SB_COM2_BAUD);

      // Touch message queue
      if (ShouldQuit())
            return 0;

      // Initialize
      hCom1 = PrepareComPort(SB_COM1_NAME, SB_COM1_BAUD, &ovCom1S, &ovCom1R);
      hCom2 = PrepareComPort(SB_COM2_NAME, SB_COM2_BAUD, &ovCom2S, &ovCom2R);

      //
      // Prepare thread parameters
      //

      // Thread 1 reads from COM1 and writes to COM2
      tp1.hSrc = hCom1;
      tp1.hDst = hCom2;
      tp1.pOvSrc = &ovCom1R;
      tp1.pOvDst = &ovCom2S;

      // Thread 2 reads from COM2 and writes to COM1
      tp2.hSrc = hCom2;
      tp2.hDst = hCom1;
      tp2.pOvSrc = &ovCom2R;
      tp2.pOvDst = &ovCom1S;

      InitializeCriticalSection(&tp1.csTotals);
      InitializeCriticalSection(&tp2.csTotals);

      // Spawn worker threads
      hThread1 = (HANDLE)_beginthreadex(0, 0,
                  Worker, &tp1, CREATE_SUSPENDED, &idThread1);
      hThread2 = (HANDLE)_beginthreadex(0, 0,
                  Worker, &tp2, CREATE_SUSPENDED, &idThread2);

      printf("Starting two workers\n");

      // Start worker threads
      ResumeThread(hThread1);
      ResumeThread(hThread2);

      printf("Press Esc to stop the bridge\n");

      // Wait forever for escape key (while worker threads work)
      bDone = FALSE;
      printf("\n\nR=Received, S=Sent, 1=COM1, 2=COM2, shows bytes transferred\n\n");
      do {
            while (_kbhit()) {
                  switch (getch()) {
                  case 27:
                        bDone = TRUE;
                        break;
                  case 0:
                  case 0xe0:
                        getch();
                        break;
                  }
            }
            
            // Make a local copy of the totals to minimize time inside
            // critical section
            EnterCriticalSection(&tp1.csTotals);
            nTmpRcv1 = tp1.nTotalRcv;
            nTmpSnt1 = tp1.nTotalSnt;
            LeaveCriticalSection(&tp1.csTotals);
            EnterCriticalSection(&tp2.csTotals);
            nTmpRcv2 = tp2.nTotalRcv;
            nTmpSnt2 = tp2.nTotalSnt;
            LeaveCriticalSection(&tp2.csTotals);

            printf("R1:%-12lu S1:%-12lu R2:%-12lu S2:%-12lu\r",
                        nTmpRcv1, nTmpSnt1, nTmpRcv2, nTmpSnt2);

            // Make sure both workers are still alive
            if (WaitForSingleObject(hThread1, 0) != WAIT_TIMEOUT) {
                  UTIL_Msg("\nWorker1 unexpectedly exited!\n");
                  bDone = TRUE;
            }
            if (WaitForSingleObject(hThread2, 0) != WAIT_TIMEOUT) {
                  UTIL_Msg("\nWorker2 unexpectedly exited!\n");
                  bDone = TRUE;
            }

            Sleep(1000);
      } while (!bDone);

      // User pressed Esc...
      printf("\n\n");

      // Tell the workers to stop
      PostThreadMessage(idThread1, WM_QUIT, 0, 0);
      PostThreadMessage(idThread2, WM_QUIT, 0, 0);

      // Wait for both workers to stop
      aWait[0] = hThread1;
      aWait[1] = hThread2;

      // Wait for the workers to stop
      WaitForMultipleObjects(2, aWait, TRUE, INFINITE);

      CloseHandle(hThread1);
      CloseHandle(hThread2);

      CloseHandle(hCom1);
      CloseHandle(hCom2);
      CloseHandle(ovCom1R.hEvent);
      CloseHandle(ovCom1S.hEvent);
      CloseHandle(ovCom2R.hEvent);
      CloseHandle(ovCom2S.hEvent);

      DeleteCriticalSection(&tp2.csTotals);
      DeleteCriticalSection(&tp1.csTotals);

      return 0;
}

0
 
LVL 3

Expert Comment

by:Stimphy
ID: 11827553
OK.. This may seem a little cheesy, but here are my 2 cents.

Its cheaper than buying or maintaining a 2nd PC.
Its easier to code and debug.

1.  Purchase a 2 or more port serial expansion card ($10-$50) or maybe you have an old one laying around.

Port1 = 9600 restricted application port
port2 = 38400 Satllite port
port3 = 9600 cheese port  

2. Make a 9-pin cable. Full handshake or cross over cable.  Connect one end to Port1 and the other to Port3.

3.  write a program to accept the data from Port2.  In that same program, buffer the info from Port2 and send it out Port3.

4. Now all the data coming into Port2 is automatically sent to Port1 Via Port3!

Simple.

Regaurds,
Dave
0
 
LVL 3

Expert Comment

by:Stimphy
ID: 11827596
By the way... here is some VB6 Code that will do what i described above.

Private Sub Form_Load()
    'May need to change the settings for the ports
    MSComm1.CommPort = 2
    MSComm1.Settings = "38400,N,8,1"
    MSComm1.PortOpen = True
    MSComm2.CommPort = 3
    MSComm2.Settings = "9600,N,8,1"
    MSComm2.PortOpen = True
End Sub

'DO NOT USE A DO EVENTS IN THE LOOP
Private Sub MSComm1_OnComm()
    Dim TempBuff As String
    Do While MSComm1.InBufferCount > 0
        TempBuff = MSComm1.Input
        MSComm2.Output = TempBuff
    Loop
End Sub

'DO NOT USE A DO EVENTS IN THE LOOP
Private Sub MSComm2_OnComm()
    Dim TempBuff As String
    Do While MSComm2.InBufferCount > 0
        TempBuff = MSComm2.Input
        MSComm1.Output = TempBuff
    Loop
End Sub

Regaurds,
Dave
0
 
LVL 11

Expert Comment

by:griessh
ID: 12042895
I think adg provided the solution the way electricd7 wanted it and should get the points.

=====
Werner
0

Featured Post

Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
wefewf 2 42
triangle challenge 4 77
count7 challenge 12 69
delphi parse string to params 3 81
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
Displaying an arrayList in a listView using the default adapter is rarely the best solution. To get full control of your display data, and to be able to refresh it after editing, requires the use of a custom adapter.
An introduction to basic programming syntax in Java by creating a simple program. Viewers can follow the tutorial as they create their first class in Java. Definitions and explanations about each element are given to help prepare viewers for future …
In this fourth video of the Xpdf series, we discuss and demonstrate the PDFinfo utility, which retrieves the contents of a PDF's Info Dictionary, as well as some other information, including the page count. We show how to isolate the page count in a…

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now