2017-12-13 16 views
0

主なユースケースがCLIを介して相互作用して、バイトパケットをシリアルで送信するように指示するPythonプログラムがあります。シリアルターゲットは、特定のコマンドプロトコルに準拠しています。 Pythonプログラムは、CLI(送信する特定のコマンド、コマンドの引数など)上のユーザー入力に基づいて、このプロトコルに準拠するパケットを構築します。スクリプトで使用されているクラスのデカップリングに関する提案が必要

このモジュールは3つのクラスで構成されています.1つは、可能なコマンドごとに固有の識別子を作成するenumサブクラスで、cmdモジュールをサブクラス化してユーザーにCLIインターフェイスを実装します(このクラスでは入力サニタイズも行います)最後に、目的のコマンドと引数を取り込み、シリアル経由で送信するパケットを構築する1つのクラス

問題は、これらのクラスがかなり結合しているということです。理想的には、私はMaster_Commクラスを独立したものにしたいので、別のモジュールからアクセスして別の起点(スクリプトファイルパーサなど)からパケットを送信することができました。そのままSerial_InterfacesendcommandメソッドにアクセスするためのMaster_Commのインスタンスだけでなく、複数の場所を実行する必要があり実装入力衛生を(持っている。

これは、より良い組織上の任意の提案を?プログラムは成長し、特にとして、(おそらく実装コマンドの数百)。

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) 
+0

確かにasyncioをチェックアウトしてください。 – GRAYgoose124

答えて

0

あなたはその__init__()コンストラクタの引数として渡すことで、あなたのMaster_Commクラスにハードコマンドを切り離すことができます。以下はCMDSという名前の新しい辞書を作成し、使用しています。この単純な実装です別途定義されます。

このテーブルは、そのインスタンスが作成されるときにMaster_Commクラスに引数として渡され、SerialInterfaceクラスに引数として渡されます(独自のクラスではなく)。

CMDSテーブルのフォーマットを変更して、コマンドに関する詳細情報を含むようにすることで、同じアイデアをさらに引き出すことができます。それはまだハードコードされたものの代わりにSerialInterfaceクラスの実装で使用します。それぞれに関連付けられたバイトのタプルの長さ)。

注:私はクラス名を変更して、名前付けのためにPEP 8 - Style Guide for Python Codeの推奨事項に従うようにしました。

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

class SerialInterface(Cmd): 
    def __init__(self, mastercomm): 
     Cmd.__init__(self) 
     self.slave_comm = mastercomm 
     # setup stuff 

    def do_cmd1(self, args): 
     try: 
      assert 0 <= int(args) <= 25, "Argument out of 0-25 range" 
      self.slave_comm.sendcommand(CommandNames.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(CommandNames.CMD2, args) 
     except (AssertionError) as e: 
      print(e) 


class MasterComm: 
    """ Customized serial communications class for communicating with serial 
     port using the serial module and commands defined by the table "cmds". 
    """ 
    def __init__(self, port, baud, cmds): 
     self.ser = serial.Serial(port=None, 
           baudrate=int(baud),) 
     self.ser.port = port 
     self.source_id = cmds['source_id'] 
     self.seq_num = cmds['seq_num'] 
     self.slave_commands = cmds['slave_commands'] 

    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(txpacket) 
     except Exception as e: 
      print(e) 


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

CMDS = { 
    'source_id': b'\xF0', 
    'seq_num': b'\x00', 
    'slave_commands' : {CommandNames.CMD1: (b'\x10', b'\x06', b'\x06'), 
         CommandNames.CMD2: (b'\x10', b'\x07', b'\x07')} 
} 

mastercomm = MasterComm(0x03b2, 8192, CMDS) 
serialinterface = SerialInterface(mastercomm) 
serialinterface.cmdloop() 
関連する問題