Re: Re-evaluating a string?

2006-07-24 Thread John Machin

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,position,chan=1)
   hi,lo = divmod(position  0x, 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,position,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,position,chan=1):
return struct.pack(3sBBHs, !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

-- 
http://mail.python.org/mailman/listinfo/python-list


Re-evaluating a string?

2006-07-23 Thread bugnthecode
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.write('!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

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-evaluating a string?

2006-07-23 Thread Tim Chase
 serialport.write('!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(data)
'!SC\x01\x05\xfa\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.write(''.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






-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-evaluating a string?

2006-07-23 Thread John Machin
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.write('!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(BBH, channel, rate, value) + \r
print repr(command) # for debugging, or if you're desperate to see some
hex values :-)
serialport.write(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

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-evaluating a string?

2006-07-23 Thread bugnthecode
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_WAYand 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.python
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(localpsc, 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.lowByte,
position.highByte, '\r'])
#localpsc.write(controlString)
#localpsc.flushInput() #discard the echo!

Following line from John Machin
controlString = !SC%c%c%c%c\r % (ch, rate, position.lowByte,
position.highByte)
localpsc.write(controlString)

psc = serial.Serial(1, 2400)

mypos = Position(2500)

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

-- 
http://mail.python.org/mailman/listinfo/python-list


Re: Re-evaluating a string?

2006-07-23 Thread John Machin
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_WAYand 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 0110 or 0110 (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 = 0x, 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 = 0x


 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.python
 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(localpsc, 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.lowByte,
 position.highByte, '\r'])
 #localpsc.write(controlString)
 #localpsc.flushInput() #discard the echo!

 Following line from John Machin
 controlString = !SC%c%c%c%c\r % (ch, rate, position.lowByte,
 position.highByte)
 localpsc.write(controlString)

 psc = serial.Serial(1, 2400)

 mypos = Position(2500)

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

import struct
DEBUG = True

def moveServo(localpsc, 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 0x
cmd = !SC + struct.pack(BBH, 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 

Re: Re-evaluating a string?

2006-07-23 Thread Tim Chase
 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_expression and value1 or value2 is a common python 
idiom for something akin to C/C++/Java's ternary 
boolean_expression? 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_WAYand 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%3Adocs.python.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,position,chan=1)
hi,lo = divmod(position  0x, 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




-- 
http://mail.python.org/mailman/listinfo/python-list