firmware uploader + pin colors
This commit is contained in:
parent
200cc10f32
commit
8db6947620
34
README.md
34
README.md
|
@ -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
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
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
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
|
@ -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)
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
intelhex==2.3.0
|
||||
pyserial==3.5
|
Loading…
Reference in New Issue