Constructing a hex array from binary data from serial port - python-3.x

I have an external device, serially connected to a PC.
Data is binary, not characters, meaning that I should not interpret data as ASCII characters.
In the PC, I have Python 3.7 that reads the serial device with the use of pyserial.
I want to fill a int8 array with the incoming data.
I am working with threads, here is where I am so far, but this is not my first piece of code, I have tried several things, none of which worked.
def get_data(sent, m_serport)
constr_resp = np.int8([0])
resp = np.int8([0])
resp_index = 0
while (1):
if (m_serport.in_waiting > 0):
resp = master_ser.read(1)
constr_resp = np.concatenate(constr_resp, resp)
resp_index = resp_index + 1
parse(constr_resp, resp_index)
This one generates the following error:
TypeError: 'bytes' object cannot be interpreted as an integer
I have a somewhat strong C background, and Python is very confusing to me when it comes to data types.
I hope my question is easily understood.
Thanks.

I think getting data should start with building a list of bytes:
def get_data(sent, m_serport)
alist = []
resp_index = 0
while (1):
if (m_serport.in_waiting > 0):
resp = master_ser.read(1)
alist.append(resp)
resp_index += resp_index
# parse(alist, resp_index)
return alist
You may not need resp_index since it should just be len(alist). Also I don't think you want the parse in this loop, but I don't know what it's supposed to be doing.

Kostbil, using python to access external data can be a little tricky but trust me, it's no big deal. In this case, debugging might be easier if you know what line the error is...
You could also use print() to debug.
In my opinion, you could call the decode method i.e .decode() on the data you're getting externally before performing any integer operation. say, externalData.decode()
Hope this works.

Related

Python PyVisa convert queried binary data to ascii data

I'm currently using a keysight VNA product and I control it using PyVisa. Since I have a rapid changing system, I wish to query binary data instead of ascii data from the machine since it is about 10 times faster. The issue I am having is to convert the data to ascii again.
Minimal exampel code:
import pyvisa as visa
import numpy as np
device_adress = ''TCPIP0::localhost::hislip1,4880::INSTR''
rm = visa.ResourceManager('C:\\Windows\\System32\\visa32.dll')
device = rm.open_resource(device_adres)
# presetting device for SNP data measurment
# ...
device.query_ascii_values('CALC:DATA:SNP? 2', container = np.ndarray) # works super but is slow
device.write('FORM:DATA REAL,64')
device.query_binary_values('CALC:DATA:SNP? 2', container = np.ndarray) # 10 times faster but how to read data
Official docs to query binary doesn't give me anything. I found the functions for the code on git here and some helper functions for converting data here, but I am still unable to convert the data such that the converted data is the same as the one I got from the ascii query command. If possible I would like the 'container=np.ndarray' to kept.
Functions from the last link that I have tested:
bin_data = device.query_binary_values('CALC:DATA:SNP? 2', container = np.ndarray)
num = from_binary_block(bin_data) # "Convert a binary block into an iterable of numbers."
ascii_data = to_ascii_block(num) # "Turn an iterable of numbers in an ascii block of data."
but the data from query_ascii_values and the values of ascii_data don't match. Any help is higly appreciated.
Edit:
With the following code
device.write(f"SENS:SWE:POIN 5;")
data_bin = device.query_binary_values('CALC:DATA? SDATA', container=np.ndarray)
I got
data_bin = array([-5.0535379e-34, 1.3452465e-43, -1.7349754e+09, 1.3452465e-43,
-8.6640313e+22, 8.9683102e-44, 5.0314407e-06, 3.1389086e-43,
4.8143607e-36, 3.1389086e-43, -4.1738553e-12, 1.3452465e-43,
-1.5767541e+11, 8.9683102e-44, -2.8241991e+32, 1.7936620e-43,
4.3024710e+16, 1.3452465e-43, 2.1990014e+07, 8.9683102e-44],
dtype=float32)

Sum of two numbers Python

This is my code, but the Spyder keeps saying there is an indexError of list index out of range for a = int(tokens[0]). Please advise.
import sys
input_ = sys.stdin.read()
tokens = input_.split()
a = int(tokens[0])
b = int(tokens[1])
print(a+b)
The below also works, but I see someone running the above code in Linux and worked, and I am on windows, wondering what is the cause of the above not running properly. Thanks all!
def sum_of_two_digits(first_digit, second_digit):
return first_digit + second_digit
if __name__ == '__main__':
a, b = map(int, input().split())
print(sum_of_two_digits(a, b))
To prove you're getting the input you expect, you can print(len(tokens)) or simply print(input_). But suffice to say this is not a Linux/Windows issue. Rather, your tokens variable is empty by the time you index into it (tokens[0]).
You're not getting anything into the input_ value. This may be because you're using read() and are inputing the values in an unexpected way (I am guessing?). input() will probably serve you better - note that the 'Linux' version you refer to uses input(). read() will block until you send an escape sequence, though that probably has happened if you get to the list index error.

