Announcement

Collapse
No announcement yet.

Serial Port Control Lines

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Serial Port Control Lines

    I love PowerBASIC and the tech support team. VERY helpful! Now, I want to directly control CTS, RTS, DSR and DTR status lines in an embedded system. Can I do this directly in PB/DLL (and PowerBASIC for DOS) without using third-party software like MarshallSoft stuff? Thanks, everybody!

  • #2
    (Also see the thread in the PB/DOS forum).

    In Windows, you'll need to use the Win32 API to manipulate a comm port. PowerBASIC and libraries such as WSC4PB wrap these API calls into a "programmer friendly" set of functions to make your life easier. While doing this with native PB code is admirable, it's a huge task! If you consider that it will take more than just a few hours to write your own functions (which it will definitely do), then a commercial library for less than US$100 is actually very economic. I do have some raw API code around here somewhere (written by a PB/DLL 5.0 user) that may help you get started.

    I dont mean to be too negative on this, but I've "been there, done that, brought the T-Shirt"...

    Lance
    PowerBASIC Support
    Lance
    mailto:[email protected]

    Comment


    • #3
      Thank you, Lance. You're just great!

      Loren

      Comment


      • #4
        Did you ever find a solution?

        I'm running into a problem right now that
        seems to stem from PowerBASIC opening the
        serial port and THEN setting the control
        line behavior. I'm talking to an instrument
        that resets (and loses all of its data) whenever
        the DTR line goes high. The instrument makers
        programming environment clearly can open the
        serial port without having the DTR go high, but
        PowerBASIC DLL always opens with it high, and then
        lowers it when DTRLINE = %FALSE is set in a following
        COMM SET command. Anyone know how to get PB to
        set the control line behavior before the serial port
        is opened?



        ------------------
        Michael Burns
        Michael Burns

        Comment


        • #5
          I don't know whether this will help you, but the following is some code I put together to open a serial port via the API. It was for PB/CC 1.0 (before the advent of the COMM statements in PB/C 2.0).
          Code:
          FUNCTION OpenPort&(szPort AS ASCIIZ)
              DIM hComm AS LONG, fSuccess AS LONG, CommMask AS LONG
              DIM cDCB AS DCB, ComProp AS COMMPROP, CTO AS COMMTIMEOUTS
              DIM szDCB AS ASCIIZ * 64
              DIM x%
          
              hComm = CreateFile( szPort, _
                                    %GENERIC_READ OR %GENERIC_WRITE, _
                                    BYVAL 0, _
                                    BYVAL 0, _
                                    BYVAL %OPEN_EXISTING, _
                                    BYVAL 0, _
                                    BYVAL 0)
              IF hComm = %INVALID_HANDLE_VALUE OR hComm = %ERROR_FILE_NOT_FOUND THEN
                  PRINT "ComPort Open Error!"
                  EXIT FUNCTION
              END IF
          
              fSuccess = GetCommState(hComm, cdcb)
              IF ISFALSE fSuccess THEN
                  PRINT "ComPort GetState Error!"
                  EXIT FUNCTION
              END IF
          
              szDCB = "19200,n,8,1,p"
              IF ISFALSE BuildCommDCB(szDCB, cdcb) THEN
                  PRINT "BuildCommDCB failure"
                  EXIT FUNCTION
              END IF
          
              cdcb.BaudRate = 19200
              cdcb.ByteSize = 8
              cdcb.Parity   = %NOPARITY
              cdcb.StopBits = %ONESTOPBIT
          
              BIT SET cdcb.fBits,2          ' CTS       (set to 1)
              BIT RESET cdcb.fBits,3        ' DSR       (set to 0)
          
          '$IF 0
              BIT SET cdcb.fBits,4          ' DTR 1/2    (= DTR_CONTROL_ENABLE) (set to 1)
              BIT RESET cdcb.fBits,5        ' DTR 2/2    (= DTR_CONTROL_ENABLE) (set to 0)
          
              BIT SET cdcb.fBits,6          ' DSRSensitivity
              BIT SET cdcb.fbits,7          ' ContinueOnXOFF
          
              BIT RESET cdcb.fBits,8        ' XON/XOFF output (Set to 0)       ' Halts Class 2 XON!!! Force to 0!
              BIT RESET cdcb.fBits,9        ' XON/XOFF input  (Set to 0)
          
              BIT SET cdcb.fBits,12       ' RTS 1/2    (= RTS_CONTROL_ENABLE)
              BIT SET cdcb.fBits,13       ' RTS 2/2    (= RTS_CONTROL_ENABLE)
          '$ENDIF
          
              fSuccess = SetCommState(hComm, cdcb)
              IF ISFALSE fSuccess THEN
                  PRINT "ComPort SetState Error!"
                  EXIT FUNCTION
              END IF
          
          $IF 0
          PRINT "DCB Bits..."
          FOR x% = 0 TO (LEN(cdcb.fbits) -1) * 8
              PRINT BIT(cdcb.fbits,x%);
          NEXT x%
          PRINT
              PRINT "Baud Rate         ", cdcb.BaudRate
              PRINT "ByteSize          ", cdcb.ByteSize
              PRINT "Parity            ", cdcb.Parity
              PRINT "Stop Bits         ", cdcb.StopBits
          
              PRINT "0  fBinary        ", BIT(cdcb.fbits,0)
              PRINT "1  fParity        ", BIT(cdcb.fbits,1)
              PRINT "2  fOutxCtsFlow   ", BIT(cdcb.fbits,2)
              PRINT "3  fOutxDsrFlow   ", BIT(cdcb.fbits,3)
              PRINT "45 fDtrControl    ", BIT(cdcb.fbits,4) BIT(cdcb.fbits,5)
              PRINT "6  fDsrSensitivity", BIT(cdcb.fbits,6)
              PRINT "7  fContinueOnXoff", BIT(cdcb.fbits,7)
              PRINT "8  fOutX          ", BIT(cdcb.fbits,8)
              PRINT "9  fInX           ", BIT(cdcb.fbits,9)
              PRINT "10 fErrorChar     ", BIT(cdcb.fbits,10)
              PRINT "11 fNull          ", BIT(cdcb.fbits,11)
              PRINT "12 fRtsControl    ", BIT(cdcb.fbits,12) BIT(cdcb.fbits,13)
              PRINT "14 fAbortOnError  ", BIT(cdcb.fbits,14)
          WAITKEY$
          $ENDIF
          
              fSuccess = GetCommProperties(hComm, ComProp)
              IF ISFALSE fSuccess THEN
                  PRINT "ComPort GetCommProperties Error!"
                  EXIT FUNCTION
              END IF
          
              IF (ComProp.dwProvCapabilities AND %PCF_RTSCTS) THEN _
                  PRINT "RTS/CTS capable modem detected"
          
              SetupComm hComm, MAX%(%BufferSize,Comprop.dwCurrentRxQueue), MAX%(%BufferSize,Comprop.dwCurrentTxQueue)
              fSuccess = GetCommProperties(hComm, ComProp)
              PRINT "TX Que size =" Comprop.dwCurrentTxQueue
              PRINT "RX Que size =" Comprop.dwCurrentRxQueue
          
              IF ISFALSE (ComProp.dwMaxBaud AND %BAUD_19200) AND ComProp.dwMaxBaud <> %BAUD_USER THEN
                  PRINT "Modem does not support 19200 Baud!"
                  EXIT FUNCTION
              END IF
          
              IF ISFALSE (ComProp.dwProvSubType AND %PST_FAX) THEN
                  PRINT "Modem does not support Fax mode!"
                  EXIT FUNCTION
              END IF
          
              GetCommTimeouts hComm, CTO
              IF ISFALSE (ComProp.dwProvCapabilities AND %PCF_INTTIMEOUTS) THEN
                  PRINT "Modem Timeouts NOT available"
              ELSE
                  CTO.ReadIntervalTimeout = %MAXDWORD
                  CTO.ReadTotalTimeoutMultiplier = 50
                  CTO.ReadTotalTimeoutConstant = 50
                  CTO.WriteTotalTimeoutMultiplier = 1
                  CTO.WriteTotalTimeoutConstant = 20000
          
                  SetCommTimeouts hComm, CTO
              END IF
          
              PurgeComm hComm, %PURGE_TXCLEAR OR %PURGE_RXCLEAR OR %PURGE_TXABORT OR %PURGE_RXABORT
          
          '    sleep 100
              FUNCTION = hComm
          END FUNCTION
          From there you use ReadFile() and WriteFile(), and finally CloseHandle().


          ------------------
          Lance
          PowerBASIC Support
          mailto:[email protected][email protected]</A>
          Lance
          mailto:[email protected]

          Comment


          • #6
            The only thread I could find about setting up all these values is using the old BIT commands...

            I have a need to use WaitCommEvent, but with issues in it blocking the thread as well as the port from having anything done to it so I can abort the wait I have to use example code from CodeProject and http://www.powerbasic.com/support/pb...=WaitCommEvent to create a WinAPI version. For anyone using this with current compilers a better/easier layout is (Hopefully this will make it to .06 builds):

            Code:
            Type DCBnew
              DCBlength As Dword
              BaudRate As Dword
              fBinary As Bit * 1 In Dword
              fParity As Bit * 1
              fOutxCtsFlow As Bit * 1
              fOutxDsrFlow As Bit * 1
              fDtrControl As Bit * 2
              fDsrSensitivity As Bit * 1
              fTXContinueOnXoff As Bit * 1
              fOutX As Bit * 1
              fInX As Bit * 1
              fErrorChar As Bit * 1
              fNull As Bit * 1
              fRtsControl As Bit * 2
              fAbortOnError As Bit * 1
              fDummy2 As Bit * 17
              wReserved As Word
              XonLim As Word
              XoffLim As Word
              ByteSize As Byte
              Parity As Byte
              StopBits As Byte
              XonChar As Byte
              XoffChar As Byte
              ErrorChar As Byte
              EofChar As Byte
              EvtChar As Byte
              wReserved2 As Integer
            End Type
            sigpic
            Mobile Solutions
            Sys Analyst and Development

            Comment


            • #7
              Roger,
              but with issues in it blocking the thread
              If something is blocking your thread then a common solution is to create a new thread and run the blocking code in that. The new thread then blocks but the original thread continues.

              as well as the port from having anything done to it
              Isn't that what the lpOverlapped parameter in WaitCommEvent is for?

              Paul.

              Comment


              • #8
                For quite some time now I have been working on and off on my SerialPort.inc file that would make handling the serial port much easier.

                But from my archives (Sorry I do not know who to give credit to, as I found this years ago) is serial port routines to directly control lines (may need some modifications, since I think I got it back in PB6???)

                Anyways, this should help :coffee4:
                Code:
                'enhanced serial port functions including handshake
                'signal manipulation/checking etc.
                '
                'Requires WINAPI32.INC
                '
                'Sets default parameters for COM port
                SUB INITCOMM(HCOM AS LONG,COMMSTR AS STRING)
                    COMM OPEN COMMSTR AS HCOM
                    COMM RESET HCOM,FLOW
                    COMM SET HCOM, BAUD = 9600 ' 9600 baud
                    COMM SET HCOM, BYTE = 8 ' 8 bits
                    COMM SET HCOM, PARITY = 0 ' No parity
                    COMM SET HCOM, STOP = 0 ' 1 stop bit
                    COMM SET HCOM, TXBUFFER = 1024 ' 1k transmit buffer
                    COMM SET HCOM, RXBUFFER = 32768 '32k receive buffer
                END SUB
                'Write single binary byte to COM port
                SUB SERWRTBIN(HCOM AS LONG,DAT AS BYTE)
                    COMM SEND HCOM,CHR$(DAT)
                END SUB
                'Get single binary byte from COM port
                'TOSEC specifies timeout in seconds,error status is returned in SERERR
                'Timeout must guard against midnight rollover for timer
                FUNCTION SERRDBIN(HCOM AS LONG,TOSEC AS LONG,SERERR AS LONG) AS BYTE
                    DIM LL1 AS LONG,LL2 AS LONG,LL3 AS LONG,SS AS STRING
                    LL1=TIMER
                    LL2=(LL1 + TOSEC)-86399
                    IF LL2>0 THEN
                        DO
                            LL3=TIMER
                        LOOP UNTIL LL3<LL1
                        LL1=LL3
                        TOSEC=LL2
                    END IF
                    DO
                        LL2=TIMER
                        LL3=COMM(HCOM,RXQUE)
                    LOOP UNTIL LL2>(LL1+TOSEC) OR LL3>0
                    IF LL2>(LL1+TOSEC) THEN
                        SERERR=255
                        FUNCTION=0
                        EXIT FUNCTION
                    END IF
                    COMM RECV HCOM, 1,SS
                    FUNCTION=ASC(SS)
                END FUNCTION
                'Write string to COM port
                SUB SERWRTSTR(HCOM AS LONG,DAT AS STRING)
                    COMM SEND HCOM,DAT
                END SUB
                'Get received string from COM port
                FUNCTION SERGETSTR(HCOM AS LONG) AS STRING
                    DIM LL AS LONG,SS AS STRING
                    LL=COMM(HCOM,RXQUE)
                    COMM RECV HCOM,LL,SS
                    FUNCTION=SS
                END FUNCTION
                'Get string terminated by linefeed-TOSEC specifies timeout,error status returned in SERERR
                'Linefeed is last byte in string
                FUNCTION SERGETLINESTR(HCOM AS LONG,TOSEC AS LONG,SERERR AS LONG) AS STRING
                    DIM SS AS STRING,BB AS BYTE,LL AS LONG
                    LL=TOSEC
                    SERERR=0
                    SS=""
                    DO
                        BB=SERRDBIN(HCOM,LL,SERERR)
                        SS=SS + CHR$(BB)
                    LOOP UNTIL BB=10 OR SERERR>0
                    FUNCTION=SS
                END FUNCTION
                'Gets single byte string from COM port-TOSEC specifies timeout
                'Error status is returned in SERERR
                FUNCTION SERRDSTR(HCOM AS LONG,TOSEC AS LONG,SERERR AS LONG) AS STRING
                    DIM BB AS BYTE,SS AS STRING
                    BB= SERRDBIN(HCOM,TOSEC,SERERR)
                    FUNCTION=CHR$(BB)
                END FUNCTION
                'Clear receive buffer
                SUB RXCLEAR(HCOM AS LONG)
                    DIM SS AS STRING
                    SS=SERGETSTR(HCOM)
                END SUB
                'SETS RTS
                SUB SETRTS(HCOM AS LONG)
                    DIM APIHCOM AS LONG
                    DIM LL AS LONG
                    APIHCOM=FILEATTR(HCOM,2)
                    LL&=ESCAPECOMMFUNCTION(APIHCOM,%SETRTS)
                END SUB
                'CLEARS RTS
                SUB CLRRTS(HCOM AS LONG)
                    DIM APIHCOM AS LONG
                    DIM LL AS LONG
                    APIHCOM&=FILEATTR(HCOM,2)
                    LL&=ESCAPECOMMFUNCTION(APIHCOM&,%CLRRTS)
                END SUB
                'SETS DTR
                SUB SETDTR(HCOM AS LONG)
                    DIM APIHCOM AS LONG
                    DIM LL AS LONG
                    APIHCOM&=FILEATTR(HCOM,2)
                    LL&=ESCAPECOMMFUNCTION(APIHCOM&,%SETDTR)
                END SUB
                'CLEAR DTR
                SUB CLRDTR(HCOM AS LONG)
                    DIM APIHCOM AS LONG
                    DIM LL AS LONG
                    APIHCOM&=FILEATTR(HCOM,2)
                    LL&=ESCAPECOMMFUNCTION(APIHCOM&,%CLRDTR)
                END SUB
                'ASSERT BREAK
                SUB SETBREAK(HCOM AS LONG)
                    DIM APIHCOM AS LONG
                    DIM LL AS LONG
                    APIHCOM&=FILEATTR(HCOM,2)
                    LL&=ESCAPECOMMFUNCTION(APIHCOM&,%SETBREAK)
                END SUB
                'CLEAR BREAK
                SUB CLRBREAK(HCOM AS LONG)
                    DIM APIHCOM AS LONG
                    DIM LL AS LONG
                    APIHCOM&=FILEATTR(HCOM,2)
                    LL&=ESCAPECOMMFUNCTION(APIHCOM&,%CLRBREAK)
                END SUB
                'GET MODEM STATUS SIGNALS
                FUNCTION GETCOMSTS(HCOM AS LONG)AS LONG
                    DIM APIHCOM AS LONG
                    DIM LL AS LONG
                    DIM STS AS LONG
                    APIHCOM&=FILEATTR(HCOM,2)
                    LL=GETCOMMMODEMSTATUS(APIHCOM&,STS )
                    FUNCTION=STS
                END FUNCTION
                'CHECK CTS
                FUNCTION GETCTS(HCOM AS LONG) AS LONG
                    FUNCTION=GETCOMSTS(HCOM) AND %MS_CTS_ON
                END FUNCTION
                'CHECK DSR
                FUNCTION GETDSR(HCOM AS LONG) AS LONG
                    FUNCTION=GETCOMSTS(HCOM) AND %MS_DSR_ON
                END FUNCTION
                'CHECK CD
                FUNCTION GETCD(HCOM AS LONG) AS LONG
                    FUNCTION=GETCOMSTS(HCOM) AND %MS_RLSD_ON
                END FUNCTION
                'CHECK RING
                FUNCTION GETRING(HCOM AS LONG) AS LONG
                    FUNCTION=GETCOMSTS(HCOM) AND %MS_RING_ON
                END FUNCTION
                '------------------
                Engineer's Motto: If it aint broke take it apart and fix it

                "If at 1st you don't succeed... call it version 1.0"

                "Half of Programming is coding"....."The other 90% is DEBUGGING"

                "Document my code????" .... "WHYYY??? do you think they call it CODE? "

                Comment


                • #9
                  Originally posted by Paul Dixon View Post
                  Roger,
                  ...

                  Isn't that what the lpOverlapped parameter in WaitCommEvent is for?

                  Paul.
                  Yes, but how do you make an overlapped Com Port using internal PB commands? PB's COM and an non-Overlapped CreateFile API both hang when trying to close the port. I even tried things like Setting Break and having WaitCommEvent watch for it too, but it still hung.

                  I created the API version fine now. I have yet to create the needed event and overlapped stuff, but it is fairly quick. Main difference I notice is the API is picky about certain combinations of Stop Bits/Bits Per Byte/Parity and doesn't allow setting them and the PB docs for Com Set don't mention that...haven't tried them, but I'm curious if the calls fail there too or if it corrects them to be valid and re-submits them.
                  sigpic
                  Mobile Solutions
                  Sys Analyst and Development

                  Comment


                  • #10
                    Roger,
                    The PB wrapper functions are GREAT!!! (In most cases), in the few cases that PB did not make easier (For users to learn from, and lets face it "Windows API is quite intimidating" at first look)

                    One thing you will find (if working with multiple serial port devices) is that they each take their own spin on different settings. So be warned that if things work great at first, but years later does not work, then the most likely cause is another device used a setting that you did not think of (or change) when using your own code.

                    By the way...what is it that you are trying to communicate with??? (Simplifies things a lot) :coffee4:
                    Engineer's Motto: If it aint broke take it apart and fix it

                    "If at 1st you don't succeed... call it version 1.0"

                    "Half of Programming is coding"....."The other 90% is DEBUGGING"

                    "Document my code????" .... "WHYYY??? do you think they call it CODE? "

                    Comment


                    • #11
                      Handle thread blocking calls with abort?

                      Put your 'blocking calls' in their own threads of execution and adapt this code:

                      Terminate Worker Threads Using Windows Events (and Using Thread Local Storage) Demo Dec 23 2005
                      Michael Mattias
                      Tal Systems Inc. (retired)
                      Racine WI USA
                      [email protected]
                      http://www.talsystems.com

                      Comment


                      • #12
                        Originally posted by Cliff Nichols View Post
                        Roger,
                        By the way...what is it that you are trying to communicate with??? (Simplifies things a lot) :coffee4:
                        In the end it is going to be a wedge type application to send handheld scanner data to the keyboard. I made it Overlapped and it didn't seem to do much other than not hanging now and still no way of closing the port. Making it overlapped seemed to almost make WaitCommEvent redundant too. I think it would be easier just to do the Readfile Call and a Wait function. Using WaitCommEvent seems to imply I can get my event set by other ways like Breaks and Errors, but I'd think Readfile would set it for those too.

                        A little bit more work to get the data, but I think it will be quicker and less CPU intense to Wait rather than poll. I may combine it with some of the Window code from my other Sendy app I posted here a while back to activate specific windows to give keys to, etc. I'm still debating if I want to monitor more than one COM port too (Other Wedge applications do, but I think the keys have too much of a chance of getting out of sync).
                        sigpic
                        Mobile Solutions
                        Sys Analyst and Development

                        Comment


                        • #13
                          I've got this working pretty slick and fast. Only weird thing I've noticed now is the fParity value doesn't appear to get set with SetCommState. After setting it I can perform a GetCommState and it shows 0. The value itself is a little odd since it is just T/F and there is a Parity value already that has all the types of Parity and None, so fParity isn't really needed.

                          PB's built in COM doesn't appear to use or be able to set it either since I can set parity using it, disconnect, then connect with the API seeing all values set but fParity. Hyper Terminal doesn't have any luck either...so, how was this flag intended to be used?
                          sigpic
                          Mobile Solutions
                          Sys Analyst and Development

                          Comment


                          • #14
                            It looks as though fParity is intended to specify error trapping for parity errors. Whether it does anything at all is at the mercy of the comm driver.

                            Comment


                            • #15
                              Yeah, from the documentation and after going through 50+ pages of Google results the only thing that makes sense is a comment in one of the results about Parity being the type of Parity to send and fParity being if you use it or not on receive. It could be unsupported on the 3 ports/devices I tried it on. Everything seems to work fine though. A 0-1% CPU usage on wait is nice!
                              sigpic
                              Mobile Solutions
                              Sys Analyst and Development

                              Comment

                              Working...
                              X