4
\$\begingroup\$

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)
Mathieu Guindon
75.5k18 gold badges194 silver badges467 bronze badges
asked Sep 24, 2014 at 19:07
\$\endgroup\$
1
  • 2
    \$\begingroup\$ Welcome to Code Review! It looks like you have the beginnings of an interesting question, but first you must have a version of the code that works. \$\endgroup\$ Commented Sep 24, 2014 at 22:10

1 Answer 1

4
\$\begingroup\$

Maybe my approach is crude, but the first thought I had was to use a simple dictionary with key as "ping host". If user separates command and parameters with multiple spaces or tabs, that too can be handled by preprocessing the command before indexing the dictionary.

Another approach that may be more pythonic would be to convert the input into a tuple and use that tuple to index the dictionary.

Maybe there is a specific reason why you require hierarchy, which is not obvious to me.

answered Nov 2, 2014 at 11:38
\$\endgroup\$
1
  • \$\begingroup\$ Thanks for the answer. It actually never occurred to me to use spaces within the key. \$\endgroup\$ Commented Nov 3, 2014 at 14:51

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.