Trying to use a string variable in serial .write in Python - python

I am communicating with a power supply through rs232. I can communicate no problem when I send for example:
port.write("\x31")
but if instead I have a string as a variable
teststring='"\\x31"'
(which prints out as "\x31")
and I try:
port.write(teststring)
it does not send the command to the supply. I have tried:
port.write(bytes(teststring,'utf-8'))
and
port.write(teststring.encode('utf-8'))
But it still is somehow not sending the same as just entering the text. I need to be able to change this variable, so I cannot just code the text in.
Any help is appreciated!
Using comments below, I am now using an integer
testint=31
and if I print
chr(testint) I get a an odd box with 00 in the top row and 1F in the bottom. What I now need to be able to do is convert the 31 to 0x31, so I can use chr(0x31) which when printed produces 1. Hopefully the .write command will treat chr(0x31) the same as "\x31" ?

teststring in your example is escaping the backslash; you have "\\x30", instead of "\x30". "\x30" is a length-1 string containing the byte 0x30; "\\x30" is a length-4 string containing the characters \, x, 3 and 0. Dropping the first slash in teststring should behave exactly like using port.write("\x30").

Related

Adding single backslash to binary string in python

Am communicating with a piece of equipment over RS232, and it seems to only interpret commands correctly when issued commands in the following format:
b'\xXX'
for example:
equipment_ser.write(b'\xE1')
The argument is variable, and so I convert to hex before formatting the command. I'm having trouble coming up with a consistent way to ensure only 1 backslash while preserving the hex command. I need the entire range - \x00 to \xFF.
One approach was to use 'unicode escape':
setpoint_command_INT = 1
setpoint_command_HEX = "{0:#0{1}x}".format(setpoint_command_INT,4)
setpoint_command_HEX_partially_formatted = r'\x' + setpoint_command_HEX[2:4]
setpoint_command_HEX_fully_formatted = setpoint_command_HEX_partially_formatted.encode('utf_8').decode('unicode_escape')
works ok for the above example:
Out[324]: '\x01'
but not for large numbers where the code process changes it:
setpoint_command_INT = 240
Out[332]: 'ð'
How can I format this command so that I have the single backslash while preserving the ability to command across the full range 0-255?
Thanks
Edit:
The correct way to do this is as said by Michael below:
bytes((240,))
Thank you for the prompt responses.
In your code, you are sending a single byte
equipment_ser.write(b'\xE1')
In other words, you're sending decimal 225 but as a single byte.
For any integer value in the range 0-255 you can create its byte equivalent by:
import sys
N = 225 # for example
b = N.to_bytes(1, sys.byteorder)
equipment_ser.write(b)

hex header of file, magic numbers, python

