473,837 Members | 1,689 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Re-evaluating a string?

I'm writing a program to send data over the serial port. I'm using
pyserial, and I'm on WindowsXP. When I use literals I can get the data
accross how I want it for example:

1 2 3 4 5 6
serialport.writ e('!SC'+'\x01'+ '\x05'+'\xFA'+' \x00'+'\r')

1=Get devices attention
2=Select channel on device
3=Rate for movement
4=Low byte of 16 bits
5=High bytes of 16 bits
6=Carriage return signaling command is over

This command works as desired. Sends the first 3 ASCII characters, then
some numbers in hex followed by a carriage return.

My problem is that the "write()" function only takes a string, and I
want to substitute variables for the hex literals.

I know that I can use the "hex()" function and it will return a string
with the appropriate hex value, and I could combine this with some
other literals like "\\" to create my desired hex literal, but then I
would need something to re-parse my string to change my ASCII text into
the appropriate hex values.

Any ideas on how I may do this? Any help is greatly appreciated.

Thanks,
Will

Jul 23 '06 #1
6 1725
serialport.writ e('!SC'+'\x01'+ '\x05'+'\xFA'+' \x00'+'\r')
[cut]
My problem is that the "write()" function only takes a string, and I
want to substitute variables for the hex literals.
Well, you can try something like
>>import types
def makeString(a):
.... return ''.join([type(x) != types.IntType and
.... str(x) or chr(x) for x in a])
....
>>data = ['!SC', 1, 5, 0xFA, 0, '\r']
makeString(da ta)
'!SC\x01\x05\xf a\x00\r'
Thus, you can mix and match your desired data in a list, and then
let Python intelligently smash together the string you want, so
you can later pass that to your write() call.

It does hiccup (read "throw an exception") if you have an empty
string in your list. It also falls down if you try and put in an
integer constant that isn't in range(256). My advice regarding
these would be "don't do that". :) Alternatively, you can
concoct some cousin-function to chr() that takes any old garbage
along with a default, and returns either the chr() of it, unless
that throws an expception, in which case you just return
something like '\x00' (whatever you specified as the default).

This allows you to use your favorite notation. If you like hex
notation, you can use it (as in the "0xFA" in the above data).
If you prefer integers, you can toss them in the mix.

Alternatively, you can create a suite of API wrapper functions,
such as
def move(rate, low, high, channel=1):
serialport.writ e(''.join([type(x) != types.IntType and
.... str(x) or chr(x) for x in
.... ['!SC', channel, rate, low, high, '\r']
.... ]))

(that could be uncompacted a bit for readibility's sake...)

You could then just call move(5, 0xFA, 0) and the function does
the heavy work for you. Might also be more readable later for
other folks coming to the project (if there are others).

Just a couple ideas you might want to try.

-tkc


Jul 23 '06 #2
bugnthecode wrote:
I'm writing a program to send data over the serial port. I'm using
pyserial, and I'm on WindowsXP. When I use literals I can get the data
accross how I want it for example:

1 2 3 4 5 6
serialport.writ e('!SC'+'\x01'+ '\x05'+'\xFA'+' \x00'+'\r')

1=Get devices attention
2=Select channel on device
3=Rate for movement
4=Low byte of 16 bits
5=High bytes of 16 bits
6=Carriage return signaling command is over

This command works as desired. Sends the first 3 ASCII characters, then
some numbers in hex followed by a carriage return.

My problem is that the "write()" function only takes a string, and I
want to substitute variables for the hex literals.

I know that I can use the "hex()" function and it will return a string
with the appropriate hex value, and I could combine this with some
other literals like "\\" to create my desired hex literal, but then I
would need something to re-parse my string to change my ASCII text into
the appropriate hex values.
No need. That would be like travelling from Brooklyn to the Bronx via
Walla Walla, WA. And "the appropriate hex values" exist only as ASCII
text, anyway.

The following code (a) is untested (b) assumes each of the 3 numbers
(channel, rate, value) is UNsigned.

channel = 1
rate = 5
value = 0xFA # or value = 250
if HARD_WAY:
vhi, vlo = divmod(value, 256)
command = "!SC" + chr(channel) + chr(rate) + chr(vlo) + chr(vhi) +
"\r"
elif MEDIUM_WAY:
vhi, vlo = divmod(value, 256)
command = "!SC%c%c%c% c\r" % (channel, rate, vlo, vhi)
else:
import struct
command = "!SC" + struct.pack("<B BH", channel, rate, value) + "\r"
print repr(command) # for debugging, or if you're desperate to see some
hex values :-)
serialport.writ e(command)

