Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • World
  • Users
  • Groups
Skins
  • Light
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Code Project
  1. Home
  2. General Programming
  3. C / C++ / MFC
  4. Device on RS232 only responds to first send request (Visual C++)

Device on RS232 only responds to first send request (Visual C++)

Scheduled Pinned Locked Moved C / C++ / MFC
c++csharpvisual-studiocomtesting
12 Posts 3 Posters 0 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • D Offline
    D Offline
    David MacKinnon
    wrote on last edited by
    #1

    I have a device (Fluke data logger which uses 9600-8-N-1 and no flow control) for which I need to write an serial interface in Visual Studio 2010 (C++) but have not been able to get more than a single response from the unit. I can connect, send the request for (as an example) device identification, but subsequent requests for data from the unit produce no response (variable read remains equal to zero after each Readfile request). I know the unit works fine because I can use a standard terminal program to obtain the responses I a need. Nothing in the forums here, on MSDN, or repeated Google searches seems to answer my question. This has been frustrating me for more than a week so I am looking for a fresh set of eyes to point out what I am probably missing. This is a stripped-down version of the test code. Any ideas are welcome. For purposes of testing the device response I'm not using overlapping for testing, but will employ overlapping in the "real" code.

    #include "stdafx.h"

    #include #include #include #define STRICT
    #define WIN32_LEAN_AND_MEAN
    #include int _tmain(int argc, _TCHAR* argv[])
    {
    int ch;
    HANDLE screen = GetStdHandle(STD_OUTPUT_HANDLE);

    //---------------------------
    // Get keyboard mode
    printf("Getting keyboard mode\\n");
    HANDLE keyboard = GetStdHandle(STD\_INPUT\_HANDLE);
    DWORD mode;
    if (!GetConsoleMode(keyboard, &mode))
    {
    	printf ("GetConsoleMode failed with error %d.\\n", 
    		GetLastError());
    }
    // Set for raw reading
    printf("Setting keyboard mode\\n");
    mode &= ~ ENABLE\_PROCESSED\_INPUT;
    if (!SetConsoleMode(keyboard, mode))
    {
    	printf ("SetConsoleMode failed with error %d.\\n", 
    		GetLastError());
    }
    
    
    //---------------------------
    // Configure the comm port.
    printf("opening comm port\\n");
    TCHAR \*port\_name = TEXT("COM1"); // Keyspan port
    HANDLE file;
    file = CreateFile(port\_name,
        GENERIC\_READ | GENERIC\_WRITE,
        0, 
        NULL, 
        OPEN\_EXISTING,
        0,
        NULL);
    if ( INVALID\_HANDLE\_VALUE == file) {
    	printf ("CreateFile failed with error %d.\\n", 
    		GetLastError());
    	CloseHandle(file);
        if ( \_kbhit() ) {
            ch = \_getch();
        }
        return 1;
    }
    
    // Get the current DCB.
    printf("Getting com state\\n");
    DCB port;
    SecureZeroMemory(&port, sizeof(port));
    port.DCBlength = sizeof(port);
    if (!GetCommState(file, &port))
    {
    
    J L D 3 Replies Last reply
    0
    • D David MacKinnon

      I have a device (Fluke data logger which uses 9600-8-N-1 and no flow control) for which I need to write an serial interface in Visual Studio 2010 (C++) but have not been able to get more than a single response from the unit. I can connect, send the request for (as an example) device identification, but subsequent requests for data from the unit produce no response (variable read remains equal to zero after each Readfile request). I know the unit works fine because I can use a standard terminal program to obtain the responses I a need. Nothing in the forums here, on MSDN, or repeated Google searches seems to answer my question. This has been frustrating me for more than a week so I am looking for a fresh set of eyes to point out what I am probably missing. This is a stripped-down version of the test code. Any ideas are welcome. For purposes of testing the device response I'm not using overlapping for testing, but will employ overlapping in the "real" code.

      #include "stdafx.h"

      #include #include #include #define STRICT
      #define WIN32_LEAN_AND_MEAN
      #include int _tmain(int argc, _TCHAR* argv[])
      {
      int ch;
      HANDLE screen = GetStdHandle(STD_OUTPUT_HANDLE);

      //---------------------------
      // Get keyboard mode
      printf("Getting keyboard mode\\n");
      HANDLE keyboard = GetStdHandle(STD\_INPUT\_HANDLE);
      DWORD mode;
      if (!GetConsoleMode(keyboard, &mode))
      {
      	printf ("GetConsoleMode failed with error %d.\\n", 
      		GetLastError());
      }
      // Set for raw reading
      printf("Setting keyboard mode\\n");
      mode &= ~ ENABLE\_PROCESSED\_INPUT;
      if (!SetConsoleMode(keyboard, mode))
      {
      	printf ("SetConsoleMode failed with error %d.\\n", 
      		GetLastError());
      }
      
      
      //---------------------------
      // Configure the comm port.
      printf("opening comm port\\n");
      TCHAR \*port\_name = TEXT("COM1"); // Keyspan port
      HANDLE file;
      file = CreateFile(port\_name,
          GENERIC\_READ | GENERIC\_WRITE,
          0, 
          NULL, 
          OPEN\_EXISTING,
          0,
          NULL);
      if ( INVALID\_HANDLE\_VALUE == file) {
      	printf ("CreateFile failed with error %d.\\n", 
      		GetLastError());
      	CloseHandle(file);
          if ( \_kbhit() ) {
              ch = \_getch();
          }
          return 1;
      }
      
      // Get the current DCB.
      printf("Getting com state\\n");
      DCB port;
      SecureZeroMemory(&port, sizeof(port));
      port.DCBlength = sizeof(port);
      if (!GetCommState(file, &port))
      {
      
      J Offline
      J Offline
      jeron1
      wrote on last edited by
      #2

      Have you tried, lengthening your timeouts, or even disabling them (but then you need to read 256 bytes in order to return) ?

      "the debugger doesn't tell me anything because this code compiles just fine" - random QA comment "Facebook is where you tell lies to your friends. Twitter is where you tell the truth to strangers." - chriselst "I don't drink any more... then again, I don't drink any less." - Mike Mullikins uncle

      D 2 Replies Last reply
      0
      • J jeron1

        Have you tried, lengthening your timeouts, or even disabling them (but then you need to read 256 bytes in order to return) ?

        "the debugger doesn't tell me anything because this code compiles just fine" - random QA comment "Facebook is where you tell lies to your friends. Twitter is where you tell the truth to strangers." - chriselst "I don't drink any more... then again, I don't drink any less." - Mike Mullikins uncle

        D Offline
        D Offline
        David MacKinnon
        wrote on last edited by
        #3

        I tried both lengthening the timeouts and rewriting the code using overlapped communication as per bt[^] but the result is the same. First command is received and I can get a response. The second command, while sent without error, is followed by no response. If it helps, after running the code I have to run the terminal program and issue a command twice to get it back to a responsive state. Otherwise running the code twice in a row doesn't even return anything for the first command. It's like it gets stuck waiting after sending the response.

        J 1 Reply Last reply
        0
        • D David MacKinnon

          I tried both lengthening the timeouts and rewriting the code using overlapped communication as per bt[^] but the result is the same. First command is received and I can get a response. The second command, while sent without error, is followed by no response. If it helps, after running the code I have to run the terminal program and issue a command twice to get it back to a responsive state. Otherwise running the code twice in a row doesn't even return anything for the first command. It's like it gets stuck waiting after sending the response.

          J Offline
          J Offline
          jeron1
          wrote on last edited by
          #4

          Could the terminal program be appending and sending a necessary line feed or carraige return, that the other device needs?

          "the debugger doesn't tell me anything because this code compiles just fine" - random QA comment "Facebook is where you tell lies to your friends. Twitter is where you tell the truth to strangers." - chriselst "I don't drink any more... then again, I don't drink any less." - Mike Mullikins uncle

          D 1 Reply Last reply
          0
          • J jeron1

            Could the terminal program be appending and sending a necessary line feed or carraige return, that the other device needs?

            "the debugger doesn't tell me anything because this code compiles just fine" - random QA comment "Facebook is where you tell lies to your friends. Twitter is where you tell the truth to strangers." - chriselst "I don't drink any more... then again, I don't drink any less." - Mike Mullikins uncle

            D Offline
            D Offline
            David MacKinnon
            wrote on last edited by
            #5

            I already append a carriage return (the documentation says either a carriage return or linefeed will be accepted). Even adding extra CRs and LFs has no effect.

            J 1 Reply Last reply
            0
            • D David MacKinnon

              I already append a carriage return (the documentation says either a carriage return or linefeed will be accepted). Even adding extra CRs and LFs has no effect.

              J Offline
              J Offline
              jeron1
              wrote on last edited by
              #6

              Could you connect a PC with a terminal program in place of the device and see what is being sent by your app and make sure it is OK?

              "the debugger doesn't tell me anything because this code compiles just fine" - random QA comment "Facebook is where you tell lies to your friends. Twitter is where you tell the truth to strangers." - chriselst "I don't drink any more... then again, I don't drink any less." - Mike Mullikins uncle

              1 Reply Last reply
              0
              • D David MacKinnon

                I have a device (Fluke data logger which uses 9600-8-N-1 and no flow control) for which I need to write an serial interface in Visual Studio 2010 (C++) but have not been able to get more than a single response from the unit. I can connect, send the request for (as an example) device identification, but subsequent requests for data from the unit produce no response (variable read remains equal to zero after each Readfile request). I know the unit works fine because I can use a standard terminal program to obtain the responses I a need. Nothing in the forums here, on MSDN, or repeated Google searches seems to answer my question. This has been frustrating me for more than a week so I am looking for a fresh set of eyes to point out what I am probably missing. This is a stripped-down version of the test code. Any ideas are welcome. For purposes of testing the device response I'm not using overlapping for testing, but will employ overlapping in the "real" code.

                #include "stdafx.h"

                #include #include #include #define STRICT
                #define WIN32_LEAN_AND_MEAN
                #include int _tmain(int argc, _TCHAR* argv[])
                {
                int ch;
                HANDLE screen = GetStdHandle(STD_OUTPUT_HANDLE);

                //---------------------------
                // Get keyboard mode
                printf("Getting keyboard mode\\n");
                HANDLE keyboard = GetStdHandle(STD\_INPUT\_HANDLE);
                DWORD mode;
                if (!GetConsoleMode(keyboard, &mode))
                {
                	printf ("GetConsoleMode failed with error %d.\\n", 
                		GetLastError());
                }
                // Set for raw reading
                printf("Setting keyboard mode\\n");
                mode &= ~ ENABLE\_PROCESSED\_INPUT;
                if (!SetConsoleMode(keyboard, mode))
                {
                	printf ("SetConsoleMode failed with error %d.\\n", 
                		GetLastError());
                }
                
                
                //---------------------------
                // Configure the comm port.
                printf("opening comm port\\n");
                TCHAR \*port\_name = TEXT("COM1"); // Keyspan port
                HANDLE file;
                file = CreateFile(port\_name,
                    GENERIC\_READ | GENERIC\_WRITE,
                    0, 
                    NULL, 
                    OPEN\_EXISTING,
                    0,
                    NULL);
                if ( INVALID\_HANDLE\_VALUE == file) {
                	printf ("CreateFile failed with error %d.\\n", 
                		GetLastError());
                	CloseHandle(file);
                    if ( \_kbhit() ) {
                        ch = \_getch();
                    }
                    return 1;
                }
                
                // Get the current DCB.
                printf("Getting com state\\n");
                DCB port;
                SecureZeroMemory(&port, sizeof(port));
                port.DCBlength = sizeof(port);
                if (!GetCommState(file, &port))
                {
                
                L Offline
                L Offline
                leon de boer
                wrote on last edited by
                #7

                First housekeeping when you open a comport you really need to put the colon in ... its "COM1:". Yes your string works on some versions of Windows but not all, the documentation spells it out

                To open a serial port
                - Insert a colon after the communication port pointed to with the first parameter, lpzPortName.
                For example, specify COM1: as the communication port.

                In the ReadFile documentation it spells out the blocking function. ReadFile function (Windows)[^] You will have an error which will be a Readtimeout. Why because you set the read timeout to 1 second and execute a read and there won't be any data because you haven't yet sent another command. From that moment on you are toast as your code does not ever clear the error condition and ReadFile will always return with reading zero bytes because you haven't cleared the error. The big obvious is there isn't even a single GetLastError in your code much less dealing with the error. The reason the terminal program fixes the problem is at some point they go and clear the error. You could try brutal and SetLastError to zero just before the ReadFile .. I don't like it but it will probably work :-) While the thread error variable has an error value I am pretty sure that none of the IO functions will work so I am pretty sure WriteFile will also bail always writing zero bytes while it's set. It should also return success but the actual bytes written will always be zero because the fail out is for pre-existing error that hasn't been cleared. I don't particually like the way you are using the com port but probably the easiest way to fix you problem is make the ReadFile timeout bail immediately .. so set no timeout on the read. How to do that is given in the documentation COMMTIMEOUTS structure (Windows)[^] Quote => "A value of MAXDWORD, combined with zero values for both the ReadTotalTimeoutConstant and ReadTotalTimeoutMultiplier members, specifies that the read operation is to return immediately with the bytes that have already been received, even if no b

                D 1 Reply Last reply
                0
                • J jeron1

                  Have you tried, lengthening your timeouts, or even disabling them (but then you need to read 256 bytes in order to return) ?

                  "the debugger doesn't tell me anything because this code compiles just fine" - random QA comment "Facebook is where you tell lies to your friends. Twitter is where you tell the truth to strangers." - chriselst "I don't drink any more... then again, I don't drink any less." - Mike Mullikins uncle

                  D Offline
                  D Offline
                  David MacKinnon
                  wrote on last edited by
                  #8

                  I tried different timeouts and the following work for the first read:

                  CTimeouts.ReadIntervalTimeout = 20;          // msec between bytes arriving
                  CTimeouts.ReadTotalTimeoutMultiplier = 10;   // msec\*bytes = 2560
                  CTimeouts.ReadTotalTimeoutConstant = 100;    // Added to above
                  CTimeouts.WriteTotalTimeoutMultiplier = 0;   //10;  // msec\*bytes = 1280
                  CTimeouts.WriteTotalTimeoutConstant = 0;     //100;
                  

                  I also added a loop using ClearCommError to verify that cbInQue has returned before performing ReadFile so was able to do that as soon as data arrived. Everything in that first request-receipt cycle works fine. I still have the problem that the next WriteFile is essentially ignored, although it is sent without errors. The device appears to be waiting for something after the read was completed before it can respond to whatever is sent on the transmit line.

                  J 1 Reply Last reply
                  0
                  • D David MacKinnon

                    I tried different timeouts and the following work for the first read:

                    CTimeouts.ReadIntervalTimeout = 20;          // msec between bytes arriving
                    CTimeouts.ReadTotalTimeoutMultiplier = 10;   // msec\*bytes = 2560
                    CTimeouts.ReadTotalTimeoutConstant = 100;    // Added to above
                    CTimeouts.WriteTotalTimeoutMultiplier = 0;   //10;  // msec\*bytes = 1280
                    CTimeouts.WriteTotalTimeoutConstant = 0;     //100;
                    

                    I also added a loop using ClearCommError to verify that cbInQue has returned before performing ReadFile so was able to do that as soon as data arrived. Everything in that first request-receipt cycle works fine. I still have the problem that the next WriteFile is essentially ignored, although it is sent without errors. The device appears to be waiting for something after the read was completed before it can respond to whatever is sent on the transmit line.

                    J Offline
                    J Offline
                    jeron1
                    wrote on last edited by
                    #9

                    Does WriteFile say bytes sent > 0? Do you see data on the wire (a breakout box might be handy)? Can you connect a PC with a terminal program in place of the device (with a null modem cable) so you can see (and verify) what, if anything is being sent by your program and manually send the data you expect to get. A scenario where you could set break points and see exactly what code is being executed and the value of the variables.

                    "the debugger doesn't tell me anything because this code compiles just fine" - random QA comment "Facebook is where you tell lies to your friends. Twitter is where you tell the truth to strangers." - chriselst "I don't drink any more... then again, I don't drink any less." - Mike Mullikins uncle

                    D 1 Reply Last reply
                    0
                    • D David MacKinnon

                      I have a device (Fluke data logger which uses 9600-8-N-1 and no flow control) for which I need to write an serial interface in Visual Studio 2010 (C++) but have not been able to get more than a single response from the unit. I can connect, send the request for (as an example) device identification, but subsequent requests for data from the unit produce no response (variable read remains equal to zero after each Readfile request). I know the unit works fine because I can use a standard terminal program to obtain the responses I a need. Nothing in the forums here, on MSDN, or repeated Google searches seems to answer my question. This has been frustrating me for more than a week so I am looking for a fresh set of eyes to point out what I am probably missing. This is a stripped-down version of the test code. Any ideas are welcome. For purposes of testing the device response I'm not using overlapping for testing, but will employ overlapping in the "real" code.

                      #include "stdafx.h"

                      #include #include #include #define STRICT
                      #define WIN32_LEAN_AND_MEAN
                      #include int _tmain(int argc, _TCHAR* argv[])
                      {
                      int ch;
                      HANDLE screen = GetStdHandle(STD_OUTPUT_HANDLE);

                      //---------------------------
                      // Get keyboard mode
                      printf("Getting keyboard mode\\n");
                      HANDLE keyboard = GetStdHandle(STD\_INPUT\_HANDLE);
                      DWORD mode;
                      if (!GetConsoleMode(keyboard, &mode))
                      {
                      	printf ("GetConsoleMode failed with error %d.\\n", 
                      		GetLastError());
                      }
                      // Set for raw reading
                      printf("Setting keyboard mode\\n");
                      mode &= ~ ENABLE\_PROCESSED\_INPUT;
                      if (!SetConsoleMode(keyboard, mode))
                      {
                      	printf ("SetConsoleMode failed with error %d.\\n", 
                      		GetLastError());
                      }
                      
                      
                      //---------------------------
                      // Configure the comm port.
                      printf("opening comm port\\n");
                      TCHAR \*port\_name = TEXT("COM1"); // Keyspan port
                      HANDLE file;
                      file = CreateFile(port\_name,
                          GENERIC\_READ | GENERIC\_WRITE,
                          0, 
                          NULL, 
                          OPEN\_EXISTING,
                          0,
                          NULL);
                      if ( INVALID\_HANDLE\_VALUE == file) {
                      	printf ("CreateFile failed with error %d.\\n", 
                      		GetLastError());
                      	CloseHandle(file);
                          if ( \_kbhit() ) {
                              ch = \_getch();
                          }
                          return 1;
                      }
                      
                      // Get the current DCB.
                      printf("Getting com state\\n");
                      DCB port;
                      SecureZeroMemory(&port, sizeof(port));
                      port.DCBlength = sizeof(port);
                      if (!GetCommState(file, &port))
                      {
                      
                      D Offline
                      D Offline
                      David MacKinnon
                      wrote on last edited by
                      #10

                      Much thanks to all who made suggestions. I implemented many of them. In the end, the problem was solved by "kicking" the device with TransmitCommChar(hComm, 13); after the read request.

                      1 Reply Last reply
                      0
                      • J jeron1

                        Does WriteFile say bytes sent > 0? Do you see data on the wire (a breakout box might be handy)? Can you connect a PC with a terminal program in place of the device (with a null modem cable) so you can see (and verify) what, if anything is being sent by your program and manually send the data you expect to get. A scenario where you could set break points and see exactly what code is being executed and the value of the variables.

                        "the debugger doesn't tell me anything because this code compiles just fine" - random QA comment "Facebook is where you tell lies to your friends. Twitter is where you tell the truth to strangers." - chriselst "I don't drink any more... then again, I don't drink any less." - Mike Mullikins uncle

                        D Offline
                        D Offline
                        David MacKinnon
                        wrote on last edited by
                        #11

                        It ended up that I had to force-transmit a carriage return after the ReadFile to "kick" the device using TransmitCommChar. After the "kick" it responds to the next WriteFile with the appropriate response. Using a second PC was going to be my next course of action.

                        1 Reply Last reply
                        0
                        • L leon de boer

                          First housekeeping when you open a comport you really need to put the colon in ... its "COM1:". Yes your string works on some versions of Windows but not all, the documentation spells it out

                          To open a serial port
                          - Insert a colon after the communication port pointed to with the first parameter, lpzPortName.
                          For example, specify COM1: as the communication port.

                          In the ReadFile documentation it spells out the blocking function. ReadFile function (Windows)[^] You will have an error which will be a Readtimeout. Why because you set the read timeout to 1 second and execute a read and there won't be any data because you haven't yet sent another command. From that moment on you are toast as your code does not ever clear the error condition and ReadFile will always return with reading zero bytes because you haven't cleared the error. The big obvious is there isn't even a single GetLastError in your code much less dealing with the error. The reason the terminal program fixes the problem is at some point they go and clear the error. You could try brutal and SetLastError to zero just before the ReadFile .. I don't like it but it will probably work :-) While the thread error variable has an error value I am pretty sure that none of the IO functions will work so I am pretty sure WriteFile will also bail always writing zero bytes while it's set. It should also return success but the actual bytes written will always be zero because the fail out is for pre-existing error that hasn't been cleared. I don't particually like the way you are using the com port but probably the easiest way to fix you problem is make the ReadFile timeout bail immediately .. so set no timeout on the read. How to do that is given in the documentation COMMTIMEOUTS structure (Windows)[^] Quote => "A value of MAXDWORD, combined with zero values for both the ReadTotalTimeoutConstant and ReadTotalTimeoutMultiplier members, specifies that the read operation is to return immediately with the bytes that have already been received, even if no b

                          D Offline
                          D Offline
                          David MacKinnon
                          wrote on last edited by
                          #12

                          Excellent points and suggestions, and I've implemented much of what you suggested. In the end it turned out the device was waiting for a response from the computer to indicate the read was completed, which I accomplished with a TransmitCommChar. Clunky but it works.

                          1 Reply Last reply
                          0
                          Reply
                          • Reply as topic
                          Log in to reply
                          • Oldest to Newest
                          • Newest to Oldest
                          • Most Votes


                          • Login

                          • Don't have an account? Register

                          • Login or register to search.
                          • First post
                            Last post
                          0
                          • Categories
                          • Recent
                          • Tags
                          • Popular
                          • World
                          • Users
                          • Groups