PySerail Readline enters infinite loop - python

I am working on a BP sensor serial and am using serial readline() to read the output provided by the port, when I initiate the port as serial.Serial('/dev/ttyUSB2',115200,timeout=1) and print the date read using readline() in a loop as follows
for I in range(1,10)
print('integration')
print(ser.readline())
the readline() seems to into infinite loop as the program prints integration once and then goes infinite however when I try the same with timeout=0 the program prints integration 9 times with blank space after each line. Need to know what I am doing wrong as the same code seems to work fine with other sensors like laser distance sensor etc.
Already referred to Reference1 Reference2 and a few more.

ser.readline() expects to find a \n character so it keeps reading data until it finds it.
You need to make sure your sensor is sending this default EOL character. If that is not the case, you can specify a different character.
There used to be a simple way to do that but apparently, it's not working anymore. The workaround is to use TextIOWrapper, see here. Pay attention to the first answer to that question to make sure you change the default buffer size.

Related

Cannot get reset_input_buffer() function to work at all in Pyserial 3.5. Does anyone have any idea what may be happening?

I am trying to simulate a communication protocol where I am following a pattern, so I constantly loop though looking for the same set of characters to reply information. I'm using an RS-232 adapter and the protocol I am simulating is asynchronous and half-duplex where the rx/tx lines are tied together by design and that causes a sort of echo when reading after writing.
That said, I need to be able to clear the input buffer after every write I send out in order to avoid reading what I just wrote. So whenever I use reset_input_buffer() it does not clear the last message I sent out. I have tried to fix this using a couple of methods, such as: using reset_output_buffer() together with reset_input_buffer(), using reset_input_buffer() twice, and using flush(). None of these methods make any difference, the only other method that works to clear the buffer is closing and immediately opening the port but this causes a delay that messes with the timing as it is critical at certain times.
I'm open to any suggestions, please help!

Gets different \n\r format in files in the same script

I tried to read up on how to open files properly in python (concerning formatting of special characters, in this case carriage return) but still can't figure it out.
I'm writing this script in nano on my rpi (over ssh from my pc using putty).
The script collects data from sensors connected via I2C and SPI and prints them to logfiles. Any events, anomalies and errors are to be registered in an eventlog, with timestamp. that way, I dont need the ordinary print function and can make the program run in the backround and keep track of what it's doing by looking at the eventlog over FTP.
The following parts of the program gives different line handling
first occasion
second occasion
The first gives a file that gets a ^M at the beginning of each line except the first when i view it in nano, but it looks fine and dandy when i open it in notebook on my PC.
The second looks good in nano, but have no newlines or carriage returns when I open it in notepad and is impossible to read properly.
First: Why are they different? I have looked at it over and over again. Because one is inside a function and the other "raw" in the code (it is inside a while loop)
Second: What does it take to get the files to look proper in both nano and notepad?
Hopefully I've given enough details :)

Serial port writing style

I am using two libraries to connect with a port, and two of them uses different styles in writing these commands. I want to understand the difference because I want to use the second one, but it results in port becoming unresponsive after some time, I wonder if it causes a kind of overloading. Here are the methods.
Method 1:
if self.port:
self.port.flushOutput()
self.port.flushInput()
for c in cmd:
self.port.write(c)
self.port.write("\r\n")
Method 2:
if self.port:
cmd += b"\r\n"
self.port.flushInput()
self.port.write(cmd)
self.port.flush()
The major difference I first encounter is that the first one splitting the command in to letters then send it. I wonder if this makes any difference. And as I said the second code fails after some time( it is unclear, if these methods are the problem). I don't understand what flushes do there. I want to understand the difference between these and know if the second one prone to errors.
Note: Please note that self.port is serial.Serial object.
Any advice appreciated.
Well, from the pySerial documentation the function flushInput has been renamed to reset_input_buffer and flushOutput to reset_output_buffer:
reset_input_buffer()
Flush input buffer, discarding all it’s contents.
Changed in version 3.0: renamed from flushInput()
reset_output_buffer()
Clear output buffer, aborting the current output and discarding all that is in the buffer.
Changed in version 3.0: renamed from flushOutput()
The first method is less likely to fail because the output buffer is reset before attempting a write. This implies that the buffer is always empty before writing, hence the odds the write will fail are lower.
The problem is that both the methods are error prone:
There is no guarantee that all the data you are attempting to write will be written by the write() function, either with or without the for loop. This can happen if the output buffer is already full. But the write() functions returns the number of bytes successfully written to the buffer. Hence you should loop untill the number of written bytes is equal to the number of bytes you wanted to write:
toWrite = "the command\r\n"
written = 0
while written < len(toWrite) :
written += self.port.write(toWrite[written:])
if written == 0 :
# the buffer is full
# wait untill some bytes are actually transmitted
time.slepp(100)
Note that "writing to the buffer" doesn't mean that the data is instantly trasmitted on the serial port, the buffer will be flushed on the serial port when the operative system thinks is time to do so, or when you force it by calling the flush() function which will wait for all the data to be written on the port.
Note also that this approach will block the thread execution untill the write is successfully completed, this can take a while if the serial port is slow or you want to write a big amount of data.
If your program is ok with that you are fine, otherwise you can dedicate a different thread to serial port communication or adopt a non-blocking approach. In the former you will have to handle multithread communication, in the latter you will have to manage internally your buffer and delete only the successfully written bytes.
Finally if your program is really simple an approach like this should do the trick:
if self.port:
cmd+=b"\r\n"
for c in cmd:
self.port.write(c)
self.port.flush()
But it will be extremely unefficient.