Do check out the manual sections relating to the struct module.

If any value is signed, you definitely want to use the struct module
(with "b" or "h" instead of "B" or "H" of course) instead of mucking
about byte-bashing.

HTH,
John

Jul 24 '06 #3
Thanks Tim, and John for your quick responses!

Tim, I tested your function and it works! Though I don't completely
understand how. Could you possibly explain this?

John, I test your "MEDUIM_WAY "and it works as well. How is it that
putting the string together this way translates into a hex value to be
transmitted to the serial port? When I manually tried to put a string
together I couldn't get this to happen. I was trying:

controlString = '!SC' + '\\' + ch.__str__() + '\\' + rate.__str__()
....etc

also I noticed you added another line to the code which appears to
split the low and high bytes for me? If so thanks! Could you also offer
an explanation on how this works. I tried a google search and couldn't
get a decent explanation. I implemented this a little differently as
you can see in my Position class. Could you possibly offer any info on
the benefits/drawbacks of the different methods?

Thanks again to both of you for your quick responses and help.

Will

import serial
import types

class Position:
def __init__(self, num):
"""Takes the position as an int, and splits the low and high
bytes

into instance members."""
self.lowByte = num & 0x00FF
self.highByte = (num & 0xFF00) >8

def __str__(self):
"""Mainly for debugging purposes. Allows meaningful output when
printed"""
return 'Low: ' + self.lowByte.__ str__() + '\nHigh: ' +
self.highByte._ _str__()

def makeString(a):
"""Takes in a list, and intelligentlly smashes everything
together.

Outputs everything as a hex string.
Posted by: Tim Chase on comp.lang.pytho n"""
return ''.join([type(x) != types.IntType and
str(x) or chr(x) for x in a])

def getVer(localpsc ):
"""Gets the version from the PSC. Mainly just to verify a
connection"""

localpsc.write( '!SCVER?\r')
localpsc.read(8 ) #Discard the echo!
s = localpsc.read(3 )
print s

def moveServo(local psc, ch, rate, position):
"""Takes in a serial object, the desired channel, the ramp rate,
and
the desired position of ther servo. Moves the servo to the desired
postion."""

#localpsc.write ('!SC', ch, rate, position.low, position.high, '\r')
#controlString = makeString(['!SC', ch, rate, position.lowByt e,
position.highBy te, '\r'])
#localpsc.write (controlString)
#localpsc.flush Input() #discard the echo!

"""Followin g line from John Machin"""
controlString = "!SC%c%c%c% c\r" % (ch, rate, position.lowByt e,
position.highBy te)
localpsc.write( controlString)

psc = serial.Serial(1 , 2400)

mypos = Position(2500)

moveServo(psc, 0, 5, mypos)
psc.close()

Jul 24 '06 #4
bugnthecode wrote:
Thanks Tim, and John for your quick responses!

Tim, I tested your function and it works!
Though I don't completely
understand how. Could you possibly explain this?

John, I test your "MEDUIM_WAY "and it works as well.
Now try the struct module approach.

