firmware uploader + pin colors

This commit is contained in:
Valentin Sasek 2020-12-13 20:46:11 +02:00
parent 200cc10f32
commit 8db6947620
21 changed files with 60245 additions and 52 deletions

View File

@ -1,17 +1,17 @@
# friendly-buspirate
<img src="friendly-buspirate.png" align="right" width="500px">
Friendly user interface for <a href="http://dangerousprototypes.com/docs/Bus_Pirate" target="_blank">Bus Pirate</a>
Designed to reduce the number of steps you need to take so you can focus on the important part of your project
## Features
* Detect modes available in firmware
* Automatically connect to the last selected port
* Reopen last edited script
## Notes
* Only tested on windows
# friendly-buspirate
<img src="friendly-buspirate.png" align="right" width="500px">
Friendly user interface for <a href="http://dangerousprototypes.com/docs/Bus_Pirate" target="_blank">Bus Pirate</a>
Designed to reduce the number of steps you need to take so you can focus on the important part of your project
## Features
* Detect modes available in firmware
* Automatically connect to the last selected port
* Reopen last edited script
## Notes
* Only tested on windows

View File

@ -26,6 +26,7 @@ from modules.aux_mode import AuxMode
from modules.pinout import Pinout
from modules.menu import AppMenu
_WINDOW_TITLE = 'Friendly BusPirate (v0.1) - UI automation over BusPirate'
@ -39,12 +40,15 @@ class App(tk.Tk):
self.protocol('WM_DELETE_WINDOW', self.close)
self.settings = Settings()
self.tasks = []
self.tasks.append(loop.create_task(self.updater(interval)))
self.create_task(self.updater(interval))
self.port = None
self.initUi()
self.columnconfigure(0,weight=1)
self.rowconfigure(0,weight=1)
def create_task(self,task):
self.tasks.append(loop.create_task(task))
def initUi(self):
root = PanedWindow(self, orient='horizontal')
root.grid(row=0,column=0,sticky='wens')

View File

@ -37,13 +37,7 @@ class BusPyrate(Frame):
self.last_v_index = None
self.last_line = 1
self.cmd_stack = Queue()
# self.info = None
# self.version = None
# # self.read_info()
# self.current_mode = None
# self.pins = None
self.allow_read = True
def __call__(self):
return {'settings':None}
@ -75,9 +69,10 @@ class BusPyrate(Frame):
self.send('#')
self.com.flushInput()
def send(self,cmd,newline = '\n'):
def send(self,cmd,end = '\n'):
if self.com is None: return
self.com.write((cmd+newline).encode())
if not self.allow_read: return
self.com.write((cmd+end).encode())
def exec(self):
self.last_line = self.console.index('end').split('.')[0]
@ -91,11 +86,30 @@ class BusPyrate(Frame):
self.cmd_after = self.after(1000,self.exec)
def read_serial(self):
if self.com is None: return
if self.com.inWaiting() > 0:
if self.com is None:
if not self.parent.port_selector()['autoconnect']:
return
else:
self.parent.port_selector.connect()
self.after(1000,self.read_serial)
return
in_waiting = 0
try:
in_waiting = self.com.inWaiting()
except:
self.disconnect()
self.parent.port_selector.disconnected()
if not self.parent.port_selector()['autoconnect']:
return
if in_waiting > 0:
in_data = self.com.read(self.com.inWaiting())
self.print(in_data.decode('ascii'))
self.after(50,self.read_serial)
try:
self.print(in_data.decode('UTF8'))
except Exception as ex:
print(in_data,ex)
if self.allow_read:
self.after(50,self.read_serial)
def print(self,text):
self.console.configure(state='normal')
@ -167,7 +181,7 @@ class BusPyrate(Frame):
def info(self):
self.send('i')
def mode(self,mode):
def mode(self,mode):
self.current_mode = mode
for i, c in enumerate(mode):
if i == 0:

View File

@ -25,12 +25,6 @@ class Editor(Frame):
self.root = root
self.parent = parent
self.opened_file = None
# self.columnconfigure(0,weight=1)
# self.rowconfigure(0,weight=1)
# self.script_path_lbl = Label(self,text='Path:')
# self.script_path_lbl.grid(row=0,column=0,sticky='wns')
# self.script_path = ttk.Combobox(self,width=50)
# self.script_path.grid(row=0,column=1,sticky='wn')
self.editor = tkst.ScrolledText(self,tabstyle='wordprocessor')
self.editor.grid(row=0,column=0,columnspan=2,sticky='wens')
self.columnconfigure(0,weight=1)

