tags:

views:

99

answers:

4

So I have kind of a ignorant (maybe?) question. I'm working with writing to a serial device for the first time. I have a frame [12, 0, 0, 0, 0, 0, 0, 0, 7, 0, X, Y] that I need to send. X and Y are checksum values. My understanding in using the pyserial module is that I need to convert this frame into a string representation. Ok that's fine, but I'm confused on what format things are supposed to be in. I tried doing

a = [12, 0, 0, 0, 0, 0, 0, 0, 7, 0, X, Y]
send = "".join(chr(t) for t in a)

But my confusion comes from the fact that X and Y, when using chr, transform into weird strings (assuming their ascii representation). For example if X is 36, chr(x) is '$' instead of '\x24'. Is there a way I can get a string representing the '\xnn' value instead of the ascii code? What's confusing me is that 12 and 7 convert to '\x0b' and '\x07' correctly. Am I missing something?

Update:
So it might be that I'm not quite understanding how serial writes are being done or what my device is expecting of me. This is a portion of my C code that is working:


fd=open("/dev/ttyS2",O_RDWR|O_NDELAY);
char buff_out[20]
//Next line is psuedo
for i in buff_out print("%x ",buff_out[i]); // prints b 0 0 0 0 0 0 0 9 b3 36 
write(fd,buff_out,11);  
sleep()
read(fd,buff_in,size);
for i in buff_in print("%x ",buff_in[i]); // prints the correct frame that I'm expecting


Python:



frame = [11, 0, 0, 0, 0, 0, 0, 0, 9] + [crc1, crc1]

senddata = "".join(chr(x) for x in frame)



IEC = serial.Serial(port='/dev/ttyS2', baudrate=1200, timeout=0)
IEC.send(senddata)

IEC.read(18) # number of bytes to read doesn't matter, it's always 0

Am I going about this the right way? Obviously you can't tell exactly since it's device specific and I can't really give too many specifics out. But is that the correct format that serial.send() expects data in?

+1  A: 

The character with the ASCII-code 36 is '$'. Look it up in any ASCII table. Python only displays the hex escapes if the character is not printable (control characters etc).

At the lowest level, it's the same bit pattern anyway - no matter whether Python prints it as a hex escape or as the char with that ASCII value.

But you might want to use the struct module, it takes care of such conversions for you.

delnan
I tried struct too. I guess I'm just not sure how the module wants me to give it data
Falmarri
A: 

I would guess you want struct.

>>> import struct
>>> struct.pack('>B', 12)
'\x0c'
>>> vals = [12, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0xa, 0xb]
>>> ''.join(struct.pack('>B', x) for x in vals)
'\x0c\x00\x00\x00\x00\x00\x00\x00\x07\x00\n\x0b'
Seth
*Thouh shalt not use a list comprehension where a generator expression doth suffice.*
delnan
@delnan - Fair enough.
Seth
A: 

What you do is perfectly fine: your send is what you want: a sequence of bytes with the values you want (a).

If you want to see what are the hexadecimal codes of the characters in send, you can do:

import binascii
print binascii.hexlify(send)

or

print ''.join(r'\x%02x' % ord(char) for char in send)

(if you want \x prefixes).

What you see when directly printing repr(send) is a representation of send, which uses ASCII: 65 represents 'A', but character 12 is '\x0c'. This is merely a convention used by Python, which is convenient when the string contains words, for instance: it is better to display 'Hello' than \x48\x65\x6c\x6c\x6f!

EOL
+2  A: 

It's perfectly normal for ASCII bytes to be represented by single characters if they can be printed, and by the \x?? notation otherwise. In both cases they represent a single byte, and you can write strings in either fashion:

>>> '\x68\x65\x6c\x6c\x6f'
'hello'

However if you're using Python 2.6 or later then you might find it easier and more natural to use the built-in bytearray rather than messing around with ord or struct.

>>> vals = [12, 0, 0, 0, 0, 0, 0, 0, 7, 0, 36, 100]
>>> b = bytearray(vals)
>>> b
bytearray(b'\x0c\x00\x00\x00\x00\x00\x00\x00\x07\x00$d')

You can convert to a str (or bytes in Python 3) just by casting, and can index the bytearray to get the integers back.

>>> str(b)
'\x0c\x00\x00\x00\x00\x00\x00\x00\x07\x00$d'
>>> b[0]
12
>>> b[-1]
100

As to your serial Python code, it looks fine to me - I'm not sure why you think there is a problem...

Scott Griffiths
+1 bytearray is a much more natural choice when dealing with strings of bytes
gnibbler
There's a problem because it works in C and not in python ;) I'll keep looking at it. The C is really complex so maybe I missed something
Falmarri