Are you 100% certain that the servo position can't be negative? What
would you do if it could be negative?
How is it that
putting the string together this way translates into a hex value to be
transmitted to the serial port?
Like I tried to tell you before, there is no such thing as transmitting
a hex value. You are transmitting 8-bit bytes, one bit at a time. The
number 6 might be transmitted as 00000110 or 01100000 (the latter, IIRC
-- it's been a while). The number 6 can be represented in a computer
program as 6 or 0x6. As your write() function expects a string, you
need to represent it in your program as a string e.g. '\x06' or chr(6)
or "%c" % 6.

Read about chr() in the manual:
http://docs.python.org/lib/built-in-funcs.html

Read about string formatting in the manual:
http://docs.python.org/lib/typesseq-strings.html
When I manually tried to put a string
together I couldn't get this to happen. I was trying:

controlString = '!SC' + '\\' + ch.__str__() + '\\' + rate.__str__()
...etc
Ugh. FWIW, use str(foo) instead of foo.__str__()
>
also I noticed you added another line to the code which appears to
split the low and high bytes for me? If so thanks! Could you also offer
an explanation on how this works. I tried a google search and couldn't
get a decent explanation.
I presume you mean
vhi, vlo = divmod(value, 256)
What did you search for?
If you are on Windows:
do(click on Start, hover on All Programs, hover on Python 2.4,
click on Python Manuals, type in divmod, press Enter key twice)
else:
deduce that divmod can only be a built-in function (I didn't
declare it, did I?)
read web docs on built-in functions
(http://docs.python.org/lib/built-in-funcs.html)
I implemented this a little differently as
you can see in my Position class. Could you possibly offer any info on
the benefits/drawbacks of the different methods?
No great difference. Better than both is to use the struct module.
>
Thanks again to both of you for your quick responses and help.

Will

import serial
import types

class Position:
It is extreme overkill, IMHO, to use a class for this trivium.

def __init__(self, num):
"""Takes the position as an int, and splits the low and high
bytes

into instance members."""
self.lowByte = num & 0x00FF
self.highByte = (num & 0xFF00) >8
If you are sure that 0 <= num <= 0xFFFF, then you don't need the 0xFF00
mask. If you are unsure, then don't just silently transmit what may
well be rubbish; check, or use an assertion:
assert 0 <= num <= 0xFFFF
>
def __str__(self):
"""Mainly for debugging purposes. Allows meaningful output when
printed"""
FFS. Use the repr() built-in, like I suggested.
return 'Low: ' + self.lowByte.__ str__() + '\nHigh: ' +
self.highByte._ _str__()

def makeString(a):
"""Takes in a list, and intelligentlly smashes everything
together.

Outputs everything as a hex string.
No it doesn't.
Posted by: Tim Chase on comp.lang.pytho n"""
return ''.join([type(x) != types.IntType and
str(x) or chr(x) for x in a])

def getVer(localpsc ):
"""Gets the version from the PSC. Mainly just to verify a
connection"""

localpsc.write( '!SCVER?\r')
localpsc.read(8 ) #Discard the echo!
s = localpsc.read(3 )
print s

def moveServo(local psc, ch, rate, position):
"""Takes in a serial object, the desired channel, the ramp rate,
and
the desired position of ther servo. Moves the servo to the desired
postion."""

#localpsc.write ('!SC', ch, rate, position.low, position.high, '\r')
#controlString = makeString(['!SC', ch, rate, position.lowByt e,
position.highBy te, '\r'])
#localpsc.write (controlString)
#localpsc.flush Input() #discard the echo!

"""Followin g line from John Machin"""
controlString = "!SC%c%c%c% c\r" % (ch, rate, position.lowByt e,
position.highBy te)
localpsc.write( controlString)

psc = serial.Serial(1 , 2400)

mypos = Position(2500)

moveServo(psc, 0, 5, mypos)
psc.close()
import struct
DEBUG = True

def moveServo(local psc, ch, rate, position):
"""Takes in a serial object, the desired channel, the ramp rate,
and
the desired position of the servo. Moves the servo to the
desired
position."""
assert 0 <= ch <= 255 # or tighter bounds from manuf's spec
assert 0 <= rate <= 255
assert 0 <= position <= 65535 # aka 0xFFFF
cmd = "!SC" + struct.pack("<B BH", ch, rate, position) + "\r"
if DEBUG:
print "moveServo: ", repr(cmd)
localpsc.write( cmd)