5379
modules/fw/3/bpv3_fw5.10.hex Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

5379
modules/fw/3/bpv3_fw5.9.hex Normal file

File diff suppressed because it is too large Load Diff

5379
modules/fw/3/bpv3_fw6.0.hex Normal file

File diff suppressed because it is too large Load Diff

5379
modules/fw/3/bpv3_fw6.1.hex Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -14,7 +14,7 @@
#developed by Valentin Sasek <dsl400@gmail.com>
import os
from modules.menu_firmware import FirmwareMenu
from tkinter import Menu
class AppMenu(Menu):
@ -33,8 +33,11 @@ class AppMenu(Menu):
m_file.add_separator()
m_file.add_command(label='Exit',command=root.close)
self.add_cascade(label='Run Script (F5)',command=self.root.console.run_script)
self.m_firmware = FirmwareMenu(self,root)
self.add_cascade(label='Firmware',menu=self.m_firmware)
self.add_command(label='About',command=self.root.about)
def clear_recent(self):
self.root.settings('recent',[])
@ -43,4 +46,7 @@ class AppMenu(Menu):
for file in self.root.settings('recent'):
self.m_recent.add_command(label=file,command=lambda file=file: self.root.editor.open(file))
self.m_recent.add_separator()
self.m_recent.add_command(label='Clear',command=self.clear_recent)
self.m_recent.add_command(label='Clear',command=self.clear_recent)

208
modules/menu_firmware.py Normal file
View File

