Page 1 of 1
Serial Port Conversion code...
Posted: Fri Sep 02, 2022 7:43 pm
by blueb
I have a 'Non-Windows' touch screen that is hooked up to a USB port (COM8).
It has it's own IDE screen builder, and I've programmed a button on the screen to output a string with three characters: Bob
When I press this button on the touch screen the IDE debugger going to the serial port says:
Hex = 42 6F 62
String = Bob
I've tested the display and it returns the above BACK TO THE IDE (so I know it is correct)
I'd like to 'MATCH' the IDE's characters above, but PureBasic returns something much different. (see the code below)
I've tried all the Hex functions I could find in PureBasic, but can't get close.
Thus is what I get from the serial port into the PureBasic Debugger:
I've tried it in PB 6.0 x86 and x64
----------
Raw Text:
----------
1
----------
Raw Text: ₩
----------
2
----------
Raw Text: ゙
----------
3
----------
Raw Text:
----------
4
----------
Raw Text:
----------
5
What I hope to get:
Hex = 42 6F 62
String = Bob
I know this isn't much to go on, but any help would be appreciated, thanks.
My Test code:
Code: Select all
Define Buffer.b, Receive.b, Text.s
InputBuffer.i = 1024
OutputBuffer.i = 1024
Speed.i = 115200
Comport.s = "COM8"
pass.l = 1
If OpenSerialPort(0, Comport.s, Speed, #PB_SerialPort_NoParity, 8, 1, #PB_SerialPort_NoHandshake, InputBuffer, OutputBuffer)
While AvailableSerialPortInput(0) => 0 ; => 0 allows the program to keep running, while I press the touch screens button... else it finishes
If ReadSerialPortData(0, @Buffer, 1) ; Read a Byte
;Text.s = Text.s + Chr(Buffer)
Text.s = Chr(Buffer)
Debug "----------"
Debug "Raw Text: " + Text
Debug "----------"
Receive = 1
EndIf
Debug pass
; I kill the program manually.. this is just for testing the touch screen output.
pass + 1
Wend
EndIf
Re: Serial Port Conversion code...
Posted: Fri Sep 02, 2022 8:50 pm
by mk-soft
1. Looks like wrong baud rate and stop bits.
2. Which character encoding is being sent? ASCII, UTF8, etc
Also display the reception as HEX here.
Re: Serial Port Conversion code...
Posted: Fri Sep 02, 2022 11:09 pm
by Olli
You went there like a savage with your program!
First : you must be absolutely sure of the opening communication configuration.
parity, rate, bits per character, etc... : only one error, and this will be NEVER ok.
So, could you confirm you have checked every parameters you put in
OpenSerialPort() ?
Then, do a classical loop (console or window).
I prefer a window.
Code: Select all
OpenWindow(100, 0,0,600,400,"COM",#pb_window_screenCentered | #pb_window_systemMenu)
Repeat
comEvent()
Until WaitWindowEvent(33) = #pb_event_closewindow
Now, do a procedure specific for COM
Code: Select all
Procedure comEvent()
; I am called 30 times a second
Static *inMem
If *inMem = 0
*inMem = AllocateMemory(1 << 16) ; 64Kb
EndIf
*inPtr = *inMem
Delay(3)
inCom = AvailableSerialPortInput(0)
If inCom
inCount = inCom
SetWindowTitle(100, "loading...")
While inCom
Delay(3)
inStep = ReadSerialPortData(0, *inPtr, inCom)
*inPtr + inStep
inCom - inStep
Wend
SetWindowTitle(100, "Ok" + PeekS(*inMem, inCount, #pb_ascii) )
EndIf
EndProcedure
Re: Serial Port Conversion code...
Posted: Sat Sep 03, 2022 7:52 am
by infratec
Code: Select all
While AvailableSerialPortInput(0) => 0
is wrong.
If you use it this way, you can also remove it.
I it is 0 then there is no data to read.
So it should be:
Code: Select all
Repeat
If AvailableSerialPortInput(0)
...
Else
Delay(10)
EndIf
Forever
Re: Serial Port Conversion code...
Posted: Sat Sep 03, 2022 10:31 am
by Olli
2 buffers of 64kb for i/o flows, should be used. (due to the - rare but real - cuts, of Windows, which are longer than one seconds : 115200 bps means an overflow in the input buffer which could receive more than 10Kb during a cut). If the code above gives anything which seams consistent, instead of call comEvent(), you can adapt this type of procedure to be threaded.
If nothing really consistent, in the title bar, maybe the device send empty strings to close its messages. Just add a EditorGadget() in the initial code, and an AddGadgetItem(gadget, -1, PeekS(etc...) ) instead of the SetWindowTitle(). Then thread the com events.
Re: Serial Port Conversion code...
Posted: Sat Sep 03, 2022 11:27 am
by mk-soft
I have just found it again ...
Comport via thread with evaluation of the end character for ASCII
Update v0.07.1
- Added SerialPortErrorText
Comport.pb
Code: Select all
;-TOP
; Comment : Comport Manager Over Thread and Callback
; Author : mk-soft
; Version : v0.07.1
; Created : 26.01.2018
; Updated : 03.09.2022
; *****************************************************************************
CompilerIf #PB_Compiler_Thread = 0
CompilerError "Use Option Threadsafe!"
CompilerEndIf
Prototype ProtoReceiveCB(Text.s)
Prototype ProtoStatusCB(Status, *ComData)
Enumeration
#ComThread_Stopped
#ComThread_Startup
#ComThread_Running
EndEnumeration
Enumeration
#ComStatus_Nothing
#ComStatus_OpenPort
#ComStatus_ClosePort
#ComStatus_ErrorOpenPort
#ComStatus_ErrorSend
#ComStatus_ErrorReceive
#ComStatus_ErrorDataSize
EndEnumeration
Structure udtComData
; Header
ThreadID.i
Exit.i
Status.i
; Port Data
ComID.i
Port.s
Baud.i
Parity.i
DataBit.i
StopBit.i
Handshake.i
BufferSize.i
; End Of Text
EndOfText.s
; Send Data
SendSignal.i
SendCount.i
SendText.s
SendError.i
; Receive data
ReceiveCount.i
ReceiveText.s
ReceiveError.i
; Callback
*StatusCB.ProtoStatusCB
*ReceiveCB.ProtoReceiveCB
EndStructure
Procedure thComport(*ComData.udtComData)
Protected *Send, *Receive, SendText.s, SendLen, ReceiveText.s, ReceiveLen, Pos
With *ComData
; Startup
\Status = #ComThread_Startup
\SendCount = 0
\ReceiveCount = 0
\ComID = OpenSerialPort(#PB_Any, \Port, \Baud, \Parity, \DataBit, \StopBit, \Handshake, \BufferSize, \BufferSize)
If \ComID
\Status = #ComThread_Running
Else
If \StatusCB
\StatusCB(#ComStatus_ErrorOpenPort, *ComData)
EndIf
\Status = #ComThread_Stopped
ProcedureReturn 0
EndIf
If \StatusCB
\StatusCB(#ComStatus_OpenPort, *ComData)
EndIf
*Send = AllocateMemory(\BufferSize)
*Receive = AllocateMemory(\BufferSize)
; Loop
Repeat
If \SendSignal
SendText = \SendText + \EndOfText
SendLen = StringByteLength(SendText, #PB_Ascii)
If SendLen <= \BufferSize
PokeS(*Send, SendText, SendLen, #PB_Ascii)
If WriteSerialPortData(\ComID, *Send, SendLen) = 0
\SendError = SerialPortError(\ComID)
If \StatusCB
\StatusCB(#ComStatus_ErrorSend, *ComData)
EndIf
Else
\SendError = 0
\SendCount + 1
EndIf
Else
If \StatusCB
\StatusCB(#ComStatus_ErrorDataSize, *ComData)
EndIf
EndIf
\SendSignal = #False
EndIf
ReceiveLen = AvailableSerialPortInput(\ComID)
If ReceiveLen
ReceiveLen = ReadSerialPortData(\ComID, *Receive, ReceiveLen)
If ReceiveLen = 0
\ReceiveError = SerialPortError(\ComID)
If \StatusCB
\StatusCB(#ComStatus_ErrorReceive, *ComData)
EndIf
Else
\ReceiveError = 0
EndIf
ReceiveText + PeekS(*Receive, ReceiveLen, #PB_Ascii)
Repeat
pos = FindString(ReceiveText, \EndOfText, 1, #PB_String_NoCase)
If pos
\ReceiveText = Left(ReceiveText, pos - 1)
ReceiveText = Mid(ReceiveText, pos + Len(\EndOfText))
\ReceiveCount + 1
If \ReceiveCB
\ReceiveCB(\ReceiveText)
EndIf
EndIf
Until pos = 0
EndIf
Delay(10)
Until \Exit
; Shutdown
CloseSerialPort(\ComID)
If \StatusCB
\StatusCB(#ComStatus_ClosePort, *ComData)
EndIf
FreeMemory(*Send)
FreeMemory(*Receive)
\Status = #ComThread_Stopped
\ComID = 0
\Exit = 0
ProcedureReturn 1
EndWith
EndProcedure
; ----
Procedure.s SerialPortErrorText(ErrorCode)
Protected r1.s
Select ErrorCode
Case #PB_SerialPort_RxOver : r1 = "An input buffer overflow has occurred."
Case #PB_SerialPort_OverRun : r1 = "A character-buffer overrun has occurred."
Case #PB_SerialPort_RxParity : r1 = "The hardware detected a parity error."
Case #PB_SerialPort_Frame : r1 = "The hardware detected a framing error."
Case #PB_SerialPort_Break : r1 = "The hardware detected a break condition."
Case #PB_SerialPort_TxFull : r1 = "The application tried to transmit a character but the output buffer was full."
Case #PB_SerialPort_IOE : r1 = "An I/O error occurred during communications with the device."
Case #PB_SerialPort_WaitingCTS : r1 = "Specifies whether transmission is waiting for the CTS (clear-To-send) signal to be sent."
Case #PB_SerialPort_WaitingDSR : r1 = "Specifies whether transmission is waiting for the DSR (Data-set-ready) signal to be sent."
Case #PB_SerialPort_WaitingRLSD : r1 = "Specifies whether transmission is waiting for the RLSD (receive-line-signal-detect) signal to be sent."
Case #PB_SerialPort_XoffReceived: r1 = "Specifies whether transmission is waiting because the XOFF character was received."
Case #PB_SerialPort_XoffSent : r1 = "Specifies whether transmission is waiting because the XOFF character was transmitted."
Case #PB_SerialPort_EOFSent : r1 = "Specifies whether the end-of-file (EOF) character has been received."
Default : r1 = "ErrorCode " + Hex(ErrorCode)
EndSelect
ProcedureReturn r1
EndProcedure
; ----
; Threaded String Helper
Procedure AllocateString(String.s)
Protected *mem
*mem = AllocateMemory(StringByteLength(String) + SizeOf(Character))
If *mem
PokeS(*mem, String)
EndIf
ProcedureReturn *mem
EndProcedure
Procedure.s FreeString(*Mem)
Protected result.s
If *Mem
result = PeekS(*Mem)
FreeMemory(*Mem)
EndIf
ProcedureReturn result
EndProcedure
; *****************************************************************************
;- Example
CompilerIf #PB_Compiler_IsMainFile
Global ComData.udtComData
Enumeration EventCustomValue #PB_Event_FirstCustomValue
#My_Event_NewData
#My_Event_NewState
EndEnumeration
; ---------------------------------------------------------------------------
Procedure ReceiveCB(Text.s)
PostEvent(#My_Event_NewData, 0, 0, 0, AllocateString(Text))
EndProcedure
Procedure MyEventNewDataCB()
Protected Text.s
Text = FreeString(EventData())
AddGadgetItem(0, -1, Text)
SetGadgetState(0, CountGadgetItems(0) - 1)
SetGadgetState(0, -1)
EndProcedure
BindEvent(#My_Event_NewData, @MyEventNewDataCB())
; ---------------------------------------------------------------------------
Procedure StatusCB(Status, *ComData.udtComData)
PostEvent(#My_Event_NewState, 0, 0, Status, *ComData)
EndProcedure
Procedure MyEventNewStateCB()
Protected Text.s, Status, *ComData.udtComData
Status = EventType()
*ComData = EventData()
Select Status
Case #ComStatus_OpenPort
Text = "ComStatus: Open Port " + *ComData\Port
Case #ComStatus_ClosePort
Text = "ComStatus: Close Port " + *ComData\Port
Case #ComStatus_ErrorOpenPort
Text = "ComError: Open Port " + *ComData\Port
Case #ComStatus_ErrorSend
Text = "ComError Send: Port " + *ComData\Port + " - " + SerialPortErrorText(*ComData\SendError)
Case #ComStatus_ErrorReceive
Text = "ComError Receive: Port " + *ComData\Port + " - " + SerialPortErrorText(*ComData\ReceiveError)
Case #ComStatus_ErrorDataSize
Text = "ComError Send: Port " + *ComData\Port + " - Send data size to big."
EndSelect
If Bool(Text)
StatusBarText(0, 0, Text)
EndIf
EndProcedure
BindEvent(#My_Event_NewState, @MyEventNewStateCB())
; ---------------------------------------------------------------------------
Procedure InitComport()
With ComData
If \Status
ProcedureReturn 2 ; Always running
EndIf
\Port = "COM4"
\Baud = 115200
\Parity = #PB_SerialPort_NoParity
\DataBit = 8
\StopBit = 1
\Handshake = #PB_SerialPort_NoHandshake
\BufferSize = 2048
\EndOfText = #CRLF$
\StatusCB = @StatusCB()
\ReceiveCB = @ReceiveCB()
\ThreadID = CreateThread(@thComport(), ComData)
If Not \ThreadID
ProcedureReturn 0 ; Error create thread
Else
ProcedureReturn 1 ; ok
EndIf
EndWith
EndProcedure
Procedure Main()
Protected Event, Text.s, i
If OpenWindow(0, #PB_Ignore, #PB_Ignore, 800, 600, "Comport", #PB_Window_SystemMenu)
CreateStatusBar(0, WindowID(0))
AddStatusBarField(#PB_Ignore)
ListViewGadget(0, 0, 0, 800, 540)
StringGadget(1, 5, 545, 590, 25, "")
ButtonGadget(2, 605, 545, 90, 25, "Send")
ButtonGadget(3, 695, 545, 90, 25, "On/Off")
AddKeyboardShortcut(0, #PB_Shortcut_Return, 1000)
CreatePopupMenu(1)
MenuItem(101, "Copy ListView")
Repeat
Event = WaitWindowEvent()
Select Event
Case #PB_Event_CloseWindow
If ComData\Status
MessageRequester("Info", "Comport Is Open!", #PB_MessageRequester_Warning)
Else
Break
EndIf
Case #PB_Event_Gadget
Select EventGadget()
Case 0
If EventType() = #PB_EventType_RightClick
DisplayPopupMenu(1, WindowID(0))
EndIf
Case 2 ; send button
If ComData\Status = #ComThread_Running And ComData\SendSignal = #False
ComData\SendText = GetGadgetText(1)
ComData\SendSignal = #True
EndIf
Case 3 ; on/off button
If ComData\Status
ComData\Exit = 1
Else
If Not InitComport()
StatusBarText(0, 0, "Comport " + ComData\Port + ": Error Create Thread")
EndIf
EndIf
EndSelect
Case #PB_Event_Menu
Select EventMenu()
Case 101 ; popup menu
Text = ""
For i = 0 To CountGadgetItems(0) - 1
text + GetGadgetItemText(0, i) + #CRLF$
Next
SetClipboardText(Text)
EndSelect
EndSelect
ForEver
EndIf
EndProcedure : Main()
CompilerEndIf
Re: Serial Port Conversion code...
Posted: Sat Sep 03, 2022 4:13 pm
by infratec
@Olli
If I get 3 bytes in a minute for what do I need 128k buffer?
In this case the transmission speed is not a factor.
Re: Serial Port Conversion code...
Posted: Sat Sep 03, 2022 4:54 pm
by Olli
You are perfectly right : if you are sure you will have a maximum of 3 bytes per minutes, 64kb are useless.
As I absolutely do not know the purposes of blueb, I imagine, in example, a stream of several sensors (thermo, light, etc...), stream which would use the maximum of the input flow. In this way, on Windows, which can pass over the duration D we set in a Delay(D), the program could be stopped during 2 or 3 seconds. That is in this way I suggest a 64kb input buffer. For the output buffer size, this would depend of the device behaviour.
What it surprises me, it is the protocol you three are using : you just use AvailableSerialPortInput() result as a boolean data, as I consider however that this value should be used to control the input buffer : If the hardware shows a queue of 500 bytes, and then the resulting data chunk size is 100 bytes, it seems that 400 bytes must be read, until a delay overflow threshold would have been reached, to display an error. Is it on old, very old configurations, that my concept was ?
Re: Serial Port Conversion code...
Posted: Mon Sep 05, 2022 12:27 pm
by blueb
Sorry, I was busy over the weekend.
mk-soft... first thanks for updating your Comport.pb program. This will make managing Comports easier.
Olli... the 'purpose'...
This 7" touch screen display comes with it's own software to create the screens that are
NOT Widows compatible.
my model is the: NX8048P070-011C
These Capacitive Touch screens respond much better than older touch screens (TFT). see:
https://nextion.tech/intelligent-series-introduction/
After designing my screens and 'flashing' the device, I'm trying to take the units output directly from the COM port and use that information in a PureBasic program. I don't care 'what' the screen's output says... as long as I can read it and it is consistant.
Imagine I press a button on the screen and the Comport reads: 64A.
My PureBasic program monitors the port and responds in my event manager.. simple.
At the moment, this 7" screen sends it's output to another microcontroller (in my case, an Espressif ESP32 MCU and it requires Arduino software)
I'm just trying to cut out the middle-man.
Isn't that the whole idea of PureBasic.. go where no man has gone before?
I'm continuing to work on this, as these screens are terrific.
Since the display can store 120MB in flash memory, I have seen one program that contained over 30 different 'pages'.
PS - I have ordered the Nextion's MIDI I/O Iinterface which may help in the output to a regular MIDI signal... we'll see.
Re: Serial Port Conversion code...
Posted: Mon Sep 05, 2022 5:13 pm
by Olli
Hello blueb, ok.
Are you sure, the rate is 115200 ?
I suggest this : 9600, no parity, 1 bit of stop and 8 data bits.
Re: Serial Port Conversion code...
Posted: Mon Sep 05, 2022 5:36 pm
by blueb
Olli wrote: Mon Sep 05, 2022 5:13 pm
Hello blueb, ok.
Are you sure, the rate is 115200 ?
I suggest this : 9600, no parity, 1 bit of stop and 8 data bits.
From the manual...
The Serial Port Baudrate = Maximum 921600 bps
but I did try: 9600, no parity, 1 bit of stop and 8 data bits.
Re: Serial Port Conversion code...
Posted: Mon Sep 05, 2022 9:37 pm
by TassyJim
If you have the source code for the ESP32, it will have the baud rate.
If all else fails, for something like this, I use Wireshark with it's USB module to monitor the USB-serial port. That will tell you whats coming in regardless of baud rate.
I have never used these modules but I do spend a lot of time with micros and TFT screens.
The NX8048P070-011C defaults to 9600 baud but you can change the baud rate and the default baud rate to anything.
The module can send with the 'print' command as ASCII strings or 'printh' as ASCII formatted HEX followed by a space for each character. That means 3 bytes for each character so it doesn't sound likely in this case.
Jim
Re: Serial Port Conversion code...
Posted: Tue Sep 06, 2022 12:15 am
by blueb
TassyJim wrote: Mon Sep 05, 2022 9:37 pm
If you have the source code for the ESP32, it will have the baud rate.
If all else fails, for something like this, I use Wireshark with it's USB module to monitor the USB-serial port. That will tell you whats coming in regardless of baud rate.
Yes, I've 'bypassed the ESP32' and am using something like WireShark so that I can go directly to PureBasic.
As I said, I may have to use a MIDI 'middleman', but I prefer directly to PB.
Thanks for any assistance.
Re: Serial Port Conversion code...
Posted: Wed Sep 07, 2022 12:07 am
by Olli
I do not know if every character have ever a three bytes size, but there is an exchange mode, for sure, which returns a three bytes terminal code : speEOL.s = Chr(255) + Chr(255) + Chr(255). (=~= $FFFFFF on memory buffer)
I doubt also about the real 8 bits data range of each byte code exchanged. Why not a strange combo, i.e. Chr(127) + Chr(127) to get a real Chr(255) where
the bit #7 is translated to Chr(127) if bit#7 = 1 and Chr(0) if the bit #7 = 0 ?
Code: Select all
initial ASCII code
[ b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 ]
interpreted ASCII code
[ 0 | b7 | b7 | b7 | b7 | b7 | b7 | b7 ] (bit #7 is dupplicated 7 times)
[ 0 | b6 | b5 | b4 | b3 | b2 | b1 | b0 ]
All this even if the port init is set to 8 data bits...
It's only an example of "split code" where a byte is divided, for any dark reasons, in two parts : a high part, and a low part. Sometimes even, a byte is dedicated to get several high parts of several others bytes which succeed or precede this first one. My example above considers a division per nibbles of 7 bits, but others characteristics are able to be used : 6 bits or less...
This type of strange data mode allows a barcode system to use the bit #7 as a scan clock synchronization.
And, why not a reversed bit system ?
Code: Select all
₩ = semi-eol (chr(10) : part of Chr(13) + Chr(10) )
initial ASCII code
[ b7 | b6 | b5 | b4 | b3 | b2 | b1 | b0 ]
reversed ASCII code
[ b0 | b1 | b2 | b3 | b4 | b5 | b6 |?b7?]
With a scan clock sync, whatever the range order of the bits, the receiver get a hexa 7F+7F+7F+7F+7F+7F end-of-data code (of an empty data string) which means a normal bits order, or a hexa FE+FE+FE+FE+FE+FE which means a reversed bits order.
7F and FE hexa number match to a 7-bits data size.
3F and FC hexa match to a 6-bits data size.
Less often 1F and F8 hexa match to a 5-bits data size.
Here it is recalled FE, FC and F8 represent one of the three (7, 6 or 5 bits sized) reversed bits system vs 7F, 3F and 1F which represent one of the three normal system (idem : 7, 6 or 5 bits sized)
If it'd be needed, short code to reverse the 8 bits of an unsigned byte (type ascii) :
Code: Select all
Procedure.a bRev(a, b.a = 0, c = 8)
If c
b = bRev(a >> 1, b << 1 | (a & 1), c - 1)
EndIf
ProcedureReturn b
EndProcedure
Re: Serial Port Conversion code...
Posted: Fri Sep 13, 2024 6:34 pm
by Erolcum
mk-soft wrote: Sat Sep 03, 2022 11:27 am
I have just found it again ...
Comport via thread with evaluation of the end character for ASCII
Update v0.07.1
- Added SerialPortErrorText
Comport.pb
This code of yours is very good for serial port works. I used it in one of my arduino posts, thanks Michael.
It is really nice when a programming language automatically becomes a means of international communication. I mean, people can be misunderstood when they speak or write, but if they express themselves by writing programmes, they cannot be misunderstood.
my post :
https://erolcum-github-io.translate.goo ... r_pto=wapp