It's that simple. If you are ever going to do more than this one
script, it will pay to investigate the struct module. Python has
"batteries included". You don't need to find a lead mine and look up
"sal ammoniac" in your grandparents' encyclopedia :-)

Cheers,
John

Jul 24 '06 #5
Thanks Tim, and John for your quick responses!

This is one of the better lists for getting quick (and usually
helpful) responses.
Tim, I tested your function and it works! Though I don't completely
understand how. Could you possibly explain this?
>>def makeString(a):
.... return ''.join([type(x) != types.IntType and
.... str(x) or chr(x) for x in a])
....

The "boolean_expres sion and value1 or value2" is a common python
idiom for something akin to C/C++/Java's ternary
"boolean_expres sion? value1: value2" expression. There are some
gotchas (and workarounds for those gotchas) if value1 can be a
"false" value (an empty string, a zero or empty list are good
examples of this). It pretty much boils down to joining all the
elements of the list that is composed from "for every item in the
list 'a', if it's not an int, just return the str() of it; and if
it is an int, return the chr() of it". It then smashes them all
together with the join() and returns the resulting string.
John, I test your "MEDUIM_WAY "and it works as well. How is it that
putting the string together this way translates into a hex value to be
transmitted to the serial port? When I manually tried to put a string
together I couldn't get this to happen. I was trying:

controlString = '!SC' + '\\' + ch.__str__() + '\\' + rate.__str__()
The string-formatting "%c" expects a byte and prints the ascii
character relating to the byte. Also a good way to do things.
Come to think of it, John had a lot of good ideas in his post.
In your above code, the ch.__str__() creates a string
representation of the number I presume is stored in ch. The
string representation of a number is simply a string containing
that number:
>>x = 42
x.__str__()
'42'

Not very exciting. And generally stylistically better to use
str() in favor of the __str__() method call.
also I noticed you added another line to the code which appears to
split the low and high bytes for me? If so thanks! Could you also offer
an explanation on how this works.
the divmod(x,y) function divides x by y, and returns a tuple.
The first value of the tuple is the integer result of the
division, and the second value of the tuple is the remainder.
It's a one-step way of doing

hi,lo = divmod(x,y)

works like a condensing of

hi = x / y
lo = x % y
I tried a google search and couldn't
get a decent explanation.
Googling the python docs for "divmod" should do the trick.

http://www.google.com/search?q=site%...hon.org+divmod

returns several helpful hits wherein you can learn more than any
sane person should care to know. But the above primer should be
enough to get you on your way.

I think, in the case of your example string, using John's
suggestion of the %c formatting is the cleanest approach. As
such, I'd rework the move() function I suggested to simply be
something like

def move(rate,lo,hi ,chan=1):
return "!SC%c%c%c% c\r" % (chan, rate, lo, hi)

where you possibly even just pass in the "position" parameter,
and let the function do the splitting with something like

def move(rate,posit ion,chan=1)
hi,lo = divmod(position & 0xFFFF, 256)
return "!SC%c%c%c% c\r" % (chan, rate, lo, hi)

or optionally use the struct module to unpack them.

Just a few more thoughts,

-tkc


Jul 24 '06 #6

Tim Chase wrote:
[snip]
As
such, I'd rework the move() function I suggested to simply be
something like

def move(rate,lo,hi ,chan=1):
return "!SC%c%c%c% c\r" % (chan, rate, lo, hi)

where you possibly even just pass in the "position" parameter,
and let the function do the splitting with something like

def move(rate,posit ion,chan=1)
hi,lo = divmod(position & 0xFFFF, 256)
return "!SC%c%c%c% c\r" % (chan, rate, lo, hi)

or optionally use the struct module to unpack them.
Say what? We need to pack the position first, we can't use
struct.unpack on an integer, only a string. So that ends up looking
like this:

def move(rate,posit ion,chan=1):
lo, hi = struct.unpack(" <BB", struct.pack("<H ", position))
return "!SC%c%c%c% c\r" % (chan, rate, lo, hi)

which is a bit, shall we say, unfortunate. Why unpack it when we've
already packed it just so we can pack it with another method? This is
getting close to dailyWTF territory. Forget that. Let's go the whole
hog with struct.pack:

