Page 1 of 2

Send and receive Data from the serial ComPort , no lib

Posted: Wed Jan 14, 2004 5:55 am
by Rings
Code updated for 5.20+. The SerialPort library can handle this as well.

After answering the same boring questions again, i have written these small example how to read and receive Data over the serial Connector(ComPort) with only API's and with a Timer driven non blocking Receiving.
I have written this to test a Modem and its settings (AT-Hayes-Commands)

Feel free to fit your needs .

Rings

Code: Select all

;  ComPort (RS232) example , Write and Read-data, timer driven
;  good for a small terminal or a modem-configurator
;  Windows only, done on january, 14th. 2004
;  Copyright 2004 Siegfried Rings (CodeGuru)
;
OnErrorGoto(?Errorhandling) ;Enable Errorhandling (enable Linenumbering!)

;User Structure for all the ComPort-Stuff
Structure structComport
  Port.l
  Inbuffersize.l
  OutBuffersize.l
  Handle.l
  ct.COMMTIMEOUTS
  dcb.DCB
  Receivebuffer.l
  ReceivebufferLength.l
EndStructure

Enumeration
  #Gadget_TextSend
  #Gadget_TextReceive
  #Gadget_ButtonSend
  #Gadget_ButtonReceive
EndEnumeration

#Win=1
#ReceiveSendbuffer=1
#MaxReceiveBuffer=1024


Procedure.l SR_OpenComPort(*RS232.structComport)
  *RS232\Handle =0
  Device.s="COM"+Str(*RS232\Port)+":"
  Result = CreateFile_(@Device, $C0000000, 0, 0, 3, 0, 0); create and open a existing device/file ;)
  If Result = -1
    MessageRequester("info", "Com Port " + Str(*RS232\Port) + " not available. Use Serial settings (on the main menu) To setup your ports.", 48)
    ProcedureReturn 0
  EndIf
  If Result
    *RS232\Handle=Result
    mydcb.DCB
    If GetCommState_(*RS232\Handle, @mydcb) ;First retrieve the Settings from ComPort
      
      ;Set Baudrate etc.
      mydcb\Baudrate=*RS232\dcb\Baudrate ;Change the Settings to our needs
      mydcb\Bytesize=*RS232\dcb\Bytesize
      mydcb\Parity=*RS232\dcb\Parity
      mydcb\StopBits=*RS232\dcb\StopBits
      Result=SetCommState_(*RS232\Handle, @mydcb) ;and write them back to Comport
      ;Debug "SetCommState="+Str(result)   
      
      Result=SetCommTimeouts_(*RS232\Handle,*RS232\ct) ;set the Timeouts set longer for problems :)
      ;Debug "SetCommTimeouts="+Str(Result)
      
      ;Set In/Outbuffers
      If result
        Result=SetupComm_(*RS232\Handle,*RS232\Inbuffersize,*RS232\Outbuffersize)
      EndIf
    EndIf
  Else
    CloseHandle_(Result)
  EndIf
  ProcedureReturn *RS232\Handle
EndProcedure

Procedure SR_CloseComPort(*RS232.structComport)
  If *RS232\Handle
    CloseHandle_(*RS232\Handle)
    *RS232\Handle=0
  EndIf
EndProcedure

Procedure SR_WriteComPort(*RS232.structComport,Rawdata.l,RawDataLength.l)
  If *RS232\Handle=0
    ProcedureReturn
  EndIf
  Written.l
  Result=WriteFile_(*RS232\Handle,RawData,RawDataLength,@Written,0)  ;WriteData now to ComPort
  FlushFileBuffers_(*RS232\Handle);Release buffer directly
  ProcedureReturn written
EndProcedure

Procedure SR_ReadComPort(*RS232.structComport)
  If *RS232\Handle=0
    ProcedureReturn
  EndIf
  Repeat
    Result=ReadFile_(*RS232\Handle , *RS232\Receivebuffer+Offset, 256, @RetBytes, 0) ;Read content
    If RetBytes>0
      Offset=Offset+RetBytes
    EndIf
  Until RetBytes=0 Or Offset>#MaxReceiveBuffer
  *RS232\ReceivebufferLength=Offset
  ; FlushFileBuffers_(*RS232\Handle);Release buffer directly
  ProcedureReturn Offset