@ -0,0 +1,208 @@
# This file is part of Friendly BusPirate.
# Friendly BusPirate is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3 as
# published by the Free Software Foundation.
# Friendly BusPirate is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with Friendly BusPirate. If not, see <http://www.gnu.org/licenses/>.
#developed by Valentin Sasek <dsl400@gmail.com>
import os, sys, time
from tkinter import Menu
from os import listdir
from os.path import isfile, join
from intelhex import IntelHex
import serial
import asyncio
import json
PIC_FLASHSIZE = 0xAC00
BOOTLOADER_PLACEMENT = 1
BOOTLOADER_HELLO_STR = 0xC1
PIC_PAGES = 42
PIC_ROWS_IN_PAGE = 8
PIC_WORDS_IN_ROW = 64
PIC_WORD_SIZE = 3
PIC_ROW_SIZE = PIC_WORDS_IN_ROW * PIC_WORD_SIZE
PIC_PAGE_SIZE = PIC_ROWS_IN_PAGE * PIC_ROW_SIZE
PIC_LAST_PAGE = PIC_PAGES - 1
PIC_LAST_PAGE_ROW = PIC_ROWS_IN_PAGE - 1
# BUFFER_SIZE =
COMMAND_OFFSET = 3
LENGTH_OFFSET = 4
PAYLOAD_OFFSET = 5
HEADER_LENGTH = PAYLOAD_OFFSET
class FirmwareMenu(Menu):
def __init__(self,root,parent):
Menu.__init__(self,root,tearoff=0)
self.parent = parent
m_bp3 = Menu(self,tearoff=0)
self.cwd = os.getcwd()
bp3_fw_dir = join(self.cwd,'modules/fw/3')
for f in listdir(bp3_fw_dir):
if not f.endswith('.hex') and not isfile(f):
continue
m_bp3.add_command(label=f,command=lambda f=f: self.push_fw(f'3/{f}'))
m_bp4 = Menu(self,tearoff=0)
self.add_cascade(label='BP 3',menu=m_bp3)
# self.add_cascade(label='BP 4',menu=m_bp4)
def push_fw(self,f):
file_path = join(self.cwd,'modules/fw',f)
self.parent.create_task(self.fw_read_and_upload(file_path))
async def fw_read_and_upload(self,file_path):
await asyncio.sleep(.1)
o_buff = self.read_hex(file_path)
self.parent.console.send('$')
await asyncio.sleep(.1)
self.parent.console.send('y')
await asyncio.sleep(.01)
self.parent.console.send('')
await asyncio.sleep(.5)
self.parent.console.allow_read = False
await asyncio.sleep(.5)
if o_buff is not None:
await self.write_firmware(o_buff)
await asyncio.sleep(.1)
self.parent.console.allow_read = True
self.parent.console.read_serial()
self.parent.console.detect_modes()
def read_hex(self,file_path):
file_path = file_path.replace('\\','/')
try:
fw_hex = IntelHex(file_path)
self.parent.console.print(f'\nFile: {file_path}\n')
except:
self.parent.console.print('\nInvalid file!\n')
return None
data_map = {}
u_addr = 0
for p in range(0,PIC_PAGES):
if p not in data_map.keys():
data_map[p] = {}
for r in range(0,PIC_ROWS_IN_PAGE):
if r not in data_map[p].keys():
data_map[p][r] = [0xff] * PIC_WORDS_IN_ROW * PIC_WORD_SIZE
r_idx = 0
for w in range(0,PIC_WORDS_IN_ROW):
data_map[p][r][r_idx] = fw_hex[u_addr+2]
data_map[p][r][r_idx+1] = fw_hex[u_addr]
data_map[p][r][r_idx+2] = fw_hex[u_addr+1]
u_addr += 4
r_idx += 3
used = False
for b in data_map[p][r]:
if b != 0xff:
used = True
break
if p == PIC_LAST_PAGE and r == PIC_LAST_PAGE_ROW:
used = True
if not used:
del data_map[p][r]
for i in range(6):
idx = PIC_WORDS_IN_ROW * PIC_WORD_SIZE - 6 + i
data_map[PIC_LAST_PAGE][PIC_LAST_PAGE_ROW][idx] = data_map[0][0][i]
i_bl_address = ( PIC_FLASHSIZE -
(BOOTLOADER_PLACEMENT * PIC_ROWS_IN_PAGE * PIC_WORDS_IN_ROW * 2))
data_map[0][0][0] = 0x04
data_map[0][0][1] = (i_bl_address & 0x0000FE)
data_map[0][0][2] = ((i_bl_address & 0x00FF00) >> 8)
data_map[0][0][3] = 0x00
data_map[0][0][4] = ((i_bl_address & 0x7F0000) >> 16)
data_map[0][0][5] = 0x00
return data_map
async def write_firmware(self,data_map):
self.parent.console.print('\nSending Hello to the Bootloader... ')
try:
res = self.parent.console.com.write([0xc1])
await asyncio.sleep(.02)
except:
self.parent.console.print('\nCould not send hello!\n')
res = self.parent.console.com.read_all()
if chr(res[3]) != 'K':
self.parent.console.print('\nDid not receive OK\n')
return
self.parent.console.print(f'OK\n')
failed = False
try:
for p in data_map:
u_addr = p * PIC_WORDS_IN_ROW * 2 * PIC_ROWS_IN_PAGE
cmd = []
cmd.append((u_addr & 0x00FF0000) >> 16)
cmd.append((u_addr & 0x0000FF00) >> 8)
cmd.append((u_addr & 0x000000FF) >> 0)
cmd.append(0x01) #erase command
cmd.append(0x01) #1 byte, CRC
cmd.append(self.make_crc(cmd))
self.parent.console.print(f'Erasing page {p:04x} ... ')
self.parent.console.com.write(cmd)
await asyncio.sleep(.1)
res = self.parent.console.com.read_all()
if chr(res[0]) == 'K':
self.parent.console.print('OK.')
else:
failed = True
break
self.parent.console.print(f' Writing page {p:04x}: ')
for r in data_map[p]:
r_addr = u_addr + (r * PIC_WORDS_IN_ROW * 2)
cmd = []
cmd.append((r_addr & 0x00FF0000) >> 16)
cmd.append((r_addr & 0x0000FF00) >> 8)
cmd.append((r_addr & 0x000000FF) >> 0)
cmd.append(0x02) #write command
cmd.append(PIC_ROW_SIZE + 0x01) #data length + crc
for b in data_map[p][r]:
cmd.append(b)
cmd.append(self.make_crc(cmd))
self.parent.console.com.write(cmd)
await asyncio.sleep(.1)
res = self.parent.console.com.read_all()
if len(res) > 0 and chr(res[0]) == 'K':
self.parent.console.print('.')
else:
failed = True
break
if failed:
break
self.parent.console.print('OK\n')
except Exception as ex:
print(ex)
failed = True
if failed:
self.parent.console.print('\nFirmware upload failed\n')
else:
self.parent.console.print('\nFirmware uploaded successfully\n')
def make_crc(self,data):
crc = 0
for i in range(0,len(data)):
crc -= data[i]
crc &= 0x00ff
return crc