Selecting an element of a list inside a list (python)

Im attempting to write a turn based, pokemon-esque, game to test my python skills & learn new things.
I'm having trouble selecting an element from a list inside of another list.
Punch = ["Punch!", 20]
Kick = ["Kick!", 40]
Moves = [Punch, Kick]
Player = ["Jamie", 100, Moves]
print ("Do you want to punch, or kick?")
attack = input(" ")
if attack == "punch":
atk = 0
if attack == "kick":
atk = 1
damage = Player[2[atk[1]]]
print (Player[0]," uses ", Player[2[atk[0]]])
but this results in error:
TypeError: 'int' object is not subscriptable
I understand why this error happens. But I'm wondering is there is another way to call up an element of a list inside of a list.
Thanks
What you want is probably something like this :
damage = Player[2][atk][1]
But beware because you only define atk in if statements so atk could potentially not be defined after those ifs.
Moreover you place either 1 or 2 in atk but you only have two moves which makes me think you want to put either 0 or 1 in it.
Note: You should not capitalise the name of your variables as it would imply they are classes instead of variables
from the way i understand
damage=Player[2][atk][1]
As has already been mentioned . The thing to understand is what is happening when you do this.
player[2] refers to Moves and when you further subscript it, it subscripts to the Moves, so player[2][atk] simply becomes Moves[atk].
A thing to keep in mind is that it is truly just a reference, if you were to change the list Moves, the value in player[2] will also change.
For example:
code:
Moves[1][2]=1000
print(player[2][1][2])
Will give output
1000

Error during request for integers relating to RGB LED on Raspberry Pi

I have a Raspberry Pi 3 and I am writing the code using Python 3. I've added a request in my code to ask the user to enter three numbers which specify if R, G or B is on or off (0 = off and 1 = on). For example 101 would mean that R = on, B = off and G = on.
I however keep getting an error, which I think is related to the version of python that I am using (Python 3):
TypeError: object of type 'int' has no len()
I was following a youtube tutorial here: Controlling a RGB LED with a raspberry pi
import time
import RPi.GPIO as GPIO
R = 16
G = 20
B = 21
GPIO.setmode(GPIO.BCM)
GPIO.setup(R,GPIO.OUT)
GPIO.setup(G,GPIO.OUT)
GPIO.setup(B,GPIO.OUT)
GPIO.output(R,GPIO.HIGH)
GPIO.output(G,GPIO.HIGH)
GPIO.output(B,GPIO.HIGH)
def clearCh():
GPIO.cleanup(R)
GPIO.cleanup(G)
GPIO.cleanup(B)
try:
while True:
request = input("RGB-->")
if (len(request) == 3):
GPIO.output(R, int(request[0]))
GPIO.output(G, int(request[1]))
GPIO.output(B, int(request[2]))
except KeyboardInterrupt:
clearCh()
Any tips to point me in the right direction would be much appreciated.
Note, I have also tried the following: if (len(str(request)) == 3): which gave the following error:
TypeError: 'int' object has no attribute '__getitem__'
TypeError: object of type 'int' has no len()
It seems input returned data that is an integer (data type), such as the 101 that you entered. You can try converting the data returned by input to a string (another data type), but you need to store it in that format to index it. Doing len(str(request)) only converts the data in request to a string for that line of code, it does not affect the request object.
try:
while True:
request = input("RGB-->")
request = str(request)
if (len(request) == 3):
GPIO.output(R, int(request[0]))
GPIO.output(G, int(request[1]))
GPIO.output(B, int(request[2]))
When you have request as a string data type equal to 101 then request[0] points to the left-most 1, request[1] points to the 0, and so on. Finally, int() converts those numerical strings to the integer data type.
Also, don't forget to indent the lines of code under the if block.
Lastly, a good way to test out which data type you're working with is using the type() command. As an experiment (or as a "sanity check"), you can add type(request) to your code before and after converting it to a string.
It seems that the python built-in function len() does not work for integers. So what you might want to do is to make sure it is a string before measuring the length.
try:
while True:
request = str(input("RGB-->"))
if (len(request) == 3):
GPIO.output(R, int(request[0]))
GPIO.output(G, int(request[1]))
GPIO.output(B, int(request[2]))
except KeyboardInterrupt:
clearCh()

