Ejemplo n.º 1
0
    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()
Ejemplo n.º 2
0
    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()
Ejemplo n.º 3
0
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
Ejemplo n.º 4
0
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
Ejemplo n.º 5
0
def test_creation_with_initial_value(root):
    som = SmartOptionMenu(root, ['1', '2', '3'], initial_value='2')

    assert som.get() == '2'
Ejemplo n.º 6
0
def test_creation(root):
    SmartOptionMenu(root, ['1', '2', '3'])
Ejemplo n.º 7
0
def som(root):
    som_widget = SmartOptionMenu(root, ['1', '2', '3'])
    som_widget.grid()

    yield som_widget
Ejemplo n.º 8
0
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()
Ejemplo n.º 9
0
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()