Pyserial loses some data - pyserial

I use pyserial to send and receive a large data package to mcu board.
Basically, mcu just receive and immediately transmit byte in ISR.
port = serial.Serial(
'COM12',
baudrate=921600,
timeout=0,
parity='N',
stopbits=1,
bytesize=8
)
msg1 = "z200f2000 126543f4 126543f4 126543f4 126543f4 126543f4 126543f4 126543f4 "
multi_msg = ""
for i in range(1000):
multi_msg = multi_msg + msg1 + str(i) + "\r\n"
port.reset_input_buffer()
port.reset_output_buffer()
ret1 = port.write(multi_msg)
print multi_msg
print ret1
ret2 = port.in_waiting
print ret2
rcv1 = port.read(port.in_waiting)
print repr(rcv1)
First problem is that the max number of bytes in input buffer (port.in_waiting) is 65536 bytes (64KB).
It's the same if I use i.e. port.read(80000). Always read 64KB.
Is this limitation for read()?
Also, it seems that my pyserial script lose some packages and not always (about 10% fails).
If I use TeraTerm to send a large file everything is ok.
Thanks.

Solution was to put read() in separate thread to prevent buffer overruns.

Related

How do I synchronize clocks on two Raspberry Pi Picos?

I'm sending bits as LED blinks from one Pi Pico, and using another Pico to receive voltage from a photodiode and read the bits.
When sending/receiving from the same PiPico, it works accurately at 60us a bit. However, when sending from one pico and receiving from a second pico, I can only send/receive bits accurately at 0.1s a bit. If I move to sending/receiving at 0.01s, I start losing information. This leads me to believe my issue is with the clocks or sampling rates on the two pipicos, that they are slightly different.
Is there a way to synchronize two pipico clocks using Thonny/Micropython?
Code for Pico #1 sending blinks/bits:
led=Pin(13,Pin.OUT) #Led to blink
SaqVoltage = machine.ADC(28) #receive an input signal, when over a certain voltage, send the time using bits
#Ommitted code here to grab first low voltage values from SaqVoltage signal and use to determine if there is a high voltage received, when high voltage is received, send "hi" in led bits
#More omitted calibration code here for led/photodiode
hi = "0110100001101001"
while True:
SaqVoltage_value = SaqVoltage.read_u16()*3.3 / 65536 #read input signal to see if high voltage is sent
finalBitString = ""
if SaqVoltage_value > saQCutOff: #high voltage found, send "hi" sequence
finalBitString = #hi plus some start/stop sequences
for i in range (0, len(finalBitString)):
if finalBitString[i]=="1":
led(1)
elif finalBitString[i]=="0":
led(0)
utime.sleep(.01)
Code for Pico#2 receiving bits:
SaqDiode = machine.ADC(28) #read photodiode
#ommitted code here to calibrate leds/photodiodes
startSeqSaq = []
wordBits=[]
while True:
utime.sleep(.01) #sample diode every 0.01 seconds
SaqDiode_value = SaqDiode.read_u16()*3.3 / 65536
if (saqDiodeHi - saqCutOff <= SaqDiode_value): #read saq diode and determine 1 or 0
bit=1
elif (SaqDiode_value <= saqDiodeLo + saqCutOff):
bit=0
if len(startSeqSaq)==10: #record last 10 received bits to check if start sequence
startSeqSaq.pop(0)
startSeqSaq.append(bit)
elif len(startSeqSaq)<10:
startSeqSaq.append(bit)
if startSeqSaq == startSeq: #found start sequence, start reading bits
while True:
utime.sleep(.01)
SaqDiode_value = SaqDiode.read_u16()*3.3 / 65536
if (saqDiodeHi - saqCutOff <= SaqDiode_value):
bit=1
wordBits.append(bit)
elif (SaqDiode_value < saqDiodeLo + saqCutOff):
bit=0
wordBits.append(bit)
if len(wordBits)>10: #check for stop sequence
last14=wordBits[-10:]
else:
last14 = []
if last14==endSeq:
char = frombits(wordBits[:-10])
wordBits=[]
print("Function Generator Reset Signal Time in ms from Start: ", char)
break

Issue sending/receiving data over serial connection using MATLAB