EndProcedure


;- Begin of MainCode

MyRS232.structComport ;set my own Structure For all the ComPorthandling
MyRS232\Port=2
MyRS232\dcb\Baudrate=9600
MyRS232\dcb\Bytesize=8
MyRS232\dcb\StopBits=1 ;#ONESTOPBIT
MyRS232\dcb\Parity=#NOPARITY

MyRS232\Inbuffersize=256 ;size is enough
MyRS232\OutBuffersize=256

MyRS232\ct\ReadIntervalTimeOut =200; in milliseconds '#MAXDWORD
MyRS232\ct\ReadTotalTimeoutMultiplier = 1
MyRS232\ct\ReadTotalTimeoutConstant = 1
MyRS232\ct\WriteTotalTimeoutConstant = 10
MyRS232\ct\WriteTotalTimeoutMultiplier = 1

MyRS232\Receivebuffer=AllocateMemory(#ReceiveSendbuffer,#MaxReceiveBuffer) ;Reserve mem For it
MyRS232\ReceivebufferLength=0


;- Open Window
hwnd=OpenWindow(#Win, 1, 300, 400, 400, "PureBasic Window", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)
If hwnd
  ;- CreateGadgets
  StringGadget(#Gadget_TextSend, 5, 5, 200, 20, "AT")
  EditorGadget(#Gadget_TextReceive, 5, 55, 390, 340)
  ButtonGadget(#Gadget_ButtonSend,210,5,90,20,"Send")
  ButtonGadget(#Gadget_ButtonReceive,305,5,90,20,"Receive")
  
  ;- Setup Timer
  Result=SetTimer_(hwnd,1,100,0) ;Setup our timer For receiveing Data every 100 msecs
  
  ;- Setup and Open Comport
  Result=SR_OpenComPort(MyRS232)
  
  
  ;- Eventloop
  Repeat
    EventID.l = WaitWindowEvent()
    
    ;- Timer-Routine to read Data from ComPort
    If EventID =#WM_TIMER
      If MyRS232\Handle<>0
        Readed=SR_ReadComPort(MyRS232)
        If MyRS232\ReceiveBufferlength>0
          Buffer.s=Buffer.s+PeekS(MyRS232\ReceiveBuffer,MyRS232\ReceiveBufferlength)
          SetGadgetText(#Gadget_TextReceive,Buffer.s)
          MyRS232\ReceiveBufferlength=0
        EndIf
      EndIf
    EndIf
    
    If EventID =#PB_Event_Gadget
      GadgetNR = EventGadget()
      
      ;- Send Data to Comport
      If GadgetNR =#Gadget_ButtonSend
        SendText.s=GetGadgetText(#Gadget_TextSend) + Chr(13) ;add a CarriageReturn to send to modem
        ;Debug SendText
        Buffer.s=""
        SetGadgetText(#Gadget_TextReceive,Buffer.s);Reset inbuffer gadget
        Result=SR_WriteComPort(MyRS232,@SendText.s,Len(SendText.s)); Check Modem
        Debug "Characters sended:"+Str(Result)
      EndIf
      
      ;- Read Data from Comport
      If GadgetNR=#Gadget_ButtonReceive
        Readed=SR_ReadComPort(MyRS232) ; Read Incoming
        If Readed
          Debug "Characters readed="+Str(Readed)
          Buffer.s=Buffer.s+PeekS(MyRS232\ReceiveBuffer,MyRS232\ReceiveBufferlength)
          SetGadgetText(#Gadget_TextReceive,Buffer.s)
          MyRS232\ReceiveBufferlength=0 ;Shorten buffer now
        EndIf
      EndIf
    EndIf
    
  Until EventID = #PB_Event_CloseWindow
EndIf
SR_CloseComPort(MyRS232) ;Comport Close
End 

;- Error-handler
Errorhandling:
MessageRequester("Error","in line "+Str(ErrorLine() ),0)
End

Posted: Wed Jan 14, 2004 11:39 pm
by blueznl
rings, you're the greatest, snippets are *always* welcome :-)

Re: Send and receive Data from the serial ComPort , no lib

Posted: Wed Oct 11, 2006 5:12 pm
by NoahPhense
Hey Rings,

I'm at work and don't have the ability to pump this into 4.0, do you think
this will go with a little conversion?

- np

Re: Send and receive Data from the serial ComPort , no lib

Posted: Fri Oct 13, 2006 7:38 pm
by NoahPhense
Ok, I've converted this to 4.0.. works nice.

But I want to add in an Append ..

Code: Select all

Procedure AppendFile(FileName.s, String.s)
  If OpenFile(Fn, FileName.s) 
      FileSeek(Fn, Lof(Fn)) 
      WriteStringN(Fn, String) 
      CloseFile(Fn) 
  EndIf
EndProcedure
But when I add it in to the end of the timer loop, it doesn't work well.

Any ideas?

- np

Posted: Tue Oct 24, 2006 12:33 am
by Intrigued
Can you post the PB 4.0 version, or would you be so kind as to post such?

TIA

RS232 loop back connector - There are several, which do you guys recommend I use for testing. (otherwise I have to drag the client's register home soon, I only want to do that one night, when I do the final test, if possible ;-))

Posted: Sun Oct 29, 2006 4:46 pm
by NoahPhense
Intrigued wrote:Can you post the PB 4.0 version, or would you be so kind as to post such?

TIA

RS232 loop back connector - There are several, which do you guys recommend I use for testing. (otherwise I have to drag the client's register home soon, I only want to do that one night, when I do the final test, if possible ;-))
I basically just converted the code above, there were only a few keywords
that needed changing.

I had a pretty tight deadline, so I ended up using VB with Crystal Reports.

I might come back to this at a later time. Because I like the tight code
that can be used to talk with the serial port.

- np

Posted: Sun Oct 29, 2006 11:53 pm
by Intrigued
Sounds good. I'm about to continue with an application and I will need to "talk with" a cash register via RS232. So any help or direction, resources you can suggest I review... would be much appreciated. I am strictly using PB 4 now for what it's worth.

TIA (and for the follow-up)

ps. I have installed the MVCOM plugin and am looking that over. It seems like it would not be to hard to work with. I will need to take data from the cash register and then add such to a SQLite 2.8 database (2.8 is what is supported in a project I am working on). Getting the data from the cash register (my first time attempting RS232) is the biggest step for me. After I get the data into a file I should be good to go and thus be able to add the data into the SQLite database and then process the data as needed.

Posted: Mon Oct 30, 2006 9:01 am
by Rings
holy cow, only 4 lines to change for PB4:

Code: Select all

;  ComPort (RS232) example , Write and Read-data, timer driven
;  good for a small terminal or a modem-configurator
;  Windows only, done on january, 14th. 2004
;  updated for PB4.x october 2006
;  Copyright 2004/2006 Siegfried Rings (CodeGuru)
;
OnErrorGoto(?Errorhandling) ;Enable Errorhandling (enable Linenumbering!)

;User Structure for all the ComPort-Stuff
Structure structComport
 Port.l
 Inbuffersize.l
 OutBuffersize.l
 Handle.l
 ct.COMMTIMEOUTS
 dcb.DCB
 Receivebuffer.l
 ReceivebufferLength.l
EndStructure

Enumeration
 #Gadget_TextSend
 #Gadget_TextReceive
 #Gadget_ButtonSend
 #Gadget_ButtonReceive
EndEnumeration

#Win=1
;#ReceiveSendbuffer=1
#MaxReceiveBuffer=1024


Procedure.l SR_OpenComPort(*RS232.structComport)
 *RS232\Handle =0
 Device.s="COM"+Str(*RS232\Port)+":"
 Result = CreateFile_(@Device, $C0000000, 0, 0, 3, 0, 0); create and open a existing device/file ;)
 If Result = -1
  MessageRequester("info", "Com Port " + Str(*RS232\Port) + " not available. Use Serial settings (on the main menu) To setup your ports.", 48)
  ProcedureReturn 0
 EndIf
 If Result
  *RS232\Handle=Result
  mydcb.DCB
  If GetCommState_(*RS232\Handle, @mydcb) ;First retrieve the Settings from ComPort

   ;Set Baudrate etc.
   mydcb\Baudrate=*RS232\dcb\Baudrate ;Change the Settings to our needs
   mydcb\Bytesize=*RS232\dcb\Bytesize
   mydcb\Parity=*RS232\dcb\Parity
   mydcb\StopBits=*RS232\dcb\StopBits
   Result=SetCommState_(*RS232\Handle, @mydcb) ;and write them back to Comport
   ;Debug "SetCommState="+Str(result)   

   Result=SetCommTimeouts_(*RS232\Handle,*RS232\ct) ;set the Timeouts set longer for problems :)
   ;Debug "SetCommTimeouts="+Str(Result)

   ;Set In/Outbuffers
   If result
    Result=SetupComm_(*RS232\Handle,*RS232\Inbuffersize,*RS232\Outbuffersize)
   EndIf
  EndIf
 Else
  CloseHandle_(Result)
 EndIf
 ProcedureReturn *RS232\Handle
EndProcedure

Procedure SR_CloseComPort(*RS232.structComport)
 If *RS232\Handle
  CloseHandle_(*RS232\Handle)
  *RS232\Handle=0
 EndIf
EndProcedure

Procedure SR_WriteComPort(*RS232.structComport,Rawdata.l,RawDataLength.l)
 If *RS232\Handle=0
  ProcedureReturn
 EndIf
 Written.l
 Result=WriteFile_(*RS232\Handle,RawData,RawDataLength,@Written,0)  ;WriteData now to ComPort
 FlushFileBuffers_(*RS232\Handle);Release buffer directly
 ProcedureReturn written
EndProcedure

Procedure SR_ReadComPort(*RS232.structComport)
 If *RS232\Handle=0
  ProcedureReturn
 EndIf
 Repeat
  Result=ReadFile_(*RS232\Handle , *RS232\Receivebuffer+Offset, 256, @RetBytes, 0) ;Read content
  If RetBytes>0
   Offset=Offset+RetBytes
  EndIf
 Until RetBytes=0 Or Offset>#MaxReceiveBuffer
 *RS232\ReceivebufferLength=Offset
; FlushFileBuffers_(*RS232\Handle);Release buffer directly
 ProcedureReturn Offset
EndProcedure


;- Begin of MainCode

 MyRS232.structComport ;set my own Structure For all the ComPorthandling
 MyRS232\Port=1
 MyRS232\dcb\Baudrate=9600
 MyRS232\dcb\Bytesize=8
 MyRS232\dcb\StopBits=1 ;#ONESTOPBIT
 MyRS232\dcb\Parity=#NOPARITY
 
 MyRS232\Inbuffersize=256 ;
 MyRS232\OutBuffersize=256
 
 MyRS232\ct\ReadIntervalTimeOut =200; in milliseconds '#MAXDWORD
 MyRS232\ct\ReadTotalTimeoutMultiplier = 1
 MyRS232\ct\ReadTotalTimeoutConstant = 1
 MyRS232\ct\WriteTotalTimeoutConstant = 10
 MyRS232\ct\WriteTotalTimeoutMultiplier = 1
   
 MyRS232\Receivebuffer=AllocateMemory(#MaxReceiveBuffer) ;Reserve mem For it
 MyRS232\ReceivebufferLength=0


;- Open Window
hwnd=OpenWindow(#Win, 1, 300, 400, 400,"PureBasic SerialPortDemo Window", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)
If hwnd
 If CreateGadgetList(WindowID(#Win))

  ;- CreateGadgets
  StringGadget(#Gadget_TextSend, 5, 5, 200, 20, "AT")
  ;StringGadget(#Gadget_TextReceive, 5, 55, 390, 340, "",#PB_String_Multiline  )
  EditorGadget(#Gadget_TextReceive,5, 55, 390, 340)
  ButtonGadget(#Gadget_ButtonSend,210,5,90,20,"Send")
  ButtonGadget(#Gadget_ButtonReceive,305,5,90,20,"Receive")

  ;- Setup Timer
  Result=SetTimer_(hwnd,1,100,0) ;Setup our timer For receiveing Data every 100 msecs

  ;- Setup and Open Comport
  Result=SR_OpenComPort(MyRS232)
 
 
  ;- Eventloop
  Repeat
   EventID.l = WaitWindowEvent()
 
   ;- Timer-Routine to read Data from ComPort
   If EventID =#WM_TIMER
     If MyRS232\Handle<>0
       Readed=SR_ReadComPort(MyRS232)
      If MyRS232\ReceiveBufferlength>0
        Buffer.s=Buffer.s+PeekS(MyRS232\ReceiveBuffer,MyRS232\ReceiveBufferlength)
        SetGadgetText(#Gadget_TextReceive,Buffer.s)
        MyRS232\ReceiveBufferlength=0
      EndIf
     EndIf
   EndIf
 
   If EventID =#PB_Event_Gadget
     GadgetNR = EventGadget()
     
     ;- Send Data to Comport
     If GadgetNR =#Gadget_ButtonSend
      SendText.s=GetGadgetText(#Gadget_TextSend) + Chr(13) ;add a CarriageReturn to send to modem
      ;Debug SendText
      Buffer.s=""
      SetGadgetText(#Gadget_TextReceive,Buffer.s);Reset inbuffer gadget
      Result=SR_WriteComPort(MyRS232,@SendText.s,Len(SendText.s)); Check Modem
      Debug "Characters sended:"+Str(Result)
     EndIf

     ;- Read Data from Comport
     If GadgetNR=#Gadget_ButtonReceive
      Readed=SR_ReadComPort(MyRS232) ; Read Incoming
      If Readed
       Debug "Characters readed="+Str(Readed)
       Buffer.s=Buffer.s+PeekS(MyRS232\ReceiveBuffer,MyRS232\ReceiveBufferlength)
       SetGadgetText(#Gadget_TextReceive,Buffer.s)
       MyRS232\ReceiveBufferlength=0 ;Shorten buffer now
      EndIf
     EndIf
   EndIf
   
  Until EventID = #PB_Event_CloseWindow
 EndIf
EndIf
SR_CloseComPort(MyRS232) ;Comport Close
End 

;- Error-handler
Errorhandling:
 MessageRequester("Error","in line "+Str(GetErrorLineNR() ),0)
 End

Posted: Mon Oct 30, 2006 3:04 pm
by Intrigued
Thanks Rings for your time on this one. Now I just need to take the guy's register home where I can practice. I can see it now... my neighbors saying (as I bring the register into my house), "doesn't he know this is not a commercially zoned area?".

(and thanks to MV's Mark for the condensed sample code offering he offered in another thread, for reading, writing the RS232 data!)

:wink:

Posted: Wed Nov 01, 2006 10:55 am
by Marc
If you need some help, please contact me...

Regards

Posted: Wed Nov 01, 2006 9:43 pm
by Intrigued
Marc wrote:If you need some help, please contact me...

Regards
Thank you very much Mark. I may need too. I'm just waiting for my client to get the specific serial adapter cable for his Register. I'll post back how I'm coming along, or if I get stuck.

Thanks again, it's really appreciated!

Posted: Wed Nov 01, 2006 11:24 pm
by Marc
You may also need the Communication Specification (Protocol) of the Register.

Regards

Posted: Thu Nov 02, 2006 3:15 am
by Intrigued
Marc wrote:You may also need the Communication Specification (Protocol) of the Register.

Regards
I'll check his manual (he printed off the .PDF) for this information. Thanks for the headsup. I hope he gets that cable in... I'm ready to roll.

Question

Posted: Tue Jan 30, 2007 4:12 pm
by Lee87073
On trying this example recieved chars not in ascii ,is that unicode?, viewed my device with hyperterminal, then example recieves in ascii
have tried PB_Ascii flag on PeekS,still have to coneect with hyperterminal first to get required ascii?

Posted: Tue Jan 30, 2007 4:32 pm
by NoahPhense
Thanks Rings..

I even got me a USB to Serial cable for testing. Cause my new LT doesn't
have the serial ports.. ;)

- np