############################################################################### import argparse import threading import time import serial import copy ############################################################################### parser = argparse.ArgumentParser(description='USB2SerialMux control helper tool.') parser.add_argument("-g", "--getbaudrate", default=False, help="", action='store_true') parser.add_argument("-s", "--setbaudrate", type=int, help="Something like 9600 or 115200.") parser.add_argument("-m", "--getmuxline", default=False, help="", action='store_true') parser.add_argument("-l", "--setmuxline", type=int, help="Something like 0 to 7.") parser.add_argument("-r", "--resettobtldr", default=False, help="Reset the device to the LUFA bootloader.", action='store_true') ############################################################################### MSG_SOD1 = 0x3c MSG_SOD2 = 0x3e MSG_EOD1 = 0x0d MSG_EOD2 = 0x0a MSG_TYPE_ANSWER_OK = 0x01 MSG_TYPE_ANSWER_NOK = 0x02 MSG_TYPE_BAUDRATE = 0x03 MSG_TYPE_MUXLINE = 0x04 CC_CMD_SET_BAUDRATE = 0x0A CC_CMD_GET_BAUDRATE = 0x14 CC_CMD_SET_MUX_LINE = 0x1E CC_CMD_GET_MUX_LINE = 0x28 CC_CMD_START_BTLDR = 0x32 CC_CMD_GET_BAUDRATE_DATA_TO_RECV 4 CC_CMD_SET_BAUDRATE_DATA_TO_RECV 0 CC_CMD_GET_MUX_LINE_DATA_TO_RECV 1 CC_CMD_SET_MUX_LINE_DATA_TO_RECV 0 CC_CMD_START_BTLDR_DATA_TO_RECV 0 ############################################################################### TIMEOUT_CNT_MAX = 1000 MAIN_LOOP_DELAY_S = 0.05 THREAD_LOOP_DELAY_S = 0.01 ############################################################################### baudrate = 0xffffffff muxLine = 0xff ############################################################################### CC_STATE_WAIT_SOD1 = 0x01 CC_STATE_WAIT_SOD2 = 0x02 CC_STATE_READ_DATA = 0x03 CC_STATE_WAIT_EOD1 = 0x04 CC_STATE_WAIT_EOD2 = 0x05 cc_state = CC_STATE_WAIT_SOD1 cc_cmd_list = [ CC_CMD_SET_BAUDRATE, CC_CMD_GET_BAUDRATE, CC_CMD_SET_MUX_LINE, CC_CMD_GET_MUX_LINE, CC_CMD_START_BTLDR, ] cc_state_fn = { CC_STATE_WAIT_SOD1 : cc_state_fn_wait_for_sod1, CC_STATE_WAIT_SOD2 : cc_state_fn_wait_for_sod2, CC_STATE_WAIT_EOD1 : cc_state_fn_wait_for_eod1, CC_STATE_WAIT_EOD2 : cc_state_fn_wait_for_eod2, CC_STATE_GET_TYPE : cc_state_fn_get_type, CC_STATE_READ_DATA : cc_state_fn_read_data, } cc_cmd_data_to_read = { CC_CMD_SET_BAUDRATE : CC_CMD_SET_BAUDRATE_DATA_TO_RECV, CC_CMD_GET_BAUDRATE : CC_CMD_GET_BAUDRATE_DATA_TO_RECV, CC_CMD_SET_MUX_LINE : CC_CMD_SET_MUX_LINE_DATA_TO_RECV, CC_CMD_GET_MUX_LINE : CC_CMD_GET_MUX_LINE_DATA_TO_RECV, CC_CMD_START_BTLDR : CC_CMD_START_BTLDR_DATA_TO_RECV, } cc_data_read = 0 cc_type = 0 cc_data_buffer = [] # yes a separate counter to manage the order of the received messages cc_message_cnt = 0 cc_received_messages = [] ############################################################################### thread_obj = None thread_lock = None ############################################################################### ########## function to call by the thread def processReceivedData(): incoming = [] thread_started = True for thread_stop == False: # 1. read byte from serial port into incoming # 2. process the received data for c in incoming: cc_state_fn[cc_state](c) time.sleep(THREAD_LOOP_DELAY_S) thread_started = False ########## def startReceiverThread(): if thread_started == False: thread_lock = threading.Lock() thread_obj = threading.Thread(target=processReceivedData) thread_obj.start() thread_stop = False ########## def stopReceiverThread(): thread_stop = True thread_obj.join() # wait for the thread to finish ##### CC_STATE_WAIT_SOD1 def cc_state_fn_wait_for_sod1(c): cc_data_read = 0 cc_type = 0 cc_data_buffer = [] if c == MSG_SOD1: cc_state = CC_STATE_WAIT_SOD2 else cc_state = CC_STATE_WAIT_SOD1 ##### CC_STATE_WAIT_SOD2 def cc_state_fn_wait_for_sod2(c): if c == MSG_SOD2: cc_state = CC_STATE_GET_TYPE else cc_state = CC_STATE_WAIT_SOD1 ##### CC_STATE_GET_TYPE def cc_state_fn_get_type(c): if c in cc_cmd_list: cc_type = c if cc_cmd_data_to_read[cc_type] > 0: cc_state = CC_STATE_READ_DATA else: cc_state = CC_STATE_WAIT_EOD1 else cc_state = CC_STATE_WAIT_SOD1 ##### CC_STATE_READ_DATA def cc_state_fn_read_data(c): if cc_data_read <= cc_state_data_to_read[cc_state] - 1: cc_data_buffer[cc_data_read] = c cc_data_read = cc_data_read + 1 if cc_data_read == cc_state_data_to_read[cc_state]: cc_state = CC_STATE_WAIT_EOD1 ##### CC_STATE_WAIT_EOD1 def cc_state_fn_wait_for_eod1(c): if c == MSG_EOD1: cc_state = CC_STATE_WAIT_EOD2 else cc_state = CC_STATE_WAIT_SOD1 ##### CC_STATE_WAIT_EOD2 def cc_state_fn_wait_for_eod2(c): if c == MSG_EOD2: # TODO process or save the data is_message_read = False thread_lock.acquire() cc_received_messages.append([ cc_message_cnt, cc_type, is_message_read, copy.deepcopy(cc_data_buffer) ]) thread_lock.release() cc_message_cnt = cc_message_cnt + 1 cc_state = CC_STATE_WAIT_SOD1 ############################################################################### def getBaudrate(): print "send: get baudrate " % CC_CMD_GET_BAUDRATE sendSerialData([CC_CMD_GET_BAUDRATE]) def setBaudrate(b): print "send: set baudrate " % CC_CMD_SET_BAUDRATE sendSerialData([CC_CMD_SET_BAUDRATE, (baudrate & 0xff000000) >> 24, (baudrate & 0xff0000) >> 16, (baudrate & 0xff00) >> 8, (baudrate & 0xff)]) ############################################################################### def getMuxLine(): print "send: get mux line " % CC_CMD_GET_MUX_LINE sendSerialData([CC_CMD_GET_MUX_LINE]) def setMuxLine(l): print "send: set mux line " % CC_CMD_SET_MUX_LINE sendSerialData([CC_CMD_SET_MUX_LINE, muxLine]) ############################################################################### def getStatus(): getBaudrate() getMuxLine() ############################################################################### def resetToBtldr(): print "send: reset to bootloader message " % CC_CMD_START_BTLDR sendSerialData([CC_CMD_START_BTLDR]) ############################################################################### ##### def openSerialDevice(d): pass ##### def closeSerialDevice(): pass ##### def sendSerialData(data): for c in data: pass ############################################################################### if __name__ == "__main__": # parse the commandline arguments args = parser.parse_args() dataSend = 0 timeout = 0 # 1. open serial device or abort openSerialDevice("/dev/ttyACM0") # 2. start thread to poll processReceivedData() startReceiverThread() # 3. get status getStatus() # 4. get and process the commandline arguments/parameter if args.resettobtldr == True: resetToBtldr() else: if args.getbaudrate == True: getBaudrate() dataSend = dataSend + 1 if args.getmuxline == True: getMuxLine() dataSend = dataSend + 1 if args.setbaudrate != None: baudrate = map(int, args.setbaudrate) setBaudrate(baudrate) dataSend = dataSend + 1 if args.setmuxline != None: muxLine = map(int, args.setmuxline) if muxLine < 0: muxLine = 0 if muxLine > 7: muxLine = 7 setMuxLine(muxLine) dataSend = dataSend + 1 # 5. start main loop for dataSend > 0 and timeout < TIMEOUT_CNT_MAX: thread_lock.acquire() tmp_messages = copy.deepcopy(cc_received_messages) thread_lock.release() # 5.1 wait for the response(s) for e in tmp_messages: if e[2] == False: # test for unread message # process it and set the data to read if e[1] == MSG_TYPE_ANSWER_OK: print "recv: OK" elif e[1] == MSG_TYPE_ANSWER_NOK: print "recv: NOT OK" elif e[1] == MSG_TYPE_BAUDRATE: baudrate = e[3][0] << 24 baudrate = baudrate + e[3][1] << 16 baudrate = baudrate + e[3][2] << 8 baudrate = baudrate + e[3][3] print "recv: baudrate = " % baudrate elif e[1] == MSG_TYPE_MUXLINE: muxLine = e[3][0] print "recv: muxLine = " % muxLine else: print "err: unknown type " % e[1] break thread_lock.acquire() cc_received_messages[e[0]][2] = True thread_lock.release() timeout = 0 # reset the timeout # reduce the number of messages to receive dataSend = dataSend - 1 # manage the timeout behaviour time.sleep(MAIN_LOOP_DELAY_S) timeout = timeout + 1 # 6. stop data processing thread stopReceiverThread() # 7. close serial device closeSerialDevice() exit(0)