I recently connected a reactor control tower through a serial 'COMMS' port to my computer (serial to USB). It seems to create a connection on the COM4 port (as indicated on the control panel 'devices and printers' section). However, it always gives me the following message when i try to 'fwrite(s)' or 'fscanf(s)'.
Warning: Unsuccessful read: The specified amount of data was not returned within the Timeout period..
%My COM4
s = serial('COM4');
s.BaudRate = 9600;
s.DataBits = 8;
s.Parity ='none';
s.StopBits = 1;
s.FlowControl='none';
s.Terminator = ';';
s.ByteOrder = 'LittleEndian';
s.ReadAsyncMode = 'manual';
% Building write message.
devID = '02'; % device ID
cmd = 'S'; % command read or write; S for write
readM = cell(961,3);% Read at most 961-by-3 values filling a 961–by–3 matrix in column order
strF = num2str(i);
strF = '11'; %pH parameter
strP = '15'; %pH set point
val = '006.8'; %pH set value
msg_ = strcat('!', devID, cmd, strF, strP, val);%output the string
chksum = dec2hex(mod(sum(msg_),256)); %conversion to hexdec
msg = strcat(msg_,':', char(chksum), ';');
fopen(s); %connects s to the device using fopen , writes and reads text data
fwrite(s, uint8(msg)); %writes the binary data/ Convert to 8-bit unsigned integer (unit8) to the instrument connected to s.
reply=fscanf(s); %reads ASCII data from the device connected to the serial port object and returns it to reply, for binary data use fread
fclose(s); %Disconnect s from the scope, and remove s from memory and the workspace.
This leads me to believe that the device is connected but is not sending or receiving information and I am unsure as to how I can configure this or even really check if there is communication occurring between the tower and my computer.

Read UART transmision Input buffer in Matlab

I'm trying to make a serial communication between two ESP8266 Wifi chips.
To start, I tried sending a sample data 10 times in a for loop. Here is the code:
Transmiter:
for Packets = 1 : 10
SendData(client,Data(Packets));
end
Receiver:
Packets = 1
while(1)
Data(Packets) = ReceiveData(Server);
Packets = Packets + 1;
if (packets == 10)
break
end
end
it works good. The problem is when I want to send data with some delays, the transmitter should connect to receiver again and the server (receiver) receives some data indicating that connection is made again.
The received Buffer should be:
+IPD,0,1024:ùüþþþýýþþÿÿûûýþýûúþÿúóýÿþþþþþýúøûýþ...
but after reconnecting the received Buffer is:
0,CLOSED %Receiver Prompt, disconnected from Transmiter
0,CONNECT %Receiver Prompt,connected to Transmiter
+IPD,0,1024:ùüþþþýýþþÿÿûûýþýûúþÿúóýÿþþþþþýúøûýþ...
The remaining part of data will be read in next packet and same for next packets.
what should I do to receive just the data?
The send and receive functions:
function ReceivedBuffer = ReceiveData(SerialPort)
ReceivedBuffer = fread(server,1038); %Size data = 1038 Bytes
end
function SendData(SerialPort,Data)
fwrite(SerialPort,Data);
end

Best way to handle multiple connections at the same time