View File

@ -31,8 +31,6 @@ class ModeSelector(Frame):
self.btn_get_modes = Button(self.fmode_HiZ, text='Get Modes')
self.btn_get_modes.place(relx=0.5, rely=0.5, anchor='center')
self.fmode_UART = Frame(self.modes_tabs,width=100,height=100,borderwidth=2,relief='groove')
lbl_baud = Label(self.fmode_UART,text='Speed (bps):')
lbl_baud.grid(row=0,column=0,pady=2)

View File

@ -32,24 +32,24 @@ class Pinout(Frame):
self.lbl_voltages.grid(row=0,column=2,columnspan=2)
self.cmb_interval.grid(row=0,column=4,columnspan=2)
self.pin_9 = Label(self,text='GND',borderwidth=2, relief="groove",width=8)
self.pin_8 = Label(self,text='3.3v',borderwidth=2, relief="groove",width=8)
self.pin_9 = Label(self,text='GND',borderwidth=2, relief="groove",width=8,bg='black',fg='white')
self.pin_8 = Label(self,text='3.3v',borderwidth=2, relief="groove",width=8,bg='white')
self.pin_8v = Label(self,text='-',borderwidth=2, relief="groove",width=8)
self.pin_7 = Label(self,text='5.0v',borderwidth=2, relief="groove",width=8)
self.pin_7 = Label(self,text='5.0v',borderwidth=2, relief="groove",width=8,bg='gray')
self.pin_7v = Label(self,text='-',borderwidth=2, relief="groove",width=8)
self.pin_6 = Label(self,text='ADC',borderwidth=2, relief="groove",width=8)
self.pin_6 = Label(self,text='ADC',borderwidth=2, relief="groove",width=8,bg='magenta')
self.pin_6v = Label(self,text='-',borderwidth=2, relief="groove",width=8)
self.pin_5 = Label(self,text='VPU',borderwidth=2, relief="groove",width=8)
self.pin_5 = Label(self,text='VPU',borderwidth=2, relief="groove",width=8,bg='blue',fg='white')
self.pin_5v = Label(self,text='-',borderwidth=2, relief="groove",width=8)
self.pin_4 = Label(self,text='AUX',borderwidth=2, relief="groove",width=8)
self.pin_4 = Label(self,text='AUX',borderwidth=2, relief="groove",width=8,bg='green')
self.pin_4v = Label(self,text='-',borderwidth=2, relief="groove",width=8)
self.pin_3 = Label(self,text='-',borderwidth=2, relief="groove",width=8)
self.pin_3 = Label(self,text='-',borderwidth=2, relief="groove",width=8,bg='yellow')
self.pin_3v = Label(self,text='-',borderwidth=2, relief="groove",width=8)
self.pin_2 = Label(self,text='-',borderwidth=2, relief="groove",width=8)
self.pin_2 = Label(self,text='-',borderwidth=2, relief="groove",width=8,bg='orange')
self.pin_2v = Label(self,text='-',borderwidth=2, relief="groove",width=8)
self.pin_1 = Label(self,text='-',borderwidth=2, relief="groove",width=8)
self.pin_1 = Label(self,text='-',borderwidth=2, relief="groove",width=8,bg='red')
self.pin_1v = Label(self,text='-',borderwidth=2, relief="groove",width=8)
self.pin_0 = Label(self,text='-',borderwidth=2, relief="groove",width=8)
self.pin_0 = Label(self,text='-',borderwidth=2, relief="groove",width=8,bg='brown')
self.pin_0v = Label(self,text='-',borderwidth=2, relief="groove",width=8)
self.pin_9.grid(row=1,column=3)

2
requirements.txt Normal file
View File

@ -0,0 +1,2 @@
intelhex==2.3.0
pyserial==3.5