how do I monitor data from serial port and have certain data act as a flag in Python

I am working on a project for work and I am stuck on a part where I need to monitor a serial line and listen for certain words using python
so the setup is that we have a automated RAM testing machine that tests RAM one module at a time and interacts with software that came with the machine via serial. The software that came with the RAM tester is for monitoring/configuring the testing process, it also displays all of the information from the SPD chip from each module. while the RAM tester was running I ran a serial port monitoring program and I was able to see the same information that it displays in the software. The data I'm interested in is the speed of the RAM and the pass/fail result, both of which I was able to find in the data I monitored coming over the serial line. There are only 5 different speeds of RAM that we test, so I was hoping to have python monitor the serial line and wait for the speed of the RAM and the pass/fail results to come across. once python detects the speed of the RAM, and if it passes, I will have python write to an Arduino, and the Arduino will control a conveyor belt that will sort the ram by speed.
my idea is to have a variable for each of the RAM speeds and set the variables to 0. when python detects the RAM speed from the serial line it will set the corresponding variable to 1. then when the test is over the results, either pass or fail, will come over the serial line. this is where I am going to try to use a if statement. I imagine it would look something like this:
if PC-6400 == 1 and ser.read() == pass
ser.write(PC-6400) #serial write to the arduino
I know the use of the ser.read() == pass is incorrect and that's where I'm stuck. I do not know how to use a ser.read() function to look for certain words. I need it to look for the ram speed (in this case its PC-6400) and the word pass but I have not been successful in getting it to find either. I am currently suck in is getting python to detect the RAM speed so it can change the value of the variable. would it be something close to this?
if ser.read() == PC-6400
PC-6400 = 1
This whole thing is a bit difficult for me to explain and I hope it all makes sense, I thank you in advance if anyone can give me some advice on how to get this going. I am pretty new to python and this is the most adventurous project I have worked on using python so far.
I'm still a bit confused, but here's a very basic example to hopefully get you started.
This will read from a serial port. It will attempt to read 512 bytes (which just means 512 characters from a string). If 512 bytes aren't available then it will wait forever, so make sure you set a timeout when you made the serial connection.
return_str = ser.read(size = 512)
You can also see how many bytes are waiting to be read:
print "num bytes available = ", ser.inWaiting()
Once you have a string, you can check words within the string:
if "PASS" in return_str:
print "the module passed!"
if "PC-6400" in return_str:
print "module type is PC-6400"
To do something similar, but with variables:
# the name pass is reserved
pass_flag = "PASS"
PC6400 = 0
if pass_flag in return_str and "PC-6400" in return_str:
PC6400 = 1
Keep in mind that you it is possible to read part of a line if you are too quick. You can add delays by using timeouts or the time.sleep() function. You might also find you need to wait for a couple of seconds after initiating the connection as the arduino resets when you connect. This will give it time to reset before you try and read/write.

Problems with sending commands over pySerial

I'm trying to talk to a home made card over a serial port, and is therefor using pySerial. In Hyperterminal, everything works fine. I can write:
$ audio on
and the audio is enabled, but if I use
ser = serial.Serial("COM1", 38400)
ser.write("audio on\r\n")
nothing happens. I can read incoming data however, so it's not something wrong with the communication. I doesn't help if I change \r\n to just \n or \r either.
EDIT: Sometime I actually get the feedback: No such command when sending the exact same command as works from HyperTerminal. The setup is also the exact same as in HyperTerminal.
Solved:
To make it work, I had to send one and one character, and ending the transmission with \r.
Get an oscilloscope (you've got one, right?) and watch the serial line. Send one character per second through it and see what comes up on the scope (set it to trigger on the start bit). Serial port bits are in the order: start, LSB .. MSB, parity, stop.
See if there are characters that don't get through, or if there's a pattern. Another possibility is that everything is actually making it out the port, and your board is dropping characters.
Triple check that the baud rate of the device is indeed 38400
Triple check parity, stop bits, etc
Be aware of signal degradation for serial transmissions over long distances (probably not your issue)
If all the above checkout try putting the string into a byte array and sending that through the write command. Just a guess.
Sending characters via Hyperterminal deliver characters at the speed you type them. Sending characters through pyserial they are delivered as a continuous stream. The receiver (especially at high baud rates) could drop them, depending on the nature of the receiver.
Also, when you send commands to an interpreter, you only need the \r terminator (without the \n), (this is all that is sent by hyperterm, normally). HOWEVER, if you are just displaying the values, you may need the \n to generate the new line.

Categories