mercredi 13 décembre 2017

Suggestions for Decoupling Python Program

I have a python program in which the main use case is interacting with it through a CLI to instruct it to send out byte packets over serial. The serial target adheres to a certain command protocol. The python program builds packets that adhere to this protocol based on user input on the CLI (specific command to send, arguments for the command, etc).

The module for this functionality consists of three classes: one which subclasses enum to create unique identifiers for each possible command, one which subclasses the cmd module to implement a CLI interface to the user (this class also does argument input sanitizing) and finally one class which takes in the desired command and arguments and builds the packet to send out over serial

The issue I'm having is that these classes are getting pretty coupled. Ideally I wanted the Master_Comm class to be kind of independent so it could be accessed from other modules to send out packets from a different origin (say a script file parser). As it is Serial_Interface has an instance of Master_Comm to access the sendcommand method, as well as implementing input sanitation (which may need to be done multiple places.

Any suggestions on organizing this better? Especially as the program grows (possibly implementing hundreds of commands).

import serial
from cmd import Cmd
from enum import Enum, unique

@unique
class Command_Names(Enum):
    CMD1 = 1
    CMD2 = 2

class Serial_Interface(Cmd):
    def __init__(self, port, baud,):
        Cmd.__init__(self)
        self.slave_comm = Master_Comm(port=port, baud=baud)
        # setup stuff

    def do_cmd1(self, args):
        try:
            assert 0 <= int(args) <= 25, "Argument out of 0-25 range"
            self.slave_comm.sendcommand(Command_Names.CMD1, args)
        except (AssertionError) as e:
            print(e)

    def do_cmd2(self, args):
        try:
            # No args for cmd2, so don't check anything
            self.slave_comm.sendcommand(Command_Names.CMD2, args)
        except (AssertionError) as e:
            print(e)


class Master_Comm(object):
    _SLAVE_COMMANDS = {Command_Names.CMD1:           (b'\x10', b'\x06', b'\x06'),
                       Command_Names.CMD2:           (b'\x10', b'\x07', b'\x07')}

    _SOURCE_ID = b'\xF0'
    _SEQ_NUM = b'\x00'

    def __init__(self, port, baud):
        self.ser = serial.Serial(port=None,
                                 baudrate=int(baud)
                                 )
        self.ser.port = port

    def open_serial(self):
        # do stuff

    def close_serial(self):
        # do stuff

    def sendcommand(self, command, args):
        try:
            txpacket = bytearray()
            txpacket.extend(self._SOURCE_ID)
            txpacket.extend(self._SEQ_NUM)
            txpacket.extend(self._SLAVE_COMMANDS[command][0])
            txpacket.extend(self._SLAVE_COMMANDS[command][1])
            txpacket.extend(self._SLAVE_COMMANDS[command][2])
            self.ser.write(tx_bytes)
        except Exception as e:
            print(e)

Aucun commentaire:

Enregistrer un commentaire