3

Problem Description: I am trying to retrieve all data stored on a device using rs232.

How?: For this specific device, I need to:

  • Step 1: send one byte (0x80) - uInt8 (8-bit unsigned integer) through a serial port (COM5) and expect to receive 0x81 in response.
  • Step 2: send a second byte (0x81) and expect to receive all data stored, line by line.

Note: The device is automatically transmitting the data it has. It only accepts one byte at a time (in my case, sending two bytes at a time is enough to retrieve the data --- Step 1 and Step 2).

Device Testing: Before running my experiment, I first tested whether my serial connection is working. First, I tested the serial connection with a terminal emulation program called RealTerm: Serial/TCP Terminal. Second, I run a Matlab test using shell commands. I could retrieve all data stored on the device for both tests.


What have I tried?: I have tried to write a Python Script and a Node.js Script. Unfortunately, both scripts did not work, both Scripts were giving 0x00 whenever I send 0x80 (I failed to pass Step 1). I am not sure where is the issue though! (I have been trying for 7 days)

Today, I thought about running an experiment using Python Shell instead of a Script.

>>> import serial
>>> rs232 = serial.Serial(
...     port = 'COM5',
...     baudrate = 115200,
...     bytesize = serial.EIGHTBITS,
...     parity = serial.PARITY_NONE,
...     stopbits = serial.STOPBITS_ONE,
...     timeout=1
...     )
>>> rs232.write(0x80)
128
>>> rs232.read(size=1)
b'\x87'
>>> rs232.read(size=2) 
b'\x87\x87'
>>> rs232.read(size=5) 
b'\x87\x87\x87\x87\x87'

This gave me some hope because I could receive something back from the device in Step 1 experiment. Though, I am not sure why am I receiving b'\x87' (ord(rs232.read(size=1)) -> 135) instead of 0x80. Also, rs232.read(size=5) gives same values!! Well, I am new to embedded programming. I am sorry about any confusion here.

I also read something about using a buffer but didn't get the idea of how can I use it for my experiment (Step 1 and Step 2).


What am I expecting? I would like to be able to write a Python Script instead of using Python Shell to retrieve all data stored in the device and save it into a CSV file, line by line.

workable solution based on all feedbacks: After taking all advices in the answers of this question, I ended up having the following working with some an issue I would appreciate to someone help me to fix it.

import serial, time

rs232 = serial.Serial(
    port = 'COM6', 
    baudrate = 115200, 
    bytesize = serial.EIGHTBITS,
    parity = serial.PARITY_NONE,
    stopbits = serial.STOPBITS_ONE,
    timeout=5,
    write_timeout=5
    )

rs232.is_open
rs232.set_buffer_size(rx_size = 2000000, tx_size = 2000000)

# cleanup RX/TX buffer
rs232.rts=True
rs232.reset_input_buffer()
rs232.reset_output_buffer()

time.sleep(2)
rs232.write(bytes([0x80, 0x82, 0x83]))

time.sleep(5)
while True:
    myBytes = rs232.readline()

    data.append(myBytes)
    print(myBytes)
    if myBytes == b'\r\x83\x87':
        break
Joe
  • 575
  • 6
  • 24
  • Have you tried running `python -m serial.tools.list_ports` in your terminal? – 0x263A Jul 24 '22 at 03:54
  • Why don't you refer to the program of this article found by searching? [serial-terminal · GitHub Topics](https://github.com/topics/serial-terminal), [pyserial/miniterm.py at master - serial - GitHub](https://github.com/pyserial/pyserial/blob/master/serial/tools/miniterm.py) – kunif Jul 24 '22 at 10:07
  • 1
    @0x263A, I tried that and I can see `COM5` – Joe Jul 24 '22 at 11:39
  • Like my previous advice to use a terminal emulation program, this problem could again be debugged with a terminal emulation program. Create a serial link using two USB-to-serial adapters connected to each other. One end of the link is serviced by your program under test. The other end is serviced by a terminal emulation program (in place of your mystery "*device*"). Manually emulate your mystery "*device*" using the terminal emulation program. Maybe first use terminal emulation programs at both ends for verification. – sawdust Jul 26 '22 at 09:29
  • Thanks, @sawdust. Could you clarify a bite more how to conduct this test, please? This is my first time to work on embedded systems – Joe Jul 26 '22 at 13:52
  • 1
    you should reset the output and input buffers before sending and receiving. You also need to clarify what kind of duplex your connection is. – dragon2fly Jul 26 '22 at 23:46
  • You should use `write(b'\x80')` instead of `write(0x80)` !! – F. Hauri - Give Up GitHub Jul 28 '22 at 09:01

