0

For my project I need two serial ports and I need to monitor both and act accordingly.

Example of what I need to do: Port A and Port B Monitor all the time Port A and when message is received, I need to forward it to Port B and wait for reply. At the same time as above, I need to send a particular message (not the one received) to port B, I would say, every 0.5 seconds and wait for a reply on Port B.

I have it working but I miss a lot of messages... can't poll it too fast and not sure what to do to improve it.

import serial
from time import sleep
import threading
from dataclasses import dataclass
import string
lock_statusfile = threading.Lock()
global_tmr_between_readings = 10

@dataclass
class Config_STATUS:
    status_alarm: string
    status_gain1: string
    status_gain2: string
    status_gain3: string
    status_gain4: string
    status_mode: string
    status_band: string
    status_ext: string
    status_change: string
    status_lock: string
    status_contrast: string
    status_gain_res: string
    status_serial: string
    status_baud: string
    status_address: string
    status_parity: string
    status_bits: string
    status_stop: string

#global variavles use to serial commands
# unit in local cannot accept command
global_msg_unit_local = "x"
serial_port_A = serial.Serial(
        port='/dev/ttyAMA0',
        baudrate = 9600,
        parity=serial.PARITY_EVEN,
        stopbits=serial.STOPBITS_ONE,
        bytesize=serial.SEVENBITS,
        timeout=1
)
serial_port_B = serial.Serial(
        port='/dev/ttyAMA1',
        baudrate = 9600,
        parity=serial.PARITY_EVEN,
        stopbits=serial.STOPBITS_ONE,
        bytesize=serial.SEVENBITS,
        timeout=1
)
#saves message received on serial port
global_serial_message_received_B = ""
global_serial_message_received_A = ""

#send command to port B
def Send_cmd_PortB(cmd):
   msg_received=""
   print("SEND STATUS TO PORT B")
   serial_port_B.write(cmd.encode(encoding='UTF-8'))
   i=0
   while i<10:
      msg_received = serial_port_B.read(100)
      if len(msg_received.decode(encoding='UTF-8')) > 19:
         i = 10
         print("RECEIVE STATUS FROM PORT B")
      else:
         i=i+1
         sleep(0.1)

   return msg_received.decode(encoding='UTF-8')

def Read_Status():
   with lock_statusfile:
      #Send status command on portB to DIGI and update status class
      aux = "A"
      msg_received = Send_cmd_PortB("{" + aux + "A}\\")
      if len(msg_received) == 22:
         Config_STATUS.status_alarm = msg_received[14]
         Config_STATUS.status_gain1 = msg_received[4:6] + "." + msg_received[6]
         Config_STATUS.status_gain2 = msg_received[8:10] + "." + msg_received[10]
         Config_STATUS.status_mode = msg_received[12]
   return msg_received



######################################################################
# Monitoring serial port B
def Monitoring_SerialPort_B_thr():
   global global_tmr_between_readings
   while(True):
      
      # #while monitoring Com port read DIGI status
      if global_tmr_between_readings <= 10 and global_tmr_between_readings >=0:
         global_tmr_between_readings = global_tmr_between_readings -1
      else:
         msg_received = Read_Status()
         if len(msg_received) != 22:
             print("Loading Data from port B: time out")
         global_tmr_between_readings = 10

      #read from port B
      serial_message_B = serial_port_B.read(100)
      
      #message from port B is valid?
      if len(serial_message_B) > 3 and len(serial_message_B) < 30:
         aux = serial_message_B.decode('UTF-8')
         print("RECEIVED FROM Port B: " + aux)
         #send message received on portB from DIGI to portA to PC
         serial_port_A.write(serial_message_B)
         print("FOWARD FROM portB to portA: " + aux)
 

######################################################################
# Monitoring serial port A
def Monitoring_SerialPort_A_thr():
    while(True):
      #read portA
      serial_message_A = serial_port_A.read(100)
      #if valid message send it to portB
      if len(serial_message_A) > 3 and len(serial_message_A) < 30:
         aux = serial_message_A.decode('UTF-8')
         print("RECEIVED FROM portA: " + aux)
         #send message received on portA to portB
         serial_port_B.write(serial_message_A)
         print("FOWARD FROM portA to portB: " + aux)         



if __name__ == "__main__":
   Monitoring_SerialPort_B_thread = threading.Thread(target = Monitoring_SerialPort_B_thr)
   Monitoring_SerialPort_A_thread = threading.Thread(target = Monitoring_SerialPort_A_thr)

   Monitoring_SerialPort_B_thread.start()
   Monitoring_SerialPort_A_thread.start()

   Monitoring_SerialPort_B_thread.join()
   Monitoring_SerialPort_A_thread.join()
1
  • This is a general programming question, not Pi specific. I suggest you start by reading input first; forget Port B
    – Milliways
    Sep 27, 2022 at 2:05

1 Answer 1

1

It's probably a mistake to use timeouts. You probably should read character by character and assemble each message rather than expecting each message to be ready immediately the first character is seen.

My guess is you are reading the message too fast, i.e. the message is still in transmission when you start to read it.

I suggest you refactor your code.

2
  • Joan solved my problem. thank you! Instead of serial_message_B = serial_port_B.read(100) changed to serial_message_B = serial_port_B.read() and read one caracter at the time.
    – otuga
    Sep 27, 2022 at 12:53
  • Well done for getting it working.
    – joan
    Sep 27, 2022 at 13:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.