I'm trying to design a protocol for sending/receiving serial data.
The basic plan is to allow for text data to be entered in the command prompt, translate that to a hex string and send it out over the serial connection.
The hex protocol with the serial device is as follows:
byte[0]: address of the serial device peripheral we are interested in
byte[1]: command to send
byte[2]: optional parameter
byte[3]: optional parameter
I like the idea of dictionaries to do that command line translation so that I can do something like this.
commands = {
...
'ping': [0x01, 0x01, 0x00, 0x00],
...
}
input = raw_input("<< ")
if input in commands:
serial.write(commands[input])
else:
print "Unknown command" + input
This seems fine for simple commands like ping but I'm not sure what to do when it comes to implementing more complex commands like pinging a specified peripheral
>> ping host
My first idea is to tokenize the input and use nested dictionaries to hold the commands.
commands = {
'ping': {
'default': [0x01, 0x01, 0x00, 0x00],
'host': [0x01, 0x01, 0x00, 0x00],
'sensor': [0x02, 0x01, 0x00, 0x00]
}
}
I haven't looked up how to tokenize a string yet so I'll use pseudo for that here.
input = raw_input(">> ")
tokens = tokenize(input)
if tokens[0] in commands:
if tokens[1] is not '':
if tokens[1] in commands[tokens[0]]:
if tokens[2] is not '':
...
else:
serial.write(commands[tokens[0]][tokens[1]])
else:
print "Unknown Address" + tokens[1]
else:
serial.write(commands[token[0]]['default']
else:
print "Unknown command" + tokens[0]
I feel like I may be headed in the wrong direction here though, I'm worried the dictionary will become somewhat unwieldy, any thoughts? How would you do a lookup table of this sort?
I've somewhat implemented what would be the final solution for this style of lookup.
First I define my protocol dictionary
myProtocol.py
class MyProtocol:
''' Handshaking '''
_zero = 0x00
_start = 0xA9
_stop = 0x9A
_ack = 0xB8
_nack = 0x8B
_err = 0xEE
handshake = {
'zero' : _zero,
'start' : _start,
'stop' : _stop,
'ack' : _ack,
'nack' : _nack,
'err' : _err
}
''' Address '''
_host = 0x01 # target device
_sdcard = 0x03
addresses = {
'host' : _host
}
''' Common Commands '''
_ping = 0x01 # request an ack
_get = 0x02 # retrieve data
_set = 0x03 # modify settings
''' Command Strings '''
command = {
# default ping
'ping' : [_host, _ping, _zero, _zero],
# commands issued to the device itself
'host' : {
'ping' : [_host, _ping, _zero, _zero],
'get' : {
'date' : [_host, _get, 0x01, _zero]
},
'set' : {
'date' : [_host, _set, 0x01, 0x01], # to be followed by a message with the date
}
}
};
Next, the program to read user input and transform it into a hex command. This code is ignoring the actual serial communication for now, just receiving input and printing out the associated command (for valid input).
serialCom.py
def processInput(inList, dictionary):
# recursively process a list of input
head = inList[0]
tail = inList[1:]
if head == 'exit':
print "received exit command"
ser.close()
exit()
# is this a valid token?
if head in dictionary:
print head + " ",
# are there more commands to process?
if len(tail) > 0:
processInput(tail, dictionary[head])
else:
# have we found a command
if isinstance(dictionary[head], list):
print "\n command found:",
for i in dictionary[head]:
print "%#04X" % i,
print
elif isinstance(dictionary[head], dict):
print ":: insufficient arguments"
print " requires:"
for i in sorted(dictionary.keys()): #dictionary[head].keys():
# print the possible arguments
print " " + i
else:
# this shouldn't happen, the command dictionary is corrupt
print ":: invalid command dictionary"
else:
print ":: invalid command[" + head + "]"
print " possible commands:"
for i in sorted(dictionary.keys()):
# print the possible commands
print " " + i
while 1:
# get keyboard input
command = raw_input("<< ")
token = command.split()
processInput(token, MyProtocol.command)