def __init__(self): super().__init__() self.title('bootyControl') # local variables self.hex_file_path = '' self.port_name = None self.log_string = StringIO() self.ch = logging.StreamHandler(self.log_string) logger.addHandler(self.ch) booty_logger = logging.getLogger('booty') booty_logger.addHandler(self.ch) # gui setup self.page_title = tk.Label(self, text='bootyControl', font=('Helvetica', 16)) self.page_title.grid(row=0, column=0, columnspan=2, sticky='news') self.ser_port_label = tk.Label(self, text='Serial Port') self.ser_port_label.grid(row=1, column=0, sticky='nes') self.ser_port_om = SmartOptionMenu(self, list_ports.comports(), callback=self.choose_ser_port) self.ser_port_om.grid(row=1, column=1, sticky='nws') self.ser_baud_label = tk.Label(self, text='Baud Rate') self.ser_baud_label.grid(row=2, column=0, sticky='nes') self.ser_baud_entry = tk.Entry(self) self.ser_baud_entry.grid(row=2, column=1, sticky='nws') self.ser_baud_entry.insert(0, '115200') self.choose_hex_btn = tk.Button(self, text='Choose hex file...', command=self.choose_hex_file) self.choose_hex_btn.grid(row=3, column=0, columnspan=2, sticky='news') self.erase_btn = tk.Button(self, text="Erase Device", command=self.erase_device) self.erase_btn.grid(row=4, column=0, columnspan=2, sticky='news') self.load_btn = tk.Button(self, text="Load Device", command=self.load_device) self.load_btn.grid(row=5, column=0, columnspan=2, sticky='news') self.load_btn['state'] = 'disabled' self.verify_btn = tk.Button(self, text="Verify Device", command=self.verify_device) self.verify_btn.grid(row=6, column=0, columnspan=2, sticky='news') self.verify_btn['state'] = 'disabled' self.console_text = tk.Text(self) self.console_text.grid(row=7, column=0, columnspan=2, sticky='news') self.console_text['state'] = 'disabled' self.mainloop()
def __init__(self): super().__init__() self.hex_file_path = '' self.port_name = None self.serial_port = None self.hex_data = None self.hex_data_idx = 0 self.title(self.TITLE) self.geometry('400x150') self.rowconfigure(0, weight=1) self.columnconfigure(1, weight=1) self.page_title = Label(self, text=self.TITLE, font=('Helvetica', 14)) self.page_title.grid(row=0, column=0, columnspan=2, sticky='news') self.serial_port_menu = SmartOptionMenu( self, self.get_ports(), callback=self.select_serial_port) self.serial_port_menu.grid(row=1, column=0, sticky='ew') self.select_hex_button = Button(self, text='Select firmware file...', command=self.select_hex_file) self.select_hex_button.grid(row=2, column=0, columnspan=2, sticky='news') self.select_hex_button['state'] = 'disabled' self.flash_button = Button(self, text='Flash Firmware', command=self.flash_firmware) self.flash_button.grid(row=3, column=0, columnspan=2, sticky='news') self.flash_button['state'] = 'disabled' self.progress = Progressbar(self, orient=HORIZONTAL, length=100, mode='determinate') self.progress.grid(row=4, column=0, columnspan=2, sticky='news') self.statusbar = Label(self, text='Not Connected', bd=1, relief=SUNKEN, anchor=W) self.statusbar.grid(row=5, column=0, columnspan=2, sticky='we') self.after(1000, self.update_ports) self.mainloop()
def test_callback_with_param(root): item_value = 0 def callback(value): nonlocal item_value item_value += int(value) som = SmartOptionMenu(root, ['1', '2', '3'], callback=callback) som.grid() som.set('2') som.set('2') som.set('2') assert item_value == 6
def test_callback_no_param(root): item_value = 0 def callback(): nonlocal item_value item_value += 1 som = SmartOptionMenu(root, ['1', '2', '3'], callback=callback) som.grid() som.set('1') som.set('3') som.set('2') assert item_value == 3
def test_creation_with_initial_value(root): som = SmartOptionMenu(root, ['1', '2', '3'], initial_value='2') assert som.get() == '2'
def test_creation(root): SmartOptionMenu(root, ['1', '2', '3'])
def som(root): som_widget = SmartOptionMenu(root, ['1', '2', '3']) som_widget.grid() yield som_widget
class Application(Tk): TITLE = 'BlueBus Firmware Tool' BAUDRATE = '115200' TIMEOUT = 10 tx_buffer = [] def __init__(self): super().__init__() self.hex_file_path = '' self.port_name = None self.serial_port = None self.hex_data = None self.hex_data_idx = 0 self.title(self.TITLE) self.geometry('400x150') self.rowconfigure(0, weight=1) self.columnconfigure(1, weight=1) self.page_title = Label(self, text=self.TITLE, font=('Helvetica', 14)) self.page_title.grid(row=0, column=0, columnspan=2, sticky='news') self.serial_port_menu = SmartOptionMenu( self, self.get_ports(), callback=self.select_serial_port) self.serial_port_menu.grid(row=1, column=0, sticky='ew') self.select_hex_button = Button(self, text='Select firmware file...', command=self.select_hex_file) self.select_hex_button.grid(row=2, column=0, columnspan=2, sticky='news') self.select_hex_button['state'] = 'disabled' self.flash_button = Button(self, text='Flash Firmware', command=self.flash_firmware) self.flash_button.grid(row=3, column=0, columnspan=2, sticky='news') self.flash_button['state'] = 'disabled' self.progress = Progressbar(self, orient=HORIZONTAL, length=100, mode='determinate') self.progress.grid(row=4, column=0, columnspan=2, sticky='news') self.statusbar = Label(self, text='Not Connected', bd=1, relief=SUNKEN, anchor=W) self.statusbar.grid(row=5, column=0, columnspan=2, sticky='we') self.after(1000, self.update_ports) self.mainloop() def get_ports(self): ports = ['Select Device...'] if platform.system() == 'Linux': for f in glob('/dev/ttyUSB*'): ports.append(f) elif platform.system() == 'Darwin': for f in glob('/dev/tty.usbserial*'): ports.append(f) else: for port in list_ports.comports(): try: Serial(port.device) ports.append(port.device) except serialutil.SerialException: pass return ports def update_ports(self): option = self.serial_port_menu.option_menu menu = option.children['menu'] menu.delete(0, END) for port in self.get_ports(): menu.add_command( label=port, command=lambda p=port: self.serial_port_menu.set(p)) self.after(1000, self.update_ports) def request_bc127_mode(self): for i in generate_packet(PROTOCOL_CMD_BC127_MODE_REQUEST, [0x00]): self.tx_buffer.append(i) def request_erase_flash(self): for i in generate_packet(PROTOCOL_CMD_ERASE_FLASH_REQUEST, [0x00]): self.tx_buffer.append(i) def request_flash_write(self): data = self.hex_data[self.hex_data_idx] pkt = generate_packet(PROTOCOL_CMD_WRITE_DATA_REQUEST, data) for i in pkt: self.tx_buffer.append(i) def request_platform(self): for i in generate_packet(PROTOCOL_CMD_PLATFORM_REQUEST, [0x00]): self.tx_buffer.append(i) def request_start_app(self): for i in generate_packet(PROTOCOL_CMD_START_APP_REQUEST, [0x00]): self.tx_buffer.append(i) def select_hex_file(self): self.hex_file_path = askopenfilename(title='Select Firmware...', filetypes=[('hex', '*.hex')]) self.flash_button['state'] = 'disable' if not self.hex_file_path: self.set_status('ERROR: Could not find firmware file') return self.hex_data = read_hexfile(self.hex_file_path) if not self.hex_data: self.set_status('ERROR: Could not read firmware file') return self.flash_button['state'] = 'normal' self.set_status('Ready to Flash') def select_serial_port(self, port_name): port_name = self.serial_port_menu.get() self.port_name = port_name.split('-')[0].strip() if self.port_name == 'Select Device...': return # Reload the device and verify self.serial_port = Serial(port_name, self.BAUDRATE) self.serial_port.write(b'bootloader\r\n') sleep(0.1) # Wait for data to reach unit before closing the ports self.serial_port.close() self.set_status('Connecting...') # Allow the bootloader to spool sleep(1) # Re-open the serial port self.serial_port = Serial(port_name, self.BAUDRATE, parity=PARITY_ODD) self.serial_port.write(b'\r\n') # Clear the port sleep(0.25) while self.serial_port.in_waiting: if self.serial_port.read(): pass self.request_platform() self.handle_serial() def flash_firmware(self): self.flash_button['state'] = 'disable' self.select_hex_button['state'] = 'disable' self.set_status('Erasing Flash...') self.request_erase_flash() self.handle_serial() def handle_serial(self): start = int(time()) has_response = False rx_buffer = [] while not has_response: while self.serial_port.in_waiting: rx_buffer.append(self.serial_port.read()) if len(rx_buffer) >= 2: if len(rx_buffer) == ord(rx_buffer[1]): command = int(hex(ord(rx_buffer.pop(0))), 16) _ = rx_buffer.pop(0) # Remove the length xor = rx_buffer.pop() # Remove the XOR if command == PROTOCOL_CMD_PLATFORM_RESPONSE: string = [b.decode('ascii') for b in rx_buffer] self.set_status('Connected: %s' % ''.join(string)) self.select_hex_button['state'] = 'normal' has_response = True if command == PROTOCOL_CMD_ERASE_FLASH_RESPONSE: self.set_status('Writing Flash: 0%') self.request_flash_write() if command == PROTOCOL_CMD_WRITE_DATA_RESPONSE_OK: data_size = len(self.hex_data) self.hex_data_idx += 1 progress = (self.hex_data_idx / data_size) * 100 self.progress['value'] = progress self.set_status('Writing Flash: %d%%' % progress) if self.hex_data_idx < data_size: self.request_flash_write() else: self.request_start_app() if command == PROTOCOL_CMD_START_APP_RESPONSE: self.set_status('Flash Complete') self.flash_button['state'] = 'disable' self.select_hex_button['state'] = 'disable' self.progress['value'] = 0 has_response = True if command == PROTOCOL_BAD_PACKET_RESPONSE: self.set_status( 'ERROR: Protocol Error -- Try again') if command == PROTOCOL_CMD_WRITE_DATA_RESPONSE_ERR: self.set_status('ERROR: Write Failed - try again') has_response = True rx_buffer = [] start = int(time()) if len(self.tx_buffer) > 0: self.serial_port.write(self.tx_buffer) self.tx_buffer = [] if not has_response and int(time()) - start > self.TIMEOUT: self.set_status( 'ERROR: Failed to get a response within 5 seconds') has_response = True self.update() def set_status(self, text): self.statusbar.config(text=text) self.statusbar.update()
class Application(tk.Tk): def __init__(self): super().__init__() self.title('bootyControl') # local variables self.hex_file_path = '' self.port_name = None self.log_string = StringIO() self.ch = logging.StreamHandler(self.log_string) logger.addHandler(self.ch) booty_logger = logging.getLogger('booty') booty_logger.addHandler(self.ch) # gui setup self.page_title = tk.Label(self, text='bootyControl', font=('Helvetica', 16)) self.page_title.grid(row=0, column=0, columnspan=2, sticky='news') self.ser_port_label = tk.Label(self, text='Serial Port') self.ser_port_label.grid(row=1, column=0, sticky='nes') self.ser_port_om = SmartOptionMenu(self, list_ports.comports(), callback=self.choose_ser_port) self.ser_port_om.grid(row=1, column=1, sticky='nws') self.ser_baud_label = tk.Label(self, text='Baud Rate') self.ser_baud_label.grid(row=2, column=0, sticky='nes') self.ser_baud_entry = tk.Entry(self) self.ser_baud_entry.grid(row=2, column=1, sticky='nws') self.ser_baud_entry.insert(0, '115200') self.choose_hex_btn = tk.Button(self, text='Choose hex file...', command=self.choose_hex_file) self.choose_hex_btn.grid(row=3, column=0, columnspan=2, sticky='news') self.erase_btn = tk.Button(self, text="Erase Device", command=self.erase_device) self.erase_btn.grid(row=4, column=0, columnspan=2, sticky='news') self.load_btn = tk.Button(self, text="Load Device", command=self.load_device) self.load_btn.grid(row=5, column=0, columnspan=2, sticky='news') self.load_btn['state'] = 'disabled' self.verify_btn = tk.Button(self, text="Verify Device", command=self.verify_device) self.verify_btn.grid(row=6, column=0, columnspan=2, sticky='news') self.verify_btn['state'] = 'disabled' self.console_text = tk.Text(self) self.console_text.grid(row=7, column=0, columnspan=2, sticky='news') self.console_text['state'] = 'disabled' self.mainloop() def choose_hex_file(self): self.hex_file_path = askopenfilename(title='choose hex file', filetypes=[('hex', '*.hex')]) self.update_console('hex file chosen: {}'.format(self.hex_file_path)) if self.port_name: self.load_btn['state'] = 'normal' self.verify_btn['state'] = 'normal' def choose_ser_port(self): port_name = self.ser_port_om.get() self.port_name = port_name.split('-')[0].strip() self.update_console('serial port chosen: {}'.format(self.port_name)) if self.hex_file_path: self.load_btn['state'] = 'normal' self.verify_btn['state'] = 'normal' def erase_device(self): baudrate = int(self.ser_baud_entry.get()) sp = create_serial_port(self.port_name, baudrate) blt = create_blt(sp) self.update_console(clear=True) # allow time for threads and hardware to spin up time.sleep(0.5) self.update_console('loading...') if erase_device(blt): self.update_console('device erased!') else: self.update_console('device erase failed') blt.end_thread() time.sleep(0.01) sp.close() def load_device(self): baudrate = int(self.ser_baud_entry.get()) sp = create_serial_port(self.port_name, baudrate) blt = create_blt(sp) self.update_console(clear=True) # allow time for threads and hardware to spin up time.sleep(0.5) self.update_console('loading...') if load_hex(blt, self.hex_file_path): self.update_console('device successfully loaded!') else: self.update_console('device load failed') blt.end_thread() time.sleep(0.01) sp.close() def verify_device(self): baudrate = int(self.ser_baud_entry.get()) sp = create_serial_port(self.port_name, baudrate) blt = create_blt(sp) self.update_console(clear=True) # allow time for threads and hardware to spin up time.sleep(0.5) self.update_console('verifying...') if verify_hex(blt, self.hex_file_path): self.update_console('device verified!') else: self.update_console('device verification failed') blt.end_thread() time.sleep(0.01) sp.close() def update_console(self, string=None, clear=False): if string: logger.info(string) self.console_text['state'] = 'normal' if clear: self.console_text.delete(1.0, tk.END) self.console_text.insert(tk.END, self.log_string.getvalue().strip() + '\n') self.log_string.seek(0) self.log_string.truncate(0) self.console_text['state'] = 'disabled' self.update()