I have an application which listens to multiple connections and verifies whether the user is active or not
I use a 1 thread socket handling method with WSAASyncSelect.
The problem is that sometimes when a lot of users connecting at the same time some users get no reply
i think it is because the "send" hasn't been called yet and the program has received another connection so it goes again to handle the new connection ignoring the previous one. Like WSAASyncSelect has triggered and now it processing a new connection instead of completing the previous request.
So what to do to fix this issue? i tried to stop the events from WSAASyncSelect temporary by calling it with zero parameters when handling the connection until finish it then re enable network events but that didn't help either.
Here are the codes that handling the events (recieve then decrypt and then compare the bytes then send data according to what in listbox ie Active user or not)
This called upon receive of FD_READ
WSAAsyncSelect s, frmMain.hwnd, 0, 0 'Disabling Notifications event
Do Until bytesRecieved = SOCKET_ERROR
bytesRecieved = recv(wParam, buffer(Bytes), 500, 0)
If bytesRecieved > 0 Then
Bytes = Bytes + bytesRecieved
ElseIf bytesRecieved = 0 Then
Exit Sub
End If
Loop
Call MemCopy(ByVal decryptedArrival, buffer(0), Bytes)
WSAAsyncSelect s, frmMain.hwnd, WINSOCKMSG, FD_CONNECT + FD_READ + FD_CLOSE + FD_ACCEPT + FD_WRITE
If frmMain.chkSaveLog.value = vbChecked Then
frmMain.txtConnectionsLog.Text = frmMain.txtConnectionsLog.Text & Now & " Receiving a connection (" & wParam & ")" & vbNewLine
AutoScroll
If frmMain.chkAutoSave.value = vbChecked Then
strCurrentLogLine = Now & " Receiving a connection (" & wParam & ")"
AutoSaveLog (strCurrentLogLine)
frmMain.cmdClearLogs.Enabled = True
End If
End If
Below here is a decryption of bytes then comparing by ID as byte identifier like 1 = check for update
2 - send user info etc
in a Select Case statement following by a send Api.
And the accepting procedure
This called upon receive of FD_ACCEPT
Function AcceptConnection(wParam As Long)
lpString = String(32, 0)
AcSock = accept(wParam, sockaddress, Len(sockaddress))
strTempIP = getascip(sockaddress.sin_addr)
frmMain.txtConnectionsLog.Text = frmMain.txtConnectionsLog.Text & Now & " Getting a connection from IP address: " & _
strTempIP & " (" & AcSock & ")" & vbNewLine
AutoScroll
If frmMain.chkAutoSave.value = vbChecked Then
strCurrentLogLine = Now & " Getting a connection from IP address: " & strTempIP & " (" & AcSock & ")" & vbNewLine
AutoSaveLog (strCurrentLogLine)
End If
End Function
Are there any suggestions for a better performance?
What you showed is NOT the correct way to use WSAAsyncSelect(). Try something more like this instead:
When creating a listening socket:
lSock = socket(...)
bind(lSock, ...)
listen(lSock, ...)
WSAAsyncSelect lSock, frmMain.hwnd, WINSOCKMSG, FD_ACCEPT
When a listening socket receives FD_ACCEPT:
Function AcceptConnection(wParam As Long)
AcSock = accept(wParam, sockaddress, Len(sockaddress))
If AcSock = INVALID_SOCKET Then
Exit Sub
End If
WSAAsyncSelect AcSock, frmMain.hwnd, WINSOCKMSG, FD_READ + FD_CLOSE + FD_WRITE
...
End Function
When an accepted client socket receives FD_READ:
Function ReadConnection(wParam As Long)
Do
bytesRecieved = recv(wParam, ReadBuffer(ReadBytes), 500, 0)
If bytesRecieved = SOCKET_ERROR Then
If WSAGetLastError() <> WSAEWOULDBLOCK Then
Exit Sub
End If
ElseIf bytesRecieved = 0 Then
Exit Sub
Else
ReadBytes = ReadBytes + bytesRecieved
End If
Loop Until bytesRecieved = SOCKET_ERROR
' process ReadBuffer up to ReadBytes number of bytes as needed...
' remove processed bytes from front of ReadBuffer and decrement ReadBytes accordingly
...
End Function
When an accepted client socket receives FD_WRITE:
Function WriteConnection(wParam As Long)
While SendBytes > 0
bytesSent = send(wParam, SendBuffer(0), SendBytes, 0)
If bytesSent = SOCKET_ERROR Then
Exit Sub
End If
' remove bytesSent number of bytes from front of SendBuffer ...
SendBytes = SendBytes - bytesSent;
End While
End Function
The trick is that you need to allocate separate ReadBuffer and SendBuffer buffers for each accepted client. Make sure that each time you receive FD_READ that you are appending bytes only to the ReadBuffer of the socket that triggered FD_READ, and each time you receive FD_WRITE that you are removing bytes only from the SendBuffer of the socket that triggered FD_WRITE.
When recv() has no more bytes to read, process that socket's ReadBuffer as needed, removing only complete messages from the front and leaving incomplete messages for later processing.
When send() fails with WSAEWOULDBLOCK, append any unsent bytes to the SendBuffer of the socket that caused send() to fail. When you receive an FD_WRITE event for a socket, check that socket's SenBuffer and resend any bytes that are in it, stopping when the buffer is exhausted or an WSAEWOULDBLOCK error occurs.
Very easy, and quite effective, way to do it is to fork out for every incoming connection. This will most likely require you to restructure your application, but the basic flow should be as follows:
1. New connection is opened to the server
2. Server accepts the connection and forks out
3. The fork closes the original socket for listening, so only the parent will be accepting new connections
4. And then your magic happens, separate from the original thread.
This way you do not have to worry about issues of concurrency, as long as your machine can handle all the traffic and load because each connections is independent.

VB6 RS232 not receiving full data from device using MSCOMM Controll

I have a clinical device that sends data on com port, I want to receive data from device
it also received First Frame (254) character after send ACK on ENQ
it receive [ETB] [CR][LF] characters
then I again send ACK for next frame, but not receive data
only receiving EOT char
Device Communication as per device is:
<-[ENQ]
->[ACK]
<-[STX]1H|**********************-[ETB]21[CR][LF]
->[ACK]
<-[STX]1H|**********************-[ETX]8E[CR][LF]
->[ACK]
<-[EOT]
my code is:
'MSComm1.Settings = "9600,n,8,1"
'MSComm1.InputLen = 1
Private Sub MSComm1_OnComm()
Dim InBuff As String
InBuff = MSComm1.Input
if Chr$(5)=InBuff then 'ENQ received
MSComm1.Output=Chr$(6) & VbCr
elseif Chr$(10)=InBuff then 'LF received
MSComm1.Output=Chr$(6) & VbCr
else
text1.text=text1.text & InBuff
end if
End Sub
Device sending full data because 1 software comes with device which receive full data as
but I didn't receive next frame after send ACK again,
if any one have idea what output have to send FOR next ACK, please advice me
thanks in advance
Do something like this...
MSComm1.InputLen = 1 ' for sending single character from device
MSComm1.RThreshold = 1 ' for firing events on receiving a single character
Dim InBuff As String
if MSComm1.CommEvent = comEvReceive then
do
InBuff = MSComm1.Input
Loop Until MSComm1.InBufferCount < 1
Firstly receive all the data and after that use that in your own way.