pySerial works in one script but not another - python

Now getting output, yet it is wrong Post modified to reflect progress.
I have been reading the documentation as well as following links from this site. I was able to find a script that works in reading data from my Arduino serial output.
It is as follows:
import time
import serial
# configure the serial connections (the parameters differs on the device you are connecting to)
ser = serial.Serial(
port='/dev/ttyACM0',
baudrate=115200,
parity=serial.PARITY_ODD,
stopbits=serial.STOPBITS_TWO,
bytesize=serial.SEVENBITS
)
ser.isOpen()
print 'Enter your commands below.\r\nInsert "exit" to leave the application.'
input=1
while 1 :
# get keyboard input
input = raw_input(">> ")
# Python 3 users
# input = input(">> ")
if input == 'exit':
ser.close()
exit()
else:
# send the character to the device
# (note that I happend a \r\n carriage return and line feed to the characters - this is requested by my device)
ser.write(input + '\r\n')
out = ''
# let's wait one second before reading output (let's give device time to answer)
time.sleep(1)
while ser.inWaiting() > 0:
out += ser.read(1)
if out != '':
print ">>" + out
The output window of Python opens and the code is executed. I am able to type 'exit' to exit or 'read' and a ton of lines from the Arduino serial monitor are now populated in the Python output window.
What I would like is to have the output from the Arduino to constantly be populated in the Python output window. (later I will try to plot the data using Matplotlib)
The code I used to attempt to read everything from the Arduinb is as such:
import time
import serial
# configure the serial connections (the parameters differs on the device you are connecting to)
ser = serial.Serial(
port='/dev/ttyACM0',
baudrate=115200,
parity=serial.PARITY_ODD,
stopbits=serial.STOPBITS_TWO,
bytesize=serial.SEVENBITS
)
ser.isOpen()
input=1
while True:
#First things first, lets wait for data prior to reading
time.sleep(1)
if (ser.inWaiting()>0):
myArduinoData = ser.read()
print myArduinoData
However, when I use the above code the Python execution hangs and I get no output from the serial monitor. This was now corrected by the above code and the community help
The new problem is the output only giving a single digit value and not the two to three digit value output to the Arduino serial monitor.
thanks to #jalo I was able to get the values in question by specifying a byte value in my inWaiting and ser.read statements. The change is as follows:
(ser.inWaiting()>4):
ser = ser.read(4)
Thank you.

Related

Interfacing MIDI device (Akai LPD8 mk2) from Python - works for reading but not sending

