multiprocessing with serial port - python

I've a target board which sends me CPU load for every 1sec which communicates through serial port. I want to write a python code which reads data from serial port for every 1sec second and writes to a file and also it should check for user input i.e. if user enters command it should pass that command to target board.

You can create two threads, one listening for user input, the other polling the serial port every second. Check out threading for information on multithreading in python and pyserial for information on reading from serial ports. The threading package provides your desired repetition functionality: https://docs.python.org/2/library/threading.html#timer-objects
[EDIT]
Sample code, obviously replace /dev/ttyS1 with the desired port and do something useful with the user input:
import serial
import threading
def read_from_serial():
# port = "/dev/ttyS1"
# ser = serial.Serial(port, 19200, timeout = 1)
# print ser.readline()
# ser.close()
print "read"
threading.Timer(1, read_from_serial).start()
if __name__ == "__main__":
serial_thread = threading.Thread(target = read_from_serial())
serial_thread.start()
while True:
print raw_input("User input: ")

Related

Communicate with a terminal using pySerial

I have a terminal which I connect to with serial communication, and I want to read from it and write to it some commands I prepared in advance in a string array
Using pySerial, I need to write a code that will read the lines with a stop condition which is a wait from the console for input from the user, and then write the commands from the array
Just want to clarify, it's like an automatic PuTTY, and no I can't connect to the terminal through ssh, and no I can't bood the machine's terminal since it's not a pc
here is what i tried:
import serial
Baud_Rate = 9600
Ser = serial.Serial('COM4', Baud_Rate)
while Ser.isOpen():
input('Error: Ser is already open, please close it manually. if the port is
closed, press enter\n')
try:
Ser.close()
except serial.serialutil.PortNotOpenError:
pass
Ser.open()
Serial_com = [] #a str array with the relevant commands
for i in range(len(Serial_com)):
ter = Ser.readline()
while ter != 0xaf:
#print(str(ter))
print(str(ter.decode('utf-8').rstrip('\r\n')))
ter = Ser.readline()
sleep(1)
if i == 0:
print('login: root')
Ser.write(bytes("root", encoding='utf-8'))
else:
print('\n\n\n\n\nroot # Ser: ~ # ' + str(Serial_com[i]))
Ser.write(bytes(Serial_com[i], encoding='utf8'))
I realized that once the serial port is waiting for the python code (or the user) to write commands, that it sends the character 0xaf. It might be a coincidence, but still I wrote that as a stop condition for the reading from the terminal
the code can read from the serial port, but once it needs to write to the serial port it won't proceed
I can't share the rest because it's confedencial for a project

Simple TELNET in Python - loop paused if no data coming

I'm trying to build a very simple TELNET client in Python and I'm getting problem on the last part: sending/receiving data to/from the server.
With the code I have, if no data arrives at the very beginnig, the loop get paused and I can't even send commands.
Here the interested part of the code:
# Infinite cycle that allows user to get and send data from/to the host
while True:
incoming_data = my_socket.recv(4096)
if not incoming_data:
print('Problem occurred - Connection closed')
my_socket.close()
sys.exit()
else:
# display data sent from the host trough the stdout
sys.stdout.write(incoming_data)
# Commands sent to the host
command = sys.stdin.readline()
my_socket.send(command)
(I think the program kinda of works if I try to connect to some hosts that send data at the beginning.)
The idea would be have two loops, running at the same time, getting data or sending data, but I can't get it to work.
I can't use the telnet library and I don't want to use the select library (only sys and socket).
You want to use the threading library.
The following program runs the receiving in one thread and the sending in another:
import socket
from threading import Thread
def listen(conn):
while True:
received = conn.recv(1024).decode()
print("Message received: " + received)
def send(conn):
while True:
to_send = input("Input message to send: ").encode()
conn.sendall(to_send)
host = "127.0.0.1"
port = 12345
sock = socket.socket()
sock.connect((host, port))
Thread(target=listen, args=[sock]).start()
Thread(target=send, args=[sock]).start()
This program is for Python 3. Python 2 is very similar, except print() works differently, and you don't need to encode() and decode() everything being sent through a socket.
The listen and send functions are run in parallel, so that as soon as data arrives, it is printed, but you can also send data at any time. Practically, you would probably want to make some changes so that the data isn't just printed over the input prompt. However, this would be hard just in a command line application.
Research queues for control over data passing between threads.
Let me know if you have any more questions.

Raspberry Pi is stuck when no char is received on the serial port

I am using an XBee module connected to my RPI, serial communication is established between both, the problem is my code gets stuck if there is no data present by the XBee, is there a away to solve this, I tried timeout but wasn't successful.
code:
ser = serial.Serial (
port = "/dev/ttyAMAO",
baudrate = 9600,
parity = serial.PARITY_NONE,
stopbits = serial,STOPBITS_ONE,
bytesize = serial.EIGHTBITS,
timeout = 0
)
ser = serial.Serial("/dev/ttyAMAO")
for c in ser.read():
l.append(c)
ser.read()
is a blocking call it is probably better to check if there is anything there to read first
if ser.inWaiting(): #only true if there is data waiting to be read
for c in ser.read():
....
or if you want your serial thread to run in parallel to your main program (ie. dont block user interface ever at all..) you should maybe look into something like twisted or asyncio
although typically with serial you are working with some device that wants 2-way communication, usually initiated with a query to the serial device, and you do want to actually block until you get a response. I will usually make a class to handle this for me
class MySerial:
def __init__(self,port,baudrate):
self.ser = serial.Serial(port,baudrate)
def query(cmd,terminal_char="\r"):
self.ser.write(cmd)
return ''.join(iter(ser.read,terminal_char))
s = MySerial("COM9",11200)
result = s.query("get -temp\r")
print result
this will accumulate an entire response until the specified terminal character is recieved

Select API not waiting the specified timeout

I am doing a combination of Socket programming and pexpect in the same code. I have got it working but with a minor glitch. The select API waits for the specified 5 seconds in the first iteration. As soon as it received an input from the client it no longer waits for 5 seconds even though it is specified in the loop. In short after the first client server interaction takes place, select has no effect! I understand how to bypass this in C++ but I am comparatively new to Python and am unable to figure out the reason. I have attached the code below and is a pretty simple one.
#!/usr/bin/python
#Basic Functionailty: to create a process and to take inputs from client machines
#This input will be given to a background process which will display the user the parsed output
#using pexpect
import pexpect
import socket
import select
TCP_IP = '127.0.0.1'
TCP_PORT = 50050
BUFFER_SIZE = 1024
#spawning a pexpect process and printing everything before the prompt appears
child = pexpect.spawn('./pox.py')
child.expect ('POX>')
print child.before
#binding to a port number and acting as a server
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind((TCP_IP, TCP_PORT))
server.listen(1)
input = [server]
#loop infinitely and get input and serve it to the process
#in addition to which if the process shows some messages display
#it to the user
while 1:
print 'Before select'
inputready,outputready,exceptready = select.select(input,[],[],5)
for s in inputready:
if s == server:
#if the input is from the server
conn, addr = s.accept()
print 'Connection address:', addr
input.append(conn)
data = conn.recv(BUFFER_SIZE)
if not data: continue
print "received data:", data
child.sendline (data)
else:
#if a time out occurs check the pexpect if it has any debug messages
i = child.expect ([pexpect.TIMEOUT, 'POX>'], timeout=1)
print child.before
if i == 0:
print child.before
You've modified input:
input.append(conn)
(and then called conn.recv to get some data, which will block until there is some data or EOF, but presumably there was some and you got it).
Having done that, on the next trip through the loop, it's likely that there is receive data, or EOF, ready for input on conn. I assume you immediately call child.expect (because s == conn and hence s != server). I'd bet that at this point, conn is at EOF, so that returns immediately, having done nothing. conn is still open, and still in input, so every time you call select it returns right away telling you that you can read another EOF from conn.

Python code to receive variable data continuously from serial port

I have Python 2.7.4 and pyserial-2.5 win32 installed on my PC. Here I am using a microcontroller device as a master (primary) and my pc as a slave (secondary). Here every time microcontroller will transmit data, and my PC has to receive the data through serial port. I want a code in Python to receive continuous data. Here the transmitted data size will vary all the time. Here I wrote a code to transmit data, and the code is
import serial
ser= serial.serial("COM10", 9600)
ser.write("Hello world\n")
x = ser.readline()
print(x)
With this code I can transmit data to the other PC, I crosschecked by opening HyperTerminal on the other PC and I can see the transmitted data (hello world).
I also wrote the code to receive data:
import serial
ser=serial.serial("COM10", 9600)
while 1:
if ser.inwaiting():
val = ser.readline(ser.inwaiting())
print(val)
if I send the data (how are you) from HyperTerminal, I can receive the data in my PC, with the above code.
Until this every thing is fine.
My question now is, when the microcontroller is transmitting variable data at variable time periods, I need to receive that data in my PC with Python. Do I need to use a buffer to store the received data? If yes, how will the code be? Why and how to use a buffer in Python? According to my search in internet, buffer is used to slice the string.
Typically what you do for communicating with a micro is to use single characters for something lightweight or create a communication protocol. Basically you have a start flag, end flag, and some sort of checksum to make sure the data gets across correctly. There are many ways to do this.
The below code is for Python 3. You may have to make changes for bytes data.
# On micro
data = b"[Hello,1234]"
serial.write(data)
On the computer you would run
def read_data(ser, buf=b'', callback=None):
if callback is None:
callback = print
# Read enough data for a message
buf += ser.read(ser.inwaiting()) # If you are using threading +10 or something so the thread has to wait for more data, this makes the thread sleep and allows the main thread to run.
while b"[" not in buf or b"]" not in buf:
buf += ser.read(ser.inwaiting())
# There may be multiple messages received
while b"[" in buf and b']' in buf:
# Find the message
start = buf.find(b'[')
buf = buf[start+1:]
end = buf.find(b']')
msg_parts = buf[:end].split(",") # buf now has b"Hello, 1234"
buf = buf[end+1:]
# Check the checksum to make sure the data is valid
if msg_parts[-1] == b"1234": # There are many different ways to make a good checksum
callback(msg_parts[:-1])
return buf
running = True
ser = serial.serial("COM10", 9600)
buf = b''
while running:
buf = read_data(ser, buf)
Threading is useful if you are using a GUI. Then you can have your thread read data in the background while your GUI displays the data.
import time
import threading
running = threading.Event()
running.set()
def thread_read(ser, callback=None):
buf = b''
while running.is_set():
buf = read_data(ser, buf, callback)
def msg_parsed(msg_parts):
# Do something with the parsed data
print(msg_parsed)
ser = serial.serial("COM10", 9600)
th = threading.Thread(target=thread_read, args=(ser, msg_parsed))
th.start()
# Do other stuff while the thread is running in the background
start = time.clock()
duration = 5 # Run for 5 seconds
while running.is_set():
time.sleep(1) # Do other processing instead of sleep
if time.clock() - start > duration
running.clear()
th.join() # Wait for the thread to finish up and exit
ser.close() # Close the serial port
Note that in the threading example I use a callback which is a function that gets passed as a variable and gets called later. The other way this is done is by putting the data in a Queue and then processing the data in the Queue in a different part of the code.

Categories

Resources