I have a program in Python which analyses file headers and decides which file type it is. (https://github.com/LeoGSA/Browser-Cache-Grabber)
The problem is the following:
I read first 24 bytes of a file:
with open (from_folder+"/"+i, "rb") as myfile:
header=str(myfile.read(24))
then I look for pattern in it:
if y[1] in header:
shutil.move (from_folder+"/"+i,to_folder+y[2]+i+y[3])
where y = ['/video', r'\x47\x40\x00', '/video/', '.ts']
y[1] is the pattern and = r'\x47\x40\x00'
the file has it inside, as you can see from the picture below.
the program does NOT find this pattern (r'\x47\x40\x00') in the file header.
so, I tried to print header:
You see? Python sees it as 'G#' instead of '\x47\x40'
and if i search for 'G#'+r'\x00' in header - everything is ok. It finds it.
Question: What am I doing wrong? I want to look for r'\x47\x40\x00' and find it. Not for some strange 'G#'+r'\x00'.
OR
why python sees first two numbers as 'G#' and not as '\x47\x40', though the rest of header it sees in HEX? Is there a way to fix it?
with open (from_folder+"/"+i, "rb") as myfile:
header=myfile.read(24)
header = str(binascii.hexlify(header))[2:-1]
the result I get is:
And I can work with it
4740001b0000b00d0001c100000001efff3690e23dffffff
P.S. But anyway, if anybody will explain what was the problem with 2 first bytes - I would be grateful.
In Python 3 you'll get bytes from a binary read, rather than a string.
No need to convert it to a string by str.
Print will try to convert bytes to something human readable.
If you don't want that, convert your bytes to e.g. hex representations of the integer values of the bytes by:
aBytes = b'\x00\x47\x40\x00\x13\x00\x00\xb0'
print (aBytes)
print (''.join ([hex (aByte) for aByte in aBytes]))
Output as redirected from the console:
b'\x00G#\x00\x13\x00\x00\xb0'
0x00x470x400x00x130x00x00xb0
You can't search in aBytes directly with the in operator, since aBytes isn't a string but an array of bytes.
If you want to apply a string search on '\x00\x47\x40', use:
aBytes = b'\x00\x47\x40\x00\x13\x00\x00\xb0'
print (aBytes)
print (r'\x'.join ([''] + ['%0.2x'%aByte for aByte in aBytes]))
Which will give you:
b'\x00G#\x00\x13\x00\x00\xb0'
\x00\x47\x40\x00\x13\x00\x00\xb0
So there's a number of separate issues at play here:
print tries to print something human readable, which succeeds only for the first two chars.
You can't directly search for bytearrays in bytearrays with in, so convert them to a string containing fixed length hex representations as substrings, as shown.

Prevent terminal character set switch on data printing

I am running a console application that takes data coming from various sensors around the house. Sometimes the transmission is interrupted and thus the packet does not make sense. When that happens, the contents of the packet is output to a terminal session.
However, what has happened is that while outputting the erroneous packet, it has contained characters that changed character set of the current terminal window, rendering any text (apart from numbers) as unreadable gibberish.
What would be the best way to filter the erroneous packets before their display while retaining most of the special characters? What exactly are sequences that can change behaviour of the terminal?
I would also like to add that apart from scrambled output, the application still works as it should.
Your terminal may be responding to ANSI escape codes.
To prevent the data from inadvertently affecting the terminal, you could print the repr of the data, rather than the data itself:
For example,
good = 'hello'
bad = '\033[41mRED'
print('{!r}'.format(good))
print('{!r}'.format(bad))
yields
'hello'
'\x1b[41mRED'
whereas
print(good)
print(bad)
yields
(Btw, typing reset will reset the terminal.)
You can convert all characters outside of the ASCII range which should eliminate any stray escape sequences that will change the state of your terminal.
print s.encode('string-escape')
When you get a packet check it for validity before outputting it. One possibility is to check that each character in the packet is printable, that is, in the range of 32-127 decimal, before output. Or add checksums to the packets and reject any with bad checksums.

error sending an argument with an ampersand character in the value in python?

I'm dealing 2 scripts in python. the first one needs to send a value or an argument to the second script. Now the problem is whenever I send the value to the 2nd script, the 2nd script couldn't get all the arguments that I sent. the value that Im sending is a URL and it contains an ampersand. I noticed that it kept on cutting the value to the first appearance of &.
lets sat for example, I need to pass this :
http://www.google.com/jfljflfjej&12345
the 2nd script will receive only this :
http://www.google.com/jfljflfjej
what do I need to do to be able to catch the correct value? And what other characters that have the same issue as this?
You need to put quotes around the whole value, including the ampersand, as it is a special shell character. Alternatively, you can escape just the ampersand by putting a backslash in front of it:
http://www.google.com/jfljflfjej\&12345
The ampersand signals to the shell you want to put the command up to that point in background mode.
Any of the following characters are special in a shell:
\ ' " ` < > | ; <Space> <Tab> <Newline> ( ) [ ] ? # $ ^ & * =
These need to be escaped in the same way; use a backslash or put quotes around the value.
Maybe it's a bit late to answer you but I had the same problem and I found a simple solution to that.
You can use the function replace() to replace every ampersand with their code in HTML '%26' like this.
url = http://www.google.com/jfljflfjej&12345
print url.replace('&', '%26')
And the result:
http://www.google.com/jfljflfjej%2612345
It's a problem of coding.
In Python 3:
import urllib.parse
url = urllib.parse.quote("http://www.google.com/jfljflfjej&12345")

sending raw bits to the terminal in python

As I understand it, files like /dev/urandom provide just a constant stream of bits. The terminal emulator then tries to interpret them as strings, which results in a mess of unrecognised characters.
How would I go about doing the same thing in python, send a string of ones and zeros to the terminal as "raw bits"?
edit
I may have to clarify:
Say for example the string I want to "print" is 1011100. On an ascii system, the output should be "\". If I cat /dev/urandom, it provides a constant stream of bits. Which get printed like this: "���c�g/�t]+__��-�;". That's what I want.
Stephano: the key is the incomplete answer by "#you" above - the chr function :
import random, sys
for i in xrange(500):
sys.stdout.write(chr(random.randrange(256)))
Use the chr function. I takes an input between 0 and 255 and returns a string containing the character corresponding to that value.
And from another question on StackOverflow you can get a _bin function.
def _bin(x, width):
return ''.join(str((x>>i)&1) for i in xrange(width-1,-1,-1))
Then simply put call _bin(ord(x), 8) where x is a character (string of length one)
import sys, random
while True:
sys.stdout.write(chr(random.getrandbits(8)))
sys.stdout.flush()

Categories

Resources