PySerial has problems reading Arduino - python

I want to dump a ROM. The Arduino waits until it receives the key which is one digit. I use this digit as the starting command and as a parameter to tell the Arduino how big the ROM is. This is my Arduino code (simplified for testing):
void setup() {
Serial.begin(115200);
}
void loop() {
uint8_t key = 10;
while(key > 2){
key = Serial.read();
key -= '0';
}
Serial.print("75 A E8 98 D4 E8 8A E4 E8 EB E4 F9 C3 60 3C 55");
Serial.println("");
Serial.print("74 C E8 35 3 E8 79 E1 88 96 9F 0 EB F E8");
Serial.println("");
Serial.print("0 E8 9 1 FF 76 19 E8 4F DC 8F 46 19 61 F8 C3");
Serial.println("");
Serial.print("E8 5E E1 33 C0 EB 29 B8 1 0 81 BE A0 0 0 51");
Serial.println("");
Serial.println("EOF");
}
And this is my Python code to tell the Arduino to start dumping and to read the response:
line = " "
ser = serial.Serial("COM10", 115200, timeout=1)
ser.write("1")
ser.flush()
while line != "EOF":
line = ser.readline().strip
print line
ser.close()
The problem: its printing nothing.
PS: already tried different values for timeout but neither 0 or None worked.
EDIT: Everyone else is invited to awnser! I'm using Python 2.7.6 - Anaconda 1.9.2 32bit # Win7x64
EDIT2 The solution is to add a delay of 2secs (time.speep(2)) before the first write in python. More details here: pySerial works fine in Python interpreter, but not standalone