Preface
I have an Akai LPD8 mk2 which I would like to interface from Python.
There are two projects that (I believe) provide interfaces for the predecessor (mk1):
https://github.com/zetof/LPD8
https://github.com/DrLuke/python-lpd8
I found I needed to make a few small changes to get the reading to work with these libs (*example below, not sure how relevant this is and it could easily be because I misunderstand something).
However, no matter what I tried, I could not get the sending to the device to work. Specifically, changing the state (on/off) of the pads of the device from Python. This state is indicated by the color of the pads' lighting.
Question
A minimal example of what I thought should work is the following:
With the very nice mido library, I would like to read a few state changes of the pads. Then send them back with a small delay (similar idea here: https://stackoverflow.com/a/29501455/655404):
from time import sleep
import mido
def get_ioport_name(search):
# see footnote **
names = mido.get_ioport_names()
names = set(n for n in names if search in n)
assert len(names) == 1
return names.pop()
def get_messages(port):
return list(port.iter_pending())
name = get_ioport_name("LPD8")
port = mido.open_ioport(name) # see footnote ***
# ensure that there are no messages in the queue
get_messages(port)
#pause
input("Press a few pads, then press Enter to continue...")
msgs = get_messages(port)
print(f"Recorded these messages:\n{msgs}\n")
print("Echoing these messages:")
for m in msgs:
print(m)
port.send(m)
sleep(1)
This runs and gives no error messages. However, the expected color changes on the pads do not happen.
What am I doing wrong?
I have tried with different backends for mido (rtmidi, portmidi, pygame) as well as using rtmidi directly, all with the same result.
Footnotes
*Example for changes needed:
I had to change the constant's block here https://github.com/zetof/LPD8/blob/master/lpd8/lpd8.py#L16 to:
NOTE_ON = 144+9
NOTE_OFF = 128+9
CTRL = 176
PGM_CHG = 192+9
**Port names
names = mido.get_ioport_names() gives:
['Midi Through:Midi Through Port-0 14:0',
'LPD8 mk2:LPD8 mk2 MIDI 1 20:0',
'Midi Through:Midi Through Port-0 14:0',
'LPD8 mk2:LPD8 mk2 MIDI 1 20:0']
and set(names) gives:
{'LPD8 mk2:LPD8 mk2 MIDI 1 20:0', 'Midi Through:Midi Through Port-0 14:0'}
The result is also the same for mido.get_input_names() and mido.get_output_names().
***Ports in mido
From what I understand mido has three port classes:
open_input() # only receive
open_output() # only send
open_ioport() # both (and what I used above)
If I change from ioport to using an input/output pair, the result is the same:
port_in = mido.open_input(name)
port_out = mido.open_output(name)
# ensure that there are no messages in the queue
get_messages(port_in)
#pause
input("Press a few pads, then press Enter to continue...")
msgs = get_messages(port_in)
print(f"Recorded these messages:\n{msgs}\n")
print("Echoing these messages:")
for m in msgs:
print(m)
port_out.send(m)
sleep(1)

NFQueue/Scapy Man in the Middle

I'm trying to construct a man in the middle attack on a webpage (i.e. HTTP traffic). I'm doing this by using a Linux machine attached to Ethernet and a client attached to the Linux box via its WiFi hotspot.
What I've done so far is use NFQueue from within the IPTables Linux firewall to route all TCP packets on the FORWARD chain to the NFQueue queue, which a Python script is picking up and then processing those rules. I'm able to read the data off of the HTTP response packets, but whenever I try to modify them and pass them back (accept the packets), I'm getting an error regarding the strings:
Exception AttributeError: "'str' object has no attribute 'build_padding'" in 'netfilterqueue.global_callback' ignored
My code is here, which includes things that I've tried that didn't work. Notably, I'm using a third-party extension for scapy called scapy_http that may be interfering with things, and I'm using a webpage that is not being compressed by gzip because that was messing with things as well. The test webpage that I'm using is here.
#scapy
from scapy.all import *
#nfqueue import
from netfilterqueue import NetfilterQueue
#scapy http extension, not really needed
import scapy_http.http
#failed gzip decoding, also tried some other stuff
#import gzip
def print_and_accept(packet):
#convert nfqueue datatype to scapy-compatible
pkt = IP(packet.get_payload())
#is this an HTTP response?
if pkt[TCP].sport == 80:
#legacy trial that doesn't work
#data = packet.get_data()
print('HTTP Packet Found')
#check what's in the payload
stringLoad = str(pkt[TCP].payload)
#deleted because printing stuff out clogs output
#print(stringLoad)
#we only want to modify a specific packet:
if "<title>Acids and Bases: Use of the pKa Table</title>" in stringLoad:
print('Target Found')
#strings kind of don't work, I think this is a me problem
#stringLoad.replace('>Acids and Bases: Use of the pK<sub>a</sub>', 'This page has been modified: a random ')
#pkt[TCP].payload = stringLoad
#https://stackoverflow.com/questions/27293924/change-tcp-payload-with-nfqueue-scapy
payload_before = len(pkt[TCP].payload)
# I suspect this line is a problem: the string assigns,
# but maybe under the hood scapy doesn't like that very much
pkt[TCP].payload = str(pkt[TCP].payload).replace("Discussion", "This page has been modified")
#recalculate length
payload_after = len(pkt[TCP].payload)
payload_dif = payload_after - payload_before
pkt[IP].len = pkt[IP].len + payload_dif
#recalculate checksum
del pkt[TCP].chksum
del pkt[IP].chksum
del pkt.chksum
print('Packet Modified')
#redudant
#print(stringLoad)
#this throws an error (I think)
print(str(pkt[TCP].payload))
#no clue if this works or not yet
#goal here is to reassign modified packet to original parameter
packet.set_payload(str(pkt))
#this was also throwing the error, so tried to move away from it
#print(pkt.show2())
#bunch of legacy code that didn't work
#print(GET_print(pkt))
#print(pkt.show())
#decompressed_data = zlib.decompress(str(pkt[TCP].payload), 16 + zlib.MAX_WBITS)
#print(decompressed_data)
#print(str(gzip.decompress(pkt[TCP].payload)))
# print(pkt.getlayer(Raw).load)
#print('HTTP Contents Shown')
packet.accept()
def GET_print(packet1):
ret = "***************************************GET PACKET****************************************************\n"
ret += "\n".join(packet1.sprintf("{Raw:%Raw.load%}\n").split(r"\r\n"))
ret += "*****************************************************************************************************\n"
return ret
print('Test: Modify a very specific target')
print('Program Starting')
nfqueue = NetfilterQueue()
nfqueue.bind(1, print_and_accept)
try:
print('Packet Interface Starting')
nfqueue.run()
except KeyboardInterrupt:
print('\nProgram Ending')
nfqueue.unbind()
Apologies in advance if this is hard to read or badly formatted code; Python isn't a language that I write in often. Any help is greatly appreciated!

How to send the result data to file text?

I am trying to send the resulted data from a python script to a file text.
import string
import serial
import time
from array import array
import struct
import binascii
ser = serial.Serial(
port='COM4',\
baudrate=230400,\
parity=serial.PARITY_NONE,\
stopbits=serial.STOPBITS_ONE,\
bytesize=serial.EIGHTBITS,\
timeout=0)
text_file = open('C:\\Users\\user\\Ciphertxt.txt', 'w')
f = open(r'C:\\Users\\user\\Plaintxt.txt', 'r')
for a in f:
plaintxt_16b=a[0:32]
plaintext=binascii.unhexlify(plaintxt_16b)
clear_msg=b'\x24'+b'\x73'+b'\x10'+plaintext
ser.write(clear_msg)
time.sleep(0.5)
print(ser.read(156))
text_file.write(ser.read(156))
ser.close() # close ports
This line print(ser.read(156)) already displayed for me the good data, so I am sure about results which is:
*************************
e0370734 313198a2 885a308d 3243f6a8
Go encrypt..
Encrypt done..
196a0b32 dc118597 2dc09fb 3925841d
***********************
*************************
ccddeeff 8899aabb 44556677 112233
Go encrypt..
Encrypt done..
d6e4d64b 27d8d055 c5c7573a 8df4e9aa
***********************
*************************
54776f20 4f6e6520 4e696e65 2054776f
Go encrypt..
Encrypt done..
155d4a8c 17d78b93 409745dd e73be537
***********************
But the Ciphertxt.txt file just gives me those three lines.
**
**
**
I don't understand where the problem is.
Once you read the data from ser.read(156), that data is removed from ser and it won't be available to you again.
So, reading that data twice can either give you garbage data or not give any data at all.
You should store it in a variable. The following code would work just fine.
data = ser.read(156)
print data
text_file.write(data)
Probably, the issues lies in reading from your serial port two times by executing two ser.read, thus you should do:
ser.write(clear_msg)
time.sleep(0.5)
recv_msg = ser.read(156)
print(recv_msg) #for debugging
text_file.write(recv_msg)

Speeding Up Data Transfer Using Pyserial in Python

I have created a data transfer program using python and the pyserial module. I am currently using it to communicate text file over a radio device between a Raspberry Pi and my computer. The problem is, the file I am trying to send, which contains 5000 lines of text and is 93.0 Kb in size is taking quite a while to send. To be exact, it takes about a full minute. I need this to be done within seconds. Here is the following code, I am sure that there are many optimizations that can be made with file reading and such that would increase the data transfer speed. My radio device has a data speed of 250 kbps, which is obviously not being reached. Any help would be greatly appreciated.
Code to send(located on raspberry pi)
def s_file():
print 'start'
readline = lambda : iter(lambda:ser.read(1),"\n")
name = "".join(readline())
print name
file_loc = directory_name + name
sleep(1)
print('Waiting for command from client to send file...')
while "".join(readline()) != "<<SENDFILE>>":
pass
with open(file_loc) as FileObj:
for lines in FileObj:
ser.write(lines)
ser.write("\n<<EOF>>\n")
print 'done'
Code to receive(on my laptop)
def r_f_bird(self): #send command to bird to start func,
if ser_open == True:
readline = lambda : iter(lambda:ser.read(1),"\n")
NAME = self.tb2.get()
ser.write('/' + NAME)
print NAME
sleep(0.5)
ser.write('\n<<SENDFILE>>\n')
start = clock()
with open(str(NAME),"wb") as outfile:
while True:
line = "".join(readline())
if line == "<<EOF>>":
break
print >> outfile, line
elapsed = clock() - start
print elapsed
ser.flush()
else:
pass
Perhaps the overhead of ser.read(1) is slowing things down. It seems like you have a \n at the end of each line, so try using pySerial's readline() method rather than rolling your own. Changing line = "".join(readline()) to line = ser.readline() ought to do it. You will also need to change your loop end condition to == "<<EOF>>\n".
You may also need to add a ser.flush() on the writing side.

Read from gpsd/gpsfake with python-gps

I've been trying very hard to get gpsfake to work with python-gps for the last days.
I execute gpsfake with the following example sentences, which I found on the internet:
gpsfake test_data.log
test_data.log:
$PMGNST,05.40,2,T,961,08.3,+04583,00*4C
$GPGLL,5036.9881,N,00707.9142,E,125412.480,A*3F
$GPGGA,125412.48,5036.9881,N,00707.9142,E,2,04,20.5,00269,M,,,,*17
$GPRMC,125412.48,A,5036.9881,N,00707.9142,E,00.0,000.0,230506,00,E*4F
$GPGSA,A,2,27,04,08,24,,,,,,,,,20.5,20.5,*12
$GPGSV,3,1,10,13,81,052,,04,58,240,39,23,44,064,,24,43,188,36*75
$GPGSV,3,2,10,02,42,295,,27,34,177,40,20,21,113,,16,12,058,*7F
$GPGSV,3,3,10,08,07,189,38,10,05,293,,131,11,117,,120,28,209,*76
Once it's running, I execute a Python script I found here:
import gps
import os
import time
if __name__ == '__main__':
session = gps.gps(verbose=1)
while 1:
os.system('clear')
session.next()
# a = altitude, d = date/time, m=mode,
# o=postion/fix, s=status, y=satellites
print
print ' GPS reading'
print '----------------------------------------'
print 'latitude ' , session.fix.latitude
print 'longitude ' , session.fix.longitude
print time.strftime("%H:%M:%S")
print
print ' Satellites (total of', len(session.satellites) , ' in view)'
for i in session.satellites:
print '\t', i
time.sleep(3)
I gets a connection, but then it gets locked in class gpscommon, method read() on line 80:
frag = self.sock.recv(4096)
which tells me that no data is received or even sent.
When I try to connect over the terminal with
connect 127.0.0.1 2947
the only response is
{"class":"VERSION","release":"3.4","rev":"3.4","proto_major":3,"proto_minor":6}
and nothing else.
Does anyone have an idea how to get the correct data? I tried various NMEA log files, so I think that's not the reason.
To get location reports you'll have to start 'Watching' the devices gpsd/gpsfake is monitoring, try sending:
?WATCH={"enable":true,"json":true};
Which will enable updates from all devices in JSON format.
To stop updates:
?WATCH={"enable":false};
Once watching is enabled you'll get 'TPV' responses containing location data and 'SKY' responses with satellite data.
More information about clients: http://www.catb.org/gpsd/client-howto.html
GPSd JSON format: http://www.catb.org/gpsd/gpsd_json.html

Categories