Page 1 of 1
Reading Serial Port
Posted: Mon Oct 17, 2005 10:46 am
by mlwhitt
I know that PureBasic doesn't natively support serial communications, but I was wondering if anyone had any sample code where they used PureBasic to access the Windows API to read from a RS-232 connection.
I have a sensor that I need to access thru the Com Port. I don't need to write to it, just read the data the sensor is sending. I do know that for this device that it may not work if I have Flow Control enabled.
If anyone can help me it will be great appreciated.
Thanks.
Hello
Posted: Mon Oct 17, 2005 12:01 pm
by DominiqueB
Here is a library built for managing the rs232 port:
http://perso.wanadoo.fr/marc.vitry/purebasic
Posted: Mon Oct 17, 2005 12:06 pm
by mlwhitt
Thank you I will check it out. My French isn't that good so I might have to ask for some more help. But I think this will help.
Posted: Mon Oct 17, 2005 2:17 pm
by dracflamloc
[removed]
Posted: Mon Oct 17, 2005 2:17 pm
by TerryHough
There is likely something in my code available at
http://elfecc.no-ip.info/purebasic/inde ... erialPorts
that will help you.
Posted: Tue Oct 18, 2005 2:30 pm
by Baldrick
Here is a bit of code you may like to take a quick look at.
It may be a bit rough as I have pretty much cut & pasted from another app I have made. I have also placed the connection, Rx, etc stuff into procedures to hopefully make it easy for you to work out.
It was written using the MVCom lib DominiqueB posted you about earlier.
Hope this might help you just a little.
Code: Select all
;
; MVCom lib required for this code to work.
; Tested using Null modem cable configuration to defeat handshaking
; Db9 @ pc: p2-Rx to Tx on device, p5-gnd to gnd on device,p1p4p6- linked together on Db9
; hope this helps a little For you...
; Regards, Baldrick :)
#winw=500:#winh=400:#winx = 0:#winy= 0:pgmname.s="Quick Rs232 ComPort Connect / Receive"
Enumeration
#mainWindow
#Menu1
#Mexit
#Container1
#Connect
#Disconnect
#DataScreen
#StatusBar
EndEnumeration
MyConnection$="COM1:9600,N,8,1" ; set this string to reflect your desired ComPort settings
Procedure Inserteditortext(editorgadget,results$)
ProcedureReturn SendMessage_(GadgetID(editorgadget),#EM_REPLACESEL,0,results$)
EndProcedure
Procedure Connect(PortDesc$)
Connection=ComOpen(PortDesc$,0,256,256); handshake set as "none", in & out buffers work fine
If Connection<1 ; with a value of 1 in my tests
MessageRequester("Connection Fail","Please check ComPort settings & try again",16)
EndIf
ProcedureReturn Connection ; this will be comportId - 0 if fail
EndProcedure
Procedure Disconnect(Connection)
If Connection
ComClose(Connection)
Connection=0
EndIf
ProcedureReturn Connection ; 0 = successfully closed comport
EndProcedure
Procedure.s Rx(Connection)
cominput$="" ; must always give the cominput string a value else it will fail to retrieve
If Connection ; any data. - A small bug in the MVCOM lib
While ComInputBufferCount(Connection) ;if data in buffer
If ComInput(Connection,cominput$) ; retrieve data from buffer
inputconversion=Asc(cominput$) ; not sure why, but I have always had to do this
Rx$=Chr(inputconversion) ; to get correct character return ??
Debug cominput$
ProcedureReturn Rx$
EndIf
Wend
EndIf
EndProcedure
mainwin.l = OpenWindow(#mainWindow,#winx,#winy,#winw,#winh,#PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_SizeGadget | #PB_Window_MaximizeGadget | #PB_Window_ScreenCentered,pgmname)
If mainwin
CreateMenu(#Menu1, mainwin)
MenuTitle("&File")
MenuItem(#Mexit, "&Exit"):AddKeyboardShortcut(#mainWindow,#PB_Shortcut_Escape ,#Mexit)
CreateGadgetList(mainwin)
ContainerGadget(#Container1,10,10,10,10,#PB_Container_Flat)
ButtonGadget(#Connect,70,10,50,20,"Connect")
ButtonGadget(#Disconnect,130,10,60,20,"Disconnect")
EditorGadget(#Datascreen,10,70,80,20)
CloseGadgetList()
If CreateStatusBar(#Statusbar,mainwin)
StatusBarText(#StatusBar,0, "Not Connected: "+MyConnection$)
EndIf
EndIf
Repeat
EventId.l=WindowEvent()
timer+1:If timer>100:timer=0:Delay(1):Else:Delay(0):EndIf
Win1Width = WindowWidth():Win1Height = WindowHeight()
If win1Width<>win1WidthA Or Win1Height<>Win1HeightA
ResizeGadget(#Container1, 10, 10, win1Width-20, win1Height-55)
ResizeGadget(#DataScreen,10,40, win1Width-55,win1height-125)
win1widthA=win1width:Win1HeightA=Win1Height
EndIf
If Myconnection ; if connection is open
MyDat$=Rx(Myconnection) ;look to see if anything received
insert$=insert$+MyDat$
If MyDat$=Chr(10) ; do something with retrieved data
inserteditortext(#Datascreen,insert$); in this case when "Line feed" character, insert string
insert$="" ; into editor gadget, then reset string to""
EndIf
EndIf
If EventId=#PB_EventMenu
Select EventMenuID()
Case #MExit
quit=1
EndSelect
EndIf
If EventId=#PB_EventGadget
Select EventGadgetID()
Case #Connect
Myconnection=Connect(MyConnection$)
If Myconnection
StatusBarText(#StatusBar,0, "Connected: "+MyConnection$)
EndIf
Debug "If Connection > 0 ComPort is open - "+Str(MyConnection)
Case #Disconnect
Myconnection=Disconnect(Myconnection)
If Myconnection=0
StatusBarText(#StatusBar,0, "Not Connected: "+MyConnection$)
EndIf
Debug " If Connection = 0, comport is closed - "+Str(MyConnection)
EndSelect
EndIf
If eventid=#PB_Event_CloseWindow:quit=1:EndIf
Until quit=1
If Myconnection ; if connection is still open, then close it to be sure to free memory
Debug "Connection "+Str(Myconnection)+" still open ,now closing"
Myconnection=Disconnect(Myconnection)
Debug "Connection: "+Str(Myconnection)
Debug "You should disconnect before closing window"
EndIf
End
Posted: Wed Oct 19, 2005 3:54 am
by mlwhitt
Baldrick,
Thanks for the example, It will tell me it's connected but I am still not getting any output but I can put a sniffer on the port and see that there is output from the sensor. Maybe I am doing something wrong. Thanks for the code, I will look further into it.
Baldrick wrote:Here is a bit of code you may like to take a quick look at.
It may be a bit rough as I have pretty much cut & pasted from another app I have made. I have also placed the connection, Rx, etc stuff into procedures to hopefully make it easy for you to work out.
It was written using the MVCom lib DominiqueB posted you about earlier.
Hope this might help you just a little.
Code: Select all
;
; MVCom lib required for this code to work.
; Tested using Null modem cable configuration to defeat handshaking
; Db9 @ pc: p2-Rx to Tx on device, p5-gnd to gnd on device,p1p4p6- linked together on Db9
; hope this helps a little For you...
; Regards, Baldrick :)
#winw=500:#winh=400:#winx = 0:#winy= 0:pgmname.s="Quick Rs232 ComPort Connect / Receive"
Enumeration
#mainWindow
#Menu1
#Mexit
#Container1
#Connect
#Disconnect
#DataScreen
#StatusBar
EndEnumeration
MyConnection$="COM1:9600,N,8,1" ; set this string to reflect your desired ComPort settings
Procedure Inserteditortext(editorgadget,results$)
ProcedureReturn SendMessage_(GadgetID(editorgadget),#EM_REPLACESEL,0,results$)
EndProcedure
Procedure Connect(PortDesc$)
Connection=ComOpen(PortDesc$,0,256,256); handshake set as "none", in & out buffers work fine
If Connection<1 ; with a value of 1 in my tests
MessageRequester("Connection Fail","Please check ComPort settings & try again",16)
EndIf
ProcedureReturn Connection ; this will be comportId - 0 if fail
EndProcedure
Procedure Disconnect(Connection)
If Connection
ComClose(Connection)
Connection=0
EndIf
ProcedureReturn Connection ; 0 = successfully closed comport
EndProcedure
Procedure.s Rx(Connection)
cominput$="" ; must always give the cominput string a value else it will fail to retrieve
If Connection ; any data. - A small bug in the MVCOM lib
While ComInputBufferCount(Connection) ;if data in buffer
If ComInput(Connection,cominput$) ; retrieve data from buffer
inputconversion=Asc(cominput$) ; not sure why, but I have always had to do this
Rx$=Chr(inputconversion) ; to get correct character return ??
Debug cominput$
ProcedureReturn Rx$
EndIf
Wend
EndIf
EndProcedure
mainwin.l = OpenWindow(#mainWindow,#winx,#winy,#winw,#winh,#PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_SizeGadget | #PB_Window_MaximizeGadget | #PB_Window_ScreenCentered,pgmname)
If mainwin
CreateMenu(#Menu1, mainwin)
MenuTitle("&File")
MenuItem(#Mexit, "&Exit"):AddKeyboardShortcut(#mainWindow,#PB_Shortcut_Escape ,#Mexit)
CreateGadgetList(mainwin)
ContainerGadget(#Container1,10,10,10,10,#PB_Container_Flat)
ButtonGadget(#Connect,70,10,50,20,"Connect")
ButtonGadget(#Disconnect,130,10,60,20,"Disconnect")
EditorGadget(#Datascreen,10,70,80,20)
CloseGadgetList()
If CreateStatusBar(#Statusbar,mainwin)
StatusBarText(#StatusBar,0, "Not Connected: "+MyConnection$)
EndIf
EndIf
Repeat
EventId.l=WindowEvent()
timer+1:If timer>100:timer=0:Delay(1):Else:Delay(0):EndIf
Win1Width = WindowWidth():Win1Height = WindowHeight()
If win1Width<>win1WidthA Or Win1Height<>Win1HeightA
ResizeGadget(#Container1, 10, 10, win1Width-20, win1Height-55)
ResizeGadget(#DataScreen,10,40, win1Width-55,win1height-125)
win1widthA=win1width:Win1HeightA=Win1Height
EndIf
If Myconnection ; if connection is open
MyDat$=Rx(Myconnection) ;look to see if anything received
insert$=insert$+MyDat$
If MyDat$=Chr(10) ; do something with retrieved data
inserteditortext(#Datascreen,insert$); in this case when "Line feed" character, insert string
insert$="" ; into editor gadget, then reset string to""
EndIf
EndIf
If EventId=#PB_EventMenu
Select EventMenuID()
Case #MExit
quit=1
EndSelect
EndIf
If EventId=#PB_EventGadget
Select EventGadgetID()
Case #Connect
Myconnection=Connect(MyConnection$)
If Myconnection
StatusBarText(#StatusBar,0, "Connected: "+MyConnection$)
EndIf
Debug "If Connection > 0 ComPort is open - "+Str(MyConnection)
Case #Disconnect
Myconnection=Disconnect(Myconnection)
If Myconnection=0
StatusBarText(#StatusBar,0, "Not Connected: "+MyConnection$)
EndIf
Debug " If Connection = 0, comport is closed - "+Str(MyConnection)
EndSelect
EndIf
If eventid=#PB_Event_CloseWindow:quit=1:EndIf
Until quit=1
If Myconnection ; if connection is still open, then close it to be sure to free memory
Debug "Connection "+Str(Myconnection)+" still open ,now closing"
Myconnection=Disconnect(Myconnection)
Debug "Connection: "+Str(Myconnection)
Debug "You should disconnect before closing window"
EndIf
End
Posted: Wed Oct 19, 2005 1:24 pm
by Baldrick
mlwhitt,
Hope this doesnt sound too obvious, but have you tried an emulator program such as "HyperTerminal" with your sensor?
That is how I would normally start with a project requiring Rs232 communications. When you know your device is communicating with your computer using your emulator then you straight away know that cables, etc are correct and you can start looking into your code from there.
Posted: Wed Oct 19, 2005 4:18 pm
by mlwhitt
Baldrick,
Actually I have confirmed it with the bundled application, and a couple different terminal programs. It is working. It is sending the tempature correctly. So I am sure the cables and all are working correctly. Thanks for the tip though.
Baldrick wrote:mlwhitt,
Hope this doesnt sound too obvious, but have you tried an emulator program such as "HyperTerminal" with your sensor?
That is how I would normally start with a project requiring Rs232 communications. When you know your device is communicating with your computer using your emulator then you straight away know that cables, etc are correct and you can start looking into your code from there.
Posted: Thu Oct 20, 2005 12:37 am
by woki
Here simple code snippets to do com port with windows api calls.
Hope that helps.
Code: Select all
;r = CreateFile_("COM1:",#GENERIC_READ | GENERIC_WRITE,0,#NULL,#OPEN_EXISTING,0,#NULL)
devCB.DCB
r = OpenFile(0,"COM2:")
; use this to verify com port
If r
If GetCommState_(r,devCB)
SomeResults.s = "Baud rate = "+Str(devCB\BaudRate)+Chr(10)
SomeResults = SomeResults + "Data Bits = "+Str(devCB\ByteSize)+Chr(10)
SomeResults = SomeResults + "Parity = "+Str(devCB\Parity)+" (0-4=no,odd,even,mark,space)"+Chr(10)
SomeResults = SomeResults + "Stop Bits = "+Str(devCB\StopBits)+" (0,1,2 = 1, 1.5, 2)"+Chr(10)
MessageRequester("COM Port Test",SomeResults,0)
Else
MessageRequester("COM Port Test","Couldn't get COM port settings",0)
EndIf
Else
MessageRequester("COM Port Test","Couldn't open COM port",0)
EndIf
End
; use this to set com port
Comsettings$ ="19200,n,8,1"
retval = BuildCommDCB_(Comsettings$, devCB)
retval = SetCommState_(r, devCB)
FlushFileBuffers_(r)
; use this to read com port
Structure rx
byte1.b
byte2.b
byte3.b
EndStructure
*prx.rx = @rx
rbytes = 0 ;Bytes recived
ret = ReadFile_(r, *prx.rx, rxbytes, @rbytes, 0)
; r = handle of file to read
; *prx.rx = address of buffer that receives Data (structure for example)
; rxbytes = number of bytes to read
; @rbytes = address of number of bytes read
; close com port
ret = CloseHandle_(r)
; here the full structure of devCB.DCB (W32 programmers reference)
; perhaps you need to adjust your flow control
; typedef struct _DCB { // dcb
;
; DWORD DCBlength; // sizeof(DCB)
; DWORD BaudRate; // current baud rate
; DWORD fBinary: 1; // binary mode, no EOF check
; DWORD fParity: 1; // enable parity checking
; DWORD fOutxCtsFlow:1; // CTS output flow control
; DWORD fOutxDsrFlow:1; // DSR output flow control
; DWORD fDtrControl:2; // DTR flow control type
; DWORD fDsrSensitivity:1; // DSR sensitivity
; DWORD fTXContinueOnXoff:1; // XOFF continues Tx
;
; DWORD fOutX: 1; // XON/XOFF out flow control
; DWORD fInX: 1; // XON/XOFF in flow control
; DWORD fErrorChar: 1; // enable error replacement
; DWORD fNull: 1; // enable null stripping
; DWORD fRtsControl:2; // RTS flow control
; DWORD fAbortOnError:1; // abort reads/writes on error
; DWORD fDummy2:17; // reserved
; WORD wReserved; // not currently used
; WORD XonLim; // transmit XON threshold
;
; WORD XoffLim; // transmit XOFF threshold
; BYTE ByteSize; // number of bits/byte, 4-8
; BYTE Parity; // 0-4=no,odd,even,mark,space
; BYTE StopBits; // 0,1,2 = 1, 1.5, 2
; char XonChar; // Tx and Rx XON character
; char XoffChar; // Tx and Rx XOFF character
; char ErrorChar; // error replacement character
; char EofChar; // end of input character
; char EvtChar; // received event character
;
; WORD wReserved1; // reserved; do not use
; } DCB;
Posted: Thu Oct 20, 2005 1:42 am
by mlwhitt
Thanks, I will check this out right now.
woki wrote:Here simple code snippets to do com port with windows api calls.
Hope that helps.
Code: Select all
;r = CreateFile_("COM1:",#GENERIC_READ | GENERIC_WRITE,0,#NULL,#OPEN_EXISTING,0,#NULL)
devCB.DCB
r = OpenFile(0,"COM2:")
; use this to verify com port
If r
If GetCommState_(r,devCB)
SomeResults.s = "Baud rate = "+Str(devCB\BaudRate)+Chr(10)
SomeResults = SomeResults + "Data Bits = "+Str(devCB\ByteSize)+Chr(10)
SomeResults = SomeResults + "Parity = "+Str(devCB\Parity)+" (0-4=no,odd,even,mark,space)"+Chr(10)
SomeResults = SomeResults + "Stop Bits = "+Str(devCB\StopBits)+" (0,1,2 = 1, 1.5, 2)"+Chr(10)
MessageRequester("COM Port Test",SomeResults,0)
Else
MessageRequester("COM Port Test","Couldn't get COM port settings",0)
EndIf
Else
MessageRequester("COM Port Test","Couldn't open COM port",0)
EndIf
End
; use this to set com port
Comsettings$ ="19200,n,8,1"
retval = BuildCommDCB_(Comsettings$, devCB)
retval = SetCommState_(r, devCB)
FlushFileBuffers_(r)
; use this to read com port
Structure rx
byte1.b
byte2.b
byte3.b
EndStructure
*prx.rx = @rx
rbytes = 0 ;Bytes recived
ret = ReadFile_(r, *prx.rx, rxbytes, @rbytes, 0)
; r = handle of file to read
; *prx.rx = address of buffer that receives Data (structure for example)
; rxbytes = number of bytes to read
; @rbytes = address of number of bytes read
; close com port
ret = CloseHandle_(r)
; here the full structure of devCB.DCB (W32 programmers reference)
; perhaps you need to adjust your flow control
; typedef struct _DCB { // dcb
;
; DWORD DCBlength; // sizeof(DCB)
; DWORD BaudRate; // current baud rate
; DWORD fBinary: 1; // binary mode, no EOF check
; DWORD fParity: 1; // enable parity checking
; DWORD fOutxCtsFlow:1; // CTS output flow control
; DWORD fOutxDsrFlow:1; // DSR output flow control
; DWORD fDtrControl:2; // DTR flow control type
; DWORD fDsrSensitivity:1; // DSR sensitivity
; DWORD fTXContinueOnXoff:1; // XOFF continues Tx
;
; DWORD fOutX: 1; // XON/XOFF out flow control
; DWORD fInX: 1; // XON/XOFF in flow control
; DWORD fErrorChar: 1; // enable error replacement
; DWORD fNull: 1; // enable null stripping
; DWORD fRtsControl:2; // RTS flow control
; DWORD fAbortOnError:1; // abort reads/writes on error
; DWORD fDummy2:17; // reserved
; WORD wReserved; // not currently used
; WORD XonLim; // transmit XON threshold
;
; WORD XoffLim; // transmit XOFF threshold
; BYTE ByteSize; // number of bits/byte, 4-8
; BYTE Parity; // 0-4=no,odd,even,mark,space
; BYTE StopBits; // 0,1,2 = 1, 1.5, 2
; char XonChar; // Tx and Rx XON character
; char XoffChar; // Tx and Rx XOFF character
; char ErrorChar; // error replacement character
; char EofChar; // end of input character
; char EvtChar; // received event character
;
; WORD wReserved1; // reserved; do not use
; } DCB;