Pyserial certainly has no problem reading arduino serial ... I have done it many many times
try this
ser = serial.Serial("COM10", 115200, timeout=5)
ser.flush()
ser.write("1")
print ser.read(1000)
ser.close()
or abstract it further
class MySerial:
def __init__(self,*args,**kwargs):
kwargs["timeout"] = kwargs.get("timeout",5) #ensure timeout set
self.ser = serial.Serial(*args,**kwargs)
def query(self,cmd):
self.ser.flush()
self.ser.write(cmd)
return self.ser.read(100000)
ser = MySerial("COM10", 115200, timeout=5)
print ser.query("1")
also I am a little curious why you are writing hex to a string all space separated like that instead of just writing in bytes...
you can verify that you can get reads as follows
void setup() {
Serial.begin(115200);
}
void loop() {
Serial.read();
Serial.println("Hello World!\r");
}
this will wait for anything then send the hello world string ... make sure you see that at least then continue tweaking it to behave as you want (EG. get a specific value from the read before continuing ,send a message other than hello world ... my guess is that its not getting past your Serial.read() for whatever reason

Related

Python NMEA GNSS Cold Start command

On my hardware, I translate the usb port to com using the usb_transit_on internal command.
After that, I connect to the port using the program and when I enter this command "b5 62 06 04 04 00 ff ff 00 00 0c 5d"
I perform a cold restart and note the time spent by the satellites, the task is to do the same only without the program, the question is whether it is possible how then send command "b5 62 06 04 04 00 ff ff 00 00 0c 5d" or "$PMTK103*30"
With Python, I tried but nothing happened.
import time
import pynmea2
import serial
import csv
import io
def status():
# ser = serial.Serial('COM12')
ser = serial.Serial(
port = "COM12",
baudrate = 9600,
bytesize = serial.EIGHTBITS,
parity = serial.PARITY_NONE,
stopbits = serial.STOPBITS_ONE
)
print("Waiting for data")
ser.write(b"b5 62 06 04 04 00 ff ff 00 00 0c 5d")
while True:
message = ser.readline().decode()
message = message.strip()
if "$GNRMC" in message:
gnrmc = pynmea2.parse(message)
gnrmc_status = gnrmc.status
return gnrmc_status
else:
continue
print(status())
I thought with this command you can send a message to the GNSS module

Reading data from Arduino to Python using bluetooth

I'm sending data with Arduino through Bluetooth (jy-mcu HC-06), using this simple code:
int a;
void setup() {
Serial.begin(57600);
a = 0;
delay(2000);
}
void loop() {
Serial.println(a);
a++;
delay(40);
}
My issue is that when I try to read the data with Python (on Linux), the first 20 seconds (approx.), some data is corrupted. But after this, I can read the data correctly without any other error.
Python code:
import serial
ser = serial.Serial()
ser.port = "/dev/rfcomm0"
ser.baudrate = 57600
ser.open()
while True:
print(ser.readline())
Arduino code is a loop that sends an integer every 40ms and sums one to this integer. An example of the data corrupted:
108
109
11161831191
192
193
194
195
1111
122222222222
2220
22266
267
268
269
270
133333533333633333373
33333333344444444444444444444444444444544444444444444444491
492
493
494
I power the Arduino with an external power supply that gives 5V and 3A with a lot of stability.
I tried to read the data with an Android Bluetooth terminal app and it worked perfectly all the time. For that reason, I suppose that the error is in the Python code.
I have read a lot of information on the Internet and I have made a lot of changes in the code but nothing solves the problem. This is one of my latest codes, just to show some of my tests:
import serial, time
import sys
ser = serial.Serial()
ser.port = "/dev/rfcomm0"
ser.baudrate = 57600
ser.timeout = 1
ser.setDTR(False)
ser.setRTS(False)
ser.open()
old_data = 0
new_data = 0
ser.flushInput()
ser.flush()
ser.flushOutput()
time.sleep(1)
print("Start")
while True:
raw_data = ser.readline()
try:
ser.flushInput()
new_data = int(raw_data)
ser.flush()
except ValueError:
pass
print raw_data
if (old_data != new_data -1 and old_data != 0):
print('ERROR#####################################################')
old_data = new_data
time.sleep(0.01)
I appreciate any help, and of course, I will post here any update on this issue.
Thank you in advance!
The baudrate of bluetooth module(HC-06) is different from that of Arduino.
Try ser.baudrate = 115200 in your python code.

why is it timing out like this?

I'm trying to build a TCP-proxy script that sends and receives data, i managed to get it to listen but it doesn't seem to be connecting properly...my code looks right to me and after checking python docs(i'm trying to run it in python 2.7 and 3.6) i get this timeout message:
Output:
anon#kali:~/Desktop/python scripts$ sudo python TCP\ proxy.py 127.0.0.1 21 ftp.target.ca 21 True
[*] Listening on 127.0.0.1:21d
[==>] Received incoming connection from 127.0.0.1:44806d
Exception in thread Thread-1:
Traceback (most recent call last):
File "/usr/lib/python2.7/threading.py", line 801, in __bootstrap_inner
self.run()
File "/usr/lib/python2.7/threading.py", line 754, in run
self.__target(*self.__args, **self.__kwargs)
File "TCP proxy.py", line 60, in proxy_handler
remote_socket.connect((remote_host,remote_port))
File "/usr/lib/python2.7/socket.py", line 228, in meth
return getattr(self._sock,name)(*args)
error: [Errno 110] Connection timed out
i looked into the file "/usr/lib/python2.7/socket.py" but couldn't really understand what i was looking for as it seemed right when i compared it to python docs and my script
my code:
# import the modules
import sys
import socket
import threading
#define the server
def server_loop(local_host,local_port,remote_host,remote_port,receive_first):
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
server.bind((local_host, local_port))
server.listen(5)
print ("[*] Listening on %s:%sd" % (local_host, local_port))
except:
print("[!!] Failed to listen on %s:%sd" % (local_host,local_port))
print ("[!!] Check for others listening sockets or correct permissions")
sys.exit(0)
while True:
client_socket, addr = server.accept()
#print out the local connection information
print ("[==>] Received incoming connection from %s:%sd" % (addr[0],addr[1]))
#start a thread to talk to the remote host
proxy_thread = threading.Thread(target=proxy_handler,args=(client_socket,remote_host,remote_port,receive_first))
proxy_thread.start()
else:
print ("something went wrong")
def main():
#no fancy command-line parasing here
if len(sys.argv[1:]) !=5:
print ("Usage: ./TCP proxy.py [localhost] [localport] [remotehost] [remoteport] [receive_first]")
print("Example: ./TCP proxy.py 127.0.0.1 9000 10.12.132.1 9000 True")
#set up local listening parameters
local_host = sys.argv[1]
local_port = int(sys.argv[2])
#set up remote target
remote_host = sys.argv[3]
remote_port = int(sys.argv[4])
#this tells proxy to connect and receive data before sending to remote host
receive_first = sys.argv[5]
if "True" in receive_first:
receive_first = True
else:
receive_first = False
#now spin up our listening socket
server_loop(local_host,local_port,remote_host,remote_port,receive_first)
def proxy_handler(client_socket, remote_host, remote_port, receive_first):
#connect to the remote host
remote_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
remote_socket.connect((remote_host,remote_port))
#receive data from the remote end if necessary
if receive_first:
remote_buffer = receive_from(remote_socket)
hexdump(remote_buffer)
#send it to the repsonse handler
remote_buffer = respsonse_handler(remote_buffer)
#if data is able to be sent to local client, send it
if len(remote_buffer):
print ("[<==] Sending %d bytes to localhost." % len(remote_buffer))
client_socket.send(remote_buffer)
#now loop and read from local,sent to remote,send to local,rinse/wash/repeat
while True:
#read from local host
local_buffer = receive_from(client_socket)
if len(local_buffer):
print ("[==>] Received %d bytes from localhost." % len(local_buffer))
#send it to request handler
local_buffer = request_handler(local_buffer)
#send data to remote host
remote_socket.send(local_buffer)
print ("[==>] Sent to remote.")
#receive back response
remote_buffer = receive_from(remote_socket)
if len(remote_buffer):
print ("[<==] Received %d bytes from remote." % len(remote_buffer))
hexdump(remote_buffer)
#send response to handler
remote_buffer = response_handler(remote_buffer)
#send response to local socket
client_socket.send(remote_buffer)
print ("[<==] Sent to localhost.")
#if no data left on either side, close connection
if not len(local_buffer) or not len(remote_buffer):
client_socket.close()
remote_socket.close()
print ("[*] No more data, closing connections.")
break
#this is a pretty hex dumping function taken from the comments of http://code.activestate.com/recipes/142812-hex-dumper/
def hexdump(src, length=16):
result = []
digits = 4 if isinstance(src,unicode) else 2
for i in xrange(0,len(src), length):
s = src[i:i+length]
hexa = b' '.join(["%0*X" % (digits, ord(x)) for x in s])
text = b' '.join([x if 0x20 <= ord(x) < 0x7F else b'.' for x in s])
result.append( b"%04X %-*s %s" % (i, length*(digits + 1), hexa, text) )
print (b'/n'.join(result))
def receive_from(connection):
buffer = ""
#set a 2 second timeout; depending on your target this may need to be adjusted
connection.settimeout(2)
try:
#keep reading the buffer until no more data is there or it times out
while True:
data = connection.recv(4096)
if not data:
break
buffer += data
except:
pass
return buffer
#modify any requested destined for the remote host
def request_handler(buffer):
#perform packet modifications
return buffer
#modify any responses destined for the local host
def response_handler(buffer):
#perform packet modifications
return buffer
main()
i have tried different ftp servers/sites,etc but get the same result, where am i going wrong with my code? any input or direction would be greatly appreciated.
okay so turns out my script is good just the ftp servers i was running weren't haha
this is the final output:
anon#kali:~/Desktop/python scripts$ sudo python TCP\ proxy.py 127.0.0.1 21 ftp.uconn.edu 21 True
[*] Listening on 127.0.0.1:21d
[==>] Received incoming connection from 127.0.0.1:51532d
0000 32 32 30 20 50 72 6F 46 54 50 44 20 31 2E 32 2E 2 2 0 P r o F T P D 1 . 2 ./n0010 31 30 20 53 65 72 76 65 72 20 28 66 74 70 2E 75 1 0 S e r v e r ( f t p . u/n0020 63 6F 6E 6E 2E 65 64 75 29 20 5B 31 33 37 2E 39 c o n n . e d u ) [ 1 3 7 . 9/n0030 39 2E 32 36 2E 35 32 5D 0D 0A 9 . 2 6 . 5 2 ] . .
[<==] Sending 58 bytes to localhost.
[==>] Received 353 bytes from localhost.
[==>] Sent to remote.
[<==] Received 337 bytes from remote.

ZMQ: No subscription message on XPUB socket for multiple subscribers (Last Value Caching pattern)

I implemented the Last Value Caching (LVC) example of ZMQ (http://zguide.zeromq.org/php:chapter5#Last-Value-Caching), but can't get a 2nd subscriber to register at the backend.
The first time a subscriber comes on board, the event[0] == b'\x01' condition is met and the cached value is sent, but the second subscriber (same topic) doesn't even register (if backend in events: is never true). Everything else works fine. Data gets passed from the publisher to the subscribers (all).
What could be the reason for this? Is the way the backend is connected correct? Is this pattern only supposed to work with the first subscriber?
Update
When I subscribe the 2nd subscriber to another topic, I get the right behaviour (i.e. \x01 when subscribing). This really seems to work for the first subscriber onlt . Is is a bug in ZeroMQ?
Update 2
Here's a minimal working example that shows that the LVC pattern is not working (at least not the way it's implemented here).
# subscriber.py
import zmq
def main():
ctx = zmq.Context.instance()
sub = ctx.socket(zmq.SUB)
sub.connect("tcp://127.0.0.1:5558")
# Subscribe to every single topic from publisher
print 'subscribing (sub side)'
sub.setsockopt(zmq.SUBSCRIBE, b"my-topic")
poller = zmq.Poller()
poller.register(sub, zmq.POLLIN)
while True:
try:
events = dict(poller.poll(1000))
except KeyboardInterrupt:
print("interrupted")
break
# Any new topic data we cache and then forward
if sub in events:
msg = sub.recv_multipart()
topic, current = msg
print 'received %s on topic %s' % (current, topic)
if __name__ == '__main__':
main()
And here's the broker (as in the example, but with a bit more verbosity and an integrated publisher).
# broker.py
# from http://zguide.zeromq.org/py:lvcache
import zmq
import threading
import time
class Publisher(threading.Thread):
def __init__(self):
super(Publisher, self).__init__()
def run(self):
time.sleep(10)
ctx = zmq.Context.instance()
pub = ctx.socket(zmq.PUB)
pub.connect("tcp://127.0.0.1:5557")
cnt = 0
while True:
msg = 'hello %d' % cnt
print 'publisher is publishing %s' % msg
pub.send_multipart(['my-topic', msg])
cnt += 1
time.sleep(5)
def main():
ctx = zmq.Context.instance()
frontend = ctx.socket(zmq.SUB)
frontend.bind("tcp://*:5557")
backend = ctx.socket(zmq.XPUB)
backend.bind("tcp://*:5558")
# Subscribe to every single topic from publisher
frontend.setsockopt(zmq.SUBSCRIBE, b"")
# Store last instance of each topic in a cache
cache = {}
# We route topic updates from frontend to backend, and
# we handle subscriptions by sending whatever we cached,
# if anything:
poller = zmq.Poller()
poller.register(frontend, zmq.POLLIN)
poller.register(backend, zmq.POLLIN)
# launch a publisher
p = Publisher()
p.daemon = True
p.start()
while True:
try:
events = dict(poller.poll(1000))
except KeyboardInterrupt:
print("interrupted")
break
# Any new topic data we cache and then forward
if frontend in events:
msg = frontend.recv_multipart()
topic, current = msg
cache[topic] = current
backend.send_multipart(msg)
### this is where it fails for the 2nd subscriber.
### There's never even an event from the backend
### in events when the 2nd subscriber is subscribing.
# When we get a new subscription we pull data from the cache:
if backend in events:
print 'message from subscriber'
event = backend.recv()
# Event is one byte 0=unsub or 1=sub, followed by topic
if event[0] == b'\x01':
topic = event[1:]
print ' => subscribe to %s' % topic
if topic in cache:
print ("Sending cached topic %s" % topic)
backend.send_multipart([ topic, cache[topic] ])
elif event[0] == b'\x00':
topic = event[1:]
print ' => unsubscribe from %s' % topic
if __name__ == '__main__':
main()
Running this code (1 x broker.py, 2 x subscriber.py) shows that the first subscriber registers at the broker as expected (\x01 and cache lookup), but the 2nd subscriber does not get registered the same way. Interestingly, the 2nd subscriber is hooked up to the pub/sub channel, as after a while (10 sec) both subscribers receive data from the publisher.
This is very strange. Perhaps some of my libraries are outdated. Here's what I got:
Python 2.7.9 (v2.7.9:648dcafa7e5f, Dec 10 2014, 10:10:46)
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import zmq
>>> zmq.__version__
'14.1.1'
$ brew info zeromq
zeromq: stable 4.0.5 (bottled), HEAD
High-performance, asynchronous messaging library
http://www.zeromq.org/
/usr/local/Cellar/zeromq/4.0.5_2 (64 files, 2.8M) *
Poured from bottle
From: https://github.com/Homebrew/homebrew/blob/master/Library/Formula/zeromq.rb
==> Dependencies
Build: pkg-config ✔
Optional: libpgm ✘, libsodium ✘
Update 3
This behaviour can also be observed in zeromq 4.1.2 and pyzmq-14.7.0 (with or without libpgm and libsodium installed).
Update 4
Another observation suggests that the first subscriber is somehow handled differently: The first subscriber is the only one unsubscribing in the expected way from the XPUB socket (backend) by preceding its subscription topic with \x00. The other subscribers (I tried more than 2) stayed mute on the backend channel (although receiving messages).
Update 5
I hope I'm not going down a rabbit hole, but I've looked into the czmq bindings and ran my Python example in C. The results are the same, so I guess it's not a problem with the bindings, but with libzmq.
I also verified that the 2nd subscriber is sending a subscribe message and indeed I can see this on the wire:
First subscribe:
0000 02 00 00 00 45 00 00 3f 98 be 40 00 40 06 00 00 ....E..? ..#.#...
0010 7f 00 00 01 7f 00 00 01 fa e5 15 b6 34 f0 51 c3 ........ ....4.Q.
0020 05 e4 8b 77 80 18 31 d4 fe 33 00 00 01 01 08 0a ...w..1. .3......
0030 2a aa d1 d2 2a aa cd e9 00 09 01 6d 79 2d 74 6f *...*... ...my-to
0040 70 69 63 pic
2nd subscribe message with difference (to above) marked and explained. The same data is sent in the subscribe frame.
identification
v
0000 02 00 00 00 45 00 00 3f ed be 40 00 40 06 00 00 ....E..? ..#.#...
src port sequence number
v v v v v
0010 7f 00 00 01 7f 00 00 01 fa e6 15 b6 17 da 02 e7 ........ ........
Acknowledgement number window scaling factor
v v v v v
0020 71 4b 33 e6 80 18 31 d5 fe 33 00 00 01 01 08 0a qK3...1. .3......
timestamp value timestamp echo reply
v v v |<-------- data -------
0030 2a aa f8 2c 2a aa f4 45 00 09 01 6d 79 2d 74 6f *..,*..E ...my-to
------>|
0040 70 69 63 pic
I found the solution for this problem, and even though I read the docs front to back and back to front, I had not seen it. The key is XPUB_VERBOSE. Add this line to after the backend initialisation and everything works fine
backend.setsockopt(zmq.XPUB_VERBOSE, True)
Here's an extract from the official documentation:
ZMQ_XPUB_VERBOSE: provide all subscription messages on XPUB sockets
Sets the XPUB socket behavior on new subscriptions and
unsubscriptions. A value of 0 is the default and passes only new
subscription messages to upstream. A value of 1 passes all
subscription messages upstream.
Option value type int Option value unit 0, 1 Default value 0
Applicable socket types ZMQ_XPUB
Pieter Hintjens has some more information on this in his blog. This is the relevant section:
A few months ago we added a neat little option (ZMQ_XPUB_VERBOSE) to
XPUB sockets that disables its filtering of duplicate subscriptions.
This now works for any number of subscribers. We use this as follows:
void *publisher = zsocket_new (ctx, ZMQ_XPUB);
zsocket_set_xpub_verbose (publisher, 1);
zsocket_bind (publisher, "tcp://*:6001");
The LVC pattern description should be updated to reflect this setting, as this pattern won't work otherwise.

How to test for hexidecimal output on serial port in python

When i send a command over serial, the slave responds with a hexidecimal sequence, i.e.:
this series:
05 06 40 00 02 05 F6 5C
gives me
05 07 40 05 02 05 71 37 FF
The response always ends with the FF byte. So i want to read the bytes into a buffer untill i encounter FF. Than the buffer should be printed and the function should return.
import serial
s_port = 'COM1'
b_rate = 2400
#method for reading incoming bytes on serial
def read_serial(ser):
buf = ''
while True:
inp = ser.read(size=1) #read a byte
print inp.encode("hex") #gives me the correct bytes, each on a newline
buf = buf + inp #accumalate the response
if 0xff == inp.encode("hex"): #if the incoming byte is 0xff
print inp.encode("hex") # never here
break
return buf
#open serial
ser = serial.Serial(
port=s_port,
baudrate=b_rate,
timeout=0.1
)
while True:
command = '\x05\x06\x40\x00\x02\x05\xF6\x5C' #should come from user input
print "TX: "
ser.write(command)
rx = read_serial(ser)
print "RX: " + str(rx)
gives me:
TX:
05
07
40
05
02
05
71
37
ff
Why is the condition never met?
It's because you're comparing apples and oranges. inp.encode("hex") returns a string. Let's say you read the letter "A". "A".encode("hex") returns the string "41" and 0x41 != "41". You should either do:
if '\xff' == inp:
....
Or, convert inp into a number using ord():
if 0xff == ord(inp):
....
Then it should work as expected.

Categories

Resources