I am trying to read some serial data from raspberry pi 3 using pyserial api, I need the data in a particular sequence e.g 3xxx7xxxBxxxExxx, however, sometimes the data stream starts from Exxx3xxx7xxxBxxx, how can I ensure that I always read the right sequence irrespective of how the data streams in.
This is for reading data from a control card used in a special pump application.
import serial
import time
ser = serial.Serial(
port = '/dev/ttyACM0',
baudrate = 9600,
parity = serial.PARITY_NONE,
stopbits = seial.STOPBITS_ONE,
bytesize = serial.EIGHTBITS,
timeout = 1
)
time.sleep = 1
try:
while 1:
if ser.inWaiting() > 0:
data = ser.read(8)
print(data.hex())
this gives me the result in 3xxx7xxxBxxxExxx sometimes and other times it starts from 7xxx or Exxx, however, I always want to be able to extract the sequence 3xxx7xxxBxxxExxx irrespective of where the stream starts from.
Assuming that the marker which you use to determine the start of the sequence is a full byte 0x30 you can try the following code. It will read one byte at a time until the start marker is found. Then it will read another 7 bytes and append them:
import serial
import time
ser = serial.Serial(
port = '/dev/ttyACM0',
baudrate = 9600,
parity = serial.PARITY_NONE,
stopbits = seial.STOPBITS_ONE,
bytesize = serial.EIGHTBITS,
timeout = 1
)
time.sleep = 1
start_marker = b'\xE0'
try:
while 1:
if ser.inWaiting() > 0:
data = ser.read(1)
if data != start_marker:
continue
data += ser.read(7)
print(data.hex())
EDIT
Try this code to match the most significant 4 bits of each bytes pair:
import serial
import time
ser = serial.Serial(
port = '/dev/ttyACM0',
baudrate = 9600,
parity = serial.PARITY_NONE,
stopbits = seial.STOPBITS_ONE,
bytesize = serial.EIGHTBITS,
timeout = 1
)
time.sleep = 1
data = bytes()
try:
while 1:
if ser.inWaiting() > 0:
data += ser.read(1)
if len(data) < 8:
continue
if len(data) > 8:
data = data[-8:]
if not (
data[0] >> 4 == 0x3 and
data[2] >> 4 == 0x7 and
data[4] >> 4 == 0xB and
data[6] >> 4 == 0xE
):
continue
print(data.hex())
Related
I'm trying to use a python script to make a connection with my 4x4 keypad on Rastberry (RPi.GPIO).
The code does not work correctly, because the first and second rows does not respond. I'm trying to use pad4pi, but in my case, this not work.
This is the code I'm using in the moment.
(Main Control)
import RPi.GPIO as GPIO
import time
import serial
import Keypad
#import Open_CV
ROWS = 4 # number of rows of the Keypad
COLS = 4 #number of columns of the Keypad
keys = [ '1','2','3','A', #key code
'4','5','6','B',
'7','8','9','C',
'*','0','#','D' ]
rowsPins = [18,22,29,31] #connect to the row pinouts of the keypad
colsPins = [32,33,36,37] #connect to the column pinouts of the keypad
# the pins need to be these, because the others are already in use
# Configure the use of the serial terminal and the baud rate
ser = serial.Serial( #"/dev/ttyS0", 9600)
port='/dev/ttyS0', #Replace ttyS0 with ttyAM0 for Pi1,Pi2,Pi0
baudrate = 9600,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS,
timeout=1)
#ConfiguraĆ§Ć£o inicial dos terminais GPIO
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BOARD)
# call the video method
#video("teste.mp4")
def loop():
keypad = Keypad.Keypad(keys,rowsPins,colsPins,ROWS,COLS) #create Keypad object
keypad.setDebounceTime(50) #set the debounce time
# call the video method
#video('/home/pi/share/teste.mp4')
while(True):
key = keypad.getKey() #obtain the state of keys
if(key != keypad.NULL): #if there is key pressed, print its key code.
print ("You Pressed Key : %c "%(key))
ser.write(str.encode(key))
time.sleep(1)
#ret, frame = cap.read()
#gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
#cv2.imshow('frame',gray)
#if cv2.waitKey(1) & 0xFF == ord('q'):
# break
#cap.release()
#cv2.destroyAllWindows()
if __name__ == '__main__': #Program start from here
print ("Program is starting ... ")
try:
loop()
except KeyboardInterrupt: #When 'Ctrl+C' is pressed, exit the program.
GPIO.cleanup()
(keypad functions)
#!/usr/bin/env python3
########################################################################
# Filename : Keypad.py
# Description : The module of matrix keypad
# Author : freenove
# modification: 2016/07/13
########################################################################
import RPi.GPIO as GPIO
import time
#class Key:Define some of the properties of Key
class Key(object):
NO_KEY = '\0'
#Defines the four states of Key
IDLE = 0
PRESSED = 1
HOLD = 2
RELEASED = 3
#define OPEN and CLOSED
OPEN = 0
CLOSED =1
#constructor
def __init__(self):
self.kchar = self.NO_KEY
self.kstate = self.IDLE
self.kcode = -1
self.stateChanged = False
class Keypad(object):
NULL = '\0'
LIST_MAX = 10 #Max number of keys on the active list.
MAPSIZE = 10 #MAPSIZE is the number of rows (times 16 columns)
bitMap = [0]*MAPSIZE
key = [Key()]*LIST_MAX
holdTime = 500 #key hold time
holdTimer = 0
startTime = 0
#Allows custom keymap, pin configuration, and keypad sizes.
def __init__(self,usrKeyMap,row_Pins,col_Pins,num_Rows,num_Cols):
GPIO.setmode(GPIO.BOARD)
self.rowPins = row_Pins
self.colPins = col_Pins
self.numRows = num_Rows
self.numCols = num_Cols
self.keymap = usrKeyMap
self.setDebounceTime(10)
#Returns a single key only. Retained for backwards compatibility.
def getKey(self):
single_key = True
if(self.getKeys() and self.key[0].stateChanged and (self.key[0].kstate == self.key[0].PRESSED)):
return self.key[0].kchar
single_key = False
return self.key[0].NO_KEY
#Populate the key list.
def getKeys(self):
keyActivity = False
#Limit how often the keypad is scanned.
if((time.time() - self.startTime) > self.debounceTime*0.001):
self.scanKeys()
keyActivity = self.updateList()
self.startTime = time.time()
return keyActivity
#Hardware scan ,the result store in bitMap
def scanKeys(self):
#Re-intialize the row pins. Allows sharing these pins with other hardware.
for pin_r in self.rowPins:
GPIO.setup(pin_r,GPIO.IN,pull_up_down = GPIO.PUD_UP)
#bitMap stores ALL the keys that are being pressed.
for pin_c in self.colPins:
GPIO.setup(pin_c,GPIO.OUT)
GPIO.output(pin_c,GPIO.LOW)
for r in self.rowPins: #keypress is active low so invert to high.
self.bitMap[self.rowPins.index(r)] = self.bitWrite(self.bitMap[self.rowPins.index(r)],self.colPins.index(pin_c),not GPIO.input(r))
#Set pin to high impedance input. Effectively ends column pulse.
GPIO.output(pin_c,GPIO.HIGH)
GPIO.setup(pin_c,GPIO.IN)
#Manage the list without rearranging the keys. Returns true if any keys on the list changed state.
def updateList(self):
anyActivity = False
kk = Key()
#Delete any IDLE keys
for i in range(self.LIST_MAX):
if(self.key[i].kstate == kk.IDLE):
self.key[i].kchar = kk.NO_KEY
self.key[i].kcode = -1
self.key[i].stateChanged = False
# Add new keys to empty slots in the key list.
for r in range(self.numRows):
for c in range(self.numCols):
button = self.bitRead(self.bitMap[r],c)
keyChar = self.keymap[r * self.numCols +c]
keyCode = r * self.numCols +c
idx = self.findInList(keyCode)
#Key is already on the list so set its next state.
if(idx > -1):
self.nextKeyState(idx,button)
#Key is NOT on the list so add it.
if((idx == -1) and button):
for i in range(self.LIST_MAX):
if(self.key[i].kchar == kk.NO_KEY): #Find an empty slot or don't add key to list.
self.key[i].kchar = keyChar
self.key[i].kcode = keyCode
self.key[i].kstate = kk.IDLE #Keys NOT on the list have an initial state of IDLE.
self.nextKeyState(i,button)
break #Don't fill all the empty slots with the same key.
#Report if the user changed the state of any key.
for i in range(self.LIST_MAX):
if(self.key[i].stateChanged):
anyActivity = True
return anyActivity
#This function is a state machine but is also used for debouncing the keys.
def nextKeyState(self,idx, button):
self.key[idx].stateChanged = False
kk = Key()
if(self.key[idx].kstate == kk.IDLE):
if(button == kk.CLOSED):
self.transitionTo(idx,kk.PRESSED)
self.holdTimer = time.time() #Get ready for next HOLD state.
elif(self.key[idx].kstate == kk.PRESSED):
if((time.time() - self.holdTimer) > self.holdTime*0.001): #Waiting for a key HOLD...
self.transitionTo(idx,kk.HOLD)
elif(button == kk.OPEN): # or for a key to be RELEASED.
self.transitionTo(idx,kk.RELEASED)
elif(self.key[idx].kstate == kk.HOLD):
if(button == kk.OPEN):
self.transitionTo(idx,kk.RELEASED)
elif(self.key[idx].kstate == kk.RELEASED):
self.transitionTo(idx,kk.IDLE)
def transitionTo(self,idx,nextState):
self.key[idx].kstate = nextState
self.key[idx].stateChanged = True
#Search by code for a key in the list of active keys.
#Returns -1 if not found or the index into the list of active keys.
def findInList(self,keyCode):
for i in range(self.LIST_MAX):
if(self.key[i].kcode == keyCode):
return i
return -1
#set Debounce Time, The defaul29t is 50ms
def setDebounceTime(self,ms):
self.debounceTime = ms
#set HoldTime,The default is 500ms
def setHoldTime(self,ms):
self.holdTime = ms
#
def isPressed(self, keyChar):
for i in range(self.LIST_MAX):
if(self.key[i].kchar == keyChar):
if(self.key[i].kstate == self.self.key[i].PRESSED and self.key[i].stateChanged):
return True
return False
#
def waitForKey(self):
kk = Key()
waitKey = kk.NO_KEY
while(waitKey == kk.NO_KEY):
waitKey = self.getKey()
return waitKey
def getState(self):
return self.key[0].kstate
#
def keyStateChanged(self):
return self.key[0].stateChanged
def bitWrite(self,x,n,b):
if(b):
x |= (1<<n)
else:
x &=(~(1<<n))
return x
def bitRead(self,x,n):
if((x>>n)&1 == 1):
return True
else:
return False
Good morning, I am using git hub examples as a base to make a can bus connection through the pican2 duo can, the python can configuration and the pican2 drivers were installed correctly the problem comes when running the code since A few seconds after running the program I get the extended_id and socketcan_native error, it appears as follows:
" init() got an unexpected keyword argument 'is_extended_id'".
I am viewing the comments and it has worked for several of them and several have the same problem. If anyone has the same problem or has already solved it, can you guide me.
I am using python can 4.1.0.
And tried to fix it by downloading older versions of python can, but when entering the commands : sudo apt-get update
sudo apt-get upgrade automatically upgrades me to the newest version of python. I have to send these commands to be able to use the pican2 duo can card.
I leave the url that I am using
https://github.com/skpang/PiCAN-Python-examples/blob/master/obdii_logger.py
#!/usr/bin/python3
#
## obdii_logger.py
#
# This python3 program sends out OBDII request then logs the reply to the sd card.
# For use with PiCAN boards on the Raspberry Pi
# http://skpang.co.uk/catalog/pican2-canbus-board-for-raspberry-pi-2-p-1475.html
#
# Make sure Python-CAN is installed first http://skpang.co.uk/blog/archives/1220
#
# 24-08-16 SK Pang
#
import RPi.GPIO as GPIO
import can
import time
import os
import queue
from threading import Thread
led = 22
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
GPIO.setup(led,GPIO.OUT)
GPIO.output(led,True)
# For a list of PIDs visit https://en.wikipedia.org/wiki/OBD-II_PIDs
ENGINE_COOLANT_TEMP = 0x05
ENGINE_RPM = 0x0C
VEHICLE_SPEED = 0x0D
MAF_SENSOR = 0x10
O2_VOLTAGE = 0x14
THROTTLE = 0x11
PID_REQUEST = 0x7DF
PID_REPLY = 0x7E8
outfile = open('log.txt','w')
print('\n\rCAN Rx test')
print('Bring up CAN0....')
# Bring up can0 interface at 500kbps
os.system("sudo /sbin/ip link set can0 up type can bitrate 500000")
time.sleep(0.1)
print('Ready')
try:
bus = can.interface.Bus(channel='can0', bustype='socketcan_native')
except OSError:
print('Cannot find PiCAN board.')
GPIO.output(led,False)
exit()
def can_rx_task(): # Receive thread
while True:
message = bus.recv()
if message.arbitration_id == PID_REPLY:
q.put(message) # Put message into queue
def can_tx_task(): # Transmit thread
while True:
GPIO.output(led,True)
# Sent a Engine coolant temperature request
msg = can.Message(arbitration_id=PID_REQUEST,data=[0x02,0x01,ENGINE_COOLANT_TEMP,0x00,0x00,0x00,0x00,0x00],extended_id=False)
bus.send(msg)
time.sleep(0.05)
# Sent a Engine RPM request
msg = can.Message(arbitration_id=PID_REQUEST,data=[0x02,0x01,ENGINE_RPM,0x00,0x00,0x00,0x00,0x00],extended_id=False)
bus.send(msg)
time.sleep(0.05)
# Sent a Vehicle speed request
msg = can.Message(arbitration_id=PID_REQUEST,data=[0x02,0x01,VEHICLE_SPEED,0x00,0x00,0x00,0x00,0x00],extended_id=False)
bus.send(msg)
time.sleep(0.05)
# Sent a Throttle position request
msg = can.Message(arbitration_id=PID_REQUEST,data=[0x02,0x01,THROTTLE,0x00,0x00,0x00,0x00,0x00],extended_id=False)
bus.send(msg)
time.sleep(0.05)
GPIO.output(led,False)
time.sleep(0.1)
q = queue.Queue()
rx = Thread(target = can_rx_task)
rx.start()
tx = Thread(target = can_tx_task)
tx.start()
temperature = 0
rpm = 0
speed = 0
throttle = 0
c = ''
count = 0
# Main loop
try:
while True:
for i in range(4):
while(q.empty() == True): # Wait until there is a message
pass
message = q.get()
c = '{0:f},{1:d},'.format(message.timestamp,count)
if message.arbitration_id == PID_REPLY and message.data[2] == ENGINE_COOLANT_TEMP:
temperature = message.data[3] - 40 #Convert data into temperature in degree C
if message.arbitration_id == PID_REPLY and message.data[2] == ENGINE_RPM:
rpm = round(((message.data[3]*256) + message.data[4])/4) # Convert data to RPM
if message.arbitration_id == PID_REPLY and message.data[2] == VEHICLE_SPEED:
speed = message.data[3] # Convert data to km
if message.arbitration_id == PID_REPLY and message.data[2] == THROTTLE:
throttle = round((message.data[3]*100)/255) # Conver data to %
c += '{0:d},{1:d},{2:d},{3:d}'.format(temperature,rpm,speed,throttle)
print('\r {} '.format(c))
print(c,file = outfile) # Save data to file
count += 1
except KeyboardInterrupt:
#Catch keyboard interrupt
GPIO.output(led,False)
outfile.close() # Close logger file
os.system("sudo /sbin/ip link set can0 down")
print('\n\rKeyboard interrtupt')
I found through experimentation that changing 'socketcan-native' to 'socketcan' got me past that error. This worked for me:
bus = can.interface.Bus(channel = 'can0', bustype = 'socketcan')
The can.interface.Bus() call works for me when I use:
message = can.Message(arbitration_id=0x111, data=[0, 1, 2, 3, 4, 5, 6, 7], is_extended_id=False)
When I got the sample code it didn't have:
is_exteneded_id
Instead it had:
extended_id
I notice in your code you have:
extended_id
I want to have a Raspberry Pi collect data simultaneously from multiple Mbed microcontrollers with TCP sockets. Right now I have 2 microcontrollers sending out different data packets at regular intervals. The microcontrollers get an error message any time the package is not received so after 3 consecutive failed sends it will close and reopen its socket. With my current code I have 100% packet transfer success with only 1 microcontroller powered but with a second one sending packets it may work briefly but then will begin seeing missed packets and occasional errors.
#The server code is
import sys
import socket
from threading import Thread
from socketserver import ThreadingMixIn
# Multithreaded Python server : TCP Server Socket Thread Pool
class ClientThread(Thread):
def __init__(self,ip,port):
Thread.__init__(self)
self.ip = ip
self.port = port
print ("[+] New server socket thread started for " + ip + ":" + str(port))
def run(self):
while True :
data = conn.recv(64)
#print ("Server received from " + ip + ".")
if self.ip == '192.168.1.45':
print("hello GPS")
elif self.ip == '192.168.1.253':
time = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | (data[3])
vibes = [0]*10
for i in range(0, 10):
vibes[i] = data[(i*2)+4] << 8 | data [(i*2)+5]
print ("Server received from " + ip + " data: ", time, vibes[0], vibes[1], vibes[2], vibes[3], vibes[4], vibes[5], vibes[6], vibes[7], vibes[8], vibes[9])
# Multithreaded Python server : TCP Server Socket Program Stub
TCP_IP = '0.0.0.0'
TCP_PORT = 80
BUFFER_SIZE = 64 # Usually 1024, but we need quick response
tcpServer = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpServer.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
tcpServer.bind((TCP_IP, TCP_PORT))
threads = []
while True:
tcpServer.listen(4)
print ("Multithreaded Python server : Waiting for connections from TCP clients...")
(conn, (ip,port)) = tcpServer.accept()
newthread = ClientThread(ip,port)
newthread.start()
threads.append(newthread)
I don't really understand what is happening in this code but I assumed that the way it worked is whenever a new connection was made, a new while loop began and could operate at the same time as others. The terminal mostly prints one of the two messages randomly and on the microcontroller side when its sensor data isn't printed I can see the message not received error. Occasionally I see that a new thread is starting and sometimes an out of range error when sorting the packet.
> Server received from 192.168.1.253 data: 236604 12 6 6 25 12 12 37 18
> 18 48 Server received from 192.168.1.253 data: 236423 9 4 4 17 9 9 25
> 14 14 32 [+] New server socket thread started for 192.168.1.45:58418
> Multithreaded Python server : Waiting for connections from TCP
> clients... Server received from 192.168.1.45 data: 236423 8 6 6 16 12
> 12 23 18 18 30 hello GPS Exception in thread Thread-3: Traceback (most
> recent call last): File "/usr/lib/python3.9/threading.py", line 954,
> in _bootstrap_inner
> self.run() File "/home/pi/Documents/tcp_server2.py", line 25, in run
> vibes[i] = data[(i*2)+4] << 8 | data [(i*2)+5] IndexError: index out of range hello GPS hello GPS [+] New server socket thread started
> for 192.168.1.253:45001 Multithreaded Python server : Waiting for
> connections from TCP clients...
Can I receive multiple messages at the same time this way or do I need to do something like synchronizing the clients to not send at the same time? Is it better to put each client on a separate port and just set up tcpServer1, tcpServer2, tcpServer3,...?
Analysis:
IndexError: index out of range
This arises because your array doesn't have adequate bytes inside, that is, len(data)<=(i*2)+4 OR len(data)<=(i*2)+5.
Explanation:
After conn.recv(64), there is no guarantee that your data will receive an integral 64-length bytes array. Your argument 64 can only put a constaint that your data will be receive 64 bytes at most at a time, since accoding to Python Docs:
socket.recv(bufsize[, flags])
Receive data from the socket. The return value is a bytes object
representing the data received. The maximum amount of data to be received
at once is specified by bufsize.
...
Therefore you need a way to make sure that your data array contains all the bytes your need later on. One alternative is to wrap with a while{...} loop, repeatedly receiving data from your conn until it receive all 64 bytes.
Solution:
You can refer to myreceivce routine suggested in Python official tutorial:
# ...
def myreceive(self):
chunks = []
bytes_recd = 0
while bytes_recd < MSGLEN: # in your case, MSGLEN might be 64
chunk = self.sock.recv(min(MSGLEN - bytes_recd, 2048))
if chunk == b'':
# ...
# ...
#Armali and #MichaelLee thank you so much for the help. I am new to Python so I couldn't figure out what to do with the conn variable. I didn't know things in the "main" count as global since it isn't in C++. I am currently receiving 100% of packets from 2 microcontrollers at 10Hz with this.
import sys
import socket
from threading import Thread
from socketserver import ThreadingMixIn
import time
# Multithreaded Python server : TCP Server Socket Thread Pool
#single thread to search for new clients
class FindClients(Thread):
def __init__(self):
Thread.__init__(self)
def run(self):
while True:
tcpServer.listen(5)
print ("Multithreaded Python server : Waiting for connections from TCP clients...")
(conn, (ip,port)) = tcpServer.accept()
newthread = ClientThread(conn,ip,port)
newthread.start()
threads.append(newthread)
#thread for connected client to stay in
class ClientThread(Thread):
def __init__(self,conn,ip,port):
Thread.__init__(self)
self.conn = conn
self.ip = ip
self.port = port
print ("[+] New server socket thread started for " + self.ip + ":" + str(port))
def run(self):
while True :
chunks = []
bytes_recd = 0
if self.ip == '192.168.1.253':
MSGLEN = 64
while bytes_recd < MSGLEN:
chunk = self.conn.recv(min(MSGLEN - bytes_recd, 2048))
if chunk == b'':
raise RuntimeError("socket connection broken")
chunks.append(chunk)
bytes_recd = bytes_recd + len(chunk)
time = (chunk[0] << 24) | (chunk[1] << 16) | (chunk[2] << 8) | (chunk[3])
vibes = [0]*10
for i in range(0, 10):
vibes[i] = chunk[(i*2)+4] << 8 | chunk[(i*2)+5]
print ("Server received from " + self.ip + " data: ", time, vibes[0], vibes[1], vibes[2], vibes[3], vibes[4], vibes[5], vibes[6], vibes[7], vibes[8], vibes[9])
if self.ip == '192.168.1.45':
MSGLEN = 18
while bytes_recd < MSGLEN:
chunk = self.conn.recv(min(MSGLEN - bytes_recd, 2048))
if chunk == b'':
raise RuntimeError("socket connection broken")
chunks.append(chunk)
bytes_recd = bytes_recd + len(chunk)
print(chunks)
# Multithreaded Python server : TCP Server Socket Program Stub
TCP_IP = '0.0.0.0'
TCP_PORT = 80
BUFFER_SIZE = 64 # Usually 1024, but we need quick response
tcpServer = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpServer.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
#tcpServer.setblocking(False)
tcpServer.bind((TCP_IP, TCP_PORT))
threads = []
newthread = FindClients()
newthread.start()
while True:
Every ClientThread uses the same global conn, which is reassigned each time a new connection is accepted, so all those threads try to read from the most recent connection. You rather have to pass conn to the thread and have it store and use its private connection just as you do with ip and port.
When you corrected this, you also should print self.ip rather than ip in run.
I am was tasked with commanding a multimeter from my computer using python and storing the information into a text file. I have tried altering the code in a million ways and I can not figure out what I am doing wrong. The file already exists in my computer but nothing ever gets displayed there.
import serial
import time
import math
import string
#setting up connection to Multimeter through COM6
ser = serial.Serial('COM6')
ser.baudrate = 9600
ser.bytesize = 8
ser.parity = 'N'
ser.stopbites = 1
ser.timeout = 1
class testing():
def test():
#getting user input
serialNum = input("Serial number: ")
date = input("Date: ")
time = input("Time: ")
x = 1
if x==1:
ser.write(b'meas:volt:dc?\r\n')
returnBytes = ser.readline()
fbytes = float(returnBytes)
#print("DC voltage: " + returnBytes)
ser.close()
return fbytes
#saving and printing information to text file
lines = [serialNum, date, time, fbytes]
file = open('/Users/myname/test.txt', 'w')
file.write(''.join(lines))
file.close()
I solved the problem i posted about, however the code is still spitting out an error that I am trying to solve. but for the sake of the question, this is what i revised my code to so that the information would display in the text file
import serial
import time
import math
import string
#setting up connection to Multimeter through COM6
ser = serial.Serial('COM6')
ser.baudrate = 9600
ser.bytesize = 8
ser.parity = 'N'
ser.stopbites = 1
ser.timeout = 1
#getting user input
serialNum = str(input("Serial number: "))
date = str(input("Date: "))
time = str(input("Time: "))
#getting measurement of DC voltage
ser.write(b'meas:volt:dc?\n') #'b' encodes info from meter to bytes
returnDC = ser.readline()
fbytesDC = float(returnDC)
#getting resistance measurement
ser.write(b'meas:res?\n') #'b' encodes info from meter to bytes
returnRes = ser.readline()
fbytesRes = float(returnRes)
#close the active port
ser.close()
#saving and printing information to text file
lines = [serialNum, date, time]
file = open("C:/Users/myname/test.txt", "a+")
file.write(' '.join(lines))
file.write(" DC voltage: "+ str(fbytesDC))
file.write(" Resistance: "+ str(fbytesRes))
file.write("\n")
file.close()
I am using Arch Linux and have not found any software that allows me to flash files onto my microcontroller. My school's documentation for flashing had a python file, and when I run it, I get the Error message root: Timed out!.
The code:
########
# CHANGELOG:
# 2016-02-15 : Working Skeleton for Flashing a Hex file to SJOne comeplete!
#
import string
import os
import time
import struct
import binascii
import math
import serial.serialutil
import logging
import sys
sys.path.append('/usr/lib/python3.5/site-packages/')
from intelhex import IntelHex
import serial
###############################################################################
################# CONFIGURATION FOR pyFlash - Hyperload ######################
###############################################################################
sDeviceFile = "/dev/ttyUSB0" # Device File Path
sDeviceBaud = 38400 # Suitable Device Baud Rate
sHexFilePath = "/SJSU_Dev2/projects/lpc1758_freertos/_build/lpc1758_freertos.hex"
sGenerateBinary = "y" # "y" - Yes | "n" - No
###############################################################################
#### LOGGING OPTIONS ####
PYFLASH_DEBUG_LOG = "no" # "yes" - Debug Version. "no" - Release Version
#########################
if PYFLASH_DEBUG_LOG == "yes":
PYFLASH_BUILD_LEVEL = "DEBUG"
else:
PYFLASH_BUILD_LEVEL = "RELEASE"
if PYFLASH_BUILD_LEVEL == "DEBUG":
logging.basicConfig(stream=sys.stdout, level=logging.DEBUG)
else:
logging.basicConfig(stream=sys.stdout, level=logging.INFO)
# Things to Do:
# 1. Display Platform Information [DONE]
# 2. Enable a Debug/Release Switch [DONE]
# 3. Create ~/.pyFlash and store last used options for Flashing [PEND]
# 4. Handle Exceptions [PEND]
# 5. Ensure packing is done based on Endianness [PEND]
# 6. Re-write program with classes using this as the backbone. [PEND]
# 7. Incorporate design decisions keeping the GUI in mind [PEND]
# Issues Faced
# 1. Handling Bytes were hard - Use bytearray for most of the IO related functions. Difference between bytes and bytearray is that the latter is mutable.
# Bytes are types that are not mutable. Any changes done on them will cause a new alloc + concat and reassigning.
# Global Defines
ApplicationVersion = "1.0"
ToolName = "pyFLASH - HYPERLOAD"
ToolInfo = "Flashing Tool for SJOne"
BaudList = [4800, 9600, 19200, 38400]
ControlWordList = b'\x80\xf8\xfe\xff'
SpecialChar = {'Dollar' : '$', 'OK' : '!', 'NextLine' : '\n', 'STAR' : '*'}
sCPUSpeed = 48000000
sInitialDeviceBaud = 38400
ByteReference = b'\xff\x55\xaa'
# Common Util Functions
def printIntroMessage():
print ("#######################")
print (" ", ToolName)
print (ToolInfo)
print ("#######################")
print ("Version : ", ApplicationVersion)
print ("Build Type : ", PYFLASH_BUILD_LEVEL)
print ("#######################")
return
def printBytes(mymsg):
print ("Type info = " + (str)(type(mymsg)))
if (type(mymsg) == bytes) or (type(mymsg) == bytearray):
for x in mymsg:
print ("0x" + '{:x}'.format(x),)
print ("")
print ("Total Elements = " + (str)(len(mymsg)))
elif (type(mymsg) == str):
printBytes(bytearray(mymsg))
elif type(mymsg) == int:
print ("0x" + '{:x}'.format(mymsg),)
else:
print (mymsg)
return
def getBoardParameters(descString):
boardParametersDict = {'Board' : '', 'BlockSize' : '', 'BootloaderSize' : '', 'FlashSize' : ''}
# Parsing String to obtain required Board Parameters
boardParametersList = descString.split(':')
boardParametersDict['Board'] = boardParametersList[0]
boardParametersDict['BlockSize'] = boardParametersList[1]
boardParametersDict['BootloaderSize'] = (int(boardParametersList[2]) * 2)
boardParametersDict['FlashSize'] = boardParametersList[3]
print ("\n***** Board Information ********")
print ("Board = " + (str)(boardParametersDict['Board']))
print ("Block (Chunk) Size = " + (str)(boardParametersDict['BlockSize']) + " bytes")
print ("Bootloader Size = " + (str)(boardParametersDict['BootloaderSize']) + " bytes")
print ("Flash Size = " + (str)(boardParametersDict['FlashSize']) + " KBytes")
print ("*********************************\n")
return boardParametersDict
def printContent(lContent):
logging.debug("--------------------")
count = 0;
totalCount = 0;
for x in lContent:
print ('{:2x}'.format(x),)
if count >= 10:
print ("\n")
count = 0
else:
count = count + 1
totalCount = totalCount + 1
logging.debug("\n--------------------")
logging.debug("Total Count = ", totalCount)
logging.debug("--------------------")
return
def getControlWord(baudRate, cpuSpeed):
# TODO : Currently using known values. Replace with actual formula
logging.debug("Retrieving Control Word")
controlWord = ((cpuSpeed / (baudRate * 16)) - 1)
return controlWord
def getPageContent(bArray, blkCount, pageSize):
startOffset = blkCount * pageSize
endOffset = (startOffset + pageSize - 1)
#print "Page Start = ", startOffset, " | Page End = ", str(endOffset)
lPageContent = bytearray(pageSize)
for x in range(0, pageSize):
lPageContent[x] = bArray[x + (blkCount * pageSize)]
#print "Length of x = ", x
if x != pageSize - 1:
raw_input()
return lPageContent
def getChecksum(blocks):
# Try older method - Add and Pack into integer.
lChecksum = bytearray(1);
for x in blocks:
lChecksum[0] = (lChecksum[0] + x) % 256
return lChecksum[0]
# Class
### Main Program ###
printIntroMessage()
print (str('-' * (len(sHexFilePath) + 20)))
print ("Hex File Path = \"" + sHexFilePath + "\"")
print (str('-' * (len(sHexFilePath) + 20)))
# Fetching Hex File and Storing
hexFile = IntelHex(sHexFilePath)
if sGenerateBinary == "y":
# Create a Binary File of this Hex File
sBinFilePath= sHexFilePath.replace(".hex", ".bin")
logging.debug("Binary File Path : %s", sBinFilePath)
hexFile.tofile(sBinFilePath, format='bin')
# Obtain the actual Binary content from the Hex File
binArray = hexFile.tobinarray()
sPort = serial.Serial(
port = sDeviceFile,
baudrate = sInitialDeviceBaud,
parity = serial.PARITY_NONE,
stopbits = serial.STOPBITS_ONE,
bytesize = serial.EIGHTBITS)
sPort.reset_input_buffer()
sPort.reset_output_buffer()
sPort.flush()
# Setting Initial State of RTS Bit to False
sPort.rts = False;
# Reseting the board by toggling DTR
sPort.dtr = False;
# Reading a Byte from SJOne
msg = sPort.read(1)
if msg is ByteReference[1]:
sPort.write(ByteReference[1])
logging.debug("Initial Handshake Initiated! - Received ")
msg = sPort.read(1)
if msg is ByteReference[2]:
logging.debug("Received " + (str)(repr(msg)) + ", Sending Control Word..")
lControlWordInteger = getControlWord(sDeviceBaud, sCPUSpeed)
lControlWordPacked = struct.pack('<i', lControlWordInteger)
msg = sPort.write(bytearray(lControlWordPacked))
if msg != 4:
logging.error("Error - Sending control word failed")
else:
logging.debug("Sending Control Word Successful!")
msg = sPort.read(1)
if msg != lControlWordPacked[0]:
logging.error("Error - Failed to receive Control Word Ack")
else:
logging.debug("Ack from SJOne received!")
if sDeviceBaud != sInitialDeviceBaud:
# Switch to new BaudRate here.
logging.debug("Requested Baudrate different from Default. Changing Baudrate..")
sPort.baudrate = sDeviceBaud
else:
logging.debug("BaudRate same as Default")
# Read the CPU Desc String
msg = sPort.read(1)
if msg != SpecialChar['Dollar']:
logging.error("Failed to read CPU Description String")
else:
logging.debug("Reading CPU Desc String..")
CPUDescString = SpecialChar['Dollar']
while True:
msg = sPort.read(1)
if msg == SpecialChar['NextLine']:
break
CPUDescString = CPUDescString + msg
logging.debug("CPU Description String = %s", CPUDescString)
boardParameters = getBoardParameters(CPUDescString)
# Receive OK from SJOne
msg = sPort.read(1)
if msg != SpecialChar['OK']:
logging.error("Error - Failed to Receive OK")
else:
logging.debug("OK Received! Sending Block")
# Send Dummy Blocks -
# Update : We can send the actual blocks itself.
# Sending Blocks of Binary File
totalBlocks = (len(binArray) * 1.0 / int(boardParameters['BlockSize']))
logging.debug("Total Blocks = %f", totalBlocks)
paddingCount = len(binArray) - ((len(binArray)) % int(boardParameters['BlockSize']))
logging.debug("Total Padding Count = %d", paddingCount)
totalBlocks = math.ceil(totalBlocks)
print ("Total # of Blocks to be Flashed = ", totalBlocks)
# Pad 0's to binArray if required.
binArray = bytearray(binArray)
binArray += (b'\x00' * paddingCount)
blockCount = 0
sendDummy = False
#sendDummy = True
blockContent = bytearray(int(boardParameters['BlockSize']))
if sendDummy == True:
logging.debug("FLASHING EMPTY BLOCKS")
#
while blockCount < totalBlocks:
print ("--------------------")
blockCountPacked = struct.pack('<H', blockCount)
msg = sPort.write(blockCountPacked[1])
if msg != 1:
logging.error("Error in Sending BlockCountLowAddr")
msg = sPort.write(blockCountPacked[0])
if msg != 1:
logging.error("Error in Sending BlockCountHiAddr")
logging.debug("BlockCounts = %d", blockCount)
if sendDummy == False:
blockContent = getPageContent(binArray, blockCount, int(boardParameters['BlockSize']))
msg = sPort.write(blockContent)
if msg != len(blockContent):
logging.error("Error - Failed to sending Data Block Content")
break
#printContent(blockContent)
checksum = bytearray(1)
checksum[0] = getChecksum(blockContent)
logging.debug("Checksum = %d[0x%x]", checksum[0], checksum[0])
msg = sPort.write(checksum)
logging.debug("Size of Block Written = %d", msg)
if msg != 1:
logging.error("Error - Failed to send Entire Data Block")
msg = sPort.read(1)
if msg != SpecialChar['OK']:
logging.error("Failed to Receive Ack.. Retrying #" + str(blockCount))
else:
print ("Block # " + str(blockCount) + " flashed!")
blockCount = blockCount + 1
print ("--------------------")
if blockCount != totalBlocks:
logging.error("Error - All Blocks not Flashed")
logging.error("Total = " + str(totalBlocks))
logging.error("# of Blocks Flashed = " + str(blockCount))
else:
print ("Flashing Successful!")
endTxPacked = bytearray(2)
endTxPacked[0] = 0xFF
endTxPacked[1] = 0xFF
msg = sPort.write(bytearray(endTxPacked))
if msg != 2:
logging.error("Error in Sending End Of Transaction Signal")
msg = sPort.read(1)
logging.debug("Received Ack = " + str(msg))
if msg != SpecialChar['STAR']:
logging.error("Error - Final Ack Not Received")
else :
logging.error("Timed Out!")
sPort.baudrate = sInitialDeviceBaud
sPort.close()
The top half established the correct port (/dev/ttyUSB0) and turns the hex into binary, and the bottom half doing the flashing, which is the aspect that does not work.
The port (/dev/ttyUSB0) and baudrates are correct.
The timeout occurs because the program does not read an expected byte from the device:
# Reading a Byte from SJOne
msg = sPort.read(1)
if msg is ByteReference[1]:
# Programming code
# ...
else :
logging.error("Timed Out!")
You should probably use minicom to verify that you can communicate with the device. If you can communicate with minicom, try printing msg in the else clause.
In the comments, you say that printing msg yields
b'\x00'
However, ByteReference is defined as
ByteReference = b'\xff\x55\xaa'
This means that ByteReference[1] should be
b'\x55'
So msg does not match the expected value. This means the if clause that performs the programming will not be reached.