1 Answers1

1

My suggestion:

  1. make sure that connection settings are really the same (I would compare them to Matlab)
  2. send correct commands: the first is b'\x80' and the second b'\x82' from your screenshots, although here you are writing b'\x81'
  3. add 5s timeout on both write and read, so you will definitely know if something is waiting
  4. reset in and out buffers as was suggested in the comments
  5. use logging to see the timings of each command
  6. add additional sleep to see if anything changes
  7. as a last resort you could try with a different library https://pyvisa.readthedocs.io/en/latest/index.html

My test script would be something like this (run with python -u to avoid buffering of log output):

import logging
import serial
import time
from pathlib import Path

logging.basicConfig(level='INFO', format='%(asctime)s - %(message)s')

logging.info('open')
rs232 = serial.Serial(
    port='COM5',
    baudrate=115200,
    bytesize=serial.EIGHTBITS,
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_ONE,
    timeout=5,
    write_timeout=5,
)

logging.info('reset buffers')
rs232.reset_input_buffer()
rs232.reset_output_buffer()

logging.info('write first')
rs232.write(b'\x80')

# time.sleep(1)  # see if uncommenting changes anything

logging.info('read first')
reply = rs232.read(size=1)
logging.info(reply)

logging.info('write second')
rs232.write(b'\x82')

# time.sleep(1)  # see if uncommenting changes anything

logging.info('read second')
# reply = rs232.read_until(expected=b'\x0a\x0d')  # read single line
reply = rs232.read_until(expected=b'\x80')
Path('result.csv').write_text(reply.decode().replace('\n\r', '\r\n'))
logging.info(reply)

logging.info('close')
rs232.close()
bzu
  • 1,242
  • 1
  • 8
  • 14
  • Thanks, @bzu. How can I read all the data stored in the device and stored in a CSV file? Should read until it reaches a value '\80'. Your code works partially. – Joe Jul 31 '22 at 13:27
  • 1
    @Joe Currently it reads a single line (delimiter b'\x0a\x0d' or b'\n\r'). If b'\x80' is the last character, use read_until() with `expected=b'\x80'`. – bzu Jul 31 '22 at 13:32
  • For writing to file you call `result.decode()` which will get you plain text that you can store (assuming there are no special characters returned). – bzu Jul 31 '22 at 13:46
  • Thanks, @bzu. `.decode().replace('\n\r', '\r\n')` isn't working. `UnicodeDecodeError: 'utf-8' codec can't decode byte 0x81 in position 1: invalid start byte` – Joe Jul 31 '22 at 14:44
  • `rs232.read_until(expected=b'\x0a\x0d')` is giving me as output: b'\x00\x81308 921 q53 246 133 137 022 1 0 1 1 1 130 C13 330 0000000199 04002201\n\r'. `\x00\x81` shouldn't be there. I am using: `time.sleep(2) rs232.write(bytes([0x80, 0x82, 0x83]))` – Joe Jul 31 '22 at 14:45
  • I have updated my question adding a workable code but having issues with stop condition using `while` loop. Thank you, @bzu – Joe Jul 31 '22 at 15:28
  • From what I see (again the screenshot) the last bytes in the output were b'\x0a\x0d\x83'. The first 2 are '\n\r' used as line end and the last could be the end of output. If this is correct use `rs232.read_until(expected=b'\x83')` without while loop to get all the data and reprocess it later. – bzu Jul 31 '22 at 16:51
  • `rs232.read_until(expected=b'\x83')` doesn't retrieve the whole data stored in the device. I checked using `while` loop. Is there a way to extract all data without using `while` loop? – Joe Jul 31 '22 at 19:03