def move(rate,posit ion,chan=1):
return struct.pack("<3 sBBHs", "!SC", chan, rate, position, "\r")

What I tell you 3 times is true ... just use struct.pack and stop
faffing about. Get used to it. One day you'll have to output a negative
1-or-two-byte integer, a four-byte integer, a float even -- no
scratching your head about what bits to shift, what mask to use, just
fill in the codes from the manual and away you go.

HTH,
John

Cheers,
John

Jul 24 '06 #7

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
4326
by: Nel | last post by:
I have a question related to the "security" issues posed by Globals ON. It is good programming technique IMO to initialise variables, even if it's just $foo = 0; $bar = ""; Surely it would be better to promote better programming than rely on PHP to compensate for lazy programming?
4
6433
by: Craig Bailey | last post by:
Anyone recommend a good script editor for Mac OS X? Just finished a 4-day PHP class in front of a Windows machine, and liked the editor we used. Don't recall the name, but it gave line numbers as well as some color coding, etc. Having trouble finding the same in an editor that'll run on OS X. -- Floydian Slip(tm) - "Broadcasting from the dark side of the moon"
1
4102
by: Chris | last post by:
Sorry to post so much code all at once but I'm banging my head against the wall trying to get this to work! Does anyone have any idea where I'm going wrong? Thanks in advance and sorry again for adding so much code... <TABLE border="1" bordercolor="#000000" cellspacing="0"> <TR>
11
4017
by: James | last post by:
My form and results are on one page. If I use : if ($Company) { $query = "Select Company, Contact From tblworking Where ID = $Company Order By Company ASC"; }
4
18548
by: Alan Walkington | last post by:
Folks: How can I get an /exec'ed/ process to run in the background on an XP box? I have a monitor-like process which I am starting as 'exec("something.exe");' and, of course the exec function blocks until something.exe terminates. Just what I /don't/ want. (Wouldn't an & be nice here! Sigh) I need something.exe to disconnect and run in the background while I
1
3707
by: John Ryan | last post by:
What PHP code would I use to check if submitted sites to my directory actually exist?? I want to use something that can return the server code to me, ie HTTP 300 OK, or whatever. Can I do this with sockets??
10
4233
by: James | last post by:
What is the best method for creating a Web Page that uses both PHP and HTML ? <HTML> BLA BLA BLA BLA BLA
8
4421
by: Beowulf | last post by:
Hi Guru's, I have a query regarding using PHP to maintain a user profiles list. I want to be able to have a form where users can fill in their profile info (Name, hobbies etc) and attach an image, which will upload the record to a mySql db so users can then either view all profiles or query.. I.e. show all males in UK, all femails over 35 etc. Now, I'm not asking for How to do this but more what would be the best way? I've looked at...
1
3642
by: joost | last post by:
Hello, I'm kind of new to mySQL but more used to Sybase/PHP What is illegal about this query or can i not use combined query's in mySQL? DELETE FROM manufacturers WHERE manufacturers_id NOT IN ( SELECT manufacturers_id FROM products )
3
3495
by: presspley | last post by:
I have bought the book on advanced dreamweaver and PHP recently. I have installed MySQL and PHP server but am getting an error on the $GET statement show below. It says there is a problem with the variable $GET but $GET is not a variable, I thought it came from the page that calls the PHP file? if(($_GET)==""){ this gets an error
0
9851
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
1
10639
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows Update option using the Control Panel or Settings app; it automatically checks for updates and installs any it finds, whether you like it or not. For most users, this new feature is actually very convenient. If you want to control the update process,...
0
10286
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
9419
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
7824
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
7012
by: conductexam | last post by:
I have .net C# application in which I am extracting data from word file and save it in database particularly. To store word all data as it is I am converting the whole word file firstly in HTML and then checking html paragraph one by one. At the time of converting from word file to html my equations which are in the word document file was convert into image. Globals.ThisAddIn.Application.ActiveDocument.Select();...
0
5680
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
5863
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
4481
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.