Proper Syntax for List Comprehension Involving an Integer and a Float?

I have a List of Lists that looks like this (Python3):
myLOL = ["['1466279297', '703.0']", "['1466279287', '702.0']", "['1466279278', '702.0']", "['1466279268', '706.0']", "['1466279258', '713.0']"]
I'm trying to use a list comprehension to convert the first item of each inner list to an int and the second item to a float so that I end up with this:
newLOL = [[1466279297, 703.0], [1466279287, 702.0], [1466279278, 702.0], [1466279268, 706.0], [1466279258, 713.0]]
I'm learning list comprehensions, can somebody please help me with this syntax?
Thank you!
[edit - to explain why I asked this question]
This question is a means to an end - the syntax requested is needed for testing. I'm collecting sensor data on a ZigBee network, and I'm using an Arduino to format the sensor messages in JSON. These messages are published to an MQTT broker (Mosquitto) running on a Raspberry Pi. A Redis server (also running on the Pi) serves as an in-memory message store. I'm writing a service (python-MQTT client) to parse the JSON and send a LoL (a sample of the data you see in my question) to Redis. Finally, I have a dashboard running on Apache on the Pi. The dashboard utilizes Highcharts to plot the sensor data dynamically (via a web socket connection between the MQTT broker and the browser). Upon loading the page, I pull historical chart data from my Redis LoL to "very quickly" populate the charts on my dashboard (before any realtime data is added dynamically). I realize I can probably format the sensor data the way I want in the Redis store, but that is a problem I haven't worked out yet. Right now, I'm trying to get my historical data to plot correctly in Highcharts. With the data properly formatted, I can get this piece working.
Well, you could use ast.literal_eval:
from ast import literal_eval
myLOL = ["['1466279297', '703.0']", "['1466279287', '702.0']", "['1466279278', '702.0']", "['1466279268', '706.0']", "['1466279258', '713.0']"]
items = [[int(literal_eval(i)[0]), float(literal_eval(i)[1])] for i in myLOL]
Try:
import json
newLOL = [[int(a[0]), float(a[1])] for a in (json.loads(s.replace("'", '"')) for s in myLOL)]
Here I'm considering each element of the list as a JSON, but since it's using ' instead of " for the strings, I have to replace it first (it only works because you said there will be only numbers).
This may work? I wish I was more clever.
newLOL = []
for listObj in myLOL:
listObj = listObj.replace('[', '').replace(']', '').replace("'", '').split(',')
newListObj = [int(listObj[0]), float(listObj[1])]
newLOL.append(newListObj)
Iterates through your current list, peels the string apart into a list by replace un-wanted string chracters and utilizing a split on the comma. Then we take the modified list object and create another new list object with the values being the respective ints and floats. We then append the prepared newListObj to the newLOL list. Considering you want an actual set of lists within your list. Your previously documented input list actually contains strings, which look like lists.
This is a very strange format and the best solution is likely to change the code which generates that.
That being said, you can use ast.literal_eval to safely evaluate the elements of the list as Python tokens:
>>> lit = ast.literal_eval
>>> [[lit(str_val) for str_val in lit(str_list)] for str_list in myLOL]
[[1466279297, 703.0], [1466279287, 702.0], [1466279278, 702.0], [1466279268, 706.0], [1466279258, 713.0]]
We need to do it twice - once to turn the string into a list containing two strings, and then once per resulting string to convert it into a number.
Note that this will succeed even if the strings contain other valid tokens. If you want to validate the format too, you'd want to do something like:
>>> def process_str_list(str_list):
... l = ast.literal_eval(str_list)
... if not isinstance(l, list):
... raise TypeError("Expected list")
... str_int, str_float = l
... return [int(str_int), float(str_float)]
...
>>> [process_str_list(str_list) for str_list in myLOL]
[[1466279297, 703.0], [1466279287, 702.0], [1466279278, 702.0], [1466279268, 706.0], [1466279258, 713.0]]
Your input consists of a list of strings, where each string is the string representation of a list. The first task is to convert the strings back into lists:
import ast
lol2 = map(ast.literal_eval, mylol) # [['1466279297', '703.0'], ...]
Now, you can simply get int and float values from lol2:
newlol = [[int(a[0]), float(a[1])] for a in lol2]

Resources