[FL-3435] External apps removed (#2934)
Co-authored-by: Aleksandr Kutuzov <alleteam@gmail.com>
3
.github/CODEOWNERS
vendored
|
@ -22,9 +22,6 @@
|
||||||
/applications/main/subghz/ @skotopes @DrZlo13 @hedger @Skorpionm
|
/applications/main/subghz/ @skotopes @DrZlo13 @hedger @Skorpionm
|
||||||
/applications/main/u2f/ @skotopes @DrZlo13 @hedger @nminaylov
|
/applications/main/u2f/ @skotopes @DrZlo13 @hedger @nminaylov
|
||||||
|
|
||||||
/applications/external/bt_hid_app/ @skotopes @DrZlo13 @hedger @gornekich
|
|
||||||
/applications/external/picopass/ @skotopes @DrZlo13 @hedger @gornekich
|
|
||||||
|
|
||||||
/applications/services/bt/ @skotopes @DrZlo13 @hedger @gornekich
|
/applications/services/bt/ @skotopes @DrZlo13 @hedger @gornekich
|
||||||
/applications/services/cli/ @skotopes @DrZlo13 @hedger @nminaylov
|
/applications/services/cli/ @skotopes @DrZlo13 @hedger @nminaylov
|
||||||
/applications/services/crypto/ @skotopes @DrZlo13 @hedger @nminaylov
|
/applications/services/crypto/ @skotopes @DrZlo13 @hedger @nminaylov
|
||||||
|
|
2
.github/workflows/build.yml
vendored
|
@ -201,7 +201,7 @@ jobs:
|
||||||
|
|
||||||
- name: Build example & external apps with uFBT
|
- name: Build example & external apps with uFBT
|
||||||
run: |
|
run: |
|
||||||
for appdir in 'applications/external' 'applications/examples'; do
|
for appdir in 'applications/examples'; do
|
||||||
for app in $(find "$appdir" -maxdepth 1 -mindepth 1 -type d); do
|
for app in $(find "$appdir" -maxdepth 1 -mindepth 1 -type d); do
|
||||||
pushd $app
|
pushd $app
|
||||||
TARGETS_FAM=$(grep "targets" application.fam || echo "${{ matrix.target }}")
|
TARGETS_FAM=$(grep "targets" application.fam || echo "${{ matrix.target }}")
|
||||||
|
|
3
.gitmodules
vendored
|
@ -26,9 +26,6 @@
|
||||||
[submodule "lib/cxxheaderparser"]
|
[submodule "lib/cxxheaderparser"]
|
||||||
path = lib/cxxheaderparser
|
path = lib/cxxheaderparser
|
||||||
url = https://github.com/robotpy/cxxheaderparser.git
|
url = https://github.com/robotpy/cxxheaderparser.git
|
||||||
[submodule "applications/external/dap_link/lib/free-dap"]
|
|
||||||
path = applications/external/dap_link/lib/free-dap
|
|
||||||
url = https://github.com/ataradov/free-dap.git
|
|
||||||
[submodule "lib/heatshrink"]
|
[submodule "lib/heatshrink"]
|
||||||
path = lib/heatshrink
|
path = lib/heatshrink
|
||||||
url = https://github.com/flipperdevices/heatshrink.git
|
url = https://github.com/flipperdevices/heatshrink.git
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
--ignore-ccache -C gccarm --rules-config .pvsconfig -e lib/cmsis_core -e lib/fatfs -e lib/fnv1a-hash -e lib/FreeRTOS-Kernel -e lib/heatshrink -e lib/libusb_stm32 -e lib/littlefs -e lib/mbedtls -e lib/micro-ecc -e lib/microtar -e lib/mlib -e lib/qrcode -e lib/ST25RFAL002 -e lib/stm32wb_cmsis -e lib/stm32wb_copro -e lib/stm32wb_hal -e lib/u8g2 -e lib/nanopb -e */arm-none-eabi/* -e applications/external/dap_link/lib/free-dap
|
--ignore-ccache -C gccarm --rules-config .pvsconfig -e lib/cmsis_core -e lib/fatfs -e lib/fnv1a-hash -e lib/FreeRTOS-Kernel -e lib/heatshrink -e lib/libusb_stm32 -e lib/littlefs -e lib/mbedtls -e lib/micro-ecc -e lib/microtar -e lib/mlib -e lib/qrcode -e lib/ST25RFAL002 -e lib/stm32wb_cmsis -e lib/stm32wb_copro -e lib/stm32wb_hal -e lib/u8g2 -e lib/nanopb -e */arm-none-eabi/*
|
||||||
|
|
|
@ -33,22 +33,10 @@ Applications for main Flipper menu.
|
||||||
- `nfc` - NFC application, HF rfid, EMV and etc
|
- `nfc` - NFC application, HF rfid, EMV and etc
|
||||||
- `subghz` - SubGhz application, 433 fobs and etc
|
- `subghz` - SubGhz application, 433 fobs and etc
|
||||||
- `u2f` - U2F Application
|
- `u2f` - U2F Application
|
||||||
|
|
||||||
|
|
||||||
## External
|
|
||||||
|
|
||||||
External applications deployed to SD Card
|
|
||||||
|
|
||||||
- `clock` - Clock application
|
- `clock` - Clock application
|
||||||
- `dap_link` - DAP Link OnChip debugger
|
|
||||||
- `hid_app` - USB/BT Remote controller
|
|
||||||
- `music_player` - Music player app (demo)
|
- `music_player` - Music player app (demo)
|
||||||
- `nfc_magic` - NFC MFC Magic card application
|
|
||||||
- `picopass` - Picopass reader / writer
|
|
||||||
- `signal_generator` - Signal generator app: PWM and clock generator
|
|
||||||
- `snake_game` - Snake game application
|
- `snake_game` - Snake game application
|
||||||
- `spi_mem_manager` - SPI Memory reader / flasher
|
|
||||||
- `weather_station` - SubGHz weather station
|
|
||||||
|
|
||||||
## services
|
## services
|
||||||
|
|
||||||
|
|
6
applications/external/application.fam
vendored
|
@ -1,6 +0,0 @@
|
||||||
# Placeholder
|
|
||||||
App(
|
|
||||||
appid="external_apps",
|
|
||||||
name="External apps bundle",
|
|
||||||
apptype=FlipperAppType.METAPACKAGE,
|
|
||||||
)
|
|
|
@ -1,17 +0,0 @@
|
||||||
App(
|
|
||||||
appid="avr_isp",
|
|
||||||
name="AVR Flasher",
|
|
||||||
apptype=FlipperAppType.EXTERNAL,
|
|
||||||
entry_point="avr_isp_app",
|
|
||||||
requires=["gui"],
|
|
||||||
stack_size=4 * 1024,
|
|
||||||
order=20,
|
|
||||||
fap_icon="avr_app_icon_10x10.png",
|
|
||||||
fap_category="GPIO",
|
|
||||||
fap_icon_assets="images",
|
|
||||||
fap_private_libs=[
|
|
||||||
Lib(
|
|
||||||
name="driver",
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
Before Width: | Height: | Size: 3.5 KiB |
|
@ -1,179 +0,0 @@
|
||||||
#include "avr_isp_app_i.h"
|
|
||||||
|
|
||||||
static bool avr_isp_app_custom_event_callback(void* context, uint32_t event) {
|
|
||||||
furi_assert(context);
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
return scene_manager_handle_custom_event(app->scene_manager, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool avr_isp_app_back_event_callback(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
return scene_manager_handle_back_event(app->scene_manager);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_app_tick_event_callback(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
scene_manager_handle_tick_event(app->scene_manager);
|
|
||||||
}
|
|
||||||
|
|
||||||
AvrIspApp* avr_isp_app_alloc() {
|
|
||||||
AvrIspApp* app = malloc(sizeof(AvrIspApp));
|
|
||||||
|
|
||||||
app->file_path = furi_string_alloc();
|
|
||||||
furi_string_set(app->file_path, STORAGE_APP_DATA_PATH_PREFIX);
|
|
||||||
app->error = AvrIspErrorNoError;
|
|
||||||
|
|
||||||
// GUI
|
|
||||||
app->gui = furi_record_open(RECORD_GUI);
|
|
||||||
|
|
||||||
// View Dispatcher
|
|
||||||
app->view_dispatcher = view_dispatcher_alloc();
|
|
||||||
app->scene_manager = scene_manager_alloc(&avr_isp_scene_handlers, app);
|
|
||||||
view_dispatcher_enable_queue(app->view_dispatcher);
|
|
||||||
|
|
||||||
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
|
|
||||||
view_dispatcher_set_custom_event_callback(
|
|
||||||
app->view_dispatcher, avr_isp_app_custom_event_callback);
|
|
||||||
view_dispatcher_set_navigation_event_callback(
|
|
||||||
app->view_dispatcher, avr_isp_app_back_event_callback);
|
|
||||||
view_dispatcher_set_tick_event_callback(
|
|
||||||
app->view_dispatcher, avr_isp_app_tick_event_callback, 100);
|
|
||||||
|
|
||||||
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
|
||||||
|
|
||||||
// Open Notification record
|
|
||||||
app->notifications = furi_record_open(RECORD_NOTIFICATION);
|
|
||||||
|
|
||||||
// SubMenu
|
|
||||||
app->submenu = submenu_alloc();
|
|
||||||
view_dispatcher_add_view(
|
|
||||||
app->view_dispatcher, AvrIspViewSubmenu, submenu_get_view(app->submenu));
|
|
||||||
|
|
||||||
// Widget
|
|
||||||
app->widget = widget_alloc();
|
|
||||||
view_dispatcher_add_view(app->view_dispatcher, AvrIspViewWidget, widget_get_view(app->widget));
|
|
||||||
|
|
||||||
// Text Input
|
|
||||||
app->text_input = text_input_alloc();
|
|
||||||
view_dispatcher_add_view(
|
|
||||||
app->view_dispatcher, AvrIspViewTextInput, text_input_get_view(app->text_input));
|
|
||||||
|
|
||||||
// Popup
|
|
||||||
app->popup = popup_alloc();
|
|
||||||
view_dispatcher_add_view(app->view_dispatcher, AvrIspViewPopup, popup_get_view(app->popup));
|
|
||||||
|
|
||||||
//Dialog
|
|
||||||
app->dialogs = furi_record_open(RECORD_DIALOGS);
|
|
||||||
|
|
||||||
// Programmer view
|
|
||||||
app->avr_isp_programmer_view = avr_isp_programmer_view_alloc();
|
|
||||||
view_dispatcher_add_view(
|
|
||||||
app->view_dispatcher,
|
|
||||||
AvrIspViewProgrammer,
|
|
||||||
avr_isp_programmer_view_get_view(app->avr_isp_programmer_view));
|
|
||||||
|
|
||||||
// Reader view
|
|
||||||
app->avr_isp_reader_view = avr_isp_reader_view_alloc();
|
|
||||||
view_dispatcher_add_view(
|
|
||||||
app->view_dispatcher,
|
|
||||||
AvrIspViewReader,
|
|
||||||
avr_isp_reader_view_get_view(app->avr_isp_reader_view));
|
|
||||||
|
|
||||||
// Writer view
|
|
||||||
app->avr_isp_writer_view = avr_isp_writer_view_alloc();
|
|
||||||
view_dispatcher_add_view(
|
|
||||||
app->view_dispatcher,
|
|
||||||
AvrIspViewWriter,
|
|
||||||
avr_isp_writer_view_get_view(app->avr_isp_writer_view));
|
|
||||||
|
|
||||||
// Chip detect view
|
|
||||||
app->avr_isp_chip_detect_view = avr_isp_chip_detect_view_alloc();
|
|
||||||
view_dispatcher_add_view(
|
|
||||||
app->view_dispatcher,
|
|
||||||
AvrIspViewChipDetect,
|
|
||||||
avr_isp_chip_detect_view_get_view(app->avr_isp_chip_detect_view));
|
|
||||||
|
|
||||||
// Enable 5v power, multiple attempts to avoid issues with power chip protection false triggering
|
|
||||||
uint8_t attempts = 0;
|
|
||||||
while(!furi_hal_power_is_otg_enabled() && attempts++ < 5) {
|
|
||||||
furi_hal_power_enable_otg();
|
|
||||||
furi_delay_ms(10);
|
|
||||||
}
|
|
||||||
|
|
||||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneStart);
|
|
||||||
|
|
||||||
return app;
|
|
||||||
} //-V773
|
|
||||||
|
|
||||||
void avr_isp_app_free(AvrIspApp* app) {
|
|
||||||
furi_assert(app);
|
|
||||||
|
|
||||||
// Disable 5v power
|
|
||||||
if(furi_hal_power_is_otg_enabled()) {
|
|
||||||
furi_hal_power_disable_otg();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Submenu
|
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewSubmenu);
|
|
||||||
submenu_free(app->submenu);
|
|
||||||
|
|
||||||
// Widget
|
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewWidget);
|
|
||||||
widget_free(app->widget);
|
|
||||||
|
|
||||||
// TextInput
|
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewTextInput);
|
|
||||||
text_input_free(app->text_input);
|
|
||||||
|
|
||||||
// Popup
|
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewPopup);
|
|
||||||
popup_free(app->popup);
|
|
||||||
|
|
||||||
//Dialog
|
|
||||||
furi_record_close(RECORD_DIALOGS);
|
|
||||||
|
|
||||||
// Programmer view
|
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewProgrammer);
|
|
||||||
avr_isp_programmer_view_free(app->avr_isp_programmer_view);
|
|
||||||
|
|
||||||
// Reader view
|
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewReader);
|
|
||||||
avr_isp_reader_view_free(app->avr_isp_reader_view);
|
|
||||||
|
|
||||||
// Writer view
|
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewWriter);
|
|
||||||
avr_isp_writer_view_free(app->avr_isp_writer_view);
|
|
||||||
|
|
||||||
// Chip detect view
|
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, AvrIspViewChipDetect);
|
|
||||||
avr_isp_chip_detect_view_free(app->avr_isp_chip_detect_view);
|
|
||||||
|
|
||||||
// View dispatcher
|
|
||||||
view_dispatcher_free(app->view_dispatcher);
|
|
||||||
scene_manager_free(app->scene_manager);
|
|
||||||
|
|
||||||
// Notifications
|
|
||||||
furi_record_close(RECORD_NOTIFICATION);
|
|
||||||
app->notifications = NULL;
|
|
||||||
|
|
||||||
// Close records
|
|
||||||
furi_record_close(RECORD_GUI);
|
|
||||||
|
|
||||||
// Path strings
|
|
||||||
furi_string_free(app->file_path);
|
|
||||||
|
|
||||||
free(app);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t avr_isp_app(void* p) {
|
|
||||||
UNUSED(p);
|
|
||||||
AvrIspApp* avr_isp_app = avr_isp_app_alloc();
|
|
||||||
|
|
||||||
view_dispatcher_run(avr_isp_app->view_dispatcher);
|
|
||||||
|
|
||||||
avr_isp_app_free(avr_isp_app);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
|
@ -1,31 +0,0 @@
|
||||||
#include "avr_isp_app_i.h"
|
|
||||||
#include <lib/toolbox/path.h>
|
|
||||||
#include <flipper_format/flipper_format_i.h>
|
|
||||||
|
|
||||||
#define TAG "AvrIsp"
|
|
||||||
|
|
||||||
bool avr_isp_load_from_file(AvrIspApp* app) {
|
|
||||||
furi_assert(app);
|
|
||||||
|
|
||||||
FuriString* file_path = furi_string_alloc();
|
|
||||||
FuriString* file_name = furi_string_alloc();
|
|
||||||
|
|
||||||
DialogsFileBrowserOptions browser_options;
|
|
||||||
dialog_file_browser_set_basic_options(
|
|
||||||
&browser_options, AVR_ISP_APP_EXTENSION, &I_avr_app_icon_10x10);
|
|
||||||
browser_options.base_path = STORAGE_APP_DATA_PATH_PREFIX;
|
|
||||||
|
|
||||||
// Input events and views are managed by file_select
|
|
||||||
bool res = dialog_file_browser_show(app->dialogs, file_path, app->file_path, &browser_options);
|
|
||||||
|
|
||||||
if(res) {
|
|
||||||
path_extract_dirname(furi_string_get_cstr(file_path), app->file_path);
|
|
||||||
path_extract_filename(file_path, file_name, true);
|
|
||||||
strncpy(app->file_name_tmp, furi_string_get_cstr(file_name), AVR_ISP_MAX_LEN_NAME);
|
|
||||||
}
|
|
||||||
|
|
||||||
furi_string_free(file_name);
|
|
||||||
furi_string_free(file_path);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "helpers/avr_isp_types.h"
|
|
||||||
#include <avr_isp_icons.h>
|
|
||||||
|
|
||||||
#include "scenes/avr_isp_scene.h"
|
|
||||||
#include <gui/gui.h>
|
|
||||||
#include <gui/view_dispatcher.h>
|
|
||||||
#include <gui/scene_manager.h>
|
|
||||||
#include <gui/modules/submenu.h>
|
|
||||||
#include <gui/modules/widget.h>
|
|
||||||
#include <notification/notification_messages.h>
|
|
||||||
#include <gui/modules/text_input.h>
|
|
||||||
#include <dialogs/dialogs.h>
|
|
||||||
#include <storage/storage.h>
|
|
||||||
#include <gui/modules/popup.h>
|
|
||||||
|
|
||||||
#include "views/avr_isp_view_programmer.h"
|
|
||||||
#include "views/avr_isp_view_reader.h"
|
|
||||||
#include "views/avr_isp_view_writer.h"
|
|
||||||
#include "views/avr_isp_view_chip_detect.h"
|
|
||||||
|
|
||||||
#define AVR_ISP_MAX_LEN_NAME 64
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
Gui* gui;
|
|
||||||
ViewDispatcher* view_dispatcher;
|
|
||||||
SceneManager* scene_manager;
|
|
||||||
NotificationApp* notifications;
|
|
||||||
DialogsApp* dialogs;
|
|
||||||
Popup* popup;
|
|
||||||
Submenu* submenu;
|
|
||||||
Widget* widget;
|
|
||||||
TextInput* text_input;
|
|
||||||
FuriString* file_path;
|
|
||||||
char file_name_tmp[AVR_ISP_MAX_LEN_NAME];
|
|
||||||
AvrIspProgrammerView* avr_isp_programmer_view;
|
|
||||||
AvrIspReaderView* avr_isp_reader_view;
|
|
||||||
AvrIspWriterView* avr_isp_writer_view;
|
|
||||||
AvrIspChipDetectView* avr_isp_chip_detect_view;
|
|
||||||
AvrIspError error;
|
|
||||||
} AvrIspApp;
|
|
||||||
|
|
||||||
bool avr_isp_load_from_file(AvrIspApp* app);
|
|
|
@ -1,496 +0,0 @@
|
||||||
#include "avr_isp.h"
|
|
||||||
#include "../lib/driver/avr_isp_prog_cmd.h"
|
|
||||||
#include "../lib/driver/avr_isp_spi_sw.h"
|
|
||||||
|
|
||||||
#include <furi.h>
|
|
||||||
|
|
||||||
#define AVR_ISP_PROG_TX_RX_BUF_SIZE 320
|
|
||||||
#define TAG "AvrIsp"
|
|
||||||
|
|
||||||
struct AvrIsp {
|
|
||||||
AvrIspSpiSw* spi;
|
|
||||||
bool pmode;
|
|
||||||
AvrIspCallback callback;
|
|
||||||
void* context;
|
|
||||||
};
|
|
||||||
|
|
||||||
AvrIsp* avr_isp_alloc(void) {
|
|
||||||
AvrIsp* instance = malloc(sizeof(AvrIsp));
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_free(AvrIsp* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
if(instance->spi) avr_isp_end_pmode(instance);
|
|
||||||
free(instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_set_tx_callback(AvrIsp* instance, AvrIspCallback callback, void* context) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
instance->callback = callback;
|
|
||||||
instance->context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t avr_isp_spi_transaction(
|
|
||||||
AvrIsp* instance,
|
|
||||||
uint8_t cmd,
|
|
||||||
uint8_t addr_hi,
|
|
||||||
uint8_t addr_lo,
|
|
||||||
uint8_t data) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
avr_isp_spi_sw_txrx(instance->spi, cmd);
|
|
||||||
avr_isp_spi_sw_txrx(instance->spi, addr_hi);
|
|
||||||
avr_isp_spi_sw_txrx(instance->spi, addr_lo);
|
|
||||||
return avr_isp_spi_sw_txrx(instance->spi, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool avr_isp_set_pmode(AvrIsp* instance, uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
uint8_t res = 0;
|
|
||||||
avr_isp_spi_sw_txrx(instance->spi, a);
|
|
||||||
avr_isp_spi_sw_txrx(instance->spi, b);
|
|
||||||
res = avr_isp_spi_sw_txrx(instance->spi, c);
|
|
||||||
avr_isp_spi_sw_txrx(instance->spi, d);
|
|
||||||
return res == 0x53;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_end_pmode(AvrIsp* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
if(instance->pmode) {
|
|
||||||
avr_isp_spi_sw_res_set(instance->spi, true);
|
|
||||||
// We're about to take the target out of reset
|
|
||||||
// so configure SPI pins as input
|
|
||||||
if(instance->spi) avr_isp_spi_sw_free(instance->spi);
|
|
||||||
instance->spi = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
instance->pmode = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool avr_isp_start_pmode(AvrIsp* instance, AvrIspSpiSwSpeed spi_speed) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
// Reset target before driving PIN_SCK or PIN_MOSI
|
|
||||||
|
|
||||||
// SPI.begin() will configure SS as output,
|
|
||||||
// so SPI master mode is selected.
|
|
||||||
// We have defined RESET as pin 10,
|
|
||||||
// which for many arduino's is not the SS pin.
|
|
||||||
// So we have to configure RESET as output here,
|
|
||||||
// (reset_target() first sets the correct level)
|
|
||||||
if(instance->spi) avr_isp_spi_sw_free(instance->spi);
|
|
||||||
instance->spi = avr_isp_spi_sw_init(spi_speed);
|
|
||||||
|
|
||||||
avr_isp_spi_sw_res_set(instance->spi, false);
|
|
||||||
// See avr datasheets, chapter "SERIAL_PRG Programming Algorithm":
|
|
||||||
|
|
||||||
// Pulse RESET after PIN_SCK is low:
|
|
||||||
avr_isp_spi_sw_sck_set(instance->spi, false);
|
|
||||||
|
|
||||||
// discharge PIN_SCK, value arbitrally chosen
|
|
||||||
furi_delay_ms(20);
|
|
||||||
avr_isp_spi_sw_res_set(instance->spi, true);
|
|
||||||
|
|
||||||
// Pulse must be minimum 2 target CPU speed cycles
|
|
||||||
// so 100 usec is ok for CPU speeds above 20KHz
|
|
||||||
furi_delay_ms(1);
|
|
||||||
|
|
||||||
avr_isp_spi_sw_res_set(instance->spi, false);
|
|
||||||
|
|
||||||
// Send the enable programming command:
|
|
||||||
// datasheet: must be > 20 msec
|
|
||||||
furi_delay_ms(50);
|
|
||||||
if(avr_isp_set_pmode(instance, AVR_ISP_SET_PMODE)) {
|
|
||||||
instance->pmode = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_auto_set_spi_speed_start_pmode(AvrIsp* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
AvrIspSpiSwSpeed spi_speed[] = {
|
|
||||||
AvrIspSpiSwSpeed1Mhz,
|
|
||||||
AvrIspSpiSwSpeed400Khz,
|
|
||||||
AvrIspSpiSwSpeed250Khz,
|
|
||||||
AvrIspSpiSwSpeed125Khz,
|
|
||||||
AvrIspSpiSwSpeed60Khz,
|
|
||||||
AvrIspSpiSwSpeed40Khz,
|
|
||||||
AvrIspSpiSwSpeed20Khz,
|
|
||||||
AvrIspSpiSwSpeed10Khz,
|
|
||||||
AvrIspSpiSwSpeed5Khz,
|
|
||||||
AvrIspSpiSwSpeed1Khz,
|
|
||||||
};
|
|
||||||
for(uint8_t i = 0; i < COUNT_OF(spi_speed); i++) {
|
|
||||||
if(avr_isp_start_pmode(instance, spi_speed[i])) {
|
|
||||||
AvrIspSignature sig = avr_isp_read_signature(instance);
|
|
||||||
AvrIspSignature sig_examination = avr_isp_read_signature(instance); //-V656
|
|
||||||
uint8_t y = 0;
|
|
||||||
while(y < 8) {
|
|
||||||
if(memcmp((uint8_t*)&sig, (uint8_t*)&sig_examination, sizeof(AvrIspSignature)) !=
|
|
||||||
0)
|
|
||||||
break;
|
|
||||||
sig_examination = avr_isp_read_signature(instance);
|
|
||||||
y++;
|
|
||||||
}
|
|
||||||
if(y == 8) {
|
|
||||||
if(spi_speed[i] > AvrIspSpiSwSpeed1Mhz) {
|
|
||||||
if(i < (COUNT_OF(spi_speed) - 1)) {
|
|
||||||
avr_isp_end_pmode(instance);
|
|
||||||
i++;
|
|
||||||
return avr_isp_start_pmode(instance, spi_speed[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(instance->spi) {
|
|
||||||
avr_isp_spi_sw_free(instance->spi);
|
|
||||||
instance->spi = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_commit(AvrIsp* instance, uint16_t addr, uint8_t data) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
avr_isp_spi_transaction(instance, AVR_ISP_COMMIT(addr));
|
|
||||||
/* polling flash */
|
|
||||||
if(data == 0xFF) {
|
|
||||||
furi_delay_ms(5);
|
|
||||||
} else {
|
|
||||||
/* polling flash */
|
|
||||||
uint32_t starttime = furi_get_tick();
|
|
||||||
while((furi_get_tick() - starttime) < 30) {
|
|
||||||
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FLASH_HI(addr)) != 0xFF) {
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint16_t avr_isp_current_page(AvrIsp* instance, uint32_t addr, uint16_t page_size) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
uint16_t page = 0;
|
|
||||||
switch(page_size) {
|
|
||||||
case 32:
|
|
||||||
page = addr & 0xFFFFFFF0;
|
|
||||||
break;
|
|
||||||
case 64:
|
|
||||||
page = addr & 0xFFFFFFE0;
|
|
||||||
break;
|
|
||||||
case 128:
|
|
||||||
page = addr & 0xFFFFFFC0;
|
|
||||||
break;
|
|
||||||
case 256:
|
|
||||||
page = addr & 0xFFFFFF80;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
page = addr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return page;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool avr_isp_flash_write_pages(
|
|
||||||
AvrIsp* instance,
|
|
||||||
uint16_t addr,
|
|
||||||
uint16_t page_size,
|
|
||||||
uint8_t* data,
|
|
||||||
uint32_t data_size) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
size_t x = 0;
|
|
||||||
uint16_t page = avr_isp_current_page(instance, addr, page_size);
|
|
||||||
|
|
||||||
while(x < data_size) {
|
|
||||||
if(page != avr_isp_current_page(instance, addr, page_size)) {
|
|
||||||
avr_isp_commit(instance, page, data[x - 1]);
|
|
||||||
page = avr_isp_current_page(instance, addr, page_size);
|
|
||||||
}
|
|
||||||
avr_isp_spi_transaction(instance, AVR_ISP_WRITE_FLASH_LO(addr, data[x++]));
|
|
||||||
avr_isp_spi_transaction(instance, AVR_ISP_WRITE_FLASH_HI(addr, data[x++]));
|
|
||||||
addr++;
|
|
||||||
}
|
|
||||||
avr_isp_commit(instance, page, data[x - 1]);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_erase_chip(AvrIsp* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
bool ret = false;
|
|
||||||
if(!instance->pmode) avr_isp_auto_set_spi_speed_start_pmode(instance);
|
|
||||||
if(instance->pmode) {
|
|
||||||
avr_isp_spi_transaction(instance, AVR_ISP_ERASE_CHIP);
|
|
||||||
furi_delay_ms(100);
|
|
||||||
avr_isp_end_pmode(instance);
|
|
||||||
ret = true;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
avr_isp_eeprom_write(AvrIsp* instance, uint16_t addr, uint8_t* data, uint32_t data_size) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
for(uint16_t i = 0; i < data_size; i++) {
|
|
||||||
avr_isp_spi_transaction(instance, AVR_ISP_WRITE_EEPROM(addr, data[i]));
|
|
||||||
furi_delay_ms(10);
|
|
||||||
addr++;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_write_page(
|
|
||||||
AvrIsp* instance,
|
|
||||||
uint32_t mem_type,
|
|
||||||
uint32_t mem_size,
|
|
||||||
uint16_t addr,
|
|
||||||
uint16_t page_size,
|
|
||||||
uint8_t* data,
|
|
||||||
uint32_t data_size) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
bool ret = false;
|
|
||||||
switch(mem_type) {
|
|
||||||
case STK_SET_FLASH_TYPE:
|
|
||||||
if((addr + data_size / 2) <= mem_size) {
|
|
||||||
ret = avr_isp_flash_write_pages(instance, addr, page_size, data, data_size);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case STK_SET_EEPROM_TYPE:
|
|
||||||
if((addr + data_size) <= mem_size) {
|
|
||||||
ret = avr_isp_eeprom_write(instance, addr, data, data_size);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
furi_crash(TAG " Incorrect mem type.");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool avr_isp_flash_read_page(
|
|
||||||
AvrIsp* instance,
|
|
||||||
uint16_t addr,
|
|
||||||
uint16_t page_size,
|
|
||||||
uint8_t* data,
|
|
||||||
uint32_t data_size) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
if(page_size > data_size) return false;
|
|
||||||
for(uint16_t i = 0; i < page_size; i += 2) {
|
|
||||||
data[i] = avr_isp_spi_transaction(instance, AVR_ISP_READ_FLASH_LO(addr));
|
|
||||||
data[i + 1] = avr_isp_spi_transaction(instance, AVR_ISP_READ_FLASH_HI(addr));
|
|
||||||
addr++;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool avr_isp_eeprom_read_page(
|
|
||||||
AvrIsp* instance,
|
|
||||||
uint16_t addr,
|
|
||||||
uint16_t page_size,
|
|
||||||
uint8_t* data,
|
|
||||||
uint32_t data_size) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
if(page_size > data_size) return false;
|
|
||||||
for(uint16_t i = 0; i < page_size; i++) {
|
|
||||||
data[i] = avr_isp_spi_transaction(instance, AVR_ISP_READ_EEPROM(addr));
|
|
||||||
addr++;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_read_page(
|
|
||||||
AvrIsp* instance,
|
|
||||||
uint32_t mem_type,
|
|
||||||
uint16_t addr,
|
|
||||||
uint16_t page_size,
|
|
||||||
uint8_t* data,
|
|
||||||
uint32_t data_size) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
bool res = false;
|
|
||||||
if(mem_type == STK_SET_FLASH_TYPE)
|
|
||||||
res = avr_isp_flash_read_page(instance, addr, page_size, data, data_size);
|
|
||||||
if(mem_type == STK_SET_EEPROM_TYPE)
|
|
||||||
res = avr_isp_eeprom_read_page(instance, addr, page_size, data, data_size);
|
|
||||||
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
AvrIspSignature avr_isp_read_signature(AvrIsp* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
AvrIspSignature signature;
|
|
||||||
signature.vendor = avr_isp_spi_transaction(instance, AVR_ISP_READ_VENDOR);
|
|
||||||
signature.part_family = avr_isp_spi_transaction(instance, AVR_ISP_READ_PART_FAMILY);
|
|
||||||
signature.part_number = avr_isp_spi_transaction(instance, AVR_ISP_READ_PART_NUMBER);
|
|
||||||
return signature;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t avr_isp_read_lock_byte(AvrIsp* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
uint8_t data = 0;
|
|
||||||
uint32_t starttime = furi_get_tick();
|
|
||||||
while((furi_get_tick() - starttime) < 300) {
|
|
||||||
data = avr_isp_spi_transaction(instance, AVR_ISP_READ_LOCK_BYTE);
|
|
||||||
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_LOCK_BYTE) == data) {
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
data = 0x00;
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_write_lock_byte(AvrIsp* instance, uint8_t lock) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
bool ret = false;
|
|
||||||
if(avr_isp_read_lock_byte(instance) == lock) {
|
|
||||||
ret = true;
|
|
||||||
} else {
|
|
||||||
avr_isp_spi_transaction(instance, AVR_ISP_WRITE_LOCK_BYTE(lock));
|
|
||||||
/* polling lock byte */
|
|
||||||
uint32_t starttime = furi_get_tick();
|
|
||||||
while((furi_get_tick() - starttime) < 30) {
|
|
||||||
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_LOCK_BYTE) == lock) {
|
|
||||||
ret = true;
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t avr_isp_read_fuse_low(AvrIsp* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
uint8_t data = 0;
|
|
||||||
uint32_t starttime = furi_get_tick();
|
|
||||||
while((furi_get_tick() - starttime) < 300) {
|
|
||||||
data = avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_LOW);
|
|
||||||
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_LOW) == data) {
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
data = 0x00;
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_write_fuse_low(AvrIsp* instance, uint8_t lfuse) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
bool ret = false;
|
|
||||||
if(avr_isp_read_fuse_low(instance) == lfuse) {
|
|
||||||
ret = true;
|
|
||||||
} else {
|
|
||||||
avr_isp_spi_transaction(instance, AVR_ISP_WRITE_FUSE_LOW(lfuse));
|
|
||||||
/* polling fuse */
|
|
||||||
uint32_t starttime = furi_get_tick();
|
|
||||||
while((furi_get_tick() - starttime) < 30) {
|
|
||||||
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_LOW) == lfuse) {
|
|
||||||
ret = true;
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t avr_isp_read_fuse_high(AvrIsp* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
uint8_t data = 0;
|
|
||||||
uint32_t starttime = furi_get_tick();
|
|
||||||
while((furi_get_tick() - starttime) < 300) {
|
|
||||||
data = avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_HIGH);
|
|
||||||
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_HIGH) == data) {
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
data = 0x00;
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_write_fuse_high(AvrIsp* instance, uint8_t hfuse) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
bool ret = false;
|
|
||||||
if(avr_isp_read_fuse_high(instance) == hfuse) {
|
|
||||||
ret = true;
|
|
||||||
} else {
|
|
||||||
avr_isp_spi_transaction(instance, AVR_ISP_WRITE_FUSE_HIGH(hfuse));
|
|
||||||
/* polling fuse */
|
|
||||||
uint32_t starttime = furi_get_tick();
|
|
||||||
while((furi_get_tick() - starttime) < 30) {
|
|
||||||
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_HIGH) == hfuse) {
|
|
||||||
ret = true;
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t avr_isp_read_fuse_extended(AvrIsp* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
uint8_t data = 0;
|
|
||||||
uint32_t starttime = furi_get_tick();
|
|
||||||
while((furi_get_tick() - starttime) < 300) {
|
|
||||||
data = avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_EXTENDED);
|
|
||||||
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_EXTENDED) == data) {
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
data = 0x00;
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_write_fuse_extended(AvrIsp* instance, uint8_t efuse) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
bool ret = false;
|
|
||||||
if(avr_isp_read_fuse_extended(instance) == efuse) {
|
|
||||||
ret = true;
|
|
||||||
} else {
|
|
||||||
avr_isp_spi_transaction(instance, AVR_ISP_WRITE_FUSE_EXTENDED(efuse));
|
|
||||||
/* polling fuse */
|
|
||||||
uint32_t starttime = furi_get_tick();
|
|
||||||
while((furi_get_tick() - starttime) < 30) {
|
|
||||||
if(avr_isp_spi_transaction(instance, AVR_ISP_READ_FUSE_EXTENDED) == efuse) {
|
|
||||||
ret = true;
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_write_extended_addr(AvrIsp* instance, uint8_t extended_addr) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
avr_isp_spi_transaction(instance, AVR_ISP_EXTENDED_ADDR(extended_addr));
|
|
||||||
furi_delay_ms(10);
|
|
||||||
}
|
|
|
@ -1,70 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <furi_hal.h>
|
|
||||||
|
|
||||||
typedef struct AvrIsp AvrIsp;
|
|
||||||
typedef void (*AvrIspCallback)(void* context);
|
|
||||||
|
|
||||||
struct AvrIspSignature {
|
|
||||||
uint8_t vendor;
|
|
||||||
uint8_t part_family;
|
|
||||||
uint8_t part_number;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct AvrIspSignature AvrIspSignature;
|
|
||||||
|
|
||||||
AvrIsp* avr_isp_alloc(void);
|
|
||||||
|
|
||||||
void avr_isp_free(AvrIsp* instance);
|
|
||||||
|
|
||||||
void avr_isp_set_tx_callback(AvrIsp* instance, AvrIspCallback callback, void* context);
|
|
||||||
|
|
||||||
bool avr_isp_auto_set_spi_speed_start_pmode(AvrIsp* instance);
|
|
||||||
|
|
||||||
AvrIspSignature avr_isp_read_signature(AvrIsp* instance);
|
|
||||||
|
|
||||||
void avr_isp_end_pmode(AvrIsp* instance);
|
|
||||||
|
|
||||||
bool avr_isp_erase_chip(AvrIsp* instance);
|
|
||||||
|
|
||||||
uint8_t avr_isp_spi_transaction(
|
|
||||||
AvrIsp* instance,
|
|
||||||
uint8_t cmd,
|
|
||||||
uint8_t addr_hi,
|
|
||||||
uint8_t addr_lo,
|
|
||||||
uint8_t data);
|
|
||||||
|
|
||||||
bool avr_isp_read_page(
|
|
||||||
AvrIsp* instance,
|
|
||||||
uint32_t memtype,
|
|
||||||
uint16_t addr,
|
|
||||||
uint16_t page_size,
|
|
||||||
uint8_t* data,
|
|
||||||
uint32_t data_size);
|
|
||||||
|
|
||||||
bool avr_isp_write_page(
|
|
||||||
AvrIsp* instance,
|
|
||||||
uint32_t mem_type,
|
|
||||||
uint32_t mem_size,
|
|
||||||
uint16_t addr,
|
|
||||||
uint16_t page_size,
|
|
||||||
uint8_t* data,
|
|
||||||
uint32_t data_size);
|
|
||||||
|
|
||||||
uint8_t avr_isp_read_lock_byte(AvrIsp* instance);
|
|
||||||
|
|
||||||
bool avr_isp_write_lock_byte(AvrIsp* instance, uint8_t lock);
|
|
||||||
|
|
||||||
uint8_t avr_isp_read_fuse_low(AvrIsp* instance);
|
|
||||||
|
|
||||||
bool avr_isp_write_fuse_low(AvrIsp* instance, uint8_t lfuse);
|
|
||||||
|
|
||||||
uint8_t avr_isp_read_fuse_high(AvrIsp* instance);
|
|
||||||
|
|
||||||
bool avr_isp_write_fuse_high(AvrIsp* instance, uint8_t hfuse);
|
|
||||||
|
|
||||||
uint8_t avr_isp_read_fuse_extended(AvrIsp* instance);
|
|
||||||
|
|
||||||
bool avr_isp_write_fuse_extended(AvrIsp* instance, uint8_t efuse);
|
|
||||||
|
|
||||||
void avr_isp_write_extended_addr(AvrIsp* instance, uint8_t extended_addr);
|
|
|
@ -1,23 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
//SubmenuIndex
|
|
||||||
SubmenuIndexAvrIspProgrammer = 10,
|
|
||||||
SubmenuIndexAvrIspReader,
|
|
||||||
SubmenuIndexAvrIspWriter,
|
|
||||||
SubmenuIndexAvrIsWiring,
|
|
||||||
SubmenuIndexAvrIspAbout,
|
|
||||||
|
|
||||||
//AvrIspCustomEvent
|
|
||||||
AvrIspCustomEventSceneChipDetectOk = 100,
|
|
||||||
AvrIspCustomEventSceneReadingOk,
|
|
||||||
AvrIspCustomEventSceneWritingOk,
|
|
||||||
AvrIspCustomEventSceneErrorVerification,
|
|
||||||
AvrIspCustomEventSceneErrorReading,
|
|
||||||
AvrIspCustomEventSceneErrorWriting,
|
|
||||||
AvrIspCustomEventSceneErrorWritingFuse,
|
|
||||||
AvrIspCustomEventSceneInputName,
|
|
||||||
AvrIspCustomEventSceneSuccess,
|
|
||||||
AvrIspCustomEventSceneExit,
|
|
||||||
AvrIspCustomEventSceneExitStartMenu,
|
|
||||||
} AvrIspCustomEvent;
|
|
|
@ -1,32 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <furi.h>
|
|
||||||
#include <furi_hal.h>
|
|
||||||
|
|
||||||
#define AVR_ISP_VERSION_APP "0.1"
|
|
||||||
#define AVR_ISP_DEVELOPED "SkorP"
|
|
||||||
#define AVR_ISP_GITHUB "https://github.com/flipperdevices/flipperzero-firmware"
|
|
||||||
|
|
||||||
#define AVR_ISP_APP_FILE_VERSION 1
|
|
||||||
#define AVR_ISP_APP_FILE_TYPE "Flipper Dump AVR"
|
|
||||||
#define AVR_ISP_APP_EXTENSION ".avr"
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
//AvrIspViewVariableItemList,
|
|
||||||
AvrIspViewSubmenu,
|
|
||||||
AvrIspViewProgrammer,
|
|
||||||
AvrIspViewReader,
|
|
||||||
AvrIspViewWriter,
|
|
||||||
AvrIspViewWidget,
|
|
||||||
AvrIspViewPopup,
|
|
||||||
AvrIspViewTextInput,
|
|
||||||
AvrIspViewChipDetect,
|
|
||||||
} AvrIspView;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
AvrIspErrorNoError,
|
|
||||||
AvrIspErrorReading,
|
|
||||||
AvrIspErrorWriting,
|
|
||||||
AvrIspErrorVerification,
|
|
||||||
AvrIspErrorWritingFuse,
|
|
||||||
} AvrIspError;
|
|
|
@ -1,266 +0,0 @@
|
||||||
#include "avr_isp_worker.h"
|
|
||||||
#include <furi_hal_pwm.h>
|
|
||||||
#include "../lib/driver/avr_isp_prog.h"
|
|
||||||
#include "../lib/driver/avr_isp_prog_cmd.h"
|
|
||||||
#include "../lib/driver/avr_isp_chip_arr.h"
|
|
||||||
|
|
||||||
#include <furi.h>
|
|
||||||
|
|
||||||
#define TAG "AvrIspWorker"
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
AvrIspWorkerEvtStop = (1 << 0),
|
|
||||||
|
|
||||||
AvrIspWorkerEvtRx = (1 << 1),
|
|
||||||
AvrIspWorkerEvtTxCoplete = (1 << 2),
|
|
||||||
AvrIspWorkerEvtTx = (1 << 3),
|
|
||||||
AvrIspWorkerEvtState = (1 << 4),
|
|
||||||
|
|
||||||
//AvrIspWorkerEvtCfg = (1 << 5),
|
|
||||||
|
|
||||||
} AvrIspWorkerEvt;
|
|
||||||
|
|
||||||
struct AvrIspWorker {
|
|
||||||
FuriThread* thread;
|
|
||||||
volatile bool worker_running;
|
|
||||||
uint8_t connect_usb;
|
|
||||||
AvrIspWorkerCallback callback;
|
|
||||||
void* context;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define AVR_ISP_WORKER_PROG_ALL_EVENTS (AvrIspWorkerEvtStop)
|
|
||||||
#define AVR_ISP_WORKER_ALL_EVENTS \
|
|
||||||
(AvrIspWorkerEvtTx | AvrIspWorkerEvtTxCoplete | AvrIspWorkerEvtRx | AvrIspWorkerEvtStop | \
|
|
||||||
AvrIspWorkerEvtState)
|
|
||||||
|
|
||||||
//########################/* VCP CDC */#############################################
|
|
||||||
#include "usb_cdc.h"
|
|
||||||
#include <cli/cli_vcp.h>
|
|
||||||
#include <cli/cli.h>
|
|
||||||
#include <furi_hal_usb_cdc.h>
|
|
||||||
|
|
||||||
#define AVR_ISP_VCP_CDC_CH 1
|
|
||||||
#define AVR_ISP_VCP_CDC_PKT_LEN CDC_DATA_SZ
|
|
||||||
#define AVR_ISP_VCP_UART_RX_BUF_SIZE (AVR_ISP_VCP_CDC_PKT_LEN * 5)
|
|
||||||
|
|
||||||
static void vcp_on_cdc_tx_complete(void* context);
|
|
||||||
static void vcp_on_cdc_rx(void* context);
|
|
||||||
static void vcp_state_callback(void* context, uint8_t state);
|
|
||||||
static void vcp_on_cdc_control_line(void* context, uint8_t state);
|
|
||||||
static void vcp_on_line_config(void* context, struct usb_cdc_line_coding* config);
|
|
||||||
|
|
||||||
static const CdcCallbacks cdc_cb = {
|
|
||||||
vcp_on_cdc_tx_complete,
|
|
||||||
vcp_on_cdc_rx,
|
|
||||||
vcp_state_callback,
|
|
||||||
vcp_on_cdc_control_line,
|
|
||||||
vcp_on_line_config,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* VCP callbacks */
|
|
||||||
|
|
||||||
static void vcp_on_cdc_tx_complete(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
AvrIspWorker* instance = context;
|
|
||||||
furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtTxCoplete);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vcp_on_cdc_rx(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
AvrIspWorker* instance = context;
|
|
||||||
furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtRx);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vcp_state_callback(void* context, uint8_t state) {
|
|
||||||
UNUSED(context);
|
|
||||||
|
|
||||||
AvrIspWorker* instance = context;
|
|
||||||
instance->connect_usb = state;
|
|
||||||
furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtState);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vcp_on_cdc_control_line(void* context, uint8_t state) {
|
|
||||||
UNUSED(context);
|
|
||||||
UNUSED(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void vcp_on_line_config(void* context, struct usb_cdc_line_coding* config) {
|
|
||||||
UNUSED(context);
|
|
||||||
UNUSED(config);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_worker_vcp_cdc_init(void* context) {
|
|
||||||
furi_hal_usb_unlock();
|
|
||||||
Cli* cli = furi_record_open(RECORD_CLI);
|
|
||||||
//close cli
|
|
||||||
cli_session_close(cli);
|
|
||||||
//disable callbacks VCP_CDC=0
|
|
||||||
furi_hal_cdc_set_callbacks(0, NULL, NULL);
|
|
||||||
//set 2 cdc
|
|
||||||
furi_check(furi_hal_usb_set_config(&usb_cdc_dual, NULL) == true);
|
|
||||||
//open cli VCP_CDC=0
|
|
||||||
cli_session_open(cli, &cli_vcp);
|
|
||||||
furi_record_close(RECORD_CLI);
|
|
||||||
|
|
||||||
furi_hal_cdc_set_callbacks(AVR_ISP_VCP_CDC_CH, (CdcCallbacks*)&cdc_cb, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_worker_vcp_cdc_deinit(void) {
|
|
||||||
//disable callbacks AVR_ISP_VCP_CDC_CH
|
|
||||||
furi_hal_cdc_set_callbacks(AVR_ISP_VCP_CDC_CH, NULL, NULL);
|
|
||||||
|
|
||||||
Cli* cli = furi_record_open(RECORD_CLI);
|
|
||||||
//close cli
|
|
||||||
cli_session_close(cli);
|
|
||||||
furi_hal_usb_unlock();
|
|
||||||
//set 1 cdc
|
|
||||||
furi_check(furi_hal_usb_set_config(&usb_cdc_single, NULL) == true);
|
|
||||||
//open cli VCP_CDC=0
|
|
||||||
cli_session_open(cli, &cli_vcp);
|
|
||||||
furi_record_close(RECORD_CLI);
|
|
||||||
}
|
|
||||||
|
|
||||||
//#################################################################################
|
|
||||||
|
|
||||||
static int32_t avr_isp_worker_prog_thread(void* context) {
|
|
||||||
AvrIspProg* prog = context;
|
|
||||||
FURI_LOG_D(TAG, "AvrIspProgWorker Start");
|
|
||||||
while(1) {
|
|
||||||
if(furi_thread_flags_get() & AvrIspWorkerEvtStop) break;
|
|
||||||
avr_isp_prog_avrisp(prog);
|
|
||||||
}
|
|
||||||
FURI_LOG_D(TAG, "AvrIspProgWorker Stop");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_worker_prog_tx_data(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
AvrIspWorker* instance = context;
|
|
||||||
furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtTx);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Worker thread
|
|
||||||
*
|
|
||||||
* @param context
|
|
||||||
* @return exit code
|
|
||||||
*/
|
|
||||||
static int32_t avr_isp_worker_thread(void* context) {
|
|
||||||
AvrIspWorker* instance = context;
|
|
||||||
avr_isp_worker_vcp_cdc_init(instance);
|
|
||||||
|
|
||||||
/* start PWM on &gpio_ext_pa4 */
|
|
||||||
furi_hal_pwm_start(FuriHalPwmOutputIdLptim2PA4, 4000000, 50);
|
|
||||||
|
|
||||||
AvrIspProg* prog = avr_isp_prog_init();
|
|
||||||
avr_isp_prog_set_tx_callback(prog, avr_isp_worker_prog_tx_data, instance);
|
|
||||||
|
|
||||||
uint8_t buf[AVR_ISP_VCP_UART_RX_BUF_SIZE];
|
|
||||||
size_t len = 0;
|
|
||||||
|
|
||||||
FuriThread* prog_thread =
|
|
||||||
furi_thread_alloc_ex("AvrIspProgWorker", 1024, avr_isp_worker_prog_thread, prog);
|
|
||||||
furi_thread_start(prog_thread);
|
|
||||||
|
|
||||||
FURI_LOG_D(TAG, "Start");
|
|
||||||
|
|
||||||
while(instance->worker_running) {
|
|
||||||
uint32_t events =
|
|
||||||
furi_thread_flags_wait(AVR_ISP_WORKER_ALL_EVENTS, FuriFlagWaitAny, FuriWaitForever);
|
|
||||||
|
|
||||||
if(events & AvrIspWorkerEvtRx) {
|
|
||||||
if(avr_isp_prog_spaces_rx(prog) >= AVR_ISP_VCP_CDC_PKT_LEN) {
|
|
||||||
len = furi_hal_cdc_receive(AVR_ISP_VCP_CDC_CH, buf, AVR_ISP_VCP_CDC_PKT_LEN);
|
|
||||||
// for(uint8_t i = 0; i < len; i++) {
|
|
||||||
// FURI_LOG_I(TAG, "--> %X", buf[i]);
|
|
||||||
// }
|
|
||||||
avr_isp_prog_rx(prog, buf, len);
|
|
||||||
} else {
|
|
||||||
furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtRx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if((events & AvrIspWorkerEvtTxCoplete) || (events & AvrIspWorkerEvtTx)) {
|
|
||||||
len = avr_isp_prog_tx(prog, buf, AVR_ISP_VCP_CDC_PKT_LEN);
|
|
||||||
|
|
||||||
// for(uint8_t i = 0; i < len; i++) {
|
|
||||||
// FURI_LOG_I(TAG, "<-- %X", buf[i]);
|
|
||||||
// }
|
|
||||||
|
|
||||||
if(len > 0) furi_hal_cdc_send(AVR_ISP_VCP_CDC_CH, buf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(events & AvrIspWorkerEvtStop) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(events & AvrIspWorkerEvtState) {
|
|
||||||
if(instance->callback)
|
|
||||||
instance->callback(instance->context, (bool)instance->connect_usb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FURI_LOG_D(TAG, "Stop");
|
|
||||||
|
|
||||||
furi_thread_flags_set(furi_thread_get_id(prog_thread), AvrIspWorkerEvtStop);
|
|
||||||
avr_isp_prog_exit(prog);
|
|
||||||
furi_delay_ms(10);
|
|
||||||
furi_thread_join(prog_thread);
|
|
||||||
furi_thread_free(prog_thread);
|
|
||||||
|
|
||||||
avr_isp_prog_free(prog);
|
|
||||||
furi_hal_pwm_stop(FuriHalPwmOutputIdLptim2PA4);
|
|
||||||
avr_isp_worker_vcp_cdc_deinit();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
AvrIspWorker* avr_isp_worker_alloc(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
UNUSED(context);
|
|
||||||
AvrIspWorker* instance = malloc(sizeof(AvrIspWorker));
|
|
||||||
|
|
||||||
instance->thread = furi_thread_alloc_ex("AvrIspWorker", 2048, avr_isp_worker_thread, instance);
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_worker_free(AvrIspWorker* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
furi_check(!instance->worker_running);
|
|
||||||
furi_thread_free(instance->thread);
|
|
||||||
free(instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_worker_set_callback(
|
|
||||||
AvrIspWorker* instance,
|
|
||||||
AvrIspWorkerCallback callback,
|
|
||||||
void* context) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
instance->callback = callback;
|
|
||||||
instance->context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_worker_start(AvrIspWorker* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_assert(!instance->worker_running);
|
|
||||||
|
|
||||||
instance->worker_running = true;
|
|
||||||
|
|
||||||
furi_thread_start(instance->thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_worker_stop(AvrIspWorker* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_assert(instance->worker_running);
|
|
||||||
|
|
||||||
instance->worker_running = false;
|
|
||||||
furi_thread_flags_set(furi_thread_get_id(instance->thread), AvrIspWorkerEvtStop);
|
|
||||||
|
|
||||||
furi_thread_join(instance->thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_worker_is_running(AvrIspWorker* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
return instance->worker_running;
|
|
||||||
}
|
|
|
@ -1,49 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <furi_hal.h>
|
|
||||||
|
|
||||||
typedef struct AvrIspWorker AvrIspWorker;
|
|
||||||
|
|
||||||
typedef void (*AvrIspWorkerCallback)(void* context, bool connect_usb);
|
|
||||||
|
|
||||||
/** Allocate AvrIspWorker
|
|
||||||
*
|
|
||||||
* @param context AvrIsp* context
|
|
||||||
* @return AvrIspWorker*
|
|
||||||
*/
|
|
||||||
AvrIspWorker* avr_isp_worker_alloc(void* context);
|
|
||||||
|
|
||||||
/** Free AvrIspWorker
|
|
||||||
*
|
|
||||||
* @param instance AvrIspWorker instance
|
|
||||||
*/
|
|
||||||
void avr_isp_worker_free(AvrIspWorker* instance);
|
|
||||||
|
|
||||||
/** Callback AvrIspWorker
|
|
||||||
*
|
|
||||||
* @param instance AvrIspWorker instance
|
|
||||||
* @param callback AvrIspWorkerOverrunCallback callback
|
|
||||||
* @param context
|
|
||||||
*/
|
|
||||||
void avr_isp_worker_set_callback(
|
|
||||||
AvrIspWorker* instance,
|
|
||||||
AvrIspWorkerCallback callback,
|
|
||||||
void* context);
|
|
||||||
|
|
||||||
/** Start AvrIspWorker
|
|
||||||
*
|
|
||||||
* @param instance AvrIspWorker instance
|
|
||||||
*/
|
|
||||||
void avr_isp_worker_start(AvrIspWorker* instance);
|
|
||||||
|
|
||||||
/** Stop AvrIspWorker
|
|
||||||
*
|
|
||||||
* @param instance AvrIspWorker instance
|
|
||||||
*/
|
|
||||||
void avr_isp_worker_stop(AvrIspWorker* instance);
|
|
||||||
|
|
||||||
/** Check if worker is running
|
|
||||||
* @param instance AvrIspWorker instance
|
|
||||||
* @return bool - true if running
|
|
||||||
*/
|
|
||||||
bool avr_isp_worker_is_running(AvrIspWorker* instance);
|
|
|
@ -1,99 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <furi_hal.h>
|
|
||||||
|
|
||||||
typedef struct AvrIspWorkerRW AvrIspWorkerRW;
|
|
||||||
|
|
||||||
typedef void (*AvrIspWorkerRWCallback)(
|
|
||||||
void* context,
|
|
||||||
const char* name,
|
|
||||||
bool detect_chip,
|
|
||||||
uint32_t flash_size);
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
AvrIspWorkerRWStatusILDE = 0,
|
|
||||||
AvrIspWorkerRWStatusEndReading = 1,
|
|
||||||
AvrIspWorkerRWStatusEndVerification = 2,
|
|
||||||
AvrIspWorkerRWStatusEndWriting = 3,
|
|
||||||
AvrIspWorkerRWStatusEndWritingFuse = 4,
|
|
||||||
|
|
||||||
AvrIspWorkerRWStatusErrorReading = (-1),
|
|
||||||
AvrIspWorkerRWStatusErrorVerification = (-2),
|
|
||||||
AvrIspWorkerRWStatusErrorWriting = (-3),
|
|
||||||
AvrIspWorkerRWStatusErrorWritingFuse = (-4),
|
|
||||||
|
|
||||||
AvrIspWorkerRWStatusReserved = 0x7FFFFFFF, ///< Prevents enum down-size compiler optimization.
|
|
||||||
} AvrIspWorkerRWStatus;
|
|
||||||
|
|
||||||
typedef void (*AvrIspWorkerRWStatusCallback)(void* context, AvrIspWorkerRWStatus status);
|
|
||||||
|
|
||||||
AvrIspWorkerRW* avr_isp_worker_rw_alloc(void* context);
|
|
||||||
|
|
||||||
void avr_isp_worker_rw_free(AvrIspWorkerRW* instance);
|
|
||||||
|
|
||||||
void avr_isp_worker_rw_start(AvrIspWorkerRW* instance);
|
|
||||||
|
|
||||||
void avr_isp_worker_rw_stop(AvrIspWorkerRW* instance);
|
|
||||||
|
|
||||||
bool avr_isp_worker_rw_is_running(AvrIspWorkerRW* instance);
|
|
||||||
|
|
||||||
void avr_isp_worker_rw_set_callback(
|
|
||||||
AvrIspWorkerRW* instance,
|
|
||||||
AvrIspWorkerRWCallback callback,
|
|
||||||
void* context);
|
|
||||||
|
|
||||||
void avr_isp_worker_rw_set_callback_status(
|
|
||||||
AvrIspWorkerRW* instance,
|
|
||||||
AvrIspWorkerRWStatusCallback callback_status,
|
|
||||||
void* context_status);
|
|
||||||
|
|
||||||
bool avr_isp_worker_rw_detect_chip(AvrIspWorkerRW* instance);
|
|
||||||
|
|
||||||
float avr_isp_worker_rw_get_progress_flash(AvrIspWorkerRW* instance);
|
|
||||||
|
|
||||||
float avr_isp_worker_rw_get_progress_eeprom(AvrIspWorkerRW* instance);
|
|
||||||
|
|
||||||
bool avr_isp_worker_rw_read_dump(
|
|
||||||
AvrIspWorkerRW* instance,
|
|
||||||
const char* file_path,
|
|
||||||
const char* file_name);
|
|
||||||
|
|
||||||
void avr_isp_worker_rw_read_dump_start(
|
|
||||||
AvrIspWorkerRW* instance,
|
|
||||||
const char* file_path,
|
|
||||||
const char* file_name);
|
|
||||||
|
|
||||||
bool avr_isp_worker_rw_verification(
|
|
||||||
AvrIspWorkerRW* instance,
|
|
||||||
const char* file_path,
|
|
||||||
const char* file_name);
|
|
||||||
|
|
||||||
void avr_isp_worker_rw_verification_start(
|
|
||||||
AvrIspWorkerRW* instance,
|
|
||||||
const char* file_path,
|
|
||||||
const char* file_name);
|
|
||||||
|
|
||||||
bool avr_isp_worker_rw_check_hex(
|
|
||||||
AvrIspWorkerRW* instance,
|
|
||||||
const char* file_path,
|
|
||||||
const char* file_name);
|
|
||||||
|
|
||||||
bool avr_isp_worker_rw_write_dump(
|
|
||||||
AvrIspWorkerRW* instance,
|
|
||||||
const char* file_path,
|
|
||||||
const char* file_name);
|
|
||||||
|
|
||||||
void avr_isp_worker_rw_write_dump_start(
|
|
||||||
AvrIspWorkerRW* instance,
|
|
||||||
const char* file_path,
|
|
||||||
const char* file_name);
|
|
||||||
|
|
||||||
bool avr_isp_worker_rw_write_fuse(
|
|
||||||
AvrIspWorkerRW* instance,
|
|
||||||
const char* file_path,
|
|
||||||
const char* file_name);
|
|
||||||
|
|
||||||
void avr_isp_worker_rw_write_fuse_start(
|
|
||||||
AvrIspWorkerRW* instance,
|
|
||||||
const char* file_path,
|
|
||||||
const char* file_name);
|
|
|
@ -1,321 +0,0 @@
|
||||||
#include "flipper_i32hex_file.h"
|
|
||||||
#include <string.h>
|
|
||||||
#include <storage/storage.h>
|
|
||||||
#include <toolbox/stream/stream.h>
|
|
||||||
#include <toolbox/stream/file_stream.h>
|
|
||||||
#include <toolbox/hex.h>
|
|
||||||
|
|
||||||
//https://en.wikipedia.org/wiki/Intel_HEX
|
|
||||||
|
|
||||||
#define TAG "FlipperI32HexFile"
|
|
||||||
|
|
||||||
#define COUNT_BYTE_PAYLOAD 32 //how much payload will be used
|
|
||||||
|
|
||||||
#define I32HEX_TYPE_DATA 0x00
|
|
||||||
#define I32HEX_TYPE_END_OF_FILE 0x01
|
|
||||||
#define I32HEX_TYPE_EXT_LINEAR_ADDR 0x04
|
|
||||||
#define I32HEX_TYPE_START_LINEAR_ADDR 0x05
|
|
||||||
|
|
||||||
struct FlipperI32HexFile {
|
|
||||||
uint32_t addr;
|
|
||||||
uint32_t addr_last;
|
|
||||||
Storage* storage;
|
|
||||||
Stream* stream;
|
|
||||||
FuriString* str_data;
|
|
||||||
FlipperI32HexFileStatus file_open;
|
|
||||||
};
|
|
||||||
|
|
||||||
FlipperI32HexFile* flipper_i32hex_file_open_write(const char* name, uint32_t start_addr) {
|
|
||||||
furi_assert(name);
|
|
||||||
|
|
||||||
FlipperI32HexFile* instance = malloc(sizeof(FlipperI32HexFile));
|
|
||||||
instance->addr = start_addr;
|
|
||||||
instance->addr_last = 0;
|
|
||||||
instance->storage = furi_record_open(RECORD_STORAGE);
|
|
||||||
instance->stream = file_stream_alloc(instance->storage);
|
|
||||||
|
|
||||||
if(file_stream_open(instance->stream, name, FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
|
|
||||||
instance->file_open = FlipperI32HexFileStatusOpenFileWrite;
|
|
||||||
FURI_LOG_D(TAG, "Open write file %s", name);
|
|
||||||
} else {
|
|
||||||
FURI_LOG_E(TAG, "Failed to open file %s", name);
|
|
||||||
instance->file_open = FlipperI32HexFileStatusErrorNoOpenFile;
|
|
||||||
}
|
|
||||||
instance->str_data = furi_string_alloc(instance->storage);
|
|
||||||
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
FlipperI32HexFile* flipper_i32hex_file_open_read(const char* name) {
|
|
||||||
furi_assert(name);
|
|
||||||
|
|
||||||
FlipperI32HexFile* instance = malloc(sizeof(FlipperI32HexFile));
|
|
||||||
instance->addr = 0;
|
|
||||||
instance->addr_last = 0;
|
|
||||||
instance->storage = furi_record_open(RECORD_STORAGE);
|
|
||||||
instance->stream = file_stream_alloc(instance->storage);
|
|
||||||
|
|
||||||
if(file_stream_open(instance->stream, name, FSAM_READ, FSOM_OPEN_EXISTING)) {
|
|
||||||
instance->file_open = FlipperI32HexFileStatusOpenFileRead;
|
|
||||||
FURI_LOG_D(TAG, "Open read file %s", name);
|
|
||||||
} else {
|
|
||||||
FURI_LOG_E(TAG, "Failed to open file %s", name);
|
|
||||||
instance->file_open = FlipperI32HexFileStatusErrorNoOpenFile;
|
|
||||||
}
|
|
||||||
instance->str_data = furi_string_alloc(instance->storage);
|
|
||||||
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void flipper_i32hex_file_close(FlipperI32HexFile* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
furi_string_free(instance->str_data);
|
|
||||||
file_stream_close(instance->stream);
|
|
||||||
stream_free(instance->stream);
|
|
||||||
furi_record_close(RECORD_STORAGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
FlipperI32HexFileRet flipper_i32hex_file_bin_to_i32hex_set_data(
|
|
||||||
FlipperI32HexFile* instance,
|
|
||||||
uint8_t* data,
|
|
||||||
uint32_t data_size) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_assert(data);
|
|
||||||
|
|
||||||
FlipperI32HexFileRet ret = {.status = FlipperI32HexFileStatusOK, .data_size = 0};
|
|
||||||
if(instance->file_open != FlipperI32HexFileStatusOpenFileWrite) {
|
|
||||||
ret.status = FlipperI32HexFileStatusErrorFileWrite;
|
|
||||||
}
|
|
||||||
uint8_t count_byte = 0;
|
|
||||||
uint32_t ind = 0;
|
|
||||||
uint8_t crc = 0;
|
|
||||||
|
|
||||||
furi_string_reset(instance->str_data);
|
|
||||||
|
|
||||||
if((instance->addr_last & 0xFF0000) < (instance->addr & 0xFF0000)) {
|
|
||||||
crc = 0x02 + 0x04 + ((instance->addr >> 24) & 0xFF) + ((instance->addr >> 16) & 0xFF);
|
|
||||||
crc = 0x01 + ~crc;
|
|
||||||
//I32HEX_TYPE_EXT_LINEAR_ADDR
|
|
||||||
furi_string_cat_printf(
|
|
||||||
instance->str_data, ":02000004%04lX%02X\r\n", (instance->addr >> 16), crc);
|
|
||||||
instance->addr_last = instance->addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
while(ind < data_size) {
|
|
||||||
if((ind + COUNT_BYTE_PAYLOAD) > data_size) {
|
|
||||||
count_byte = data_size - ind;
|
|
||||||
} else {
|
|
||||||
count_byte = COUNT_BYTE_PAYLOAD;
|
|
||||||
}
|
|
||||||
//I32HEX_TYPE_DATA
|
|
||||||
furi_string_cat_printf(
|
|
||||||
instance->str_data, ":%02X%04lX00", count_byte, (instance->addr & 0xFFFF));
|
|
||||||
crc = count_byte + ((instance->addr >> 8) & 0xFF) + (instance->addr & 0xFF);
|
|
||||||
|
|
||||||
for(uint32_t i = 0; i < count_byte; i++) {
|
|
||||||
furi_string_cat_printf(instance->str_data, "%02X", *data);
|
|
||||||
crc += *data++;
|
|
||||||
}
|
|
||||||
crc = 0x01 + ~crc;
|
|
||||||
furi_string_cat_printf(instance->str_data, "%02X\r\n", crc);
|
|
||||||
|
|
||||||
ind += count_byte;
|
|
||||||
instance->addr += count_byte;
|
|
||||||
}
|
|
||||||
if(instance->file_open) stream_write_string(instance->stream, instance->str_data);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
FlipperI32HexFileRet flipper_i32hex_file_bin_to_i32hex_set_end_line(FlipperI32HexFile* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
FlipperI32HexFileRet ret = {.status = FlipperI32HexFileStatusOK, .data_size = 0};
|
|
||||||
if(instance->file_open != FlipperI32HexFileStatusOpenFileWrite) {
|
|
||||||
ret.status = FlipperI32HexFileStatusErrorFileWrite;
|
|
||||||
}
|
|
||||||
furi_string_reset(instance->str_data);
|
|
||||||
//I32HEX_TYPE_END_OF_FILE
|
|
||||||
furi_string_cat_printf(instance->str_data, ":00000001FF\r\n");
|
|
||||||
if(instance->file_open) stream_write_string(instance->stream, instance->str_data);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void flipper_i32hex_file_bin_to_i32hex_set_addr(FlipperI32HexFile* instance, uint32_t addr) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
instance->addr = addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* flipper_i32hex_file_get_string(FlipperI32HexFile* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
return furi_string_get_cstr(instance->str_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static FlipperI32HexFileRet flipper_i32hex_file_parse_line(
|
|
||||||
FlipperI32HexFile* instance,
|
|
||||||
const char* str,
|
|
||||||
uint8_t* data,
|
|
||||||
uint32_t data_size) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_assert(data);
|
|
||||||
|
|
||||||
char* str1;
|
|
||||||
uint32_t data_wrire_ind = 0;
|
|
||||||
uint32_t data_len = 0;
|
|
||||||
FlipperI32HexFileRet ret = {.status = FlipperI32HexFileStatusErrorData, .data_size = 0};
|
|
||||||
|
|
||||||
//Search for start of data I32HEX
|
|
||||||
str1 = strstr(str, ":");
|
|
||||||
do {
|
|
||||||
if(str1 == NULL) {
|
|
||||||
ret.status = FlipperI32HexFileStatusErrorData;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
str1++;
|
|
||||||
if(!hex_char_to_uint8(*str1, str1[1], data + data_wrire_ind)) {
|
|
||||||
ret.status = FlipperI32HexFileStatusErrorData;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
str1++;
|
|
||||||
if(++data_wrire_ind > data_size) {
|
|
||||||
ret.status = FlipperI32HexFileStatusErrorOverflow;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
data_len = 5 + data[0]; // +5 bytes per header and crc
|
|
||||||
while(data_len > data_wrire_ind) {
|
|
||||||
str1++;
|
|
||||||
if(!hex_char_to_uint8(*str1, str1[1], data + data_wrire_ind)) {
|
|
||||||
ret.status = FlipperI32HexFileStatusErrorData;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
str1++;
|
|
||||||
if(++data_wrire_ind > data_size) {
|
|
||||||
ret.status = FlipperI32HexFileStatusErrorOverflow;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ret.status = FlipperI32HexFileStatusOK;
|
|
||||||
ret.data_size = data_wrire_ind;
|
|
||||||
|
|
||||||
} while(0);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool flipper_i32hex_file_check_data(uint8_t* data, uint32_t data_size) {
|
|
||||||
furi_assert(data);
|
|
||||||
|
|
||||||
uint8_t crc = 0;
|
|
||||||
uint32_t data_read_ind = 0;
|
|
||||||
if(data[0] > data_size) return false;
|
|
||||||
while(data_read_ind < data_size - 1) {
|
|
||||||
crc += data[data_read_ind++];
|
|
||||||
}
|
|
||||||
return data[data_size - 1] == ((1 + ~crc) & 0xFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
static FlipperI32HexFileRet flipper_i32hex_file_parse(
|
|
||||||
FlipperI32HexFile* instance,
|
|
||||||
const char* str,
|
|
||||||
uint8_t* data,
|
|
||||||
uint32_t data_size) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_assert(data);
|
|
||||||
|
|
||||||
FlipperI32HexFileRet ret = flipper_i32hex_file_parse_line(instance, str, data, data_size);
|
|
||||||
|
|
||||||
if((ret.status == FlipperI32HexFileStatusOK) && (ret.data_size > 4)) {
|
|
||||||
switch(data[3]) {
|
|
||||||
case I32HEX_TYPE_DATA:
|
|
||||||
if(flipper_i32hex_file_check_data(data, ret.data_size)) {
|
|
||||||
ret.data_size -= 5;
|
|
||||||
memcpy(data, data + 4, ret.data_size);
|
|
||||||
ret.status = FlipperI32HexFileStatusData;
|
|
||||||
} else {
|
|
||||||
ret.status = FlipperI32HexFileStatusErrorCrc;
|
|
||||||
ret.data_size = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case I32HEX_TYPE_END_OF_FILE:
|
|
||||||
if(flipper_i32hex_file_check_data(data, ret.data_size)) {
|
|
||||||
ret.status = FlipperI32HexFileStatusEofFile;
|
|
||||||
ret.data_size = 0;
|
|
||||||
} else {
|
|
||||||
ret.status = FlipperI32HexFileStatusErrorCrc;
|
|
||||||
ret.data_size = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case I32HEX_TYPE_EXT_LINEAR_ADDR:
|
|
||||||
if(flipper_i32hex_file_check_data(data, ret.data_size)) {
|
|
||||||
data[0] = data[4];
|
|
||||||
data[1] = data[5];
|
|
||||||
data[3] = 0;
|
|
||||||
data[4] = 0;
|
|
||||||
ret.status = FlipperI32HexFileStatusUdateAddr;
|
|
||||||
ret.data_size = 4;
|
|
||||||
} else {
|
|
||||||
ret.status = FlipperI32HexFileStatusErrorCrc;
|
|
||||||
ret.data_size = 0;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case I32HEX_TYPE_START_LINEAR_ADDR:
|
|
||||||
ret.status = FlipperI32HexFileStatusErrorUnsupportedCommand;
|
|
||||||
ret.data_size = 0;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
ret.status = FlipperI32HexFileStatusErrorUnsupportedCommand;
|
|
||||||
ret.data_size = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ret.status = FlipperI32HexFileStatusErrorData;
|
|
||||||
ret.data_size = 0;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool flipper_i32hex_file_check(FlipperI32HexFile* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
uint32_t data_size = 280;
|
|
||||||
uint8_t data[280] = {0};
|
|
||||||
bool ret = true;
|
|
||||||
|
|
||||||
if(instance->file_open != FlipperI32HexFileStatusOpenFileRead) {
|
|
||||||
FURI_LOG_E(TAG, "File is not open");
|
|
||||||
ret = false;
|
|
||||||
} else {
|
|
||||||
stream_rewind(instance->stream);
|
|
||||||
|
|
||||||
while(stream_read_line(instance->stream, instance->str_data)) {
|
|
||||||
FlipperI32HexFileRet parse_ret = flipper_i32hex_file_parse(
|
|
||||||
instance, furi_string_get_cstr(instance->str_data), data, data_size);
|
|
||||||
|
|
||||||
if(parse_ret.status < 0) {
|
|
||||||
ret = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stream_rewind(instance->stream);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
FlipperI32HexFileRet flipper_i32hex_file_i32hex_to_bin_get_data(
|
|
||||||
FlipperI32HexFile* instance,
|
|
||||||
uint8_t* data,
|
|
||||||
uint32_t data_size) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_assert(data);
|
|
||||||
|
|
||||||
FlipperI32HexFileRet ret = {.status = FlipperI32HexFileStatusOK, .data_size = 0};
|
|
||||||
if(instance->file_open != FlipperI32HexFileStatusOpenFileRead) {
|
|
||||||
ret.status = FlipperI32HexFileStatusErrorFileRead;
|
|
||||||
} else {
|
|
||||||
stream_read_line(instance->stream, instance->str_data);
|
|
||||||
ret = flipper_i32hex_file_parse(
|
|
||||||
instance, furi_string_get_cstr(instance->str_data), data, data_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
|
@ -1,55 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <furi_hal.h>
|
|
||||||
|
|
||||||
typedef struct FlipperI32HexFile FlipperI32HexFile;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
FlipperI32HexFileStatusOK = 0,
|
|
||||||
FlipperI32HexFileStatusData = 2,
|
|
||||||
FlipperI32HexFileStatusUdateAddr = 3,
|
|
||||||
FlipperI32HexFileStatusEofFile = 4,
|
|
||||||
FlipperI32HexFileStatusOpenFileWrite = 5,
|
|
||||||
FlipperI32HexFileStatusOpenFileRead = 6,
|
|
||||||
|
|
||||||
// Errors
|
|
||||||
FlipperI32HexFileStatusErrorCrc = (-1),
|
|
||||||
FlipperI32HexFileStatusErrorOverflow = (-2),
|
|
||||||
FlipperI32HexFileStatusErrorData = (-3),
|
|
||||||
FlipperI32HexFileStatusErrorUnsupportedCommand = (-4),
|
|
||||||
FlipperI32HexFileStatusErrorNoOpenFile = (-5),
|
|
||||||
FlipperI32HexFileStatusErrorFileWrite = (-6),
|
|
||||||
FlipperI32HexFileStatusErrorFileRead = (-7),
|
|
||||||
|
|
||||||
FlipperI32HexFileStatusReserved =
|
|
||||||
0x7FFFFFFF, ///< Prevents enum down-size compiler optimization.
|
|
||||||
} FlipperI32HexFileStatus;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
FlipperI32HexFileStatus status;
|
|
||||||
uint32_t data_size;
|
|
||||||
} FlipperI32HexFileRet;
|
|
||||||
|
|
||||||
FlipperI32HexFile* flipper_i32hex_file_open_write(const char* name, uint32_t start_addr);
|
|
||||||
|
|
||||||
FlipperI32HexFile* flipper_i32hex_file_open_read(const char* name);
|
|
||||||
|
|
||||||
void flipper_i32hex_file_close(FlipperI32HexFile* instance);
|
|
||||||
|
|
||||||
FlipperI32HexFileRet flipper_i32hex_file_bin_to_i32hex_set_data(
|
|
||||||
FlipperI32HexFile* instance,
|
|
||||||
uint8_t* data,
|
|
||||||
uint32_t data_size);
|
|
||||||
|
|
||||||
FlipperI32HexFileRet flipper_i32hex_file_bin_to_i32hex_set_end_line(FlipperI32HexFile* instance);
|
|
||||||
|
|
||||||
const char* flipper_i32hex_file_get_string(FlipperI32HexFile* instance);
|
|
||||||
|
|
||||||
void flipper_i32hex_file_bin_to_i32hex_set_addr(FlipperI32HexFile* instance, uint32_t addr);
|
|
||||||
|
|
||||||
bool flipper_i32hex_file_check(FlipperI32HexFile* instance);
|
|
||||||
|
|
||||||
FlipperI32HexFileRet flipper_i32hex_file_i32hex_to_bin_get_data(
|
|
||||||
FlipperI32HexFile* instance,
|
|
||||||
uint8_t* data,
|
|
||||||
uint32_t data_size);
|
|
Before Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 3.6 KiB |
Before Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 3.8 KiB |
|
@ -1,386 +0,0 @@
|
||||||
#include "avr_isp_chip_arr.h"
|
|
||||||
|
|
||||||
#include <furi.h>
|
|
||||||
|
|
||||||
//https://github.com/avrdudes/avrdude/blob/master/src/avrintel.c
|
|
||||||
|
|
||||||
const AvrIspChipArr avr_isp_chip_arr[] = { // Value of -1 typically means unknown
|
|
||||||
//{mcu_name, mcuid, family, {sig, na, ture}, flstart, flsize, pgsiz, nb, bootsz, eestart, eesize, ep, rambeg, ramsiz, nf, nl, ni}, // Source
|
|
||||||
{"ATtiny4", 0, F_AVR8L, {0x1E, 0x8F, 0x0A}, 0, 0x00200, 0x010, 0, 0, 0, 0, 0, 0x0040, 0x0020, 1, 1, 10}, // atdf, avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"ATtiny5", 1, F_AVR8L, {0x1E, 0x8F, 0x09}, 0, 0x00200, 0x010, 0, 0, 0, 0, 0, 0x0040, 0x0020, 1, 1, 11}, // atdf, avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"ATtiny9", 2, F_AVR8L, {0x1E, 0x90, 0x08}, 0, 0x00400, 0x010, 0, 0, 0, 0, 0, 0x0040, 0x0020, 1, 1, 10}, // atdf, avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"ATtiny10", 3, F_AVR8L, {0x1E, 0x90, 0x03}, 0, 0x00400, 0x010, 0, 0, 0, 0, 0, 0x0040, 0x0020, 1, 1, 11}, // atdf, avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"ATtiny20", 4, F_AVR8L, {0x1E, 0x91, 0x0F}, 0, 0x00800, 0x020, 0, 0, 0, 0, 0, 0x0040, 0x0080, 1, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"ATtiny40", 5, F_AVR8L, {0x1E, 0x92, 0x0E}, 0, 0x01000, 0x040, 0, 0, 0, 0, 0, 0x0040, 0x0100, 1, 1, 18}, // atdf, avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"ATtiny102", 6, F_AVR8L, {0x1E, 0x90, 0x0C}, 0, 0x00400, 0x010, 0, 0, 0, 0, 0, 0x0040, 0x0020, 1, 1, 16}, // atdf, avrdude, boot size (manual)
|
|
||||||
{"ATtiny104", 7, F_AVR8L, {0x1E, 0x90, 0x0B}, 0, 0x00400, 0x010, 0, 0, 0, 0, 0, 0x0040, 0x0020, 1, 1, 16}, // atdf, avrdude, boot size (manual)
|
|
||||||
|
|
||||||
{"ATtiny11", 8, F_AVR8, {0x1E, 0x90, 0x04}, 0, 0x00400, 0x001, 0, 0, 0, 0x0040, 1, 0x0060, 0x0020, 1, 1, 5}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny12", 9, F_AVR8, {0x1E, 0x90, 0x05}, 0, 0x00400, 0x001, 0, 0, 0, 0x0040, 2, 0x0060, 0x0020, 1, 1, 6}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny13", 10, F_AVR8, {0x1E, 0x90, 0x07}, 0, 0x00400, 0x020, 0, 0, 0, 0x0040, 4, 0x0060, 0x0040, 2, 1, 10}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny13A", 11, F_AVR8, {0x1E, 0x90, 0x07}, 0, 0x00400, 0x020, 0, 0, 0, 0x0040, 4, 0x0060, 0x0040, 2, 1, 10}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny15", 12, F_AVR8, {0x1E, 0x90, 0x06}, 0, 0x00400, 0x001, 0, 0, 0, 0x0040, 2, 0x0060, 0x0020, 1, 1, 9}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny22", 13, F_AVR8, {0x1E, 0x91, 0x06}, 0, 0x00800, -1, 0, 0, -1, -1, -1, 0x0060, 0x0080, 1, 1, 3}, // avr-gcc 12.2.0, boot size (manual)
|
|
||||||
{"ATtiny24", 14, F_AVR8, {0x1E, 0x91, 0x0B}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny24A", 15, F_AVR8, {0x1E, 0x91, 0x0B}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny25", 16, F_AVR8, {0x1E, 0x91, 0x08}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 15}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny26", 17, F_AVR8, {0x1E, 0x91, 0x09}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 2, 1, 12}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny28", 18, F_AVR8, {0x1E, 0x91, 0x07}, 0, 0x00800, 0x002, 0, 0, 0, 0, 0, 0x0060, 0x0020, 1, 1, 6}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny43U", 19, F_AVR8, {0x1E, 0x92, 0x0C}, 0, 0x01000, 0x040, 0, 0, 0, 0x0040, 4, 0x0060, 0x0100, 3, 1, 16}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny44", 20, F_AVR8, {0x1E, 0x92, 0x07}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0060, 0x0100, 3, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny44A", 21, F_AVR8, {0x1E, 0x92, 0x07}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0060, 0x0100, 3, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny45", 22, F_AVR8, {0x1E, 0x92, 0x06}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0060, 0x0100, 3, 1, 15}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny48", 23, F_AVR8, {0x1E, 0x92, 0x09}, 0, 0x01000, 0x040, 0, 0, 0, 0x0040, 4, 0x0100, 0x0100, 3, 1, 20}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny84", 24, F_AVR8, {0x1E, 0x93, 0x0C}, 0, 0x02000, 0x040, 0, 0, 0, 0x0200, 4, 0x0060, 0x0200, 3, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny84A", 25, F_AVR8, {0x1E, 0x93, 0x0C}, 0, 0x02000, 0x040, 0, 0, 0, 0x0200, 4, 0x0060, 0x0200, 3, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny85", 26, F_AVR8, {0x1E, 0x93, 0x0B}, 0, 0x02000, 0x040, 0, 0, 0, 0x0200, 4, 0x0060, 0x0200, 3, 1, 15}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny87", 27, F_AVR8, {0x1E, 0x93, 0x87}, 0, 0x02000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny88", 28, F_AVR8, {0x1E, 0x93, 0x11}, 0, 0x02000, 0x040, 0, 0, 0, 0x0040, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny167", 29, F_AVR8, {0x1E, 0x94, 0x87}, 0, 0x04000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny261", 30, F_AVR8, {0x1E, 0x91, 0x0C}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny261A", 31, F_AVR8, {0x1E, 0x91, 0x0C}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny441", 32, F_AVR8, {0x1E, 0x92, 0x15}, 0, 0x01000, 0x010, 0, 0, 0, 0x0100, 4, 0x0100, 0x0100, 3, 1, 30}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny461", 33, F_AVR8, {0x1E, 0x92, 0x08}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0060, 0x0100, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny461A", 34, F_AVR8, {0x1E, 0x92, 0x08}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0060, 0x0100, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny828", 35, F_AVR8, {0x1E, 0x93, 0x14}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny828R", 36, F_AVR8, {0x1E, 0x93, 0x14}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 26}, // avrdude, from ATtiny828
|
|
||||||
{"ATtiny841", 37, F_AVR8, {0x1E, 0x93, 0x15}, 0, 0x02000, 0x010, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 30}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny861", 38, F_AVR8, {0x1E, 0x93, 0x0D}, 0, 0x02000, 0x040, 0, 0, 0, 0x0200, 4, 0x0060, 0x0200, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny861A", 39, F_AVR8, {0x1E, 0x93, 0x0D}, 0, 0x02000, 0x040, 0, 0, 0, 0x0200, 4, 0x0060, 0x0200, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny1634", 40, F_AVR8, {0x1E, 0x94, 0x12}, 0, 0x04000, 0x020, 0, 0, 0, 0x0100, 4, 0x0100, 0x0400, 3, 1, 28}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny1634R", 41, F_AVR8, {0x1E, 0x94, 0x12}, 0, 0x04000, 0x020, 0, 0, 0, 0x0100, 4, 0x0100, 0x0400, 3, 1, 28}, // avrdude, from ATtiny1634
|
|
||||||
{"ATtiny2313", 42, F_AVR8, {0x1E, 0x91, 0x0A}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny2313A", 43, F_AVR8, {0x1E, 0x91, 0x0A}, 0, 0x00800, 0x020, 0, 0, 0, 0x0080, 4, 0x0060, 0x0080, 3, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny4313", 44, F_AVR8, {0x1E, 0x92, 0x0D}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0060, 0x0100, 3, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega8", 45, F_AVR8, {0x1E, 0x93, 0x07}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0060, 0x0400, 2, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega8A", 46, F_AVR8, {0x1E, 0x93, 0x07}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0060, 0x0400, 2, 1, 19}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega8HVA", 47, F_AVR8, {0x1E, 0x93, 0x10}, 0, 0x02000, 0x080, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 1, 1, 21}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATmega8U2", 48, F_AVR8, {0x1E, 0x93, 0x89}, 0, 0x02000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 29}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega16", 49, F_AVR8, {0x1E, 0x94, 0x03}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0060, 0x0400, 2, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega16A", 50, F_AVR8, {0x1E, 0x94, 0x03}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0060, 0x0400, 2, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega16HVA", 51, F_AVR8, {0x1E, 0x94, 0x0C}, 0, 0x04000, 0x080, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 1, 1, 21}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATmega16HVB", 52, F_AVR8, {0x1E, 0x94, 0x0D}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0400, 2, 1, 29}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATmega16HVBrevB", 53, F_AVR8, {0x1E, 0x94, 0x0D}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0400, 2, 1, 29}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATmega16M1", 54, F_AVR8, {0x1E, 0x94, 0x84}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 31}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATmega16HVA2", 55, F_AVR8, {0x1E, 0x94, 0x0E}, 0, 0x04000, 0x080, -1, -1, -1, -1, -1, 0x0100, 0x0400, 2, 1, 22}, // avr-gcc 12.2.0
|
|
||||||
{"ATmega16U2", 56, F_AVR8, {0x1E, 0x94, 0x89}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 29}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega16U4", 57, F_AVR8, {0x1E, 0x94, 0x88}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0500, 3, 1, 43}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega32", 58, F_AVR8, {0x1E, 0x95, 0x02}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0060, 0x0800, 2, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega32A", 59, F_AVR8, {0x1E, 0x95, 0x02}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0060, 0x0800, 2, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega32HVB", 60, F_AVR8, {0x1E, 0x95, 0x10}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 2, 1, 29}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATmega32HVBrevB", 61, F_AVR8, {0x1E, 0x95, 0x10}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 2, 1, 29}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATmega32C1", 62, F_AVR8, {0x1E, 0x95, 0x86}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 31}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATmega32M1", 63, F_AVR8, {0x1E, 0x95, 0x84}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega32U2", 64, F_AVR8, {0x1E, 0x95, 0x8A}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0400, 3, 1, 29}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega32U4", 65, F_AVR8, {0x1E, 0x95, 0x87}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0a00, 3, 1, 43}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega32U6", 66, F_AVR8, {0x1E, 0x95, 0x88}, 0, 0x08000, 0x080, 4, 0x0200, -1, -1, -1, 0x0100, 0x0a00, 3, 1, 38}, // avr-gcc 12.2.0, boot size (manual)
|
|
||||||
{"ATmega48", 67, F_AVR8, {0x1E, 0x92, 0x05}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega48A", 68, F_AVR8, {0x1E, 0x92, 0x05}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega48P", 69, F_AVR8, {0x1E, 0x92, 0x0A}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega48PA", 70, F_AVR8, {0x1E, 0x92, 0x0A}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega48PB", 71, F_AVR8, {0x1E, 0x92, 0x10}, 0, 0x01000, 0x040, 0, 0, 0, 0x0100, 4, 0x0100, 0x0200, 3, 1, 27}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega64", 72, F_AVR8, {0x1E, 0x96, 0x02}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 35}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega64A", 73, F_AVR8, {0x1E, 0x96, 0x02}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 35}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega64HVE", 74, F_AVR8, {0x1E, 0x96, 0x10}, 0, 0x10000, 0x080, 4, 0x0400, -1, -1, -1, 0x0100, 0x1000, 2, 1, 25}, // avr-gcc 12.2.0, boot size (manual)
|
|
||||||
{"ATmega64C1", 75, F_AVR8, {0x1E, 0x96, 0x86}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 31}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATmega64M1", 76, F_AVR8, {0x1E, 0x96, 0x84}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega64HVE2", 77, F_AVR8, {0x1E, 0x96, 0x10}, 0, 0x10000, 0x080, 4, 0x0400, 0, 0x0400, 4, 0x0100, 0x1000, 2, 1, 25}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATmega64RFR2", 78, F_AVR8, {0x1E, 0xA6, 0x02}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0200, 0x2000, 3, 1, 77}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega88", 79, F_AVR8, {0x1E, 0x93, 0x0A}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega88A", 80, F_AVR8, {0x1E, 0x93, 0x0A}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega88P", 81, F_AVR8, {0x1E, 0x93, 0x0F}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega88PA", 82, F_AVR8, {0x1E, 0x93, 0x0F}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega88PB", 83, F_AVR8, {0x1E, 0x93, 0x16}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 27}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega103", 84, F_AVR8, {0x1E, 0x97, 0x01}, 0, 0x20000, 0x100, 0, 0, 0, 0x1000, 1, 0x0060, 0x0fa0, 1, 1, 24}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"ATmega128", 85, F_AVR8, {0x1E, 0x97, 0x02}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x1000, 3, 1, 35}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega128A", 86, F_AVR8, {0x1E, 0x97, 0x02}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x1000, 3, 1, 35}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega128RFA1", 87, F_AVR8, {0x1E, 0xA7, 0x01}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x4000, 3, 1, 72}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega128RFR2", 88, F_AVR8, {0x1E, 0xA7, 0x02}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x4000, 3, 1, 77}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega161", 89, F_AVR8, {0x1E, 0x94, 0x01}, 0, 0x04000, 0x080, 1, 0x0400, 0, 0x0200, 1, 0x0060, 0x0400, 1, 1, 21}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"ATmega162", 90, F_AVR8, {0x1E, 0x94, 0x04}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 28}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega163", 91, F_AVR8, {0x1E, 0x94, 0x02}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 1, 0x0060, 0x0400, 2, 1, 18}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"ATmega164A", 92, F_AVR8, {0x1E, 0x94, 0x0F}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega164P", 93, F_AVR8, {0x1E, 0x94, 0x0A}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega164PA", 94, F_AVR8, {0x1E, 0x94, 0x0A}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega165", 95, F_AVR8, {0x1E, 0x94, 0x10}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 22}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"ATmega165A", 96, F_AVR8, {0x1E, 0x94, 0x10}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega165P", 97, F_AVR8, {0x1E, 0x94, 0x07}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega165PA", 98, F_AVR8, {0x1E, 0x94, 0x07}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega168", 99, F_AVR8, {0x1E, 0x94, 0x06}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega168A", 100, F_AVR8, {0x1E, 0x94, 0x06}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega168P", 101, F_AVR8, {0x1E, 0x94, 0x0B}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega168PA", 102, F_AVR8, {0x1E, 0x94, 0x0B}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega168PB", 103, F_AVR8, {0x1E, 0x94, 0x15}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 27}, // atdf, avr-gcc 7.3.0, avrdude
|
|
||||||
{"ATmega169", 104, F_AVR8, {0x1E, 0x94, 0x05}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 23}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"ATmega169A", 105, F_AVR8, {0x1E, 0x94, 0x11}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega169P", 106, F_AVR8, {0x1E, 0x94, 0x05}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega169PA", 107, F_AVR8, {0x1E, 0x94, 0x05}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega256RFR2", 108, F_AVR8, {0x1E, 0xA8, 0x02}, 0, 0x40000, 0x100, 4, 0x0400, 0, 0x2000, 8, 0x0200, 0x8000, 3, 1, 77}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega323", 109, F_AVR8, {0x1E, 0x95, 0x01}, 0, 0x08000, 0x080, 4, 0x0200, -1, -1, -1, 0x0060, 0x0800, 2, 1, 21}, // avr-gcc 12.2.0, boot size (manual)
|
|
||||||
{"ATmega324A", 110, F_AVR8, {0x1E, 0x95, 0x15}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega324P", 111, F_AVR8, {0x1E, 0x95, 0x08}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega324PA", 112, F_AVR8, {0x1E, 0x95, 0x11}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega324PB", 113, F_AVR8, {0x1E, 0x95, 0x17}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 51}, // atdf, avrdude
|
|
||||||
{"ATmega325", 114, F_AVR8, {0x1E, 0x95, 0x05}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega325A", 115, F_AVR8, {0x1E, 0x95, 0x05}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega325P", 116, F_AVR8, {0x1E, 0x95, 0x0D}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega325PA", 117, F_AVR8, {0x1E, 0x95, 0x0D}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega328", 118, F_AVR8, {0x1E, 0x95, 0x14}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega328P", 119, F_AVR8, {0x1E, 0x95, 0x0F}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega328PB", 120, F_AVR8, {0x1E, 0x95, 0x16}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 45}, // atdf, avr-gcc 7.3.0, avrdude
|
|
||||||
{"ATmega329", 121, F_AVR8, {0x1E, 0x95, 0x03}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega329A", 122, F_AVR8, {0x1E, 0x95, 0x03}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega329P", 123, F_AVR8, {0x1E, 0x95, 0x0B}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega329PA", 124, F_AVR8, {0x1E, 0x95, 0x0B}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega406", 125, F_AVR8, {0x1E, 0x95, 0x07}, 0, 0x0a000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0800, 2, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega640", 126, F_AVR8, {0x1E, 0x96, 0x08}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x2000, 3, 1, 57}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega644", 127, F_AVR8, {0x1E, 0x96, 0x09}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 28}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega644A", 128, F_AVR8, {0x1E, 0x96, 0x09}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega644P", 129, F_AVR8, {0x1E, 0x96, 0x0A}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega644PA", 130, F_AVR8, {0x1E, 0x96, 0x0A}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega644RFR2", 131, F_AVR8, {0x1E, 0xA6, 0x03}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0200, 0x2000, 3, 1, 77}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega645", 132, F_AVR8, {0x1E, 0x96, 0x05}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega645A", 133, F_AVR8, {0x1E, 0x96, 0x05}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega645P", 134, F_AVR8, {0x1E, 0x96, 0x0D}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 22}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega649", 135, F_AVR8, {0x1E, 0x96, 0x03}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega649A", 136, F_AVR8, {0x1E, 0x96, 0x03}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega649P", 137, F_AVR8, {0x1E, 0x96, 0x0B}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 23}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega1280", 138, F_AVR8, {0x1E, 0x97, 0x03}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x2000, 3, 1, 57}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega1281", 139, F_AVR8, {0x1E, 0x97, 0x04}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x2000, 3, 1, 57}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega1284", 140, F_AVR8, {0x1E, 0x97, 0x06}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x4000, 3, 1, 35}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega1284P", 141, F_AVR8, {0x1E, 0x97, 0x05}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x4000, 3, 1, 35}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega1284RFR2", 142, F_AVR8, {0x1E, 0xA7, 0x03}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x4000, 3, 1, 77}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega2560", 143, F_AVR8, {0x1E, 0x98, 0x01}, 0, 0x40000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x2000, 3, 1, 57}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega2561", 144, F_AVR8, {0x1E, 0x98, 0x02}, 0, 0x40000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0200, 0x2000, 3, 1, 57}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega2564RFR2", 145, F_AVR8, {0x1E, 0xA8, 0x03}, 0, 0x40000, 0x100, 4, 0x0400, 0, 0x2000, 8, 0x0200, 0x8000, 3, 1, 77}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega3250", 146, F_AVR8, {0x1E, 0x95, 0x06}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega3250A", 147, F_AVR8, {0x1E, 0x95, 0x06}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega3250P", 148, F_AVR8, {0x1E, 0x95, 0x0E}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega3250PA", 149, F_AVR8, {0x1E, 0x95, 0x0E}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega3290", 150, F_AVR8, {0x1E, 0x95, 0x04}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega3290A", 151, F_AVR8, {0x1E, 0x95, 0x04}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega3290P", 152, F_AVR8, {0x1E, 0x95, 0x0C}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega3290PA", 153, F_AVR8, {0x1E, 0x95, 0x0C}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega6450", 154, F_AVR8, {0x1E, 0x96, 0x06}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega6450A", 155, F_AVR8, {0x1E, 0x96, 0x06}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega6450P", 156, F_AVR8, {0x1E, 0x96, 0x0E}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega6490", 157, F_AVR8, {0x1E, 0x96, 0x04}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega6490A", 158, F_AVR8, {0x1E, 0x96, 0x04}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega6490P", 159, F_AVR8, {0x1E, 0x96, 0x0C}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 25}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega8515", 160, F_AVR8, {0x1E, 0x93, 0x06}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0060, 0x0200, 2, 1, 17}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega8535", 161, F_AVR8, {0x1E, 0x93, 0x08}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0060, 0x0200, 2, 1, 21}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"AT43USB320", 162, F_AVR8, {0xff, -1, -1}, 0, 0x10000, -1, -1, -1, -1, -1, -1, 0x0060, 0x0200, -1, -1, 0}, // avr-gcc 12.2.0
|
|
||||||
{"AT43USB355", 163, F_AVR8, {0xff, -1, -1}, 0, 0x06000, -1, -1, -1, -1, -1, -1, 0x0060, 0x0400, -1, -1, 0}, // avr-gcc 12.2.0
|
|
||||||
{"AT76C711", 164, F_AVR8, {0xff, -1, -1}, 0, 0x04000, -1, -1, -1, -1, -1, -1, 0x0060, 0x07a0, -1, -1, 0}, // avr-gcc 12.2.0
|
|
||||||
{"AT86RF401", 165, F_AVR8, {0x1E, 0x91, 0x81}, 0, 0x00800, -1, -1, -1, -1, -1, -1, 0x0060, 0x0080, 0, 1, 3}, // avr-gcc 12.2.0
|
|
||||||
{"AT90PWM1", 166, F_AVR8, {0x1E, 0x93, 0x83}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 32}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"AT90PWM2", 167, F_AVR8, {0x1E, 0x93, 0x81}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 32}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"AT90PWM2B", 168, F_AVR8, {0x1E, 0x93, 0x83}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 32}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"AT90PWM3", 169, F_AVR8, {0x1E, 0x93, 0x81}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 32}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"AT90PWM3B", 170, F_AVR8, {0x1E, 0x93, 0x83}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 32}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"AT90CAN32", 171, F_AVR8, {0x1E, 0x95, 0x81}, 0, 0x08000, 0x100, 4, 0x0400, 0, 0x0400, 8, 0x0100, 0x0800, 3, 1, 37}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"AT90CAN64", 172, F_AVR8, {0x1E, 0x96, 0x81}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 37}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"AT90PWM81", 173, F_AVR8, {0x1E, 0x93, 0x88}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0100, 3, 1, 20}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"AT90USB82", 174, F_AVR8, {0x1E, 0x93, 0x82}, 0, 0x02000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 29}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"AT90SCR100", 175, F_AVR8, {0x1E, 0x96, 0xC1}, 0, 0x10000, 0x100, 4, 0x0200, -1, -1, -1, 0x0100, 0x1000, 3, 1, 38}, // avr-gcc 12.2.0, boot size (manual)
|
|
||||||
{"AT90CAN128", 176, F_AVR8, {0x1E, 0x97, 0x81}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x1000, 3, 1, 37}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"AT90PWM161", 177, F_AVR8, {0x1E, 0x94, 0x8B}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 20}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"AT90USB162", 178, F_AVR8, {0x1E, 0x94, 0x82}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 29}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"AT90PWM216", 179, F_AVR8, {0x1E, 0x94, 0x83}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 32}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"AT90PWM316", 180, F_AVR8, {0x1E, 0x94, 0x83}, 0, 0x04000, 0x080, 4, 0x0200, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 32}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"AT90USB646", 181, F_AVR8, {0x1E, 0x96, 0x82}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 38}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"AT90USB647", 182, F_AVR8, {0x1E, 0x96, 0x82}, 0, 0x10000, 0x100, 4, 0x0400, 0, 0x0800, 8, 0x0100, 0x1000, 3, 1, 38}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"AT90S1200", 183, F_AVR8, {0x1E, 0x90, 0x01}, 0, 0x00400, 0x001, 0, 0, 0, 0x0040, 1, 0x0060, 0x0020, 1, 1, 4}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"AT90USB1286", 184, F_AVR8, {0x1E, 0x97, 0x82}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x2000, 3, 1, 38}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"AT90USB1287", 185, F_AVR8, {0x1E, 0x97, 0x82}, 0, 0x20000, 0x100, 4, 0x0400, 0, 0x1000, 8, 0x0100, 0x2000, 3, 1, 38}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"AT90S2313", 186, F_AVR8, {0x1E, 0x91, 0x01}, 0, 0x00800, 0x001, 0, 0, 0, 0x0080, 1, 0x0060, 0x0080, 1, 1, 11}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"AT90S2323", 187, F_AVR8, {0x1E, 0x91, 0x02}, 0, 0x00800, -1, 0, 0, -1, -1, -1, 0x0060, 0x0080, 1, 1, 3}, // avr-gcc 12.2.0, boot size (manual)
|
|
||||||
{"AT90S2333", 188, F_AVR8, {0x1E, 0x91, 0x05}, 0, 0x00800, 0x001, 0, 0, 0, 0x0080, 1, 0x0060, 0x0080, -1, -1, 14}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"AT90S2343", 189, F_AVR8, {0x1E, 0x91, 0x03}, 0, 0x00800, 0x001, 0, 0, 0, 0x0080, 1, 0x0060, 0x0080, 1, 1, 3}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"AT90S4414", 190, F_AVR8, {0x1E, 0x92, 0x01}, 0, 0x01000, 0x001, 0, 0, 0, 0x0100, 1, 0x0060, 0x0100, 1, 1, 13}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"AT90S4433", 191, F_AVR8, {0x1E, 0x92, 0x03}, 0, 0x01000, 0x001, 0, 0, 0, 0x0100, 1, 0x0060, 0x0080, 1, 1, 14}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"AT90S4434", 192, F_AVR8, {0x1E, 0x92, 0x02}, 0, 0x01000, 0x001, 0, 0, 0, 0x0100, 1, 0x0060, 0x0100, 1, 1, 17}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"AT90S8515", 193, F_AVR8, {0x1E, 0x93, 0x01}, 0, 0x02000, 0x001, 0, 0, 0, 0x0200, 1, 0x0060, 0x0200, 1, 1, 13}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"AT90C8534", 194, F_AVR8, {0xff, -1, -1}, 0, 0x02000, -1, -1, -1, -1, -1, -1, 0x0060, 0x0100, -1, -1, 0}, // avr-gcc 12.2.0
|
|
||||||
{"AT90S8535", 195, F_AVR8, {0x1E, 0x93, 0x03}, 0, 0x02000, 0x001, 0, 0, 0, 0x0200, 1, 0x0060, 0x0200, 1, 1, 17}, // avr-gcc 12.2.0, avrdude, boot size (manual)
|
|
||||||
{"AT94K", 196, F_AVR8, {0xff, -1, -1}, 0, 0x08000, -1, -1, -1, -1, -1, -1, 0x0060, 0x0fa0, -1, -1, 0}, // avr-gcc 12.2.0
|
|
||||||
{"ATA5272", 197, F_AVR8, {0x1E, 0x93, 0x87}, 0, 0x02000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 37}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATA5505", 198, F_AVR8, {0x1E, 0x94, 0x87}, 0, 0x04000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATA5700M322", 199, F_AVR8, {0x1E, 0x95, 0x67}, 0x08000, 0x08000, 0x040, 0, 0, 0, 0x0880, 16, 0x0200, 0x0400, 1, 1, 51}, // atdf
|
|
||||||
{"ATA5702M322", 200, F_AVR8, {0x1E, 0x95, 0x69}, 0x08000, 0x08000, 0x040, 0, 0, 0, 0x0880, 16, 0x0200, 0x0400, 1, 1, 51}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATA5781", 201, F_AVR8, {0x1E, 0x95, 0x64}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
|
|
||||||
{"ATA5782", 202, F_AVR8, {0x1E, 0x95, 0x65}, 0x08000, 0x05000, 0x040, 1, 0x5000, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATA5783", 203, F_AVR8, {0x1E, 0x95, 0x66}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
|
|
||||||
{"ATA5787", 204, F_AVR8, {0x1E, 0x94, 0x6C}, 0x08000, 0x05200, 0x040, 0, 0, 0, 0x0400, 16, 0x0200, 0x0800, 1, 1, 44}, // atdf
|
|
||||||
{"ATA5790", 205, F_AVR8, {0x1E, 0x94, 0x61}, 0, 0x04000, 0x080, 1, 0x0800, 0, 0x0800, 16, 0x0100, 0x0200, 1, 1, 30}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATA5790N", 206, F_AVR8, {0x1E, 0x94, 0x62}, 0, 0x04000, 0x080, 1, 0x0800, 0, 0x0800, 16, 0x0100, 0x0200, 1, 1, 31}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATA5791", 207, F_AVR8, {0x1E, 0x94, 0x62}, 0, 0x04000, 0x080, 1, 0x0800, 0, 0x0800, 16, 0x0100, 0x0200, 1, 1, 31}, // atdf, avr-gcc 7.3.0
|
|
||||||
{"ATA5795", 208, F_AVR8, {0x1E, 0x93, 0x61}, 0, 0x02000, 0x040, 1, 0x0800, 0, 0x0800, 16, 0x0100, 0x0200, 1, 1, 23}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATA5831", 209, F_AVR8, {0x1E, 0x95, 0x61}, 0x08000, 0x05000, 0x040, 1, 0x5000, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATA5832", 210, F_AVR8, {0x1E, 0x95, 0x62}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
|
|
||||||
{"ATA5833", 211, F_AVR8, {0x1E, 0x95, 0x63}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
|
|
||||||
{"ATA5835", 212, F_AVR8, {0x1E, 0x94, 0x6B}, 0x08000, 0x05200, 0x040, 0, 0, 0, 0x0400, 16, 0x0200, 0x0800, 1, 1, 44}, // atdf
|
|
||||||
{"ATA6285", 213, F_AVR8, {0x1E, 0x93, 0x82}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0140, 4, 0x0100, 0x0200, 2, 1, 27}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATA6286", 214, F_AVR8, {0x1E, 0x93, 0x82}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0140, 4, 0x0100, 0x0200, 2, 1, 27}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATA6289", 215, F_AVR8, {0x1E, 0x93, 0x82}, 0, 0x02000, 0x040, 4, 0x0100, -1, -1, -1, 0x0100, 0x0200, 2, 1, 27}, // avr-gcc 12.2.0, boot size (manual)
|
|
||||||
{"ATA6612C", 216, F_AVR8, {0x1E, 0x93, 0x0A}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATA6613C", 217, F_AVR8, {0x1E, 0x94, 0x06}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATA6614Q", 218, F_AVR8, {0x1E, 0x95, 0x0F}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 26}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATA6616C", 219, F_AVR8, {0x1E, 0x93, 0x87}, 0, 0x02000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATA6617C", 220, F_AVR8, {0x1E, 0x94, 0x87}, 0, 0x04000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATA8210", 221, F_AVR8, {0x1E, 0x95, 0x65}, 0x08000, 0x05000, 0x040, 1, 0x5000, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf, avr-gcc 7.3.0
|
|
||||||
{"ATA8215", 222, F_AVR8, {0x1E, 0x95, 0x64}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
|
|
||||||
{"ATA8510", 223, F_AVR8, {0x1E, 0x95, 0x61}, 0x08000, 0x05000, 0x040, 1, 0x5000, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf, avr-gcc 7.3.0
|
|
||||||
{"ATA8515", 224, F_AVR8, {0x1E, 0x95, 0x63}, -1, -1, -1, 0, 0, 0, 0x0400, 16, 0x0200, 0x0400, 1, 1, 42}, // atdf
|
|
||||||
{"ATA664251", 225, F_AVR8, {0x1E, 0x94, 0x87}, 0, 0x04000, 0x080, 0, 0, 0, 0x0200, 4, 0x0100, 0x0200, 3, 1, 20}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"M3000", 226, F_AVR8, {0xff, -1, -1}, 0, 0x10000, -1, -1, -1, -1, -1, -1, 0x1000, 0x1000, -1, -1, 0}, // avr-gcc 12.2.0
|
|
||||||
{"LGT8F88P", 227, F_AVR8, {0x1E, 0x93, 0x0F}, 0, 0x02000, 0x040, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // avrdude, from ATmega88
|
|
||||||
{"LGT8F168P", 228, F_AVR8, {0x1E, 0x94, 0x0B}, 0, 0x04000, 0x080, 4, 0x0100, 0, 0x0200, 4, 0x0100, 0x0400, 3, 1, 26}, // avrdude, from ATmega168P
|
|
||||||
{"LGT8F328P", 229, F_AVR8, {0x1E, 0x95, 0x0F}, 0, 0x08000, 0x080, 4, 0x0200, 0, 0x0400, 4, 0x0100, 0x0800, 3, 1, 26}, // avrdude, from ATmega328P
|
|
||||||
|
|
||||||
{"ATxmega8E5", 230, F_XMEGA, {0x1E, 0x93, 0x41}, 0, 0x02800, 0x080, 1, 0x0800, 0, 0x0200, 32, 0x2000, 0x0400, 7, 1, 43}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega16A4", 231, F_XMEGA, {0x1E, 0x94, 0x41}, 0, 0x05000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x0800, 6, 1, 94}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega16A4U", 232, F_XMEGA, {0x1E, 0x94, 0x41}, 0, 0x05000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x0800, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega16C4", 233, F_XMEGA, {0x1E, 0x94, 0x43}, 0, 0x05000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x0800, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega16D4", 234, F_XMEGA, {0x1E, 0x94, 0x42}, 0, 0x05000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x0800, 6, 1, 91}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega16E5", 235, F_XMEGA, {0x1E, 0x94, 0x45}, 0, 0x05000, 0x080, 1, 0x1000, 0, 0x0200, 32, 0x2000, 0x0800, 7, 1, 43}, // atdf, avr-gcc 7.3.0, avrdude
|
|
||||||
{"ATxmega32C3", 236, F_XMEGA, {0x1E, 0x95, 0x49}, 0, 0x09000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATxmega32D3", 237, F_XMEGA, {0x1E, 0x95, 0x4A}, 0, 0x09000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 6, 1, 114}, // atdf, avr-gcc 12.2.0
|
|
||||||
{"ATxmega32A4", 238, F_XMEGA, {0x1E, 0x95, 0x41}, 0, 0x09000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 6, 1, 94}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega32A4U", 239, F_XMEGA, {0x1E, 0x95, 0x41}, 0, 0x09000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega32C4", 240, F_XMEGA, {0x1E, 0x95, 0x44}, 0, 0x09000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega32D4", 241, F_XMEGA, {0x1E, 0x95, 0x42}, 0, 0x09000, 0x100, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 6, 1, 91}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega32E5", 242, F_XMEGA, {0x1E, 0x95, 0x4C}, 0, 0x09000, 0x080, 1, 0x1000, 0, 0x0400, 32, 0x2000, 0x1000, 7, 1, 43}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega64A1", 243, F_XMEGA, {0x1E, 0x96, 0x4E}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 125}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega64A1U", 244, F_XMEGA, {0x1E, 0x96, 0x4E}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega64B1", 245, F_XMEGA, {0x1E, 0x96, 0x52}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 81}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega64A3", 246, F_XMEGA, {0x1E, 0x96, 0x42}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 122}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega64A3U", 247, F_XMEGA, {0x1E, 0x96, 0x42}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega64B3", 248, F_XMEGA, {0x1E, 0x96, 0x51}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 54}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega64C3", 249, F_XMEGA, {0x1E, 0x96, 0x49}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega64D3", 250, F_XMEGA, {0x1E, 0x96, 0x4A}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 114}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega64A4", 251, F_XMEGA, {0x1E, 0x96, 0x46}, 0, 0x11000, 0x100, -1, -1, 0, 0x0800, 32, -1, -1, -1, -1, 0}, // avrdude
|
|
||||||
{"ATxmega64A4U", 252, F_XMEGA, {0x1E, 0x96, 0x46}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega64D4", 253, F_XMEGA, {0x1E, 0x96, 0x47}, 0, 0x11000, 0x100, 1, 0x1000, 0, 0x0800, 32, 0x2000, 0x1000, 6, 1, 91}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega128A1", 254, F_XMEGA, {0x1E, 0x97, 0x4C}, 0, 0x22000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 125}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega128A1revD", 255, F_XMEGA, {0x1E, 0x97, 0x41}, 0, 0x22000, 0x200, -1, -1, 0, 0x0800, 32, -1, -1, -1, -1, 0}, // avrdude
|
|
||||||
{"ATxmega128A1U", 256, F_XMEGA, {0x1E, 0x97, 0x4C}, 0, 0x22000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega128B1", 257, F_XMEGA, {0x1E, 0x97, 0x4D}, 0, 0x22000, 0x100, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 81}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega128A3", 258, F_XMEGA, {0x1E, 0x97, 0x42}, 0, 0x22000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 122}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega128A3U", 259, F_XMEGA, {0x1E, 0x97, 0x42}, 0, 0x22000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega128B3", 260, F_XMEGA, {0x1E, 0x97, 0x4B}, 0, 0x22000, 0x100, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 54}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega128C3", 261, F_XMEGA, {0x1E, 0x97, 0x52}, 0, 0x22000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega128D3", 262, F_XMEGA, {0x1E, 0x97, 0x48}, 0, 0x22000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 114}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega128A4", 263, F_XMEGA, {0x1E, 0x97, 0x46}, 0, 0x22000, 0x200, -1, -1, 0, 0x0800, 32, -1, -1, -1, -1, 0}, // avrdude
|
|
||||||
{"ATxmega128A4U", 264, F_XMEGA, {0x1E, 0x97, 0x46}, 0, 0x22000, 0x100, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega128D4", 265, F_XMEGA, {0x1E, 0x97, 0x47}, 0, 0x22000, 0x100, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x2000, 6, 1, 91}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega192A1", 266, F_XMEGA, {0x1E, 0x97, 0x4E}, 0, 0x32000, 0x200, -1, -1, 0, 0x0800, 32, -1, -1, -1, -1, 0}, // avrdude
|
|
||||||
{"ATxmega192A3", 267, F_XMEGA, {0x1E, 0x97, 0x44}, 0, 0x32000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x4000, 6, 1, 122}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega192A3U", 268, F_XMEGA, {0x1E, 0x97, 0x44}, 0, 0x32000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x4000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega192C3", 269, F_XMEGA, {0x1E, 0x97, 0x51}, 0, 0x32000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x4000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega192D3", 270, F_XMEGA, {0x1E, 0x97, 0x49}, 0, 0x32000, 0x200, 1, 0x2000, 0, 0x0800, 32, 0x2000, 0x4000, 6, 1, 114}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega256A1", 271, F_XMEGA, {0x1E, 0x98, 0x46}, 0, 0x42000, 0x200, -1, -1, 0, 0x1000, 32, -1, -1, -1, -1, 0}, // avrdude
|
|
||||||
{"ATxmega256A3", 272, F_XMEGA, {0x1E, 0x98, 0x42}, 0, 0x42000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x4000, 6, 1, 122}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega256A3B", 273, F_XMEGA, {0x1E, 0x98, 0x43}, 0, 0x42000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x4000, 6, 1, 122}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega256A3BU", 274, F_XMEGA, {0x1E, 0x98, 0x43}, 0, 0x42000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x4000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega256A3U", 275, F_XMEGA, {0x1E, 0x98, 0x42}, 0, 0x42000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x4000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega256C3", 276, F_XMEGA, {0x1E, 0x98, 0x46}, 0, 0x42000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x4000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega256D3", 277, F_XMEGA, {0x1E, 0x98, 0x44}, 0, 0x42000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x4000, 6, 1, 114}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega384C3", 278, F_XMEGA, {0x1E, 0x98, 0x45}, 0, 0x62000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x8000, 6, 1, 127}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATxmega384D3", 279, F_XMEGA, {0x1E, 0x98, 0x47}, 0, 0x62000, 0x200, 1, 0x2000, 0, 0x1000, 32, 0x2000, 0x8000, 6, 1, 114}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
|
|
||||||
{"ATtiny202", 280, F_AVR8X, {0x1E, 0x91, 0x23}, 0, 0x00800, 0x040, 1, 0, 0x01400, 0x0040, 32, 0x3f80, 0x0080, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny204", 281, F_AVR8X, {0x1E, 0x91, 0x22}, 0, 0x00800, 0x040, 1, 0, 0x01400, 0x0040, 32, 0x3f80, 0x0080, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny212", 282, F_AVR8X, {0x1E, 0x91, 0x21}, 0, 0x00800, 0x040, 1, 0, 0x01400, 0x0040, 32, 0x3f80, 0x0080, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny214", 283, F_AVR8X, {0x1E, 0x91, 0x20}, 0, 0x00800, 0x040, 1, 0, 0x01400, 0x0040, 32, 0x3f80, 0x0080, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny402", 284, F_AVR8X, {0x1E, 0x92, 0x27}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny404", 285, F_AVR8X, {0x1E, 0x92, 0x26}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny406", 286, F_AVR8X, {0x1E, 0x92, 0x25}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny412", 287, F_AVR8X, {0x1E, 0x92, 0x23}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny414", 288, F_AVR8X, {0x1E, 0x92, 0x22}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny416", 289, F_AVR8X, {0x1E, 0x92, 0x21}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny416auto", 290, F_AVR8X, {0x1E, 0x92, 0x28}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf
|
|
||||||
{"ATtiny417", 291, F_AVR8X, {0x1E, 0x92, 0x20}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3f00, 0x0100, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny424", 292, F_AVR8X, {0x1E, 0x92, 0x2C}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 30}, // atdf, avrdude
|
|
||||||
{"ATtiny426", 293, F_AVR8X, {0x1E, 0x92, 0x2B}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 30}, // atdf, avrdude
|
|
||||||
{"ATtiny427", 294, F_AVR8X, {0x1E, 0x92, 0x2A}, 0, 0x01000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 30}, // atdf, avrdude
|
|
||||||
{"ATtiny804", 295, F_AVR8X, {0x1E, 0x93, 0x25}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny806", 296, F_AVR8X, {0x1E, 0x93, 0x24}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny807", 297, F_AVR8X, {0x1E, 0x93, 0x23}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny814", 298, F_AVR8X, {0x1E, 0x93, 0x22}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny816", 299, F_AVR8X, {0x1E, 0x93, 0x21}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny817", 300, F_AVR8X, {0x1E, 0x93, 0x20}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3e00, 0x0200, 10, 1, 26}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny824", 301, F_AVR8X, {0x1E, 0x93, 0x29}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3c00, 0x0400, 10, 1, 30}, // atdf, avrdude
|
|
||||||
{"ATtiny826", 302, F_AVR8X, {0x1E, 0x93, 0x28}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3c00, 0x0400, 10, 1, 30}, // atdf, avrdude
|
|
||||||
{"ATtiny827", 303, F_AVR8X, {0x1E, 0x93, 0x27}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0080, 32, 0x3c00, 0x0400, 10, 1, 30}, // atdf, avrdude
|
|
||||||
{"ATtiny1604", 304, F_AVR8X, {0x1E, 0x94, 0x25}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3c00, 0x0400, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny1606", 305, F_AVR8X, {0x1E, 0x94, 0x24}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3c00, 0x0400, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny1607", 306, F_AVR8X, {0x1E, 0x94, 0x23}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3c00, 0x0400, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny1614", 307, F_AVR8X, {0x1E, 0x94, 0x22}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny1616", 308, F_AVR8X, {0x1E, 0x94, 0x21}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny1617", 309, F_AVR8X, {0x1E, 0x94, 0x20}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny1624", 310, F_AVR8X, {0x1E, 0x94, 0x2A}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 30}, // atdf, avrdude
|
|
||||||
{"ATtiny1626", 311, F_AVR8X, {0x1E, 0x94, 0x29}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 30}, // atdf, avrdude
|
|
||||||
{"ATtiny1627", 312, F_AVR8X, {0x1E, 0x94, 0x28}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 30}, // atdf, avrdude
|
|
||||||
{"ATtiny3214", 313, F_AVR8X, {0x1E, 0x95, 0x20}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3800, 0x0800, 10, 1, 31}, // avr-gcc 12.2.0
|
|
||||||
{"ATtiny3216", 314, F_AVR8X, {0x1E, 0x95, 0x21}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3800, 0x0800, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny3217", 315, F_AVR8X, {0x1E, 0x95, 0x22}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3800, 0x0800, 10, 1, 31}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATtiny3224", 316, F_AVR8X, {0x1E, 0x95, 0x28}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3400, 0x0c00, 10, 1, 30}, // atdf, avrdude
|
|
||||||
{"ATtiny3226", 317, F_AVR8X, {0x1E, 0x95, 0x27}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3400, 0x0c00, 10, 1, 30}, // atdf, avrdude
|
|
||||||
{"ATtiny3227", 318, F_AVR8X, {0x1E, 0x95, 0x26}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3400, 0x0c00, 10, 1, 30}, // atdf, avrdude
|
|
||||||
{"ATmega808", 319, F_AVR8X, {0x1E, 0x93, 0x26}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3c00, 0x0400, 10, 1, 36}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega809", 320, F_AVR8X, {0x1E, 0x93, 0x2A}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3c00, 0x0400, 10, 1, 40}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega1608", 321, F_AVR8X, {0x1E, 0x94, 0x27}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 36}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega1609", 322, F_AVR8X, {0x1E, 0x94, 0x26}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0100, 32, 0x3800, 0x0800, 10, 1, 40}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega3208", 323, F_AVR8X, {0x1E, 0x95, 0x30}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3000, 0x1000, 10, 1, 36}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega3209", 324, F_AVR8X, {0x1E, 0x95, 0x31}, 0, 0x08000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x3000, 0x1000, 10, 1, 40}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega4808", 325, F_AVR8X, {0x1E, 0x96, 0x50}, 0, 0x0c000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x2800, 0x1800, 10, 1, 36}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"ATmega4809", 326, F_AVR8X, {0x1E, 0x96, 0x51}, 0, 0x0c000, 0x080, 1, 0, 0x01400, 0x0100, 64, 0x2800, 0x1800, 10, 1, 40}, // atdf, avr-gcc 12.2.0, avrdude
|
|
||||||
{"AVR8EA28", 327, F_AVR8X, {0x1E, 0x93, 0x2C}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
|
|
||||||
{"AVR8EA32", 328, F_AVR8X, {0x1E, 0x93, 0x2B}, 0, 0x02000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
|
|
||||||
{"AVR16DD14", 329, F_AVR8X, {0x1E, 0x94, 0x34}, 0, 0x04000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7800, 0x0800, 16, 4, 36}, // atdf, avrdude
|
|
||||||
{"AVR16DD20", 330, F_AVR8X, {0x1E, 0x94, 0x33}, 0, 0x04000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7800, 0x0800, 16, 4, 36}, // atdf, avrdude
|
|
||||||
{"AVR16DD28", 331, F_AVR8X, {0x1E, 0x94, 0x32}, 0, 0x04000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7800, 0x0800, 16, 4, 36}, // atdf, avrdude
|
|
||||||
{"AVR16EA28", 332, F_AVR8X, {0x1E, 0x94, 0x37}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
|
|
||||||
{"AVR16DD32", 333, F_AVR8X, {0x1E, 0x94, 0x31}, 0, 0x04000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7800, 0x0800, 16, 4, 36}, // atdf, avrdude
|
|
||||||
{"AVR16EA32", 334, F_AVR8X, {0x1E, 0x94, 0x36}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
|
|
||||||
{"AVR16EA48", 335, F_AVR8X, {0x1E, 0x94, 0x35}, 0, 0x04000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
|
|
||||||
{"AVR32DD14", 336, F_AVR8X, {0x1E, 0x95, 0x3B}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7000, 0x1000, 16, 4, 36}, // atdf, avrdude
|
|
||||||
{"AVR32DD20", 337, F_AVR8X, {0x1E, 0x95, 0x3A}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7000, 0x1000, 16, 4, 36}, // atdf, avrdude
|
|
||||||
{"AVR32DA28", 338, F_AVR8X, {0x1E, 0x95, 0x34}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 41}, // atdf, avrdude
|
|
||||||
{"AVR32DB28", 339, F_AVR8X, {0x1E, 0x95, 0x37}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 42}, // atdf, avrdude
|
|
||||||
{"AVR32DD28", 340, F_AVR8X, {0x1E, 0x95, 0x39}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7000, 0x1000, 16, 4, 36}, // atdf, avrdude
|
|
||||||
{"AVR32EA28", 341, F_AVR8X, {0x1E, 0x95, 0x3E}, 0, 0x08000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
|
|
||||||
{"AVR32DA32", 342, F_AVR8X, {0x1E, 0x95, 0x33}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 44}, // atdf, avrdude
|
|
||||||
{"AVR32DB32", 343, F_AVR8X, {0x1E, 0x95, 0x36}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 44}, // atdf, avrdude
|
|
||||||
{"AVR32DD32", 344, F_AVR8X, {0x1E, 0x95, 0x38}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x7000, 0x1000, 16, 4, 36}, // atdf, avrdude
|
|
||||||
{"AVR32EA32", 345, F_AVR8X, {0x1E, 0x95, 0x3D}, 0, 0x08000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
|
|
||||||
{"AVR32DA48", 346, F_AVR8X, {0x1E, 0x95, 0x32}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 58}, // atdf, avrdude
|
|
||||||
{"AVR32DB48", 347, F_AVR8X, {0x1E, 0x95, 0x35}, 0, 0x08000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x7000, 0x1000, 16, 4, 61}, // atdf, avrdude
|
|
||||||
{"AVR32EA48", 348, F_AVR8X, {0x1E, 0x95, 0x3C}, 0, 0x08000, 0x040, 1, 0, 0x01400, 0x0200, 8, -1, -1, -1, -1, 0}, // avrdude
|
|
||||||
{"AVR64DD14", 349, F_AVR8X, {0x1E, 0x96, 0x1D}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x6000, 0x2000, 16, 4, 36}, // atdf, avrdude
|
|
||||||
{"AVR64DD20", 350, F_AVR8X, {0x1E, 0x96, 0x1C}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x6000, 0x2000, 16, 4, 36}, // atdf, avrdude
|
|
||||||
{"AVR64DA28", 351, F_AVR8X, {0x1E, 0x96, 0x15}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 41}, // atdf, avrdude
|
|
||||||
{"AVR64DB28", 352, F_AVR8X, {0x1E, 0x96, 0x19}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 42}, // atdf, avrdude
|
|
||||||
{"AVR64DD28", 353, F_AVR8X, {0x1E, 0x96, 0x1B}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x6000, 0x2000, 16, 4, 36}, // atdf, avrdude
|
|
||||||
{"AVR64EA28", 354, F_AVR8X, {0x1E, 0x96, 0x20}, 0, 0x10000, 0x080, 1, 0, 0x01400, 0x0200, 8, 0x6800, 0x1800, 16, 4, 37}, // atdf, avrdude
|
|
||||||
{"AVR64DA32", 355, F_AVR8X, {0x1E, 0x96, 0x14}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 44}, // atdf, avrdude
|
|
||||||
{"AVR64DB32", 356, F_AVR8X, {0x1E, 0x96, 0x18}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 44}, // atdf, avrdude
|
|
||||||
{"AVR64DD32", 357, F_AVR8X, {0x1E, 0x96, 0x1A}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0100, 1, 0x6000, 0x2000, 16, 4, 36}, // atdf, avrdude
|
|
||||||
{"AVR64EA32", 358, F_AVR8X, {0x1E, 0x96, 0x1F}, 0, 0x10000, 0x080, 1, 0, 0x01400, 0x0200, 8, 0x6800, 0x1800, 16, 4, 37}, // atdf, avrdude
|
|
||||||
{"AVR64DA48", 359, F_AVR8X, {0x1E, 0x96, 0x13}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 58}, // atdf, avrdude
|
|
||||||
{"AVR64DB48", 360, F_AVR8X, {0x1E, 0x96, 0x17}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 61}, // atdf, avrdude
|
|
||||||
{"AVR64EA48", 361, F_AVR8X, {0x1E, 0x96, 0x1E}, 0, 0x10000, 0x080, 1, 0, 0x01400, 0x0200, 8, 0x6800, 0x1800, 16, 4, 45}, // atdf, avrdude
|
|
||||||
{"AVR64DA64", 362, F_AVR8X, {0x1E, 0x96, 0x12}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 64}, // atdf, avrdude
|
|
||||||
{"AVR64DB64", 363, F_AVR8X, {0x1E, 0x96, 0x16}, 0, 0x10000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x6000, 0x2000, 16, 4, 65}, // atdf, avrdude
|
|
||||||
{"AVR128DA28", 364, F_AVR8X, {0x1E, 0x97, 0x0A}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 41}, // atdf, avrdude
|
|
||||||
{"AVR128DB28", 365, F_AVR8X, {0x1E, 0x97, 0x0E}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 42}, // atdf, avrdude
|
|
||||||
{"AVR128DA32", 366, F_AVR8X, {0x1E, 0x97, 0x09}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 44}, // atdf, avrdude
|
|
||||||
{"AVR128DB32", 367, F_AVR8X, {0x1E, 0x97, 0x0D}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 44}, // atdf, avrdude
|
|
||||||
{"AVR128DA48", 368, F_AVR8X, {0x1E, 0x97, 0x08}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 58}, // atdf, avrdude
|
|
||||||
{"AVR128DB48", 369, F_AVR8X, {0x1E, 0x97, 0x0C}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 61}, // atdf, avrdude
|
|
||||||
{"AVR128DA64", 370, F_AVR8X, {0x1E, 0x97, 0x07}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 64}, // atdf, avrdude
|
|
||||||
{"AVR128DB64", 371, F_AVR8X, {0x1E, 0x97, 0x0B}, 0, 0x20000, 0x200, 1, 0, 0x01400, 0x0200, 1, 0x4000, 0x4000, 16, 4, 65}, // atdf, avrdude
|
|
||||||
};
|
|
||||||
|
|
||||||
const size_t avr_isp_chip_arr_size = COUNT_OF(avr_isp_chip_arr);
|
|
|
@ -1,33 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <furi_hal.h>
|
|
||||||
|
|
||||||
#define F_AVR8L 1 // TPI programming, ATtiny(4|5|9|10|20|40|102|104)
|
|
||||||
#define F_AVR8 2 // ISP programming with SPI, "classic" AVRs
|
|
||||||
#define F_XMEGA 4 // PDI programming, ATxmega family
|
|
||||||
#define F_AVR8X 8 // UPDI programming, newer 8-bit MCUs
|
|
||||||
|
|
||||||
struct AvrIspChipArr { // Value of -1 typically means unknown
|
|
||||||
const char* name; // Name of part
|
|
||||||
uint16_t mcuid; // ID of MCU in 0..2039
|
|
||||||
uint8_t avrarch; // F_AVR8L, F_AVR8, F_XMEGA or F_AVR8X
|
|
||||||
uint8_t sigs[3]; // Signature bytes
|
|
||||||
int32_t flashoffset; // Flash offset
|
|
||||||
int32_t flashsize; // Flash size
|
|
||||||
int16_t pagesize; // Flash page size
|
|
||||||
int8_t nboots; // Number of supported boot sectors
|
|
||||||
int16_t bootsize; // Size of (smallest) boot sector
|
|
||||||
int32_t eepromoffset; // EEPROM offset
|
|
||||||
int32_t eepromsize; // EEPROM size
|
|
||||||
int32_t eeprompagesize; // EEPROM page size
|
|
||||||
int32_t sramstart; // SRAM offset
|
|
||||||
int32_t sramsize; // SRAM size
|
|
||||||
int8_t nfuses; // Number of fuse bytes
|
|
||||||
int8_t nlocks; // Number of lock bytes
|
|
||||||
uint8_t ninterrupts; // Number of vectors in interrupt vector table
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct AvrIspChipArr AvrIspChipArr;
|
|
||||||
|
|
||||||
extern const AvrIspChipArr avr_isp_chip_arr[];
|
|
||||||
extern const size_t avr_isp_chip_arr_size;
|
|
|
@ -1,639 +0,0 @@
|
||||||
#include "avr_isp_prog.h"
|
|
||||||
#include "avr_isp_prog_cmd.h"
|
|
||||||
|
|
||||||
#include <furi.h>
|
|
||||||
|
|
||||||
#define AVR_ISP_PROG_TX_RX_BUF_SIZE 320
|
|
||||||
#define TAG "AvrIspProg"
|
|
||||||
|
|
||||||
struct AvrIspProgSignature {
|
|
||||||
uint8_t vendor;
|
|
||||||
uint8_t part_family;
|
|
||||||
uint8_t part_number;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct AvrIspProgSignature AvrIspProgSignature;
|
|
||||||
|
|
||||||
struct AvrIspProgCfgDevice {
|
|
||||||
uint8_t devicecode;
|
|
||||||
uint8_t revision;
|
|
||||||
uint8_t progtype;
|
|
||||||
uint8_t parmode;
|
|
||||||
uint8_t polling;
|
|
||||||
uint8_t selftimed;
|
|
||||||
uint8_t lockbytes;
|
|
||||||
uint8_t fusebytes;
|
|
||||||
uint8_t flashpoll;
|
|
||||||
uint16_t eeprompoll;
|
|
||||||
uint16_t pagesize;
|
|
||||||
uint16_t eepromsize;
|
|
||||||
uint32_t flashsize;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct AvrIspProgCfgDevice AvrIspProgCfgDevice;
|
|
||||||
|
|
||||||
struct AvrIspProg {
|
|
||||||
AvrIspSpiSw* spi;
|
|
||||||
AvrIspProgCfgDevice* cfg;
|
|
||||||
FuriStreamBuffer* stream_rx;
|
|
||||||
FuriStreamBuffer* stream_tx;
|
|
||||||
|
|
||||||
uint16_t error;
|
|
||||||
uint16_t addr;
|
|
||||||
bool pmode;
|
|
||||||
bool exit;
|
|
||||||
bool rst_active_high;
|
|
||||||
uint8_t buff[AVR_ISP_PROG_TX_RX_BUF_SIZE];
|
|
||||||
|
|
||||||
AvrIspProgCallback callback;
|
|
||||||
void* context;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void avr_isp_prog_end_pmode(AvrIspProg* instance);
|
|
||||||
|
|
||||||
AvrIspProg* avr_isp_prog_init(void) {
|
|
||||||
AvrIspProg* instance = malloc(sizeof(AvrIspProg));
|
|
||||||
instance->cfg = malloc(sizeof(AvrIspProgCfgDevice));
|
|
||||||
instance->stream_rx =
|
|
||||||
furi_stream_buffer_alloc(sizeof(int8_t) * AVR_ISP_PROG_TX_RX_BUF_SIZE, sizeof(int8_t));
|
|
||||||
instance->stream_tx =
|
|
||||||
furi_stream_buffer_alloc(sizeof(int8_t) * AVR_ISP_PROG_TX_RX_BUF_SIZE, sizeof(int8_t));
|
|
||||||
instance->rst_active_high = false;
|
|
||||||
instance->exit = false;
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_prog_free(AvrIspProg* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
if(instance->spi) avr_isp_prog_end_pmode(instance);
|
|
||||||
furi_stream_buffer_free(instance->stream_tx);
|
|
||||||
furi_stream_buffer_free(instance->stream_rx);
|
|
||||||
free(instance->cfg);
|
|
||||||
free(instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t avr_isp_prog_spaces_rx(AvrIspProg* instance) {
|
|
||||||
return furi_stream_buffer_spaces_available(instance->stream_rx);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_prog_rx(AvrIspProg* instance, uint8_t* data, size_t len) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_assert(data);
|
|
||||||
furi_assert(len != 0);
|
|
||||||
size_t ret = furi_stream_buffer_send(instance->stream_rx, data, sizeof(uint8_t) * len, 0);
|
|
||||||
return ret == sizeof(uint8_t) * len;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t avr_isp_prog_tx(AvrIspProg* instance, uint8_t* data, size_t max_len) {
|
|
||||||
furi_assert(instance);
|
|
||||||
return furi_stream_buffer_receive(instance->stream_tx, data, sizeof(int8_t) * max_len, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_prog_exit(AvrIspProg* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
instance->exit = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_prog_set_tx_callback(AvrIspProg* instance, AvrIspProgCallback callback, void* context) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_assert(context);
|
|
||||||
instance->callback = callback;
|
|
||||||
instance->context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_prog_tx_ch(AvrIspProg* instance, uint8_t data) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_stream_buffer_send(instance->stream_tx, &data, sizeof(uint8_t), FuriWaitForever);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t avr_isp_prog_getch(AvrIspProg* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
uint8_t data[1] = {0};
|
|
||||||
while(furi_stream_buffer_receive(instance->stream_rx, &data, sizeof(int8_t), 30) == 0) {
|
|
||||||
if(instance->exit) break;
|
|
||||||
};
|
|
||||||
return data[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_prog_fill(AvrIspProg* instance, size_t len) {
|
|
||||||
furi_assert(instance);
|
|
||||||
for(size_t x = 0; x < len; x++) {
|
|
||||||
instance->buff[x] = avr_isp_prog_getch(instance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_prog_reset_target(AvrIspProg* instance, bool reset) {
|
|
||||||
furi_assert(instance);
|
|
||||||
avr_isp_spi_sw_res_set(instance->spi, (reset == instance->rst_active_high) ? true : false);
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t avr_isp_prog_spi_transaction(
|
|
||||||
AvrIspProg* instance,
|
|
||||||
uint8_t cmd,
|
|
||||||
uint8_t addr_hi,
|
|
||||||
uint8_t addr_lo,
|
|
||||||
uint8_t data) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
avr_isp_spi_sw_txrx(instance->spi, cmd);
|
|
||||||
avr_isp_spi_sw_txrx(instance->spi, addr_hi);
|
|
||||||
avr_isp_spi_sw_txrx(instance->spi, addr_lo);
|
|
||||||
return avr_isp_spi_sw_txrx(instance->spi, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_prog_empty_reply(AvrIspProg* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
if(avr_isp_prog_getch(instance) == CRC_EOP) {
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_INSYNC);
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_OK);
|
|
||||||
} else {
|
|
||||||
instance->error++;
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_prog_breply(AvrIspProg* instance, uint8_t data) {
|
|
||||||
furi_assert(instance);
|
|
||||||
if(avr_isp_prog_getch(instance) == CRC_EOP) {
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_INSYNC);
|
|
||||||
avr_isp_prog_tx_ch(instance, data);
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_OK);
|
|
||||||
} else {
|
|
||||||
instance->error++;
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_prog_get_version(AvrIspProg* instance, uint8_t data) {
|
|
||||||
furi_assert(instance);
|
|
||||||
switch(data) {
|
|
||||||
case STK_HW_VER:
|
|
||||||
avr_isp_prog_breply(instance, AVR_ISP_HWVER);
|
|
||||||
break;
|
|
||||||
case STK_SW_MAJOR:
|
|
||||||
avr_isp_prog_breply(instance, AVR_ISP_SWMAJ);
|
|
||||||
break;
|
|
||||||
case STK_SW_MINOR:
|
|
||||||
avr_isp_prog_breply(instance, AVR_ISP_SWMIN);
|
|
||||||
break;
|
|
||||||
case AVP_ISP_CONNECT_TYPE:
|
|
||||||
avr_isp_prog_breply(instance, AVP_ISP_SERIAL_CONNECT_TYPE);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
avr_isp_prog_breply(instance, AVR_ISP_RESP_0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_prog_set_cfg(AvrIspProg* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
// call this after reading cfg packet into buff[]
|
|
||||||
instance->cfg->devicecode = instance->buff[0];
|
|
||||||
instance->cfg->revision = instance->buff[1];
|
|
||||||
instance->cfg->progtype = instance->buff[2];
|
|
||||||
instance->cfg->parmode = instance->buff[3];
|
|
||||||
instance->cfg->polling = instance->buff[4];
|
|
||||||
instance->cfg->selftimed = instance->buff[5];
|
|
||||||
instance->cfg->lockbytes = instance->buff[6];
|
|
||||||
instance->cfg->fusebytes = instance->buff[7];
|
|
||||||
instance->cfg->flashpoll = instance->buff[8];
|
|
||||||
// ignore (instance->buff[9] == instance->buff[8]) //FLASH polling value. Same as “flashpoll”
|
|
||||||
instance->cfg->eeprompoll = instance->buff[10] << 8 | instance->buff[11];
|
|
||||||
instance->cfg->pagesize = instance->buff[12] << 8 | instance->buff[13];
|
|
||||||
instance->cfg->eepromsize = instance->buff[14] << 8 | instance->buff[15];
|
|
||||||
instance->cfg->flashsize = instance->buff[16] << 24 | instance->buff[17] << 16 |
|
|
||||||
instance->buff[18] << 8 | instance->buff[19];
|
|
||||||
|
|
||||||
// avr devices have active low reset, at89sx are active high
|
|
||||||
instance->rst_active_high = (instance->cfg->devicecode >= 0xe0);
|
|
||||||
}
|
|
||||||
static bool
|
|
||||||
avr_isp_prog_set_pmode(AvrIspProg* instance, uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
|
|
||||||
furi_assert(instance);
|
|
||||||
uint8_t res = 0;
|
|
||||||
avr_isp_spi_sw_txrx(instance->spi, a);
|
|
||||||
avr_isp_spi_sw_txrx(instance->spi, b);
|
|
||||||
res = avr_isp_spi_sw_txrx(instance->spi, c);
|
|
||||||
avr_isp_spi_sw_txrx(instance->spi, d);
|
|
||||||
return res == 0x53;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_prog_end_pmode(AvrIspProg* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
if(instance->pmode) {
|
|
||||||
avr_isp_prog_reset_target(instance, false);
|
|
||||||
// We're about to take the target out of reset
|
|
||||||
// so configure SPI pins as input
|
|
||||||
|
|
||||||
if(instance->spi) avr_isp_spi_sw_free(instance->spi);
|
|
||||||
instance->spi = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
instance->pmode = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool avr_isp_prog_start_pmode(AvrIspProg* instance, AvrIspSpiSwSpeed spi_speed) {
|
|
||||||
furi_assert(instance);
|
|
||||||
// Reset target before driving PIN_SCK or PIN_MOSI
|
|
||||||
|
|
||||||
// SPI.begin() will configure SS as output,
|
|
||||||
// so SPI master mode is selected.
|
|
||||||
// We have defined RESET as pin 10,
|
|
||||||
// which for many arduino's is not the SS pin.
|
|
||||||
// So we have to configure RESET as output here,
|
|
||||||
// (reset_target() first sets the correct level)
|
|
||||||
if(instance->spi) avr_isp_spi_sw_free(instance->spi);
|
|
||||||
instance->spi = avr_isp_spi_sw_init(spi_speed);
|
|
||||||
|
|
||||||
avr_isp_prog_reset_target(instance, true);
|
|
||||||
// See avr datasheets, chapter "SERIAL_PRG Programming Algorithm":
|
|
||||||
|
|
||||||
// Pulse RESET after PIN_SCK is low:
|
|
||||||
avr_isp_spi_sw_sck_set(instance->spi, false);
|
|
||||||
|
|
||||||
// discharge PIN_SCK, value arbitrally chosen
|
|
||||||
furi_delay_ms(20);
|
|
||||||
avr_isp_prog_reset_target(instance, false);
|
|
||||||
|
|
||||||
// Pulse must be minimum 2 target CPU speed cycles
|
|
||||||
// so 100 usec is ok for CPU speeds above 20KHz
|
|
||||||
furi_delay_ms(1);
|
|
||||||
|
|
||||||
avr_isp_prog_reset_target(instance, true);
|
|
||||||
|
|
||||||
// Send the enable programming command:
|
|
||||||
// datasheet: must be > 20 msec
|
|
||||||
furi_delay_ms(50);
|
|
||||||
if(avr_isp_prog_set_pmode(instance, AVR_ISP_SET_PMODE)) {
|
|
||||||
instance->pmode = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static AvrIspProgSignature avr_isp_prog_check_signature(AvrIspProg* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
AvrIspProgSignature signature;
|
|
||||||
signature.vendor = avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_VENDOR);
|
|
||||||
signature.part_family = avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_PART_FAMILY);
|
|
||||||
signature.part_number = avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_PART_NUMBER);
|
|
||||||
return signature;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool avr_isp_prog_auto_set_spi_speed_start_pmode(AvrIspProg* instance) {
|
|
||||||
AvrIspSpiSwSpeed spi_speed[] = {
|
|
||||||
AvrIspSpiSwSpeed1Mhz,
|
|
||||||
AvrIspSpiSwSpeed400Khz,
|
|
||||||
AvrIspSpiSwSpeed250Khz,
|
|
||||||
AvrIspSpiSwSpeed125Khz,
|
|
||||||
AvrIspSpiSwSpeed60Khz,
|
|
||||||
AvrIspSpiSwSpeed40Khz,
|
|
||||||
AvrIspSpiSwSpeed20Khz,
|
|
||||||
AvrIspSpiSwSpeed10Khz,
|
|
||||||
AvrIspSpiSwSpeed5Khz,
|
|
||||||
AvrIspSpiSwSpeed1Khz,
|
|
||||||
};
|
|
||||||
for(uint8_t i = 0; i < COUNT_OF(spi_speed); i++) {
|
|
||||||
if(avr_isp_prog_start_pmode(instance, spi_speed[i])) {
|
|
||||||
AvrIspProgSignature sig = avr_isp_prog_check_signature(instance);
|
|
||||||
AvrIspProgSignature sig_examination = avr_isp_prog_check_signature(instance); //-V656
|
|
||||||
uint8_t y = 0;
|
|
||||||
while(y < 8) {
|
|
||||||
if(memcmp(
|
|
||||||
(uint8_t*)&sig, (uint8_t*)&sig_examination, sizeof(AvrIspProgSignature)) !=
|
|
||||||
0)
|
|
||||||
break;
|
|
||||||
sig_examination = avr_isp_prog_check_signature(instance);
|
|
||||||
y++;
|
|
||||||
}
|
|
||||||
if(y == 8) {
|
|
||||||
if(spi_speed[i] > AvrIspSpiSwSpeed1Mhz) {
|
|
||||||
if(i < (COUNT_OF(spi_speed) - 1)) {
|
|
||||||
avr_isp_prog_end_pmode(instance);
|
|
||||||
i++;
|
|
||||||
return avr_isp_prog_start_pmode(instance, spi_speed[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(instance->spi) {
|
|
||||||
avr_isp_spi_sw_free(instance->spi);
|
|
||||||
instance->spi = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_prog_universal(AvrIspProg* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
uint8_t data;
|
|
||||||
|
|
||||||
avr_isp_prog_fill(instance, 4);
|
|
||||||
data = avr_isp_prog_spi_transaction(
|
|
||||||
instance, instance->buff[0], instance->buff[1], instance->buff[2], instance->buff[3]);
|
|
||||||
avr_isp_prog_breply(instance, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_prog_commit(AvrIspProg* instance, uint16_t addr, uint8_t data) {
|
|
||||||
furi_assert(instance);
|
|
||||||
avr_isp_prog_spi_transaction(instance, AVR_ISP_COMMIT(addr));
|
|
||||||
/* polling flash */
|
|
||||||
if(data == 0xFF) {
|
|
||||||
furi_delay_ms(5);
|
|
||||||
} else {
|
|
||||||
/* polling flash */
|
|
||||||
uint32_t starttime = furi_get_tick();
|
|
||||||
while((furi_get_tick() - starttime) < 30) {
|
|
||||||
if(avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_FLASH_HI(addr)) != 0xFF) {
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint16_t avr_isp_prog_current_page(AvrIspProg* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
uint16_t page = 0;
|
|
||||||
switch(instance->cfg->pagesize) {
|
|
||||||
case 32:
|
|
||||||
page = instance->addr & 0xFFFFFFF0;
|
|
||||||
break;
|
|
||||||
case 64:
|
|
||||||
page = instance->addr & 0xFFFFFFE0;
|
|
||||||
break;
|
|
||||||
case 128:
|
|
||||||
page = instance->addr & 0xFFFFFFC0;
|
|
||||||
break;
|
|
||||||
case 256:
|
|
||||||
page = instance->addr & 0xFFFFFF80;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
page = instance->addr;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return page;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t avr_isp_prog_write_flash_pages(AvrIspProg* instance, size_t length) {
|
|
||||||
furi_assert(instance);
|
|
||||||
size_t x = 0;
|
|
||||||
uint16_t page = avr_isp_prog_current_page(instance);
|
|
||||||
while(x < length) {
|
|
||||||
if(page != avr_isp_prog_current_page(instance)) {
|
|
||||||
--x;
|
|
||||||
avr_isp_prog_commit(instance, page, instance->buff[x++]);
|
|
||||||
page = avr_isp_prog_current_page(instance);
|
|
||||||
}
|
|
||||||
avr_isp_prog_spi_transaction(
|
|
||||||
instance, AVR_ISP_WRITE_FLASH_LO(instance->addr, instance->buff[x++]));
|
|
||||||
|
|
||||||
avr_isp_prog_spi_transaction(
|
|
||||||
instance, AVR_ISP_WRITE_FLASH_HI(instance->addr, instance->buff[x++]));
|
|
||||||
instance->addr++;
|
|
||||||
}
|
|
||||||
|
|
||||||
avr_isp_prog_commit(instance, page, instance->buff[--x]);
|
|
||||||
return STK_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_prog_write_flash(AvrIspProg* instance, size_t length) {
|
|
||||||
furi_assert(instance);
|
|
||||||
avr_isp_prog_fill(instance, length);
|
|
||||||
if(avr_isp_prog_getch(instance) == CRC_EOP) {
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_INSYNC);
|
|
||||||
avr_isp_prog_tx_ch(instance, avr_isp_prog_write_flash_pages(instance, length));
|
|
||||||
} else {
|
|
||||||
instance->error++;
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// write (length) bytes, (start) is a byte address
|
|
||||||
static uint8_t
|
|
||||||
avr_isp_prog_write_eeprom_chunk(AvrIspProg* instance, uint16_t start, uint16_t length) {
|
|
||||||
furi_assert(instance);
|
|
||||||
// this writes byte-by-byte,
|
|
||||||
// page writing may be faster (4 bytes at a time)
|
|
||||||
avr_isp_prog_fill(instance, length);
|
|
||||||
for(uint16_t x = 0; x < length; x++) {
|
|
||||||
uint16_t addr = start + x;
|
|
||||||
avr_isp_prog_spi_transaction(instance, AVR_ISP_WRITE_EEPROM(addr, instance->buff[x]));
|
|
||||||
furi_delay_ms(10);
|
|
||||||
}
|
|
||||||
return STK_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t avr_isp_prog_write_eeprom(AvrIspProg* instance, size_t length) {
|
|
||||||
furi_assert(instance);
|
|
||||||
// here is a word address, get the byte address
|
|
||||||
uint16_t start = instance->addr * 2;
|
|
||||||
uint16_t remaining = length;
|
|
||||||
if(length > instance->cfg->eepromsize) {
|
|
||||||
instance->error++;
|
|
||||||
return STK_FAILED;
|
|
||||||
}
|
|
||||||
while(remaining > AVR_ISP_EECHUNK) {
|
|
||||||
avr_isp_prog_write_eeprom_chunk(instance, start, AVR_ISP_EECHUNK);
|
|
||||||
start += AVR_ISP_EECHUNK;
|
|
||||||
remaining -= AVR_ISP_EECHUNK;
|
|
||||||
}
|
|
||||||
avr_isp_prog_write_eeprom_chunk(instance, start, remaining);
|
|
||||||
return STK_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_prog_program_page(AvrIspProg* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
uint8_t result = STK_FAILED;
|
|
||||||
uint16_t length = avr_isp_prog_getch(instance) << 8 | avr_isp_prog_getch(instance);
|
|
||||||
uint8_t memtype = avr_isp_prog_getch(instance);
|
|
||||||
// flash memory @addr, (length) bytes
|
|
||||||
if(memtype == STK_SET_FLASH_TYPE) {
|
|
||||||
avr_isp_prog_write_flash(instance, length);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if(memtype == STK_SET_EEPROM_TYPE) {
|
|
||||||
result = avr_isp_prog_write_eeprom(instance, length);
|
|
||||||
if(avr_isp_prog_getch(instance) == CRC_EOP) {
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_INSYNC);
|
|
||||||
avr_isp_prog_tx_ch(instance, result);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
instance->error++;
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_FAILED);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t avr_isp_prog_flash_read_page(AvrIspProg* instance, uint16_t length) {
|
|
||||||
furi_assert(instance);
|
|
||||||
for(uint16_t x = 0; x < length; x += 2) {
|
|
||||||
avr_isp_prog_tx_ch(
|
|
||||||
instance,
|
|
||||||
avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_FLASH_LO(instance->addr)));
|
|
||||||
avr_isp_prog_tx_ch(
|
|
||||||
instance,
|
|
||||||
avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_FLASH_HI(instance->addr)));
|
|
||||||
instance->addr++;
|
|
||||||
}
|
|
||||||
return STK_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint8_t avr_isp_prog_eeprom_read_page(AvrIspProg* instance, uint16_t length) {
|
|
||||||
furi_assert(instance);
|
|
||||||
// here again we have a word address
|
|
||||||
uint16_t start = instance->addr * 2;
|
|
||||||
for(uint16_t x = 0; x < length; x++) {
|
|
||||||
uint16_t addr = start + x;
|
|
||||||
avr_isp_prog_tx_ch(
|
|
||||||
instance, avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_EEPROM(addr)));
|
|
||||||
}
|
|
||||||
return STK_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_prog_read_page(AvrIspProg* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
uint8_t result = STK_FAILED;
|
|
||||||
uint16_t length = avr_isp_prog_getch(instance) << 8 | avr_isp_prog_getch(instance);
|
|
||||||
uint8_t memtype = avr_isp_prog_getch(instance);
|
|
||||||
if(avr_isp_prog_getch(instance) != CRC_EOP) {
|
|
||||||
instance->error++;
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_INSYNC);
|
|
||||||
if(memtype == STK_SET_FLASH_TYPE) result = avr_isp_prog_flash_read_page(instance, length);
|
|
||||||
if(memtype == STK_SET_EEPROM_TYPE) result = avr_isp_prog_eeprom_read_page(instance, length);
|
|
||||||
avr_isp_prog_tx_ch(instance, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_prog_read_signature(AvrIspProg* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
if(avr_isp_prog_getch(instance) != CRC_EOP) {
|
|
||||||
instance->error++;
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_INSYNC);
|
|
||||||
|
|
||||||
avr_isp_prog_tx_ch(instance, avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_VENDOR));
|
|
||||||
avr_isp_prog_tx_ch(instance, avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_PART_FAMILY));
|
|
||||||
avr_isp_prog_tx_ch(instance, avr_isp_prog_spi_transaction(instance, AVR_ISP_READ_PART_NUMBER));
|
|
||||||
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_OK);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_prog_avrisp(AvrIspProg* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
uint8_t ch = avr_isp_prog_getch(instance);
|
|
||||||
|
|
||||||
switch(ch) {
|
|
||||||
case STK_GET_SYNC:
|
|
||||||
FURI_LOG_D(TAG, "cmd STK_GET_SYNC");
|
|
||||||
instance->error = 0;
|
|
||||||
avr_isp_prog_empty_reply(instance);
|
|
||||||
break;
|
|
||||||
case STK_GET_SIGN_ON:
|
|
||||||
FURI_LOG_D(TAG, "cmd STK_GET_SIGN_ON");
|
|
||||||
if(avr_isp_prog_getch(instance) == CRC_EOP) {
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_INSYNC);
|
|
||||||
|
|
||||||
avr_isp_prog_tx_ch(instance, 'A');
|
|
||||||
avr_isp_prog_tx_ch(instance, 'V');
|
|
||||||
avr_isp_prog_tx_ch(instance, 'R');
|
|
||||||
avr_isp_prog_tx_ch(instance, ' ');
|
|
||||||
avr_isp_prog_tx_ch(instance, 'I');
|
|
||||||
avr_isp_prog_tx_ch(instance, 'S');
|
|
||||||
avr_isp_prog_tx_ch(instance, 'P');
|
|
||||||
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_OK);
|
|
||||||
} else {
|
|
||||||
instance->error++;
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case STK_GET_PARAMETER:
|
|
||||||
FURI_LOG_D(TAG, "cmd STK_GET_PARAMETER");
|
|
||||||
avr_isp_prog_get_version(instance, avr_isp_prog_getch(instance));
|
|
||||||
break;
|
|
||||||
case STK_SET_DEVICE:
|
|
||||||
FURI_LOG_D(TAG, "cmd STK_SET_DEVICE");
|
|
||||||
avr_isp_prog_fill(instance, 20);
|
|
||||||
avr_isp_prog_set_cfg(instance);
|
|
||||||
avr_isp_prog_empty_reply(instance);
|
|
||||||
break;
|
|
||||||
case STK_SET_DEVICE_EXT: // ignore for now
|
|
||||||
FURI_LOG_D(TAG, "cmd STK_SET_DEVICE_EXT");
|
|
||||||
avr_isp_prog_fill(instance, 5);
|
|
||||||
avr_isp_prog_empty_reply(instance);
|
|
||||||
break;
|
|
||||||
case STK_ENTER_PROGMODE:
|
|
||||||
FURI_LOG_D(TAG, "cmd STK_ENTER_PROGMODE");
|
|
||||||
if(!instance->pmode) avr_isp_prog_auto_set_spi_speed_start_pmode(instance);
|
|
||||||
avr_isp_prog_empty_reply(instance);
|
|
||||||
break;
|
|
||||||
case STK_LOAD_ADDRESS:
|
|
||||||
FURI_LOG_D(TAG, "cmd STK_LOAD_ADDRESS");
|
|
||||||
instance->addr = avr_isp_prog_getch(instance) | avr_isp_prog_getch(instance) << 8;
|
|
||||||
avr_isp_prog_empty_reply(instance);
|
|
||||||
break;
|
|
||||||
case STK_PROG_FLASH: // ignore for now
|
|
||||||
FURI_LOG_D(TAG, "cmd STK_PROG_FLASH");
|
|
||||||
avr_isp_prog_getch(instance);
|
|
||||||
avr_isp_prog_getch(instance);
|
|
||||||
avr_isp_prog_empty_reply(instance);
|
|
||||||
break;
|
|
||||||
case STK_PROG_DATA: // ignore for now
|
|
||||||
FURI_LOG_D(TAG, "cmd STK_PROG_DATA");
|
|
||||||
avr_isp_prog_getch(instance);
|
|
||||||
avr_isp_prog_empty_reply(instance);
|
|
||||||
break;
|
|
||||||
case STK_PROG_PAGE:
|
|
||||||
FURI_LOG_D(TAG, "cmd STK_PROG_PAGE");
|
|
||||||
avr_isp_prog_program_page(instance);
|
|
||||||
break;
|
|
||||||
case STK_READ_PAGE:
|
|
||||||
FURI_LOG_D(TAG, "cmd STK_READ_PAGE");
|
|
||||||
avr_isp_prog_read_page(instance);
|
|
||||||
break;
|
|
||||||
case STK_UNIVERSAL:
|
|
||||||
FURI_LOG_D(TAG, "cmd STK_UNIVERSAL");
|
|
||||||
avr_isp_prog_universal(instance);
|
|
||||||
break;
|
|
||||||
case STK_LEAVE_PROGMODE:
|
|
||||||
FURI_LOG_D(TAG, "cmd STK_LEAVE_PROGMODE");
|
|
||||||
instance->error = 0;
|
|
||||||
if(instance->pmode) avr_isp_prog_end_pmode(instance);
|
|
||||||
avr_isp_prog_empty_reply(instance);
|
|
||||||
break;
|
|
||||||
case STK_READ_SIGN:
|
|
||||||
FURI_LOG_D(TAG, "cmd STK_READ_SIGN");
|
|
||||||
avr_isp_prog_read_signature(instance);
|
|
||||||
break;
|
|
||||||
// expecting a command, not CRC_EOP
|
|
||||||
// this is how we can get back in sync
|
|
||||||
case CRC_EOP:
|
|
||||||
FURI_LOG_D(TAG, "cmd CRC_EOP");
|
|
||||||
instance->error++;
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
|
|
||||||
break;
|
|
||||||
// anything else we will return STK_UNKNOWN
|
|
||||||
default:
|
|
||||||
FURI_LOG_D(TAG, "cmd STK_ERROR_CMD");
|
|
||||||
instance->error++;
|
|
||||||
if(avr_isp_prog_getch(instance) == CRC_EOP)
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_UNKNOWN);
|
|
||||||
else
|
|
||||||
avr_isp_prog_tx_ch(instance, STK_NOSYNC);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(instance->callback) {
|
|
||||||
instance->callback(instance->context);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "avr_isp_spi_sw.h"
|
|
||||||
#include <furi_hal.h>
|
|
||||||
|
|
||||||
typedef struct AvrIspProg AvrIspProg;
|
|
||||||
typedef void (*AvrIspProgCallback)(void* context);
|
|
||||||
|
|
||||||
AvrIspProg* avr_isp_prog_init(void);
|
|
||||||
void avr_isp_prog_free(AvrIspProg* instance);
|
|
||||||
size_t avr_isp_prog_spaces_rx(AvrIspProg* instance) ;
|
|
||||||
bool avr_isp_prog_rx(AvrIspProg* instance, uint8_t* data, size_t len);
|
|
||||||
size_t avr_isp_prog_tx(AvrIspProg* instance, uint8_t* data, size_t max_len);
|
|
||||||
void avr_isp_prog_avrisp(AvrIspProg* instance);
|
|
||||||
void avr_isp_prog_exit(AvrIspProg* instance);
|
|
||||||
void avr_isp_prog_set_tx_callback(AvrIspProg* instance, AvrIspProgCallback callback, void* context);
|
|
|
@ -1,97 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
// http://ww1.microchip.com/downloads/en/appnotes/atmel-0943-in-system-programming_applicationnote_avr910.pdf
|
|
||||||
// AVR ISP Definitions
|
|
||||||
#define AVR_ISP_HWVER 0X02
|
|
||||||
#define AVR_ISP_SWMAJ 0X01
|
|
||||||
#define AVR_ISP_SWMIN 0X12
|
|
||||||
#define AVP_ISP_SERIAL_CONNECT_TYPE 0X53
|
|
||||||
#define AVP_ISP_CONNECT_TYPE 0x93
|
|
||||||
#define AVR_ISP_RESP_0 0X00
|
|
||||||
|
|
||||||
#define AVR_ISP_SET_PMODE 0xAC, 0x53, 0x00, 0x00
|
|
||||||
#define AVR_ISP_READ_VENDOR 0x30, 0x00, 0x00, 0x00
|
|
||||||
#define AVR_ISP_READ_PART_FAMILY 0x30, 0x00, 0x01, 0x00
|
|
||||||
#define AVR_ISP_READ_PART_NUMBER 0x30, 0x00, 0x02, 0x00
|
|
||||||
#define AVR_ISP_ERASE_CHIP \
|
|
||||||
0xAC, 0x80, 0x00, 0x00 //Erase Chip, Wait N ms, Release RESET to end the erase.
|
|
||||||
//The only way to end a Chip Erase cycle is by temporarily releasing the Reset line
|
|
||||||
|
|
||||||
#define AVR_ISP_EXTENDED_ADDR(data) 0x4D, 0x00, data, 0x00
|
|
||||||
#define AVR_ISP_WRITE_FLASH_LO(add, data) 0x40, (add >> 8) & 0xFF, add & 0xFF, data
|
|
||||||
#define AVR_ISP_WRITE_FLASH_HI(add, data) 0x48, (add >> 8) & 0xFF, add & 0xFF, data
|
|
||||||
#define AVR_ISP_READ_FLASH_LO(add) 0x20, (add >> 8) & 0xFF, add & 0xFF, 0x00
|
|
||||||
#define AVR_ISP_READ_FLASH_HI(add) 0x28, (add >> 8) & 0xFF, add & 0xFF, 0x00
|
|
||||||
|
|
||||||
#define AVR_ISP_WRITE_EEPROM(add, data) \
|
|
||||||
0xC0, (add >> 8) & 0xFF, add & 0xFF, data //Send cmd, Wait N ms
|
|
||||||
#define AVR_ISP_READ_EEPROM(add) 0xA0, (add >> 8) & 0xFF, add & 0xFF, 0xFF
|
|
||||||
|
|
||||||
#define AVR_ISP_COMMIT(add) \
|
|
||||||
0x4C, (add >> 8) & 0xFF, add & 0xFF, 0x00 //Send cmd, polling read last addr page
|
|
||||||
|
|
||||||
#define AVR_ISP_OSCCAL(add) 0x38, 0x00, add, 0x00
|
|
||||||
|
|
||||||
#define AVR_ISP_WRITE_LOCK_BYTE(data) 0xAC, 0xE0, 0x00, data //Send cmd, Wait N ms
|
|
||||||
#define AVR_ISP_READ_LOCK_BYTE 0x58, 0x00, 0x00, 0x00
|
|
||||||
#define AVR_ISP_WRITE_FUSE_LOW(data) 0xAC, 0xA0, 0x00, data //Send cmd, Wait N ms
|
|
||||||
#define AVR_ISP_READ_FUSE_LOW 0x50, 0x00, 0x00, 0x00
|
|
||||||
#define AVR_ISP_WRITE_FUSE_HIGH(data) 0xAC, 0xA8, 0x00, data //Send cmd, Wait N ms
|
|
||||||
#define AVR_ISP_READ_FUSE_HIGH 0x58, 0x08, 0x00, 0x00
|
|
||||||
#define AVR_ISP_WRITE_FUSE_EXTENDED(data) 0xAC, 0xA4, 0x00, data //Send cmd, Wait N ms (~write)
|
|
||||||
#define AVR_ISP_READ_FUSE_EXTENDED 0x50, 0x08, 0x00, 0x00
|
|
||||||
|
|
||||||
#define AVR_ISP_EECHUNK 0x20
|
|
||||||
|
|
||||||
// https://www.microchip.com/content/dam/mchp/documents/OTH/ApplicationNotes/ApplicationNotes/doc2525.pdf
|
|
||||||
// STK Definitions
|
|
||||||
#define STK_OK 0x10
|
|
||||||
#define STK_FAILED 0x11
|
|
||||||
#define STK_UNKNOWN 0x12
|
|
||||||
#define STK_INSYNC 0x14
|
|
||||||
#define STK_NOSYNC 0x15
|
|
||||||
#define CRC_EOP 0x20
|
|
||||||
|
|
||||||
#define STK_GET_SYNC 0x30
|
|
||||||
#define STK_GET_SIGN_ON 0x31
|
|
||||||
#define STK_SET_PARAMETER 0x40
|
|
||||||
#define STK_GET_PARAMETER 0x41
|
|
||||||
#define STK_SET_DEVICE 0x42
|
|
||||||
#define STK_SET_DEVICE_EXT 0x45
|
|
||||||
#define STK_ENTER_PROGMODE 0x50
|
|
||||||
#define STK_LEAVE_PROGMODE 0x51
|
|
||||||
#define STK_CHIP_ERASE 0x52
|
|
||||||
#define STK_CHECK_AUTOINC 0x53
|
|
||||||
#define STK_LOAD_ADDRESS 0x55
|
|
||||||
#define STK_UNIVERSAL 0x56
|
|
||||||
#define STK_UNIVERSAL_MULTI 0x57
|
|
||||||
#define STK_PROG_FLASH 0x60
|
|
||||||
#define STK_PROG_DATA 0x61
|
|
||||||
#define STK_PROG_FUSE 0x62
|
|
||||||
#define STK_PROG_FUSE_EXT 0x65
|
|
||||||
#define STK_PROG_LOCK 0x63
|
|
||||||
#define STK_PROG_PAGE 0x64
|
|
||||||
#define STK_READ_FLASH 0x70
|
|
||||||
#define STK_READ_DATA 0x71
|
|
||||||
#define STK_READ_FUSE 0x72
|
|
||||||
#define STK_READ_LOCK 0x73
|
|
||||||
#define STK_READ_PAGE 0x74
|
|
||||||
#define STK_READ_SIGN 0x75
|
|
||||||
#define STK_READ_OSCCAL 0x76
|
|
||||||
#define STK_READ_FUSE_EXT 0x77
|
|
||||||
#define STK_READ_OSCCAL_EXT 0x78
|
|
||||||
#define STK_HW_VER 0x80
|
|
||||||
#define STK_SW_MAJOR 0x81
|
|
||||||
#define STK_SW_MINOR 0x82
|
|
||||||
#define STK_LEDS 0x83
|
|
||||||
#define STK_VTARGET 0x84
|
|
||||||
#define STK_VADJUST 0x85
|
|
||||||
#define STK_OSC_PSCALE 0x86
|
|
||||||
#define STK_OSC_CMATCH 0x87
|
|
||||||
#define STK_SCK_DURATION 0x89
|
|
||||||
#define STK_BUFSIZEL 0x90
|
|
||||||
#define STK_BUFSIZEH 0x91
|
|
||||||
#define STK_STK500_TOPCARD_DETECT 0x98
|
|
||||||
|
|
||||||
#define STK_SET_EEPROM_TYPE 0X45
|
|
||||||
#define STK_SET_FLASH_TYPE 0X46
|
|
|
@ -1,71 +0,0 @@
|
||||||
#include "avr_isp_spi_sw.h"
|
|
||||||
|
|
||||||
#include <furi.h>
|
|
||||||
|
|
||||||
#define AVR_ISP_SPI_SW_MISO &gpio_ext_pa6
|
|
||||||
#define AVR_ISP_SPI_SW_MOSI &gpio_ext_pa7
|
|
||||||
#define AVR_ISP_SPI_SW_SCK &gpio_ext_pb3
|
|
||||||
#define AVR_ISP_RESET &gpio_ext_pb2
|
|
||||||
|
|
||||||
struct AvrIspSpiSw {
|
|
||||||
AvrIspSpiSwSpeed speed_wait_time;
|
|
||||||
const GpioPin* miso;
|
|
||||||
const GpioPin* mosi;
|
|
||||||
const GpioPin* sck;
|
|
||||||
const GpioPin* res;
|
|
||||||
};
|
|
||||||
|
|
||||||
AvrIspSpiSw* avr_isp_spi_sw_init(AvrIspSpiSwSpeed speed) {
|
|
||||||
AvrIspSpiSw* instance = malloc(sizeof(AvrIspSpiSw));
|
|
||||||
instance->speed_wait_time = speed;
|
|
||||||
instance->miso = AVR_ISP_SPI_SW_MISO;
|
|
||||||
instance->mosi = AVR_ISP_SPI_SW_MOSI;
|
|
||||||
instance->sck = AVR_ISP_SPI_SW_SCK;
|
|
||||||
instance->res = AVR_ISP_RESET;
|
|
||||||
|
|
||||||
furi_hal_gpio_init(instance->miso, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
|
|
||||||
furi_hal_gpio_write(instance->mosi, false);
|
|
||||||
furi_hal_gpio_init(instance->mosi, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
|
|
||||||
furi_hal_gpio_write(instance->sck, false);
|
|
||||||
furi_hal_gpio_init(instance->sck, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
|
|
||||||
furi_hal_gpio_init(instance->res, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
|
|
||||||
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_spi_sw_free(AvrIspSpiSw* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_hal_gpio_init(instance->res, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
|
||||||
furi_hal_gpio_init(instance->miso, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
|
||||||
furi_hal_gpio_init(instance->mosi, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
|
||||||
furi_hal_gpio_init(instance->sck, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
|
||||||
free(instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t avr_isp_spi_sw_txrx(AvrIspSpiSw* instance, uint8_t data) {
|
|
||||||
furi_assert(instance);
|
|
||||||
for(uint8_t i = 0; i < 8; ++i) {
|
|
||||||
furi_hal_gpio_write(instance->mosi, (data & 0x80) ? true : false);
|
|
||||||
|
|
||||||
furi_hal_gpio_write(instance->sck, true);
|
|
||||||
if(instance->speed_wait_time != AvrIspSpiSwSpeed1Mhz)
|
|
||||||
furi_delay_us(instance->speed_wait_time - 1);
|
|
||||||
|
|
||||||
data = (data << 1) | furi_hal_gpio_read(instance->miso); //-V792
|
|
||||||
|
|
||||||
furi_hal_gpio_write(instance->sck, false);
|
|
||||||
if(instance->speed_wait_time != AvrIspSpiSwSpeed1Mhz)
|
|
||||||
furi_delay_us(instance->speed_wait_time - 1);
|
|
||||||
}
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_spi_sw_res_set(AvrIspSpiSw* instance, bool state) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_hal_gpio_write(instance->res, state);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_spi_sw_sck_set(AvrIspSpiSw* instance, bool state) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_hal_gpio_write(instance->sck, state);
|
|
||||||
}
|
|
|
@ -1,24 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <furi_hal.h>
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
AvrIspSpiSwSpeed1Mhz = 0,
|
|
||||||
AvrIspSpiSwSpeed400Khz = 1,
|
|
||||||
AvrIspSpiSwSpeed250Khz = 2,
|
|
||||||
AvrIspSpiSwSpeed125Khz = 4,
|
|
||||||
AvrIspSpiSwSpeed60Khz = 8,
|
|
||||||
AvrIspSpiSwSpeed40Khz = 12,
|
|
||||||
AvrIspSpiSwSpeed20Khz = 24,
|
|
||||||
AvrIspSpiSwSpeed10Khz = 48,
|
|
||||||
AvrIspSpiSwSpeed5Khz = 96,
|
|
||||||
AvrIspSpiSwSpeed1Khz = 480,
|
|
||||||
} AvrIspSpiSwSpeed;
|
|
||||||
|
|
||||||
typedef struct AvrIspSpiSw AvrIspSpiSw;
|
|
||||||
|
|
||||||
AvrIspSpiSw* avr_isp_spi_sw_init(AvrIspSpiSwSpeed speed);
|
|
||||||
void avr_isp_spi_sw_free(AvrIspSpiSw* instance);
|
|
||||||
uint8_t avr_isp_spi_sw_txrx(AvrIspSpiSw* instance, uint8_t data);
|
|
||||||
void avr_isp_spi_sw_res_set(AvrIspSpiSw* instance, bool state);
|
|
||||||
void avr_isp_spi_sw_sck_set(AvrIspSpiSw* instance, bool state);
|
|
Before Width: | Height: | Size: 3.6 KiB |
|
@ -1,30 +0,0 @@
|
||||||
#include "../avr_isp_app_i.h"
|
|
||||||
|
|
||||||
// Generate scene on_enter handlers array
|
|
||||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
|
|
||||||
void (*const avr_isp_scene_on_enter_handlers[])(void*) = {
|
|
||||||
#include "avr_isp_scene_config.h"
|
|
||||||
};
|
|
||||||
#undef ADD_SCENE
|
|
||||||
|
|
||||||
// Generate scene on_event handlers array
|
|
||||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
|
|
||||||
bool (*const avr_isp_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = {
|
|
||||||
#include "avr_isp_scene_config.h"
|
|
||||||
};
|
|
||||||
#undef ADD_SCENE
|
|
||||||
|
|
||||||
// Generate scene on_exit handlers array
|
|
||||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
|
|
||||||
void (*const avr_isp_scene_on_exit_handlers[])(void* context) = {
|
|
||||||
#include "avr_isp_scene_config.h"
|
|
||||||
};
|
|
||||||
#undef ADD_SCENE
|
|
||||||
|
|
||||||
// Initialize scene handlers configuration structure
|
|
||||||
const SceneManagerHandlers avr_isp_scene_handlers = {
|
|
||||||
.on_enter_handlers = avr_isp_scene_on_enter_handlers,
|
|
||||||
.on_event_handlers = avr_isp_scene_on_event_handlers,
|
|
||||||
.on_exit_handlers = avr_isp_scene_on_exit_handlers,
|
|
||||||
.scene_num = AvrIspSceneNum,
|
|
||||||
};
|
|
|
@ -1,29 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <gui/scene_manager.h>
|
|
||||||
|
|
||||||
// Generate scene id and total number
|
|
||||||
#define ADD_SCENE(prefix, name, id) AvrIspScene##id,
|
|
||||||
typedef enum {
|
|
||||||
#include "avr_isp_scene_config.h"
|
|
||||||
AvrIspSceneNum,
|
|
||||||
} AvrIspScene;
|
|
||||||
#undef ADD_SCENE
|
|
||||||
|
|
||||||
extern const SceneManagerHandlers avr_isp_scene_handlers;
|
|
||||||
|
|
||||||
// Generate scene on_enter handlers declaration
|
|
||||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
|
|
||||||
#include "avr_isp_scene_config.h"
|
|
||||||
#undef ADD_SCENE
|
|
||||||
|
|
||||||
// Generate scene on_event handlers declaration
|
|
||||||
#define ADD_SCENE(prefix, name, id) \
|
|
||||||
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
|
|
||||||
#include "avr_isp_scene_config.h"
|
|
||||||
#undef ADD_SCENE
|
|
||||||
|
|
||||||
// Generate scene on_exit handlers declaration
|
|
||||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
|
|
||||||
#include "avr_isp_scene_config.h"
|
|
||||||
#undef ADD_SCENE
|
|
|
@ -1,99 +0,0 @@
|
||||||
#include "../avr_isp_app_i.h"
|
|
||||||
#include "../helpers/avr_isp_types.h"
|
|
||||||
|
|
||||||
void avr_isp_scene_about_widget_callback(GuiButtonType result, InputType type, void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
if(type == InputTypeShort) {
|
|
||||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_about_on_enter(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
FuriString* temp_str = furi_string_alloc();
|
|
||||||
furi_string_printf(temp_str, "\e#%s\n", "Information");
|
|
||||||
|
|
||||||
furi_string_cat_printf(temp_str, "Version: %s\n", AVR_ISP_VERSION_APP);
|
|
||||||
furi_string_cat_printf(temp_str, "Developed by: %s\n", AVR_ISP_DEVELOPED);
|
|
||||||
furi_string_cat_printf(temp_str, "Github: %s\n\n", AVR_ISP_GITHUB);
|
|
||||||
|
|
||||||
furi_string_cat_printf(temp_str, "\e#%s\n", "Description");
|
|
||||||
furi_string_cat_printf(
|
|
||||||
temp_str,
|
|
||||||
"This application is an AVR in-system programmer based on stk500mk1. It is compatible with AVR-based"
|
|
||||||
" microcontrollers including Arduino. You can also use it to repair the chip if you accidentally"
|
|
||||||
" corrupt the bootloader.\n\n");
|
|
||||||
|
|
||||||
furi_string_cat_printf(temp_str, "\e#%s\n", "What it can do:");
|
|
||||||
furi_string_cat_printf(temp_str, "- Create a dump of your chip on an SD card\n");
|
|
||||||
furi_string_cat_printf(temp_str, "- Flash your chip firmware from the SD card\n");
|
|
||||||
furi_string_cat_printf(temp_str, "- Act as a wired USB ISP using avrdude software\n\n");
|
|
||||||
|
|
||||||
furi_string_cat_printf(temp_str, "\e#%s\n", "Supported chip series:");
|
|
||||||
furi_string_cat_printf(
|
|
||||||
temp_str,
|
|
||||||
"Example command for avrdude flashing: avrdude.exe -p m328p -c stk500v1 -P COMxx -U flash:r:"
|
|
||||||
"X:\\sketch_sample.hex"
|
|
||||||
":i\n");
|
|
||||||
furi_string_cat_printf(
|
|
||||||
temp_str,
|
|
||||||
"Where: "
|
|
||||||
"-p m328p"
|
|
||||||
" brand of your chip, "
|
|
||||||
"-P COMxx"
|
|
||||||
" com port number in the system when "
|
|
||||||
"ISP Programmer"
|
|
||||||
" is enabled\n\n");
|
|
||||||
|
|
||||||
furi_string_cat_printf(temp_str, "\e#%s\n", "Info");
|
|
||||||
furi_string_cat_printf(
|
|
||||||
temp_str,
|
|
||||||
"ATtinyXXXX\nATmegaXXXX\nAT43Uxxx\nAT76C711\nAT86RF401\nAT90xxxxx\nAT94K\n"
|
|
||||||
"ATAxxxxx\nATA664251\nM3000\nLGT8F88P\nLGT8F168P\nLGT8F328P\n");
|
|
||||||
|
|
||||||
furi_string_cat_printf(
|
|
||||||
temp_str, "For a more detailed list of supported chips, see AVRDude help\n");
|
|
||||||
|
|
||||||
widget_add_text_box_element(
|
|
||||||
app->widget,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
128,
|
|
||||||
14,
|
|
||||||
AlignCenter,
|
|
||||||
AlignBottom,
|
|
||||||
"\e#\e! \e!\n",
|
|
||||||
false);
|
|
||||||
widget_add_text_box_element(
|
|
||||||
app->widget,
|
|
||||||
0,
|
|
||||||
2,
|
|
||||||
128,
|
|
||||||
14,
|
|
||||||
AlignCenter,
|
|
||||||
AlignBottom,
|
|
||||||
"\e#\e! ISP Programmer \e!\n",
|
|
||||||
false);
|
|
||||||
widget_add_text_scroll_element(app->widget, 0, 16, 128, 50, furi_string_get_cstr(temp_str));
|
|
||||||
furi_string_free(temp_str);
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewWidget);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_scene_about_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
UNUSED(context);
|
|
||||||
UNUSED(event);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_about_on_exit(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
// Clear views
|
|
||||||
widget_reset(app->widget);
|
|
||||||
}
|
|
|
@ -1,72 +0,0 @@
|
||||||
#include "../avr_isp_app_i.h"
|
|
||||||
|
|
||||||
void avr_isp_scene_chip_detect_callback(AvrIspCustomEvent event, void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_chip_detect_on_enter(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
switch(app->error) {
|
|
||||||
case AvrIspErrorReading:
|
|
||||||
case AvrIspErrorWriting:
|
|
||||||
case AvrIspErrorWritingFuse:
|
|
||||||
avr_isp_chip_detect_set_state(
|
|
||||||
app->avr_isp_chip_detect_view, AvrIspChipDetectViewStateErrorOccured);
|
|
||||||
break;
|
|
||||||
case AvrIspErrorVerification:
|
|
||||||
avr_isp_chip_detect_set_state(
|
|
||||||
app->avr_isp_chip_detect_view, AvrIspChipDetectViewStateErrorVerification);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
avr_isp_chip_detect_set_state(
|
|
||||||
app->avr_isp_chip_detect_view, AvrIspChipDetectViewStateNoDetect);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
app->error = AvrIspErrorNoError;
|
|
||||||
avr_isp_chip_detect_view_set_callback(
|
|
||||||
app->avr_isp_chip_detect_view, avr_isp_scene_chip_detect_callback, app);
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewChipDetect);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_scene_chip_detect_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
bool consumed = false;
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
switch(event.event) {
|
|
||||||
case AvrIspCustomEventSceneChipDetectOk:
|
|
||||||
|
|
||||||
if(scene_manager_get_scene_state(app->scene_manager, AvrIspSceneChipDetect) ==
|
|
||||||
AvrIspViewProgrammer) {
|
|
||||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneProgrammer);
|
|
||||||
} else if(
|
|
||||||
scene_manager_get_scene_state(app->scene_manager, AvrIspSceneChipDetect) ==
|
|
||||||
AvrIspViewReader) {
|
|
||||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneInputName);
|
|
||||||
} else if(
|
|
||||||
scene_manager_get_scene_state(app->scene_manager, AvrIspSceneChipDetect) ==
|
|
||||||
AvrIspViewWriter) {
|
|
||||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneLoad);
|
|
||||||
}
|
|
||||||
|
|
||||||
consumed = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if(event.type == SceneManagerEventTypeTick) {
|
|
||||||
}
|
|
||||||
return consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_chip_detect_on_exit(void* context) {
|
|
||||||
UNUSED(context);
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
ADD_SCENE(avr_isp, start, Start)
|
|
||||||
ADD_SCENE(avr_isp, about, About)
|
|
||||||
ADD_SCENE(avr_isp, programmer, Programmer)
|
|
||||||
ADD_SCENE(avr_isp, reader, Reader)
|
|
||||||
ADD_SCENE(avr_isp, input_name, InputName)
|
|
||||||
ADD_SCENE(avr_isp, load, Load)
|
|
||||||
ADD_SCENE(avr_isp, writer, Writer)
|
|
||||||
ADD_SCENE(avr_isp, wiring, Wiring)
|
|
||||||
ADD_SCENE(avr_isp, chip_detect, ChipDetect)
|
|
||||||
ADD_SCENE(avr_isp, success, Success)
|
|
|
@ -1,89 +0,0 @@
|
||||||
#include "../avr_isp_app_i.h"
|
|
||||||
#include <gui/modules/validators.h>
|
|
||||||
|
|
||||||
#define MAX_TEXT_INPUT_LEN 22
|
|
||||||
|
|
||||||
void avr_isp_scene_input_name_text_callback(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
view_dispatcher_send_custom_event(app->view_dispatcher, AvrIspCustomEventSceneInputName);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_input_name_get_timefilename(FuriString* name) {
|
|
||||||
FuriHalRtcDateTime datetime = {0};
|
|
||||||
furi_hal_rtc_get_datetime(&datetime);
|
|
||||||
furi_string_printf(
|
|
||||||
name,
|
|
||||||
"AVR_dump-%.4d%.2d%.2d-%.2d%.2d%.2d",
|
|
||||||
datetime.year,
|
|
||||||
datetime.month,
|
|
||||||
datetime.day,
|
|
||||||
datetime.hour,
|
|
||||||
datetime.minute,
|
|
||||||
datetime.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_input_name_on_enter(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
// Setup view
|
|
||||||
TextInput* text_input = app->text_input;
|
|
||||||
bool dev_name_empty = false;
|
|
||||||
|
|
||||||
FuriString* file_name = furi_string_alloc();
|
|
||||||
|
|
||||||
avr_isp_scene_input_name_get_timefilename(file_name);
|
|
||||||
furi_string_set(app->file_path, STORAGE_APP_DATA_PATH_PREFIX);
|
|
||||||
//highlighting the entire filename by default
|
|
||||||
dev_name_empty = true;
|
|
||||||
|
|
||||||
strncpy(app->file_name_tmp, furi_string_get_cstr(file_name), AVR_ISP_MAX_LEN_NAME);
|
|
||||||
text_input_set_header_text(text_input, "Name dump");
|
|
||||||
text_input_set_result_callback(
|
|
||||||
text_input,
|
|
||||||
avr_isp_scene_input_name_text_callback,
|
|
||||||
app,
|
|
||||||
app->file_name_tmp,
|
|
||||||
MAX_TEXT_INPUT_LEN, // buffer size
|
|
||||||
dev_name_empty);
|
|
||||||
|
|
||||||
ValidatorIsFile* validator_is_file =
|
|
||||||
validator_is_file_alloc_init(STORAGE_APP_DATA_PATH_PREFIX, AVR_ISP_APP_EXTENSION, "");
|
|
||||||
text_input_set_validator(text_input, validator_is_file_callback, validator_is_file);
|
|
||||||
|
|
||||||
furi_string_free(file_name);
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewTextInput);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_scene_input_name_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
if(event.type == SceneManagerEventTypeBack) {
|
|
||||||
scene_manager_previous_scene(app->scene_manager);
|
|
||||||
return true;
|
|
||||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
if(event.event == AvrIspCustomEventSceneInputName) {
|
|
||||||
if(strcmp(app->file_name_tmp, "") != 0) {
|
|
||||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneReader);
|
|
||||||
} else {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_input_name_on_exit(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
// Clear validator
|
|
||||||
void* validator_context = text_input_get_validator_callback_context(app->text_input);
|
|
||||||
text_input_set_validator(app->text_input, NULL, NULL);
|
|
||||||
validator_is_file_free(validator_context);
|
|
||||||
// Clear view
|
|
||||||
text_input_reset(app->text_input);
|
|
||||||
}
|
|
|
@ -1,22 +0,0 @@
|
||||||
#include "../avr_isp_app_i.h"
|
|
||||||
|
|
||||||
void avr_isp_scene_load_on_enter(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
if(avr_isp_load_from_file(app)) {
|
|
||||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneWriter);
|
|
||||||
} else {
|
|
||||||
scene_manager_previous_scene(app->scene_manager);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_scene_load_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
UNUSED(context);
|
|
||||||
UNUSED(event);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_load_on_exit(void* context) {
|
|
||||||
UNUSED(context);
|
|
||||||
}
|
|
|
@ -1,28 +0,0 @@
|
||||||
#include "../avr_isp_app_i.h"
|
|
||||||
|
|
||||||
void avr_isp_scene_programmer_callback(AvrIspCustomEvent event, void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_programmer_on_enter(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
avr_isp_programmer_view_set_callback(
|
|
||||||
app->avr_isp_programmer_view, avr_isp_scene_programmer_callback, app);
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewProgrammer);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_scene_programmer_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
UNUSED(context);
|
|
||||||
UNUSED(event);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_programmer_on_exit(void* context) {
|
|
||||||
UNUSED(context);
|
|
||||||
}
|
|
|
@ -1,64 +0,0 @@
|
||||||
#include "../avr_isp_app_i.h"
|
|
||||||
|
|
||||||
void avr_isp_scene_reader_callback(AvrIspCustomEvent event, void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_reader_on_enter(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
avr_isp_reader_set_file_path(
|
|
||||||
app->avr_isp_reader_view, furi_string_get_cstr(app->file_path), app->file_name_tmp);
|
|
||||||
avr_isp_reader_view_set_callback(app->avr_isp_reader_view, avr_isp_scene_reader_callback, app);
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewReader);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_scene_reader_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
UNUSED(app);
|
|
||||||
bool consumed = false;
|
|
||||||
if(event.type == SceneManagerEventTypeBack) {
|
|
||||||
//do not handle exit on "Back"
|
|
||||||
consumed = true;
|
|
||||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
switch(event.event) {
|
|
||||||
case AvrIspCustomEventSceneReadingOk:
|
|
||||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneSuccess);
|
|
||||||
consumed = true;
|
|
||||||
break;
|
|
||||||
case AvrIspCustomEventSceneExit:
|
|
||||||
scene_manager_search_and_switch_to_previous_scene(
|
|
||||||
app->scene_manager, AvrIspSceneChipDetect);
|
|
||||||
consumed = true;
|
|
||||||
break;
|
|
||||||
case AvrIspCustomEventSceneErrorVerification:
|
|
||||||
app->error = AvrIspErrorVerification;
|
|
||||||
scene_manager_search_and_switch_to_previous_scene(
|
|
||||||
app->scene_manager, AvrIspSceneChipDetect);
|
|
||||||
consumed = true;
|
|
||||||
break;
|
|
||||||
case AvrIspCustomEventSceneErrorReading:
|
|
||||||
app->error = AvrIspErrorReading;
|
|
||||||
scene_manager_search_and_switch_to_previous_scene(
|
|
||||||
app->scene_manager, AvrIspSceneChipDetect);
|
|
||||||
consumed = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if(event.type == SceneManagerEventTypeTick) {
|
|
||||||
avr_isp_reader_update_progress(app->avr_isp_reader_view);
|
|
||||||
}
|
|
||||||
return consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_reader_on_exit(void* context) {
|
|
||||||
UNUSED(context);
|
|
||||||
}
|
|
|
@ -1,75 +0,0 @@
|
||||||
#include "../avr_isp_app_i.h"
|
|
||||||
|
|
||||||
void avr_isp_scene_start_submenu_callback(void* context, uint32_t index) {
|
|
||||||
furi_assert(context);
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
|
|
||||||
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_start_on_enter(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
Submenu* submenu = app->submenu;
|
|
||||||
submenu_add_item(
|
|
||||||
submenu, "Dump AVR", SubmenuIndexAvrIspReader, avr_isp_scene_start_submenu_callback, app);
|
|
||||||
submenu_add_item(
|
|
||||||
submenu, "Flash AVR", SubmenuIndexAvrIspWriter, avr_isp_scene_start_submenu_callback, app);
|
|
||||||
submenu_add_item(
|
|
||||||
submenu,
|
|
||||||
"ISP Programmer",
|
|
||||||
SubmenuIndexAvrIspProgrammer,
|
|
||||||
avr_isp_scene_start_submenu_callback,
|
|
||||||
app);
|
|
||||||
submenu_add_item(
|
|
||||||
submenu, "Wiring", SubmenuIndexAvrIsWiring, avr_isp_scene_start_submenu_callback, app);
|
|
||||||
submenu_add_item(
|
|
||||||
submenu, "About", SubmenuIndexAvrIspAbout, avr_isp_scene_start_submenu_callback, app);
|
|
||||||
|
|
||||||
submenu_set_selected_item(
|
|
||||||
submenu, scene_manager_get_scene_state(app->scene_manager, AvrIspSceneStart));
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewSubmenu);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_scene_start_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
bool consumed = false;
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
if(event.event == SubmenuIndexAvrIspAbout) {
|
|
||||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneAbout);
|
|
||||||
consumed = true;
|
|
||||||
} else if(event.event == SubmenuIndexAvrIspProgrammer) {
|
|
||||||
scene_manager_set_scene_state(
|
|
||||||
app->scene_manager, AvrIspSceneChipDetect, AvrIspViewProgrammer);
|
|
||||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneChipDetect);
|
|
||||||
consumed = true;
|
|
||||||
} else if(event.event == SubmenuIndexAvrIspReader) {
|
|
||||||
scene_manager_set_scene_state(
|
|
||||||
app->scene_manager, AvrIspSceneChipDetect, AvrIspViewReader);
|
|
||||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneChipDetect);
|
|
||||||
consumed = true;
|
|
||||||
} else if(event.event == SubmenuIndexAvrIspWriter) {
|
|
||||||
scene_manager_set_scene_state(
|
|
||||||
app->scene_manager, AvrIspSceneChipDetect, AvrIspViewWriter);
|
|
||||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneChipDetect);
|
|
||||||
consumed = true;
|
|
||||||
} else if(event.event == SubmenuIndexAvrIsWiring) {
|
|
||||||
scene_manager_next_scene(app->scene_manager, AvrIspSceneWiring);
|
|
||||||
consumed = true;
|
|
||||||
}
|
|
||||||
scene_manager_set_scene_state(app->scene_manager, AvrIspSceneStart, event.event);
|
|
||||||
}
|
|
||||||
|
|
||||||
return consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_start_on_exit(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
submenu_reset(app->submenu);
|
|
||||||
}
|
|
|
@ -1,44 +0,0 @@
|
||||||
#include "../avr_isp_app_i.h"
|
|
||||||
|
|
||||||
void avr_isp_scene_success_popup_callback(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
view_dispatcher_send_custom_event(app->view_dispatcher, AvrIspCustomEventSceneSuccess);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_success_on_enter(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
Popup* popup = app->popup;
|
|
||||||
popup_set_icon(popup, 32, 5, &I_dolphin_nice_96x59);
|
|
||||||
popup_set_header(popup, "Success!", 8, 22, AlignLeft, AlignBottom);
|
|
||||||
popup_set_timeout(popup, 1500);
|
|
||||||
popup_set_context(popup, app);
|
|
||||||
popup_set_callback(popup, avr_isp_scene_success_popup_callback);
|
|
||||||
popup_enable_timeout(popup);
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewPopup);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_scene_success_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
if(event.event == AvrIspCustomEventSceneSuccess) {
|
|
||||||
scene_manager_search_and_switch_to_previous_scene(
|
|
||||||
app->scene_manager, AvrIspSceneStart);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_success_on_exit(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
Popup* popup = app->popup;
|
|
||||||
popup_reset(popup);
|
|
||||||
}
|
|
|
@ -1,21 +0,0 @@
|
||||||
#include "../avr_isp_app_i.h"
|
|
||||||
|
|
||||||
void avr_isp_scene_wiring_on_enter(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
widget_add_icon_element(app->widget, 0, 0, &I_avr_wiring);
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewWidget);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_scene_wiring_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
UNUSED(context);
|
|
||||||
UNUSED(event);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
void avr_isp_scene_wiring_on_exit(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
widget_reset(app->widget);
|
|
||||||
}
|
|
|
@ -1,69 +0,0 @@
|
||||||
#include "../avr_isp_app_i.h"
|
|
||||||
|
|
||||||
void avr_isp_scene_writer_callback(AvrIspCustomEvent event, void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_writer_on_enter(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
avr_isp_writer_set_file_path(
|
|
||||||
app->avr_isp_writer_view, furi_string_get_cstr(app->file_path), app->file_name_tmp);
|
|
||||||
avr_isp_writer_view_set_callback(app->avr_isp_writer_view, avr_isp_scene_writer_callback, app);
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, AvrIspViewWriter);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_scene_writer_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspApp* app = context;
|
|
||||||
bool consumed = false;
|
|
||||||
if(event.type == SceneManagerEventTypeBack) {
|
|
||||||
//do not handle exit on "Back"
|
|
||||||
consumed = true;
|
|
||||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
switch(event.event) {
|
|
||||||
case AvrIspCustomEventSceneExitStartMenu:
|
|
||||||
scene_manager_search_and_switch_to_previous_scene(
|
|
||||||
app->scene_manager, AvrIspSceneStart);
|
|
||||||
consumed = true;
|
|
||||||
break;
|
|
||||||
case AvrIspCustomEventSceneExit:
|
|
||||||
scene_manager_search_and_switch_to_previous_scene(
|
|
||||||
app->scene_manager, AvrIspSceneChipDetect);
|
|
||||||
consumed = true;
|
|
||||||
break;
|
|
||||||
case AvrIspCustomEventSceneErrorVerification:
|
|
||||||
app->error = AvrIspErrorVerification;
|
|
||||||
scene_manager_search_and_switch_to_previous_scene(
|
|
||||||
app->scene_manager, AvrIspSceneChipDetect);
|
|
||||||
consumed = true;
|
|
||||||
break;
|
|
||||||
case AvrIspCustomEventSceneErrorWriting:
|
|
||||||
app->error = AvrIspErrorWriting;
|
|
||||||
scene_manager_search_and_switch_to_previous_scene(
|
|
||||||
app->scene_manager, AvrIspSceneChipDetect);
|
|
||||||
consumed = true;
|
|
||||||
break;
|
|
||||||
case AvrIspCustomEventSceneErrorWritingFuse:
|
|
||||||
app->error = AvrIspErrorWritingFuse;
|
|
||||||
scene_manager_search_and_switch_to_previous_scene(
|
|
||||||
app->scene_manager, AvrIspSceneChipDetect);
|
|
||||||
consumed = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else if(event.type == SceneManagerEventTypeTick) {
|
|
||||||
avr_isp_writer_update_progress(app->avr_isp_writer_view);
|
|
||||||
}
|
|
||||||
return consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_scene_writer_on_exit(void* context) {
|
|
||||||
UNUSED(context);
|
|
||||||
}
|
|
|
@ -1,213 +0,0 @@
|
||||||
#include "avr_isp_view_chip_detect.h"
|
|
||||||
#include <avr_isp_icons.h>
|
|
||||||
#include <gui/elements.h>
|
|
||||||
|
|
||||||
#include "../helpers/avr_isp_worker_rw.h"
|
|
||||||
|
|
||||||
struct AvrIspChipDetectView {
|
|
||||||
View* view;
|
|
||||||
AvrIspWorkerRW* avr_isp_worker_rw;
|
|
||||||
AvrIspChipDetectViewCallback callback;
|
|
||||||
void* context;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint16_t idx;
|
|
||||||
const char* name_chip;
|
|
||||||
uint32_t flash_size;
|
|
||||||
AvrIspChipDetectViewState state;
|
|
||||||
} AvrIspChipDetectViewModel;
|
|
||||||
|
|
||||||
void avr_isp_chip_detect_view_set_callback(
|
|
||||||
AvrIspChipDetectView* instance,
|
|
||||||
AvrIspChipDetectViewCallback callback,
|
|
||||||
void* context) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_assert(callback);
|
|
||||||
|
|
||||||
instance->callback = callback;
|
|
||||||
instance->context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_chip_detect_set_state(AvrIspChipDetectView* instance, AvrIspChipDetectViewState state) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
with_view_model(
|
|
||||||
instance->view, AvrIspChipDetectViewModel * model, { model->state = state; }, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_chip_detect_view_draw(Canvas* canvas, AvrIspChipDetectViewModel* model) {
|
|
||||||
canvas_clear(canvas);
|
|
||||||
|
|
||||||
char str_buf[64] = {0};
|
|
||||||
canvas_set_font(canvas, FontPrimary);
|
|
||||||
|
|
||||||
switch(model->state) {
|
|
||||||
case AvrIspChipDetectViewStateDetected:
|
|
||||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "AVR chip detected!");
|
|
||||||
canvas_draw_icon(canvas, 29, 14, &I_chip_long_70x22);
|
|
||||||
canvas_set_font(canvas, FontSecondary);
|
|
||||||
snprintf(str_buf, sizeof(str_buf), "%ld Kb", model->flash_size / 1024);
|
|
||||||
canvas_draw_str_aligned(canvas, 64, 25, AlignCenter, AlignCenter, str_buf);
|
|
||||||
canvas_draw_str_aligned(canvas, 64, 45, AlignCenter, AlignCenter, model->name_chip);
|
|
||||||
elements_button_right(canvas, "Next");
|
|
||||||
break;
|
|
||||||
case AvrIspChipDetectViewStateErrorOccured:
|
|
||||||
canvas_draw_str_aligned(
|
|
||||||
canvas, 64, 5, AlignCenter, AlignCenter, "Error occured, try again!");
|
|
||||||
canvas_draw_icon(canvas, 29, 14, &I_chip_error_70x22);
|
|
||||||
canvas_set_font(canvas, FontSecondary);
|
|
||||||
canvas_draw_str_aligned(
|
|
||||||
canvas, 64, 45, AlignCenter, AlignCenter, "Check the wiring and retry");
|
|
||||||
break;
|
|
||||||
case AvrIspChipDetectViewStateErrorVerification:
|
|
||||||
canvas_draw_str_aligned(
|
|
||||||
canvas, 64, 5, AlignCenter, AlignCenter, "Data verification failed");
|
|
||||||
canvas_draw_icon(canvas, 29, 14, &I_chip_error_70x22);
|
|
||||||
canvas_set_font(canvas, FontSecondary);
|
|
||||||
canvas_draw_str_aligned(
|
|
||||||
canvas, 64, 45, AlignCenter, AlignCenter, "Try to restart the process");
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
//AvrIspChipDetectViewStateNoDetect
|
|
||||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "AVR chip not found!");
|
|
||||||
canvas_draw_icon(canvas, 29, 12, &I_chif_not_found_83x37);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
canvas_set_font(canvas, FontSecondary);
|
|
||||||
elements_button_left(canvas, "Retry");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_chip_detect_view_input(InputEvent* event, void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspChipDetectView* instance = context;
|
|
||||||
|
|
||||||
if(event->type == InputTypeShort) {
|
|
||||||
if(event->key == InputKeyBack) {
|
|
||||||
return false;
|
|
||||||
} else if(event->key == InputKeyRight) {
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspChipDetectViewModel * model,
|
|
||||||
{
|
|
||||||
if(model->state == AvrIspChipDetectViewStateDetected) {
|
|
||||||
if(instance->callback)
|
|
||||||
instance->callback(
|
|
||||||
AvrIspCustomEventSceneChipDetectOk, instance->context);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
false);
|
|
||||||
|
|
||||||
} else if(event->key == InputKeyLeft) {
|
|
||||||
bool detect_chip = false;
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspChipDetectViewModel * model,
|
|
||||||
{
|
|
||||||
if(model->state != AvrIspChipDetectViewStateDetecting) {
|
|
||||||
model->state = AvrIspChipDetectViewStateDetecting;
|
|
||||||
detect_chip = true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
false);
|
|
||||||
if(detect_chip) avr_isp_worker_rw_detect_chip(instance->avr_isp_worker_rw);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_chip_detect_detect_chip_callback(
|
|
||||||
void* context,
|
|
||||||
const char* name,
|
|
||||||
bool detect_chip,
|
|
||||||
uint32_t flash_size) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspChipDetectView* instance = context;
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspChipDetectViewModel * model,
|
|
||||||
{
|
|
||||||
model->name_chip = name;
|
|
||||||
model->flash_size = flash_size;
|
|
||||||
if(detect_chip) {
|
|
||||||
model->state = AvrIspChipDetectViewStateDetected;
|
|
||||||
} else {
|
|
||||||
model->state = AvrIspChipDetectViewStateNoDetect;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
void avr_isp_chip_detect_view_enter(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspChipDetectView* instance = context;
|
|
||||||
bool detect_chip = false;
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspChipDetectViewModel * model,
|
|
||||||
{
|
|
||||||
if(model->state == AvrIspChipDetectViewStateNoDetect ||
|
|
||||||
model->state == AvrIspChipDetectViewStateDetected) {
|
|
||||||
detect_chip = true;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
false);
|
|
||||||
|
|
||||||
//Start avr_isp_worker_rw
|
|
||||||
instance->avr_isp_worker_rw = avr_isp_worker_rw_alloc(instance->context);
|
|
||||||
|
|
||||||
avr_isp_worker_rw_set_callback(
|
|
||||||
instance->avr_isp_worker_rw, avr_isp_chip_detect_detect_chip_callback, instance);
|
|
||||||
|
|
||||||
if(detect_chip) avr_isp_worker_rw_detect_chip(instance->avr_isp_worker_rw);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_chip_detect_view_exit(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspChipDetectView* instance = context;
|
|
||||||
|
|
||||||
avr_isp_worker_rw_set_callback(instance->avr_isp_worker_rw, NULL, NULL);
|
|
||||||
avr_isp_worker_rw_free(instance->avr_isp_worker_rw);
|
|
||||||
}
|
|
||||||
|
|
||||||
AvrIspChipDetectView* avr_isp_chip_detect_view_alloc() {
|
|
||||||
AvrIspChipDetectView* instance = malloc(sizeof(AvrIspChipDetectView));
|
|
||||||
|
|
||||||
// View allocation and configuration
|
|
||||||
instance->view = view_alloc();
|
|
||||||
|
|
||||||
view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(AvrIspChipDetectViewModel));
|
|
||||||
view_set_context(instance->view, instance);
|
|
||||||
view_set_draw_callback(instance->view, (ViewDrawCallback)avr_isp_chip_detect_view_draw);
|
|
||||||
view_set_input_callback(instance->view, avr_isp_chip_detect_view_input);
|
|
||||||
view_set_enter_callback(instance->view, avr_isp_chip_detect_view_enter);
|
|
||||||
view_set_exit_callback(instance->view, avr_isp_chip_detect_view_exit);
|
|
||||||
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspChipDetectViewModel * model,
|
|
||||||
{ model->state = AvrIspChipDetectViewStateNoDetect; },
|
|
||||||
false);
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_chip_detect_view_free(AvrIspChipDetectView* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
view_free(instance->view);
|
|
||||||
free(instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
View* avr_isp_chip_detect_view_get_view(AvrIspChipDetectView* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
return instance->view;
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <gui/view.h>
|
|
||||||
#include "../helpers/avr_isp_types.h"
|
|
||||||
#include "../helpers/avr_isp_event.h"
|
|
||||||
|
|
||||||
typedef struct AvrIspChipDetectView AvrIspChipDetectView;
|
|
||||||
|
|
||||||
typedef void (*AvrIspChipDetectViewCallback)(AvrIspCustomEvent event, void* context);
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
AvrIspChipDetectViewStateNoDetect,
|
|
||||||
AvrIspChipDetectViewStateDetecting,
|
|
||||||
AvrIspChipDetectViewStateDetected,
|
|
||||||
AvrIspChipDetectViewStateErrorOccured,
|
|
||||||
AvrIspChipDetectViewStateErrorVerification,
|
|
||||||
} AvrIspChipDetectViewState;
|
|
||||||
|
|
||||||
void avr_isp_chip_detect_view_set_callback(
|
|
||||||
AvrIspChipDetectView* instance,
|
|
||||||
AvrIspChipDetectViewCallback callback,
|
|
||||||
void* context);
|
|
||||||
|
|
||||||
void avr_isp_chip_detect_set_state(AvrIspChipDetectView* instance, AvrIspChipDetectViewState state);
|
|
||||||
|
|
||||||
AvrIspChipDetectView* avr_isp_chip_detect_view_alloc();
|
|
||||||
|
|
||||||
void avr_isp_chip_detect_view_free(AvrIspChipDetectView* instance);
|
|
||||||
|
|
||||||
View* avr_isp_chip_detect_view_get_view(AvrIspChipDetectView* instance);
|
|
||||||
|
|
||||||
void avr_isp_chip_detect_view_exit(void* context);
|
|
|
@ -1,134 +0,0 @@
|
||||||
#include "avr_isp_view_programmer.h"
|
|
||||||
#include <avr_isp_icons.h>
|
|
||||||
|
|
||||||
#include "../helpers/avr_isp_worker.h"
|
|
||||||
#include <gui/elements.h>
|
|
||||||
|
|
||||||
struct AvrIspProgrammerView {
|
|
||||||
View* view;
|
|
||||||
AvrIspWorker* worker;
|
|
||||||
AvrIspProgrammerViewCallback callback;
|
|
||||||
void* context;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
AvrIspProgrammerViewStatus status;
|
|
||||||
} AvrIspProgrammerViewModel;
|
|
||||||
|
|
||||||
void avr_isp_programmer_view_set_callback(
|
|
||||||
AvrIspProgrammerView* instance,
|
|
||||||
AvrIspProgrammerViewCallback callback,
|
|
||||||
void* context) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_assert(callback);
|
|
||||||
|
|
||||||
instance->callback = callback;
|
|
||||||
instance->context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_programmer_view_draw(Canvas* canvas, AvrIspProgrammerViewModel* model) {
|
|
||||||
canvas_clear(canvas);
|
|
||||||
|
|
||||||
if(model->status == AvrIspProgrammerViewStatusUSBConnect) {
|
|
||||||
canvas_set_font(canvas, FontPrimary);
|
|
||||||
canvas_draw_icon(canvas, 0, 0, &I_isp_active_128x53);
|
|
||||||
elements_multiline_text(canvas, 45, 10, "ISP mode active");
|
|
||||||
} else {
|
|
||||||
canvas_set_font(canvas, FontSecondary);
|
|
||||||
canvas_draw_icon(canvas, 51, 6, &I_link_waiting_77x56);
|
|
||||||
elements_multiline_text(canvas, 0, 25, "Waiting for\nsoftware\nconnection");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_programmer_view_input(InputEvent* event, void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
UNUSED(context);
|
|
||||||
|
|
||||||
if(event->key == InputKeyBack || event->type != InputTypeShort) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_programmer_usb_connect_callback(void* context, bool status_connect) {
|
|
||||||
furi_assert(context);
|
|
||||||
AvrIspProgrammerView* instance = context;
|
|
||||||
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspProgrammerViewModel * model,
|
|
||||||
{
|
|
||||||
if(status_connect) {
|
|
||||||
model->status = AvrIspProgrammerViewStatusUSBConnect;
|
|
||||||
} else {
|
|
||||||
model->status = AvrIspProgrammerViewStatusNoUSBConnect;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_programmer_view_enter(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspProgrammerView* instance = context;
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspProgrammerViewModel * model,
|
|
||||||
{ model->status = AvrIspProgrammerViewStatusNoUSBConnect; },
|
|
||||||
true);
|
|
||||||
|
|
||||||
//Start worker
|
|
||||||
instance->worker = avr_isp_worker_alloc(instance->context);
|
|
||||||
|
|
||||||
avr_isp_worker_set_callback(
|
|
||||||
instance->worker, avr_isp_programmer_usb_connect_callback, instance);
|
|
||||||
|
|
||||||
avr_isp_worker_start(instance->worker);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_programmer_view_exit(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspProgrammerView* instance = context;
|
|
||||||
//Stop worker
|
|
||||||
if(avr_isp_worker_is_running(instance->worker)) {
|
|
||||||
avr_isp_worker_stop(instance->worker);
|
|
||||||
}
|
|
||||||
avr_isp_worker_set_callback(instance->worker, NULL, NULL);
|
|
||||||
avr_isp_worker_free(instance->worker);
|
|
||||||
}
|
|
||||||
|
|
||||||
AvrIspProgrammerView* avr_isp_programmer_view_alloc() {
|
|
||||||
AvrIspProgrammerView* instance = malloc(sizeof(AvrIspProgrammerView));
|
|
||||||
|
|
||||||
// View allocation and configuration
|
|
||||||
instance->view = view_alloc();
|
|
||||||
|
|
||||||
view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(AvrIspProgrammerViewModel));
|
|
||||||
view_set_context(instance->view, instance);
|
|
||||||
view_set_draw_callback(instance->view, (ViewDrawCallback)avr_isp_programmer_view_draw);
|
|
||||||
view_set_input_callback(instance->view, avr_isp_programmer_view_input);
|
|
||||||
view_set_enter_callback(instance->view, avr_isp_programmer_view_enter);
|
|
||||||
view_set_exit_callback(instance->view, avr_isp_programmer_view_exit);
|
|
||||||
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspProgrammerViewModel * model,
|
|
||||||
{ model->status = AvrIspProgrammerViewStatusNoUSBConnect; },
|
|
||||||
false);
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_programmer_view_free(AvrIspProgrammerView* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
view_free(instance->view);
|
|
||||||
free(instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
View* avr_isp_programmer_view_get_view(AvrIspProgrammerView* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
return instance->view;
|
|
||||||
}
|
|
|
@ -1,27 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <gui/view.h>
|
|
||||||
#include "../helpers/avr_isp_types.h"
|
|
||||||
#include "../helpers/avr_isp_event.h"
|
|
||||||
|
|
||||||
typedef struct AvrIspProgrammerView AvrIspProgrammerView;
|
|
||||||
|
|
||||||
typedef void (*AvrIspProgrammerViewCallback)(AvrIspCustomEvent event, void* context);
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
AvrIspProgrammerViewStatusNoUSBConnect,
|
|
||||||
AvrIspProgrammerViewStatusUSBConnect,
|
|
||||||
} AvrIspProgrammerViewStatus;
|
|
||||||
|
|
||||||
void avr_isp_programmer_view_set_callback(
|
|
||||||
AvrIspProgrammerView* instance,
|
|
||||||
AvrIspProgrammerViewCallback callback,
|
|
||||||
void* context);
|
|
||||||
|
|
||||||
AvrIspProgrammerView* avr_isp_programmer_view_alloc();
|
|
||||||
|
|
||||||
void avr_isp_programmer_view_free(AvrIspProgrammerView* instance);
|
|
||||||
|
|
||||||
View* avr_isp_programmer_view_get_view(AvrIspProgrammerView* instance);
|
|
||||||
|
|
||||||
void avr_isp_programmer_view_exit(void* context);
|
|
|
@ -1,215 +0,0 @@
|
||||||
#include "avr_isp_view_reader.h"
|
|
||||||
#include <gui/elements.h>
|
|
||||||
|
|
||||||
#include "../helpers/avr_isp_worker_rw.h"
|
|
||||||
|
|
||||||
struct AvrIspReaderView {
|
|
||||||
View* view;
|
|
||||||
AvrIspWorkerRW* avr_isp_worker_rw;
|
|
||||||
const char* file_path;
|
|
||||||
const char* file_name;
|
|
||||||
AvrIspReaderViewCallback callback;
|
|
||||||
void* context;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
AvrIspReaderViewStatus status;
|
|
||||||
float progress_flash;
|
|
||||||
float progress_eeprom;
|
|
||||||
} AvrIspReaderViewModel;
|
|
||||||
|
|
||||||
void avr_isp_reader_update_progress(AvrIspReaderView* instance) {
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspReaderViewModel * model,
|
|
||||||
{
|
|
||||||
model->progress_flash =
|
|
||||||
avr_isp_worker_rw_get_progress_flash(instance->avr_isp_worker_rw);
|
|
||||||
model->progress_eeprom =
|
|
||||||
avr_isp_worker_rw_get_progress_eeprom(instance->avr_isp_worker_rw);
|
|
||||||
},
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_reader_view_set_callback(
|
|
||||||
AvrIspReaderView* instance,
|
|
||||||
AvrIspReaderViewCallback callback,
|
|
||||||
void* context) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_assert(callback);
|
|
||||||
|
|
||||||
instance->callback = callback;
|
|
||||||
instance->context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_reader_set_file_path(
|
|
||||||
AvrIspReaderView* instance,
|
|
||||||
const char* file_path,
|
|
||||||
const char* file_name) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
instance->file_path = file_path;
|
|
||||||
instance->file_name = file_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_reader_view_draw(Canvas* canvas, AvrIspReaderViewModel* model) {
|
|
||||||
canvas_clear(canvas);
|
|
||||||
char str_buf[64] = {0};
|
|
||||||
|
|
||||||
canvas_set_font(canvas, FontPrimary);
|
|
||||||
switch(model->status) {
|
|
||||||
case AvrIspReaderViewStatusIDLE:
|
|
||||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Press start to dump");
|
|
||||||
canvas_set_font(canvas, FontSecondary);
|
|
||||||
elements_button_center(canvas, "Start");
|
|
||||||
break;
|
|
||||||
case AvrIspReaderViewStatusReading:
|
|
||||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Reading dump");
|
|
||||||
break;
|
|
||||||
case AvrIspReaderViewStatusVerification:
|
|
||||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Verifyng dump");
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas_set_font(canvas, FontSecondary);
|
|
||||||
canvas_draw_str(canvas, 0, 27, "Flash");
|
|
||||||
snprintf(str_buf, sizeof(str_buf), "%d%%", (uint8_t)(model->progress_flash * 100));
|
|
||||||
elements_progress_bar_with_text(canvas, 44, 17, 84, model->progress_flash, str_buf);
|
|
||||||
canvas_draw_str(canvas, 0, 43, "EEPROM");
|
|
||||||
snprintf(str_buf, sizeof(str_buf), "%d%%", (uint8_t)(model->progress_eeprom * 100));
|
|
||||||
elements_progress_bar_with_text(canvas, 44, 34, 84, model->progress_eeprom, str_buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_reader_view_input(InputEvent* event, void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
AvrIspReaderView* instance = context;
|
|
||||||
|
|
||||||
bool ret = true;
|
|
||||||
if(event->key == InputKeyBack && event->type == InputTypeShort) {
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspReaderViewModel * model,
|
|
||||||
{
|
|
||||||
if(model->status == AvrIspReaderViewStatusIDLE) {
|
|
||||||
if(instance->callback)
|
|
||||||
instance->callback(AvrIspCustomEventSceneExit, instance->context);
|
|
||||||
ret = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
false);
|
|
||||||
} else if(event->key == InputKeyOk && event->type == InputTypeShort) {
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspReaderViewModel * model,
|
|
||||||
{
|
|
||||||
if(model->status == AvrIspReaderViewStatusIDLE) {
|
|
||||||
model->status = AvrIspReaderViewStatusReading;
|
|
||||||
avr_isp_worker_rw_read_dump_start(
|
|
||||||
instance->avr_isp_worker_rw, instance->file_path, instance->file_name);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
false);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_reader_callback_status(void* context, AvrIspWorkerRWStatus status) {
|
|
||||||
furi_assert(context);
|
|
||||||
AvrIspReaderView* instance = context;
|
|
||||||
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspReaderViewModel * model,
|
|
||||||
{
|
|
||||||
switch(status) {
|
|
||||||
case AvrIspWorkerRWStatusEndReading:
|
|
||||||
model->status = AvrIspReaderViewStatusVerification;
|
|
||||||
avr_isp_worker_rw_verification_start(
|
|
||||||
instance->avr_isp_worker_rw, instance->file_path, instance->file_name);
|
|
||||||
model->status = AvrIspReaderViewStatusVerification;
|
|
||||||
break;
|
|
||||||
case AvrIspWorkerRWStatusEndVerification:
|
|
||||||
if(instance->callback)
|
|
||||||
instance->callback(AvrIspCustomEventSceneReadingOk, instance->context);
|
|
||||||
break;
|
|
||||||
case AvrIspWorkerRWStatusErrorVerification:
|
|
||||||
if(instance->callback)
|
|
||||||
instance->callback(AvrIspCustomEventSceneErrorVerification, instance->context);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
//AvrIspWorkerRWStatusErrorReading;
|
|
||||||
if(instance->callback)
|
|
||||||
instance->callback(AvrIspCustomEventSceneErrorReading, instance->context);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_reader_view_enter(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
AvrIspReaderView* instance = context;
|
|
||||||
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspReaderViewModel * model,
|
|
||||||
{
|
|
||||||
model->status = AvrIspReaderViewStatusIDLE;
|
|
||||||
model->progress_flash = 0.0f;
|
|
||||||
model->progress_eeprom = 0.0f;
|
|
||||||
},
|
|
||||||
true);
|
|
||||||
|
|
||||||
//Start avr_isp_worker_rw
|
|
||||||
instance->avr_isp_worker_rw = avr_isp_worker_rw_alloc(instance->context);
|
|
||||||
|
|
||||||
avr_isp_worker_rw_set_callback_status(
|
|
||||||
instance->avr_isp_worker_rw, avr_isp_reader_callback_status, instance);
|
|
||||||
|
|
||||||
avr_isp_worker_rw_start(instance->avr_isp_worker_rw);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_reader_view_exit(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspReaderView* instance = context;
|
|
||||||
//Stop avr_isp_worker_rw
|
|
||||||
if(avr_isp_worker_rw_is_running(instance->avr_isp_worker_rw)) {
|
|
||||||
avr_isp_worker_rw_stop(instance->avr_isp_worker_rw);
|
|
||||||
}
|
|
||||||
|
|
||||||
avr_isp_worker_rw_free(instance->avr_isp_worker_rw);
|
|
||||||
}
|
|
||||||
|
|
||||||
AvrIspReaderView* avr_isp_reader_view_alloc() {
|
|
||||||
AvrIspReaderView* instance = malloc(sizeof(AvrIspReaderView));
|
|
||||||
|
|
||||||
// View allocation and configuration
|
|
||||||
instance->view = view_alloc();
|
|
||||||
|
|
||||||
view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(AvrIspReaderViewModel));
|
|
||||||
view_set_context(instance->view, instance);
|
|
||||||
view_set_draw_callback(instance->view, (ViewDrawCallback)avr_isp_reader_view_draw);
|
|
||||||
view_set_input_callback(instance->view, avr_isp_reader_view_input);
|
|
||||||
view_set_enter_callback(instance->view, avr_isp_reader_view_enter);
|
|
||||||
view_set_exit_callback(instance->view, avr_isp_reader_view_exit);
|
|
||||||
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_reader_view_free(AvrIspReaderView* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
view_free(instance->view);
|
|
||||||
free(instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
View* avr_isp_reader_view_get_view(AvrIspReaderView* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
return instance->view;
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <gui/view.h>
|
|
||||||
#include "../helpers/avr_isp_types.h"
|
|
||||||
#include "../helpers/avr_isp_event.h"
|
|
||||||
|
|
||||||
typedef struct AvrIspReaderView AvrIspReaderView;
|
|
||||||
|
|
||||||
typedef void (*AvrIspReaderViewCallback)(AvrIspCustomEvent event, void* context);
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
AvrIspReaderViewStatusIDLE,
|
|
||||||
AvrIspReaderViewStatusReading,
|
|
||||||
AvrIspReaderViewStatusVerification,
|
|
||||||
} AvrIspReaderViewStatus;
|
|
||||||
|
|
||||||
void avr_isp_reader_update_progress(AvrIspReaderView* instance);
|
|
||||||
|
|
||||||
void avr_isp_reader_set_file_path(
|
|
||||||
AvrIspReaderView* instance,
|
|
||||||
const char* file_path,
|
|
||||||
const char* file_name);
|
|
||||||
|
|
||||||
void avr_isp_reader_view_set_callback(
|
|
||||||
AvrIspReaderView* instance,
|
|
||||||
AvrIspReaderViewCallback callback,
|
|
||||||
void* context);
|
|
||||||
|
|
||||||
AvrIspReaderView* avr_isp_reader_view_alloc();
|
|
||||||
|
|
||||||
void avr_isp_reader_view_free(AvrIspReaderView* instance);
|
|
||||||
|
|
||||||
View* avr_isp_reader_view_get_view(AvrIspReaderView* instance);
|
|
||||||
|
|
||||||
void avr_isp_reader_view_exit(void* context);
|
|
|
@ -1,268 +0,0 @@
|
||||||
#include "avr_isp_view_writer.h"
|
|
||||||
#include <gui/elements.h>
|
|
||||||
|
|
||||||
#include "../helpers/avr_isp_worker_rw.h"
|
|
||||||
#include <float_tools.h>
|
|
||||||
|
|
||||||
struct AvrIspWriterView {
|
|
||||||
View* view;
|
|
||||||
AvrIspWorkerRW* avr_isp_worker_rw;
|
|
||||||
const char* file_path;
|
|
||||||
const char* file_name;
|
|
||||||
AvrIspWriterViewCallback callback;
|
|
||||||
void* context;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
AvrIspWriterViewStatus status;
|
|
||||||
float progress_flash;
|
|
||||||
float progress_eeprom;
|
|
||||||
} AvrIspWriterViewModel;
|
|
||||||
|
|
||||||
void avr_isp_writer_update_progress(AvrIspWriterView* instance) {
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspWriterViewModel * model,
|
|
||||||
{
|
|
||||||
model->progress_flash =
|
|
||||||
avr_isp_worker_rw_get_progress_flash(instance->avr_isp_worker_rw);
|
|
||||||
model->progress_eeprom =
|
|
||||||
avr_isp_worker_rw_get_progress_eeprom(instance->avr_isp_worker_rw);
|
|
||||||
},
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_writer_view_set_callback(
|
|
||||||
AvrIspWriterView* instance,
|
|
||||||
AvrIspWriterViewCallback callback,
|
|
||||||
void* context) {
|
|
||||||
furi_assert(instance);
|
|
||||||
furi_assert(callback);
|
|
||||||
|
|
||||||
instance->callback = callback;
|
|
||||||
instance->context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_writer_set_file_path(
|
|
||||||
AvrIspWriterView* instance,
|
|
||||||
const char* file_path,
|
|
||||||
const char* file_name) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
instance->file_path = file_path;
|
|
||||||
instance->file_name = file_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_writer_view_draw(Canvas* canvas, AvrIspWriterViewModel* model) {
|
|
||||||
canvas_clear(canvas);
|
|
||||||
char str_flash[32] = {0};
|
|
||||||
char str_eeprom[32] = {0};
|
|
||||||
|
|
||||||
canvas_set_font(canvas, FontPrimary);
|
|
||||||
|
|
||||||
switch(model->status) {
|
|
||||||
case AvrIspWriterViewStatusIDLE:
|
|
||||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Press start to write");
|
|
||||||
canvas_set_font(canvas, FontSecondary);
|
|
||||||
elements_button_center(canvas, "Start");
|
|
||||||
snprintf(str_flash, sizeof(str_flash), "%d%%", (uint8_t)(model->progress_flash * 100));
|
|
||||||
snprintf(str_eeprom, sizeof(str_eeprom), "%d%%", (uint8_t)(model->progress_eeprom * 100));
|
|
||||||
break;
|
|
||||||
case AvrIspWriterViewStatusWriting:
|
|
||||||
if(float_is_equal(model->progress_flash, 0.f)) {
|
|
||||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Verifying firmware");
|
|
||||||
snprintf(str_flash, sizeof(str_flash), "***");
|
|
||||||
snprintf(str_eeprom, sizeof(str_eeprom), "***");
|
|
||||||
} else {
|
|
||||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Writing dump");
|
|
||||||
snprintf(str_flash, sizeof(str_flash), "%d%%", (uint8_t)(model->progress_flash * 100));
|
|
||||||
snprintf(
|
|
||||||
str_eeprom, sizeof(str_eeprom), "%d%%", (uint8_t)(model->progress_eeprom * 100));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case AvrIspWriterViewStatusVerification:
|
|
||||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Verifying dump");
|
|
||||||
snprintf(str_flash, sizeof(str_flash), "%d%%", (uint8_t)(model->progress_flash * 100));
|
|
||||||
snprintf(str_eeprom, sizeof(str_eeprom), "%d%%", (uint8_t)(model->progress_eeprom * 100));
|
|
||||||
break;
|
|
||||||
case AvrIspWriterViewStatusWritingFuse:
|
|
||||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Writing fuse");
|
|
||||||
snprintf(str_flash, sizeof(str_flash), "%d%%", (uint8_t)(model->progress_flash * 100));
|
|
||||||
snprintf(str_eeprom, sizeof(str_eeprom), "%d%%", (uint8_t)(model->progress_eeprom * 100));
|
|
||||||
break;
|
|
||||||
case AvrIspWriterViewStatusWritingFuseOk:
|
|
||||||
canvas_draw_str_aligned(canvas, 64, 5, AlignCenter, AlignCenter, "Done!");
|
|
||||||
snprintf(str_flash, sizeof(str_flash), "%d%%", (uint8_t)(model->progress_flash * 100));
|
|
||||||
snprintf(str_eeprom, sizeof(str_eeprom), "%d%%", (uint8_t)(model->progress_eeprom * 100));
|
|
||||||
canvas_set_font(canvas, FontSecondary);
|
|
||||||
elements_button_center(canvas, "Reflash");
|
|
||||||
elements_button_right(canvas, "Exit");
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas_set_font(canvas, FontSecondary);
|
|
||||||
canvas_draw_str(canvas, 0, 27, "Flash");
|
|
||||||
// snprintf(str_buf, sizeof(str_buf), "%d%%", (uint8_t)(model->progress_flash * 100));
|
|
||||||
elements_progress_bar_with_text(canvas, 44, 17, 84, model->progress_flash, str_flash);
|
|
||||||
canvas_draw_str(canvas, 0, 43, "EEPROM");
|
|
||||||
// snprintf(str_buf, sizeof(str_buf), "%d%%", (uint8_t)(model->progress_eeprom * 100));
|
|
||||||
elements_progress_bar_with_text(canvas, 44, 34, 84, model->progress_eeprom, str_eeprom);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool avr_isp_writer_view_input(InputEvent* event, void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
AvrIspWriterView* instance = context;
|
|
||||||
|
|
||||||
bool ret = true;
|
|
||||||
if(event->key == InputKeyBack && event->type == InputTypeShort) {
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspWriterViewModel * model,
|
|
||||||
{
|
|
||||||
if((model->status == AvrIspWriterViewStatusIDLE) ||
|
|
||||||
(model->status == AvrIspWriterViewStatusWritingFuseOk)) {
|
|
||||||
if(instance->callback)
|
|
||||||
instance->callback(AvrIspCustomEventSceneExit, instance->context);
|
|
||||||
ret = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
false);
|
|
||||||
} else if(event->key == InputKeyOk && event->type == InputTypeShort) {
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspWriterViewModel * model,
|
|
||||||
{
|
|
||||||
if((model->status == AvrIspWriterViewStatusIDLE) ||
|
|
||||||
(model->status == AvrIspWriterViewStatusWritingFuseOk)) {
|
|
||||||
model->status = AvrIspWriterViewStatusWriting;
|
|
||||||
|
|
||||||
avr_isp_worker_rw_write_dump_start(
|
|
||||||
instance->avr_isp_worker_rw, instance->file_path, instance->file_name);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
false);
|
|
||||||
} else if(event->key == InputKeyRight && event->type == InputTypeShort) {
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspWriterViewModel * model,
|
|
||||||
{
|
|
||||||
if((model->status == AvrIspWriterViewStatusIDLE) ||
|
|
||||||
(model->status == AvrIspWriterViewStatusWritingFuseOk)) {
|
|
||||||
if(instance->callback)
|
|
||||||
instance->callback(AvrIspCustomEventSceneExitStartMenu, instance->context);
|
|
||||||
ret = false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
false);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void avr_isp_writer_callback_status(void* context, AvrIspWorkerRWStatus status) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspWriterView* instance = context;
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspWriterViewModel * model,
|
|
||||||
{
|
|
||||||
switch(status) {
|
|
||||||
case AvrIspWorkerRWStatusEndWriting:
|
|
||||||
model->status = AvrIspWriterViewStatusVerification;
|
|
||||||
avr_isp_worker_rw_verification_start(
|
|
||||||
instance->avr_isp_worker_rw, instance->file_path, instance->file_name);
|
|
||||||
model->status = AvrIspWriterViewStatusVerification;
|
|
||||||
break;
|
|
||||||
case AvrIspWorkerRWStatusErrorVerification:
|
|
||||||
if(instance->callback)
|
|
||||||
instance->callback(AvrIspCustomEventSceneErrorVerification, instance->context);
|
|
||||||
break;
|
|
||||||
case AvrIspWorkerRWStatusEndVerification:
|
|
||||||
avr_isp_worker_rw_write_fuse_start(
|
|
||||||
instance->avr_isp_worker_rw, instance->file_path, instance->file_name);
|
|
||||||
model->status = AvrIspWriterViewStatusWritingFuse;
|
|
||||||
break;
|
|
||||||
case AvrIspWorkerRWStatusErrorWritingFuse:
|
|
||||||
if(instance->callback)
|
|
||||||
instance->callback(AvrIspCustomEventSceneErrorWritingFuse, instance->context);
|
|
||||||
break;
|
|
||||||
case AvrIspWorkerRWStatusEndWritingFuse:
|
|
||||||
model->status = AvrIspWriterViewStatusWritingFuseOk;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
//AvrIspWorkerRWStatusErrorWriting;
|
|
||||||
if(instance->callback)
|
|
||||||
instance->callback(AvrIspCustomEventSceneErrorWriting, instance->context);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_writer_view_enter(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
|
|
||||||
AvrIspWriterView* instance = context;
|
|
||||||
with_view_model(
|
|
||||||
instance->view,
|
|
||||||
AvrIspWriterViewModel * model,
|
|
||||||
{
|
|
||||||
model->status = AvrIspWriterViewStatusIDLE;
|
|
||||||
model->progress_flash = 0.0f;
|
|
||||||
model->progress_eeprom = 0.0f;
|
|
||||||
},
|
|
||||||
true);
|
|
||||||
|
|
||||||
//Start avr_isp_worker_rw
|
|
||||||
instance->avr_isp_worker_rw = avr_isp_worker_rw_alloc(instance->context);
|
|
||||||
|
|
||||||
avr_isp_worker_rw_set_callback_status(
|
|
||||||
instance->avr_isp_worker_rw, avr_isp_writer_callback_status, instance);
|
|
||||||
|
|
||||||
avr_isp_worker_rw_start(instance->avr_isp_worker_rw);
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_writer_view_exit(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
AvrIspWriterView* instance = context;
|
|
||||||
|
|
||||||
//Stop avr_isp_worker_rw
|
|
||||||
if(avr_isp_worker_rw_is_running(instance->avr_isp_worker_rw)) {
|
|
||||||
avr_isp_worker_rw_stop(instance->avr_isp_worker_rw);
|
|
||||||
}
|
|
||||||
|
|
||||||
avr_isp_worker_rw_free(instance->avr_isp_worker_rw);
|
|
||||||
}
|
|
||||||
|
|
||||||
AvrIspWriterView* avr_isp_writer_view_alloc() {
|
|
||||||
AvrIspWriterView* instance = malloc(sizeof(AvrIspWriterView));
|
|
||||||
|
|
||||||
// View allocation and configuration
|
|
||||||
instance->view = view_alloc();
|
|
||||||
|
|
||||||
view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(AvrIspWriterViewModel));
|
|
||||||
view_set_context(instance->view, instance);
|
|
||||||
view_set_draw_callback(instance->view, (ViewDrawCallback)avr_isp_writer_view_draw);
|
|
||||||
view_set_input_callback(instance->view, avr_isp_writer_view_input);
|
|
||||||
view_set_enter_callback(instance->view, avr_isp_writer_view_enter);
|
|
||||||
view_set_exit_callback(instance->view, avr_isp_writer_view_exit);
|
|
||||||
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
void avr_isp_writer_view_free(AvrIspWriterView* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
view_free(instance->view);
|
|
||||||
free(instance);
|
|
||||||
}
|
|
||||||
|
|
||||||
View* avr_isp_writer_view_get_view(AvrIspWriterView* instance) {
|
|
||||||
furi_assert(instance);
|
|
||||||
|
|
||||||
return instance->view;
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <gui/view.h>
|
|
||||||
#include "../helpers/avr_isp_types.h"
|
|
||||||
#include "../helpers/avr_isp_event.h"
|
|
||||||
|
|
||||||
typedef struct AvrIspWriterView AvrIspWriterView;
|
|
||||||
|
|
||||||
typedef void (*AvrIspWriterViewCallback)(AvrIspCustomEvent event, void* context);
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
AvrIspWriterViewStatusIDLE,
|
|
||||||
AvrIspWriterViewStatusWriting,
|
|
||||||
AvrIspWriterViewStatusVerification,
|
|
||||||
AvrIspWriterViewStatusWritingFuse,
|
|
||||||
AvrIspWriterViewStatusWritingFuseOk,
|
|
||||||
} AvrIspWriterViewStatus;
|
|
||||||
|
|
||||||
void avr_isp_writer_update_progress(AvrIspWriterView* instance);
|
|
||||||
|
|
||||||
void avr_isp_writer_set_file_path(
|
|
||||||
AvrIspWriterView* instance,
|
|
||||||
const char* file_path,
|
|
||||||
const char* file_name);
|
|
||||||
|
|
||||||
void avr_isp_writer_view_set_callback(
|
|
||||||
AvrIspWriterView* instance,
|
|
||||||
AvrIspWriterViewCallback callback,
|
|
||||||
void* context);
|
|
||||||
|
|
||||||
AvrIspWriterView* avr_isp_writer_view_alloc();
|
|
||||||
|
|
||||||
void avr_isp_writer_view_free(AvrIspWriterView* instance);
|
|
||||||
|
|
||||||
View* avr_isp_writer_view_get_view(AvrIspWriterView* instance);
|
|
||||||
|
|
||||||
void avr_isp_writer_view_exit(void* context);
|
|
105
applications/external/dap_link/README.md
vendored
|
@ -1,105 +0,0 @@
|
||||||
# Flipper Zero as CMSIS DAP/DAP Link
|
|
||||||
Flipper Zero as a [Free-DAP](https://github.com/ataradov/free-dap) based SWD\JTAG debugger. Free-DAP is a free and open source firmware implementation of the [CMSIS-DAP](https://www.keil.com/pack/doc/CMSIS_Dev/DAP/html/index.html) debugger.
|
|
||||||
|
|
||||||
## Protocols
|
|
||||||
SWD, JTAG , CMSIS-DAP v1 (18 KiB/s), CMSIS-DAP v2 (46 KiB/s), VCP (USB-UART).
|
|
||||||
|
|
||||||
WinUSB for driverless installation for Windows 8 and above.
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
### VSCode + Cortex-Debug
|
|
||||||
Set `"device": "cmsis-dap"`
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>BluePill configuration example</summary>
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"name": "Attach (DAP)",
|
|
||||||
"cwd": "${workspaceFolder}",
|
|
||||||
"executable": "./build/firmware.elf",
|
|
||||||
"request": "attach",
|
|
||||||
"type": "cortex-debug",
|
|
||||||
"servertype": "openocd",
|
|
||||||
"device": "cmsis-dap",
|
|
||||||
"configFiles": [
|
|
||||||
"interface/cmsis-dap.cfg",
|
|
||||||
"target/stm32f1x.cfg",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
```
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Flipper Zero configuration example</summary>
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"name": "Attach (DAP)",
|
|
||||||
"cwd": "${workspaceFolder}",
|
|
||||||
"executable": "./build/latest/firmware.elf",
|
|
||||||
"request": "attach",
|
|
||||||
"type": "cortex-debug",
|
|
||||||
"servertype": "openocd",
|
|
||||||
"device": "cmsis-dap",
|
|
||||||
"svdFile": "./debug/STM32WB55_CM4.svd",
|
|
||||||
"rtos": "FreeRTOS",
|
|
||||||
"configFiles": [
|
|
||||||
"interface/cmsis-dap.cfg",
|
|
||||||
"./debug/stm32wbx.cfg",
|
|
||||||
],
|
|
||||||
"postAttachCommands": [
|
|
||||||
"source debug/flipperapps.py",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
```
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### OpenOCD
|
|
||||||
Use `interface/cmsis-dap.cfg`. You will need OpenOCD v0.11.0.
|
|
||||||
|
|
||||||
Additional commands:
|
|
||||||
* `cmsis_dap_backend hid` for CMSIS-DAP v1 protocol.
|
|
||||||
* `cmsis_dap_backend usb_bulk` for CMSIS-DAP v2 protocol.
|
|
||||||
* `cmsis_dap_serial DAP_Oyevoxo` use DAP-Link running on Flipper named `Oyevoxo`.
|
|
||||||
* `cmsis-dap cmd 81` - reboot connected DAP-Link.
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Flash BluePill</summary>
|
|
||||||
|
|
||||||
```
|
|
||||||
openocd -f interface/cmsis-dap.cfg -f target/stm32f1x.cfg -c init -c "program build/firmware.bin reset exit 0x8000000"
|
|
||||||
```
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Flash Flipper Zero using DAP v2 protocol</summary>
|
|
||||||
|
|
||||||
```
|
|
||||||
openocd -f interface/cmsis-dap.cfg -c "cmsis_dap_backend usb_bulk" -f debug/stm32wbx.cfg -c init -c "program build/latest/firmware.bin reset exit 0x8000000"
|
|
||||||
```
|
|
||||||
</details>
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>Reboot connected DAP-Link on Flipper named Oyevoxo</summary>
|
|
||||||
|
|
||||||
```
|
|
||||||
openocd -f interface/cmsis-dap.cfg -c "cmsis_dap_serial DAP_Oyevoxo" -c "transport select swd" -c "adapter speed 4000000" -c init -c "cmsis-dap cmd 81" -c "exit"
|
|
||||||
```
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### PlatformIO
|
|
||||||
Use `debug_tool = cmsis-dap` and `upload_protocol = cmsis-dap`. [Documentation](https://docs.platformio.org/en/latest/plus/debug-tools/cmsis-dap.html#debugging-tool-cmsis-dap). Remember that Windows 8 and above do not require drivers.
|
|
||||||
|
|
||||||
<details>
|
|
||||||
<summary>BluePill platformio.ini example</summary>
|
|
||||||
|
|
||||||
```
|
|
||||||
[env:bluepill_f103c8]
|
|
||||||
platform = ststm32
|
|
||||||
board = bluepill_f103c8
|
|
||||||
debug_tool = cmsis-dap
|
|
||||||
upload_protocol = cmsis-dap
|
|
||||||
```
|
|
||||||
</details>
|
|
24
applications/external/dap_link/application.fam
vendored
|
@ -1,24 +0,0 @@
|
||||||
App(
|
|
||||||
appid="dap_link",
|
|
||||||
name="DAP Link",
|
|
||||||
apptype=FlipperAppType.EXTERNAL,
|
|
||||||
entry_point="dap_link_app",
|
|
||||||
requires=[
|
|
||||||
"gui",
|
|
||||||
"dialogs",
|
|
||||||
],
|
|
||||||
stack_size=4 * 1024,
|
|
||||||
order=20,
|
|
||||||
fap_icon="dap_link.png",
|
|
||||||
fap_category="GPIO",
|
|
||||||
fap_private_libs=[
|
|
||||||
Lib(
|
|
||||||
name="free-dap",
|
|
||||||
cincludes=["."],
|
|
||||||
sources=[
|
|
||||||
"dap.c",
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
fap_icon_assets="icons",
|
|
||||||
)
|
|
234
applications/external/dap_link/dap_config.h
vendored
|
@ -1,234 +0,0 @@
|
||||||
// SPDX-License-Identifier: BSD-3-Clause
|
|
||||||
// Copyright (c) 2022, Alex Taradov <alex@taradov.com>. All rights reserved.
|
|
||||||
|
|
||||||
#ifndef _DAP_CONFIG_H_
|
|
||||||
#define _DAP_CONFIG_H_
|
|
||||||
|
|
||||||
/*- Includes ----------------------------------------------------------------*/
|
|
||||||
#include <furi_hal_gpio.h>
|
|
||||||
|
|
||||||
/*- Definitions -------------------------------------------------------------*/
|
|
||||||
#define DAP_CONFIG_ENABLE_JTAG
|
|
||||||
|
|
||||||
#define DAP_CONFIG_DEFAULT_PORT DAP_PORT_SWD
|
|
||||||
#define DAP_CONFIG_DEFAULT_CLOCK 4200000 // Hz
|
|
||||||
|
|
||||||
#define DAP_CONFIG_PACKET_SIZE 64
|
|
||||||
#define DAP_CONFIG_PACKET_COUNT 1
|
|
||||||
|
|
||||||
#define DAP_CONFIG_JTAG_DEV_COUNT 8
|
|
||||||
|
|
||||||
// DAP_CONFIG_PRODUCT_STR must contain "CMSIS-DAP" to be compatible with the standard
|
|
||||||
#define DAP_CONFIG_VENDOR_STR "Flipper Zero"
|
|
||||||
#define DAP_CONFIG_PRODUCT_STR "Generic CMSIS-DAP Adapter"
|
|
||||||
#define DAP_CONFIG_SER_NUM_STR usb_serial_number
|
|
||||||
#define DAP_CONFIG_CMSIS_DAP_VER_STR "2.0.0"
|
|
||||||
|
|
||||||
#define DAP_CONFIG_RESET_TARGET_FN dap_app_target_reset
|
|
||||||
#define DAP_CONFIG_VENDOR_FN dap_app_vendor_cmd
|
|
||||||
|
|
||||||
// Attribute to use for performance-critical functions
|
|
||||||
#define DAP_CONFIG_PERFORMANCE_ATTR
|
|
||||||
|
|
||||||
// A value at which dap_clock_test() produces 1 kHz output on the SWCLK pin
|
|
||||||
// #define DAP_CONFIG_DELAY_CONSTANT 19000
|
|
||||||
#define DAP_CONFIG_DELAY_CONSTANT 6290
|
|
||||||
|
|
||||||
// A threshold for switching to fast clock (no added delays)
|
|
||||||
// This is the frequency produced by dap_clock_test(1) on the SWCLK pin
|
|
||||||
#define DAP_CONFIG_FAST_CLOCK 2400000 // Hz
|
|
||||||
|
|
||||||
/*- Prototypes --------------------------------------------------------------*/
|
|
||||||
extern char usb_serial_number[16];
|
|
||||||
|
|
||||||
/*- Implementations ---------------------------------------------------------*/
|
|
||||||
extern GpioPin flipper_dap_swclk_pin;
|
|
||||||
extern GpioPin flipper_dap_swdio_pin;
|
|
||||||
extern GpioPin flipper_dap_reset_pin;
|
|
||||||
extern GpioPin flipper_dap_tdo_pin;
|
|
||||||
extern GpioPin flipper_dap_tdi_pin;
|
|
||||||
|
|
||||||
extern void dap_app_vendor_cmd(uint8_t cmd);
|
|
||||||
extern void dap_app_target_reset();
|
|
||||||
extern void dap_app_disconnect();
|
|
||||||
extern void dap_app_connect_swd();
|
|
||||||
extern void dap_app_connect_jtag();
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
static inline void DAP_CONFIG_SWCLK_TCK_write(int value) {
|
|
||||||
furi_hal_gpio_write(&flipper_dap_swclk_pin, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
static inline void DAP_CONFIG_SWDIO_TMS_write(int value) {
|
|
||||||
furi_hal_gpio_write(&flipper_dap_swdio_pin, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
static inline void DAP_CONFIG_TDI_write(int value) {
|
|
||||||
#ifdef DAP_CONFIG_ENABLE_JTAG
|
|
||||||
furi_hal_gpio_write(&flipper_dap_tdi_pin, value);
|
|
||||||
#else
|
|
||||||
(void)value;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
static inline void DAP_CONFIG_TDO_write(int value) {
|
|
||||||
#ifdef DAP_CONFIG_ENABLE_JTAG
|
|
||||||
furi_hal_gpio_write(&flipper_dap_tdo_pin, value);
|
|
||||||
#else
|
|
||||||
(void)value;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
static inline void DAP_CONFIG_nTRST_write(int value) {
|
|
||||||
(void)value;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
static inline void DAP_CONFIG_nRESET_write(int value) {
|
|
||||||
furi_hal_gpio_write(&flipper_dap_reset_pin, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
static inline int DAP_CONFIG_SWCLK_TCK_read(void) {
|
|
||||||
return furi_hal_gpio_read(&flipper_dap_swclk_pin);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
static inline int DAP_CONFIG_SWDIO_TMS_read(void) {
|
|
||||||
return furi_hal_gpio_read(&flipper_dap_swdio_pin);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
static inline int DAP_CONFIG_TDO_read(void) {
|
|
||||||
#ifdef DAP_CONFIG_ENABLE_JTAG
|
|
||||||
return furi_hal_gpio_read(&flipper_dap_tdo_pin);
|
|
||||||
#else
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
static inline int DAP_CONFIG_TDI_read(void) {
|
|
||||||
#ifdef DAP_CONFIG_ENABLE_JTAG
|
|
||||||
return furi_hal_gpio_read(&flipper_dap_tdi_pin);
|
|
||||||
#else
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
static inline int DAP_CONFIG_nTRST_read(void) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
static inline int DAP_CONFIG_nRESET_read(void) {
|
|
||||||
return furi_hal_gpio_read(&flipper_dap_reset_pin);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
static inline void DAP_CONFIG_SWCLK_TCK_set(void) {
|
|
||||||
LL_GPIO_SetOutputPin(flipper_dap_swclk_pin.port, flipper_dap_swclk_pin.pin);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
static inline void DAP_CONFIG_SWCLK_TCK_clr(void) {
|
|
||||||
LL_GPIO_ResetOutputPin(flipper_dap_swclk_pin.port, flipper_dap_swclk_pin.pin);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
static inline void DAP_CONFIG_SWDIO_TMS_in(void) {
|
|
||||||
LL_GPIO_SetPinMode(flipper_dap_swdio_pin.port, flipper_dap_swdio_pin.pin, LL_GPIO_MODE_INPUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
static inline void DAP_CONFIG_SWDIO_TMS_out(void) {
|
|
||||||
LL_GPIO_SetPinMode(flipper_dap_swdio_pin.port, flipper_dap_swdio_pin.pin, LL_GPIO_MODE_OUTPUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
static inline void DAP_CONFIG_SETUP(void) {
|
|
||||||
furi_hal_gpio_init(&flipper_dap_swdio_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
|
|
||||||
furi_hal_gpio_init(&flipper_dap_swclk_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
|
|
||||||
furi_hal_gpio_init(&flipper_dap_reset_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
|
|
||||||
#ifdef DAP_CONFIG_ENABLE_JTAG
|
|
||||||
furi_hal_gpio_init(&flipper_dap_tdo_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
|
|
||||||
furi_hal_gpio_init(&flipper_dap_tdi_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
static inline void DAP_CONFIG_DISCONNECT(void) {
|
|
||||||
furi_hal_gpio_init(&flipper_dap_swdio_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
|
|
||||||
furi_hal_gpio_init(&flipper_dap_swclk_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
|
|
||||||
furi_hal_gpio_init(&flipper_dap_reset_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
|
|
||||||
#ifdef DAP_CONFIG_ENABLE_JTAG
|
|
||||||
furi_hal_gpio_init(&flipper_dap_tdo_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
|
|
||||||
furi_hal_gpio_init(&flipper_dap_tdi_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
|
|
||||||
#endif
|
|
||||||
dap_app_disconnect();
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
static inline void DAP_CONFIG_CONNECT_SWD(void) {
|
|
||||||
furi_hal_gpio_init(
|
|
||||||
&flipper_dap_swdio_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
|
|
||||||
furi_hal_gpio_write(&flipper_dap_swdio_pin, true);
|
|
||||||
|
|
||||||
furi_hal_gpio_init(
|
|
||||||
&flipper_dap_swclk_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
|
|
||||||
furi_hal_gpio_write(&flipper_dap_swclk_pin, true);
|
|
||||||
|
|
||||||
furi_hal_gpio_init(
|
|
||||||
&flipper_dap_reset_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
|
|
||||||
furi_hal_gpio_write(&flipper_dap_reset_pin, true);
|
|
||||||
|
|
||||||
#ifdef DAP_CONFIG_ENABLE_JTAG
|
|
||||||
furi_hal_gpio_init(&flipper_dap_tdo_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
|
|
||||||
furi_hal_gpio_init(&flipper_dap_tdi_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
|
|
||||||
#endif
|
|
||||||
dap_app_connect_swd();
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
static inline void DAP_CONFIG_CONNECT_JTAG(void) {
|
|
||||||
furi_hal_gpio_init(
|
|
||||||
&flipper_dap_swdio_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
|
|
||||||
furi_hal_gpio_write(&flipper_dap_swdio_pin, true);
|
|
||||||
|
|
||||||
furi_hal_gpio_init(
|
|
||||||
&flipper_dap_swclk_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
|
|
||||||
furi_hal_gpio_write(&flipper_dap_swclk_pin, true);
|
|
||||||
|
|
||||||
furi_hal_gpio_init(
|
|
||||||
&flipper_dap_reset_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
|
|
||||||
furi_hal_gpio_write(&flipper_dap_reset_pin, true);
|
|
||||||
|
|
||||||
#ifdef DAP_CONFIG_ENABLE_JTAG
|
|
||||||
furi_hal_gpio_init(&flipper_dap_tdo_pin, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
|
|
||||||
|
|
||||||
furi_hal_gpio_init(
|
|
||||||
&flipper_dap_tdi_pin, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
|
|
||||||
furi_hal_gpio_write(&flipper_dap_tdi_pin, true);
|
|
||||||
#endif
|
|
||||||
dap_app_connect_jtag();
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
static inline void DAP_CONFIG_LED(int index, int state) {
|
|
||||||
(void)index;
|
|
||||||
(void)state;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
__attribute__((always_inline)) static inline void DAP_CONFIG_DELAY(uint32_t cycles) {
|
|
||||||
asm volatile("1: subs %[cycles], %[cycles], #1 \n"
|
|
||||||
" bne 1b \n"
|
|
||||||
: [cycles] "+l"(cycles));
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // _DAP_CONFIG_H_
|
|
527
applications/external/dap_link/dap_link.c
vendored
|
@ -1,527 +0,0 @@
|
||||||
#include <dap.h>
|
|
||||||
#include <furi.h>
|
|
||||||
#include <furi_hal_version.h>
|
|
||||||
#include <furi_hal_gpio.h>
|
|
||||||
#include <furi_hal_uart.h>
|
|
||||||
#include <furi_hal_console.h>
|
|
||||||
#include <furi_hal_resources.h>
|
|
||||||
#include <furi_hal_power.h>
|
|
||||||
#include <stm32wbxx_ll_usart.h>
|
|
||||||
#include <stm32wbxx_ll_lpuart.h>
|
|
||||||
|
|
||||||
#include "dap_link.h"
|
|
||||||
#include "dap_config.h"
|
|
||||||
#include "gui/dap_gui.h"
|
|
||||||
#include "usb/dap_v2_usb.h"
|
|
||||||
#include <dialogs/dialogs.h>
|
|
||||||
#include "dap_link_icons.h"
|
|
||||||
|
|
||||||
/***************************************************************************/
|
|
||||||
/****************************** DAP COMMON *********************************/
|
|
||||||
/***************************************************************************/
|
|
||||||
|
|
||||||
struct DapApp {
|
|
||||||
FuriThread* dap_thread;
|
|
||||||
FuriThread* cdc_thread;
|
|
||||||
FuriThread* gui_thread;
|
|
||||||
|
|
||||||
DapState state;
|
|
||||||
DapConfig config;
|
|
||||||
};
|
|
||||||
|
|
||||||
void dap_app_get_state(DapApp* app, DapState* state) {
|
|
||||||
*state = app->state;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define DAP_PROCESS_THREAD_TICK 500
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
DapThreadEventStop = (1 << 0),
|
|
||||||
} DapThreadEvent;
|
|
||||||
|
|
||||||
void dap_thread_send_stop(FuriThread* thread) {
|
|
||||||
furi_thread_flags_set(furi_thread_get_id(thread), DapThreadEventStop);
|
|
||||||
}
|
|
||||||
|
|
||||||
GpioPin flipper_dap_swclk_pin;
|
|
||||||
GpioPin flipper_dap_swdio_pin;
|
|
||||||
GpioPin flipper_dap_reset_pin;
|
|
||||||
GpioPin flipper_dap_tdo_pin;
|
|
||||||
GpioPin flipper_dap_tdi_pin;
|
|
||||||
|
|
||||||
/***************************************************************************/
|
|
||||||
/****************************** DAP PROCESS ********************************/
|
|
||||||
/***************************************************************************/
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint8_t data[DAP_CONFIG_PACKET_SIZE];
|
|
||||||
uint8_t size;
|
|
||||||
} DapPacket;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
DAPThreadEventStop = DapThreadEventStop,
|
|
||||||
DAPThreadEventRxV1 = (1 << 1),
|
|
||||||
DAPThreadEventRxV2 = (1 << 2),
|
|
||||||
DAPThreadEventUSBConnect = (1 << 3),
|
|
||||||
DAPThreadEventUSBDisconnect = (1 << 4),
|
|
||||||
DAPThreadEventApplyConfig = (1 << 5),
|
|
||||||
DAPThreadEventAll = DAPThreadEventStop | DAPThreadEventRxV1 | DAPThreadEventRxV2 |
|
|
||||||
DAPThreadEventUSBConnect | DAPThreadEventUSBDisconnect |
|
|
||||||
DAPThreadEventApplyConfig,
|
|
||||||
} DAPThreadEvent;
|
|
||||||
|
|
||||||
#define USB_SERIAL_NUMBER_LEN 16
|
|
||||||
char usb_serial_number[USB_SERIAL_NUMBER_LEN] = {0};
|
|
||||||
|
|
||||||
const char* dap_app_get_serial(DapApp* app) {
|
|
||||||
UNUSED(app);
|
|
||||||
return usb_serial_number;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dap_app_rx1_callback(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
FuriThreadId thread_id = (FuriThreadId)context;
|
|
||||||
furi_thread_flags_set(thread_id, DAPThreadEventRxV1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dap_app_rx2_callback(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
FuriThreadId thread_id = (FuriThreadId)context;
|
|
||||||
furi_thread_flags_set(thread_id, DAPThreadEventRxV2);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dap_app_usb_state_callback(bool state, void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
FuriThreadId thread_id = (FuriThreadId)context;
|
|
||||||
if(state) {
|
|
||||||
furi_thread_flags_set(thread_id, DAPThreadEventUSBConnect);
|
|
||||||
} else {
|
|
||||||
furi_thread_flags_set(thread_id, DAPThreadEventUSBDisconnect);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dap_app_process_v1() {
|
|
||||||
DapPacket tx_packet;
|
|
||||||
DapPacket rx_packet;
|
|
||||||
memset(&tx_packet, 0, sizeof(DapPacket));
|
|
||||||
rx_packet.size = dap_v1_usb_rx(rx_packet.data, DAP_CONFIG_PACKET_SIZE);
|
|
||||||
dap_process_request(rx_packet.data, rx_packet.size, tx_packet.data, DAP_CONFIG_PACKET_SIZE);
|
|
||||||
dap_v1_usb_tx(tx_packet.data, DAP_CONFIG_PACKET_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dap_app_process_v2() {
|
|
||||||
DapPacket tx_packet;
|
|
||||||
DapPacket rx_packet;
|
|
||||||
memset(&tx_packet, 0, sizeof(DapPacket));
|
|
||||||
rx_packet.size = dap_v2_usb_rx(rx_packet.data, DAP_CONFIG_PACKET_SIZE);
|
|
||||||
size_t len = dap_process_request(
|
|
||||||
rx_packet.data, rx_packet.size, tx_packet.data, DAP_CONFIG_PACKET_SIZE);
|
|
||||||
dap_v2_usb_tx(tx_packet.data, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_app_vendor_cmd(uint8_t cmd) {
|
|
||||||
// openocd -c "cmsis-dap cmd 81"
|
|
||||||
if(cmd == 0x01) {
|
|
||||||
furi_hal_power_reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_app_target_reset() {
|
|
||||||
FURI_LOG_I("DAP", "Target reset");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dap_init_gpio(DapSwdPins swd_pins) {
|
|
||||||
switch(swd_pins) {
|
|
||||||
case DapSwdPinsPA7PA6:
|
|
||||||
flipper_dap_swclk_pin = gpio_ext_pa7;
|
|
||||||
flipper_dap_swdio_pin = gpio_ext_pa6;
|
|
||||||
break;
|
|
||||||
case DapSwdPinsPA14PA13:
|
|
||||||
flipper_dap_swclk_pin = (GpioPin){.port = GPIOA, .pin = LL_GPIO_PIN_14};
|
|
||||||
flipper_dap_swdio_pin = (GpioPin){.port = GPIOA, .pin = LL_GPIO_PIN_13};
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
flipper_dap_reset_pin = gpio_ext_pa4;
|
|
||||||
flipper_dap_tdo_pin = gpio_ext_pb3;
|
|
||||||
flipper_dap_tdi_pin = gpio_ext_pb2;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dap_deinit_gpio(DapSwdPins swd_pins) {
|
|
||||||
// setup gpio pins to default state
|
|
||||||
furi_hal_gpio_init(&flipper_dap_reset_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
|
||||||
furi_hal_gpio_init(&flipper_dap_tdo_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
|
||||||
furi_hal_gpio_init(&flipper_dap_tdi_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
|
||||||
|
|
||||||
if(DapSwdPinsPA14PA13 == swd_pins) {
|
|
||||||
// PA14 and PA13 are used by SWD
|
|
||||||
furi_hal_gpio_init_ex(
|
|
||||||
&flipper_dap_swclk_pin,
|
|
||||||
GpioModeAltFunctionPushPull,
|
|
||||||
GpioPullDown,
|
|
||||||
GpioSpeedLow,
|
|
||||||
GpioAltFn0JTCK_SWCLK);
|
|
||||||
furi_hal_gpio_init_ex(
|
|
||||||
&flipper_dap_swdio_pin,
|
|
||||||
GpioModeAltFunctionPushPull,
|
|
||||||
GpioPullUp,
|
|
||||||
GpioSpeedVeryHigh,
|
|
||||||
GpioAltFn0JTMS_SWDIO);
|
|
||||||
} else {
|
|
||||||
furi_hal_gpio_init(&flipper_dap_swclk_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
|
||||||
furi_hal_gpio_init(&flipper_dap_swdio_pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int32_t dap_process(void* p) {
|
|
||||||
DapApp* app = p;
|
|
||||||
DapState* dap_state = &(app->state);
|
|
||||||
|
|
||||||
// allocate resources
|
|
||||||
FuriHalUsbInterface* usb_config_prev;
|
|
||||||
app->config.swd_pins = DapSwdPinsPA7PA6;
|
|
||||||
DapSwdPins swd_pins_prev = app->config.swd_pins;
|
|
||||||
|
|
||||||
// init pins
|
|
||||||
dap_init_gpio(swd_pins_prev);
|
|
||||||
|
|
||||||
// init dap
|
|
||||||
dap_init();
|
|
||||||
|
|
||||||
// get name
|
|
||||||
const char* name = furi_hal_version_get_name_ptr();
|
|
||||||
if(!name) {
|
|
||||||
name = "Flipper";
|
|
||||||
}
|
|
||||||
snprintf(usb_serial_number, USB_SERIAL_NUMBER_LEN, "DAP_%s", name);
|
|
||||||
|
|
||||||
// init usb
|
|
||||||
usb_config_prev = furi_hal_usb_get_config();
|
|
||||||
dap_common_usb_alloc_name(usb_serial_number);
|
|
||||||
dap_common_usb_set_context(furi_thread_get_id(furi_thread_get_current()));
|
|
||||||
dap_v1_usb_set_rx_callback(dap_app_rx1_callback);
|
|
||||||
dap_v2_usb_set_rx_callback(dap_app_rx2_callback);
|
|
||||||
dap_common_usb_set_state_callback(dap_app_usb_state_callback);
|
|
||||||
furi_hal_usb_set_config(&dap_v2_usb_hid, NULL);
|
|
||||||
|
|
||||||
// work
|
|
||||||
uint32_t events;
|
|
||||||
while(1) {
|
|
||||||
events = furi_thread_flags_wait(DAPThreadEventAll, FuriFlagWaitAny, FuriWaitForever);
|
|
||||||
|
|
||||||
if(!(events & FuriFlagError)) {
|
|
||||||
if(events & DAPThreadEventRxV1) {
|
|
||||||
dap_app_process_v1();
|
|
||||||
dap_state->dap_counter++;
|
|
||||||
dap_state->dap_version = DapVersionV1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(events & DAPThreadEventRxV2) {
|
|
||||||
dap_app_process_v2();
|
|
||||||
dap_state->dap_counter++;
|
|
||||||
dap_state->dap_version = DapVersionV2;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(events & DAPThreadEventUSBConnect) {
|
|
||||||
dap_state->usb_connected = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(events & DAPThreadEventUSBDisconnect) {
|
|
||||||
dap_state->usb_connected = false;
|
|
||||||
dap_state->dap_version = DapVersionUnknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(events & DAPThreadEventApplyConfig) {
|
|
||||||
if(swd_pins_prev != app->config.swd_pins) {
|
|
||||||
dap_deinit_gpio(swd_pins_prev);
|
|
||||||
swd_pins_prev = app->config.swd_pins;
|
|
||||||
dap_init_gpio(swd_pins_prev);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(events & DAPThreadEventStop) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// deinit usb
|
|
||||||
furi_hal_usb_set_config(usb_config_prev, NULL);
|
|
||||||
dap_common_usb_free_name();
|
|
||||||
dap_deinit_gpio(swd_pins_prev);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***************************************************************************/
|
|
||||||
/****************************** CDC PROCESS ********************************/
|
|
||||||
/***************************************************************************/
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
CDCThreadEventStop = DapThreadEventStop,
|
|
||||||
CDCThreadEventUARTRx = (1 << 1),
|
|
||||||
CDCThreadEventCDCRx = (1 << 2),
|
|
||||||
CDCThreadEventCDCConfig = (1 << 3),
|
|
||||||
CDCThreadEventApplyConfig = (1 << 4),
|
|
||||||
CDCThreadEventAll = CDCThreadEventStop | CDCThreadEventUARTRx | CDCThreadEventCDCRx |
|
|
||||||
CDCThreadEventCDCConfig | CDCThreadEventApplyConfig,
|
|
||||||
} CDCThreadEvent;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
FuriStreamBuffer* rx_stream;
|
|
||||||
FuriThreadId thread_id;
|
|
||||||
FuriHalUartId uart_id;
|
|
||||||
struct usb_cdc_line_coding line_coding;
|
|
||||||
} CDCProcess;
|
|
||||||
|
|
||||||
static void cdc_uart_irq_cb(UartIrqEvent ev, uint8_t data, void* ctx) {
|
|
||||||
CDCProcess* app = ctx;
|
|
||||||
|
|
||||||
if(ev == UartIrqEventRXNE) {
|
|
||||||
furi_stream_buffer_send(app->rx_stream, &data, 1, 0);
|
|
||||||
furi_thread_flags_set(app->thread_id, CDCThreadEventUARTRx);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cdc_usb_rx_callback(void* context) {
|
|
||||||
CDCProcess* app = context;
|
|
||||||
furi_thread_flags_set(app->thread_id, CDCThreadEventCDCRx);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cdc_usb_control_line_callback(uint8_t state, void* context) {
|
|
||||||
UNUSED(context);
|
|
||||||
UNUSED(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cdc_usb_config_callback(struct usb_cdc_line_coding* config, void* context) {
|
|
||||||
CDCProcess* app = context;
|
|
||||||
app->line_coding = *config;
|
|
||||||
furi_thread_flags_set(app->thread_id, CDCThreadEventCDCConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
static FuriHalUartId cdc_init_uart(
|
|
||||||
DapUartType type,
|
|
||||||
DapUartTXRX swap,
|
|
||||||
uint32_t baudrate,
|
|
||||||
void (*cb)(UartIrqEvent ev, uint8_t data, void* ctx),
|
|
||||||
void* ctx) {
|
|
||||||
FuriHalUartId uart_id = FuriHalUartIdUSART1;
|
|
||||||
if(baudrate == 0) baudrate = 115200;
|
|
||||||
|
|
||||||
switch(type) {
|
|
||||||
case DapUartTypeUSART1:
|
|
||||||
uart_id = FuriHalUartIdUSART1;
|
|
||||||
furi_hal_console_disable();
|
|
||||||
furi_hal_uart_deinit(uart_id);
|
|
||||||
if(swap == DapUartTXRXSwap) {
|
|
||||||
LL_USART_SetTXRXSwap(USART1, LL_USART_TXRX_SWAPPED);
|
|
||||||
} else {
|
|
||||||
LL_USART_SetTXRXSwap(USART1, LL_USART_TXRX_STANDARD);
|
|
||||||
}
|
|
||||||
furi_hal_uart_init(uart_id, baudrate);
|
|
||||||
furi_hal_uart_set_irq_cb(uart_id, cb, ctx);
|
|
||||||
break;
|
|
||||||
case DapUartTypeLPUART1:
|
|
||||||
uart_id = FuriHalUartIdLPUART1;
|
|
||||||
furi_hal_uart_deinit(uart_id);
|
|
||||||
if(swap == DapUartTXRXSwap) {
|
|
||||||
LL_LPUART_SetTXRXSwap(LPUART1, LL_LPUART_TXRX_SWAPPED);
|
|
||||||
} else {
|
|
||||||
LL_LPUART_SetTXRXSwap(LPUART1, LL_LPUART_TXRX_STANDARD);
|
|
||||||
}
|
|
||||||
furi_hal_uart_init(uart_id, baudrate);
|
|
||||||
furi_hal_uart_set_irq_cb(uart_id, cb, ctx);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return uart_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cdc_deinit_uart(DapUartType type) {
|
|
||||||
switch(type) {
|
|
||||||
case DapUartTypeUSART1:
|
|
||||||
furi_hal_uart_deinit(FuriHalUartIdUSART1);
|
|
||||||
LL_USART_SetTXRXSwap(USART1, LL_USART_TXRX_STANDARD);
|
|
||||||
furi_hal_console_init();
|
|
||||||
break;
|
|
||||||
case DapUartTypeLPUART1:
|
|
||||||
furi_hal_uart_deinit(FuriHalUartIdLPUART1);
|
|
||||||
LL_LPUART_SetTXRXSwap(LPUART1, LL_LPUART_TXRX_STANDARD);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int32_t cdc_process(void* p) {
|
|
||||||
DapApp* dap_app = p;
|
|
||||||
DapState* dap_state = &(dap_app->state);
|
|
||||||
|
|
||||||
dap_app->config.uart_pins = DapUartTypeLPUART1;
|
|
||||||
dap_app->config.uart_swap = DapUartTXRXNormal;
|
|
||||||
|
|
||||||
DapUartType uart_pins_prev = dap_app->config.uart_pins;
|
|
||||||
DapUartTXRX uart_swap_prev = dap_app->config.uart_swap;
|
|
||||||
|
|
||||||
CDCProcess* app = malloc(sizeof(CDCProcess));
|
|
||||||
app->thread_id = furi_thread_get_id(furi_thread_get_current());
|
|
||||||
app->rx_stream = furi_stream_buffer_alloc(512, 1);
|
|
||||||
|
|
||||||
const uint8_t rx_buffer_size = 64;
|
|
||||||
uint8_t* rx_buffer = malloc(rx_buffer_size);
|
|
||||||
|
|
||||||
app->uart_id = cdc_init_uart(
|
|
||||||
uart_pins_prev, uart_swap_prev, dap_state->cdc_baudrate, cdc_uart_irq_cb, app);
|
|
||||||
|
|
||||||
dap_cdc_usb_set_context(app);
|
|
||||||
dap_cdc_usb_set_rx_callback(cdc_usb_rx_callback);
|
|
||||||
dap_cdc_usb_set_control_line_callback(cdc_usb_control_line_callback);
|
|
||||||
dap_cdc_usb_set_config_callback(cdc_usb_config_callback);
|
|
||||||
|
|
||||||
uint32_t events;
|
|
||||||
while(1) {
|
|
||||||
events = furi_thread_flags_wait(CDCThreadEventAll, FuriFlagWaitAny, FuriWaitForever);
|
|
||||||
|
|
||||||
if(!(events & FuriFlagError)) {
|
|
||||||
if(events & CDCThreadEventCDCConfig) {
|
|
||||||
if(dap_state->cdc_baudrate != app->line_coding.dwDTERate) {
|
|
||||||
dap_state->cdc_baudrate = app->line_coding.dwDTERate;
|
|
||||||
if(dap_state->cdc_baudrate > 0) {
|
|
||||||
furi_hal_uart_set_br(app->uart_id, dap_state->cdc_baudrate);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(events & CDCThreadEventUARTRx) {
|
|
||||||
size_t len =
|
|
||||||
furi_stream_buffer_receive(app->rx_stream, rx_buffer, rx_buffer_size, 0);
|
|
||||||
|
|
||||||
if(len > 0) {
|
|
||||||
dap_cdc_usb_tx(rx_buffer, len);
|
|
||||||
}
|
|
||||||
dap_state->cdc_rx_counter += len;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(events & CDCThreadEventCDCRx) {
|
|
||||||
size_t len = dap_cdc_usb_rx(rx_buffer, rx_buffer_size);
|
|
||||||
if(len > 0) {
|
|
||||||
furi_hal_uart_tx(app->uart_id, rx_buffer, len);
|
|
||||||
}
|
|
||||||
dap_state->cdc_tx_counter += len;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(events & CDCThreadEventApplyConfig) {
|
|
||||||
if(uart_pins_prev != dap_app->config.uart_pins ||
|
|
||||||
uart_swap_prev != dap_app->config.uart_swap) {
|
|
||||||
cdc_deinit_uart(uart_pins_prev);
|
|
||||||
uart_pins_prev = dap_app->config.uart_pins;
|
|
||||||
uart_swap_prev = dap_app->config.uart_swap;
|
|
||||||
app->uart_id = cdc_init_uart(
|
|
||||||
uart_pins_prev,
|
|
||||||
uart_swap_prev,
|
|
||||||
dap_state->cdc_baudrate,
|
|
||||||
cdc_uart_irq_cb,
|
|
||||||
app);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(events & CDCThreadEventStop) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cdc_deinit_uart(uart_pins_prev);
|
|
||||||
free(rx_buffer);
|
|
||||||
furi_stream_buffer_free(app->rx_stream);
|
|
||||||
free(app);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/***************************************************************************/
|
|
||||||
/******************************* MAIN APP **********************************/
|
|
||||||
/***************************************************************************/
|
|
||||||
|
|
||||||
static DapApp* dap_app_alloc() {
|
|
||||||
DapApp* dap_app = malloc(sizeof(DapApp));
|
|
||||||
dap_app->dap_thread = furi_thread_alloc_ex("DAP Process", 1024, dap_process, dap_app);
|
|
||||||
dap_app->cdc_thread = furi_thread_alloc_ex("DAP CDC", 1024, cdc_process, dap_app);
|
|
||||||
dap_app->gui_thread = furi_thread_alloc_ex("DAP GUI", 1024, dap_gui_thread, dap_app);
|
|
||||||
return dap_app;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dap_app_free(DapApp* dap_app) {
|
|
||||||
furi_assert(dap_app);
|
|
||||||
furi_thread_free(dap_app->dap_thread);
|
|
||||||
furi_thread_free(dap_app->cdc_thread);
|
|
||||||
furi_thread_free(dap_app->gui_thread);
|
|
||||||
free(dap_app);
|
|
||||||
}
|
|
||||||
|
|
||||||
static DapApp* app_handle = NULL;
|
|
||||||
|
|
||||||
void dap_app_disconnect() {
|
|
||||||
app_handle->state.dap_mode = DapModeDisconnected;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_app_connect_swd() {
|
|
||||||
app_handle->state.dap_mode = DapModeSWD;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_app_connect_jtag() {
|
|
||||||
app_handle->state.dap_mode = DapModeJTAG;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_app_set_config(DapApp* app, DapConfig* config) {
|
|
||||||
app->config = *config;
|
|
||||||
furi_thread_flags_set(furi_thread_get_id(app->dap_thread), DAPThreadEventApplyConfig);
|
|
||||||
furi_thread_flags_set(furi_thread_get_id(app->cdc_thread), CDCThreadEventApplyConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
DapConfig* dap_app_get_config(DapApp* app) {
|
|
||||||
return &app->config;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t dap_link_app(void* p) {
|
|
||||||
UNUSED(p);
|
|
||||||
|
|
||||||
if(furi_hal_usb_is_locked()) {
|
|
||||||
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
|
|
||||||
DialogMessage* message = dialog_message_alloc();
|
|
||||||
dialog_message_set_header(message, "Connection\nis active!", 3, 2, AlignLeft, AlignTop);
|
|
||||||
dialog_message_set_text(
|
|
||||||
message,
|
|
||||||
"Disconnect from\nPC or phone to\nuse this function.",
|
|
||||||
3,
|
|
||||||
30,
|
|
||||||
AlignLeft,
|
|
||||||
AlignTop);
|
|
||||||
dialog_message_set_icon(message, &I_ActiveConnection_50x64, 78, 0);
|
|
||||||
dialog_message_show(dialogs, message);
|
|
||||||
dialog_message_free(message);
|
|
||||||
furi_record_close(RECORD_DIALOGS);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// alloc app
|
|
||||||
DapApp* app = dap_app_alloc();
|
|
||||||
app_handle = app;
|
|
||||||
|
|
||||||
furi_thread_start(app->dap_thread);
|
|
||||||
furi_thread_start(app->cdc_thread);
|
|
||||||
furi_thread_start(app->gui_thread);
|
|
||||||
|
|
||||||
// wait until gui thread is finished
|
|
||||||
furi_thread_join(app->gui_thread);
|
|
||||||
|
|
||||||
// send stop event to threads
|
|
||||||
dap_thread_send_stop(app->dap_thread);
|
|
||||||
dap_thread_send_stop(app->cdc_thread);
|
|
||||||
|
|
||||||
// wait for threads to stop
|
|
||||||
furi_thread_join(app->dap_thread);
|
|
||||||
furi_thread_join(app->cdc_thread);
|
|
||||||
|
|
||||||
// free app
|
|
||||||
dap_app_free(app);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
55
applications/external/dap_link/dap_link.h
vendored
|
@ -1,55 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
DapModeDisconnected,
|
|
||||||
DapModeSWD,
|
|
||||||
DapModeJTAG,
|
|
||||||
} DapMode;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
DapVersionUnknown,
|
|
||||||
DapVersionV1,
|
|
||||||
DapVersionV2,
|
|
||||||
} DapVersion;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
bool usb_connected;
|
|
||||||
DapMode dap_mode;
|
|
||||||
DapVersion dap_version;
|
|
||||||
uint32_t dap_counter;
|
|
||||||
uint32_t cdc_baudrate;
|
|
||||||
uint32_t cdc_tx_counter;
|
|
||||||
uint32_t cdc_rx_counter;
|
|
||||||
} DapState;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
DapSwdPinsPA7PA6, // Pins 2, 3
|
|
||||||
DapSwdPinsPA14PA13, // Pins 10, 12
|
|
||||||
} DapSwdPins;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
DapUartTypeUSART1, // Pins 13, 14
|
|
||||||
DapUartTypeLPUART1, // Pins 15, 16
|
|
||||||
} DapUartType;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
DapUartTXRXNormal,
|
|
||||||
DapUartTXRXSwap,
|
|
||||||
} DapUartTXRX;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
DapSwdPins swd_pins;
|
|
||||||
DapUartType uart_pins;
|
|
||||||
DapUartTXRX uart_swap;
|
|
||||||
} DapConfig;
|
|
||||||
|
|
||||||
typedef struct DapApp DapApp;
|
|
||||||
|
|
||||||
void dap_app_get_state(DapApp* app, DapState* state);
|
|
||||||
|
|
||||||
const char* dap_app_get_serial(DapApp* app);
|
|
||||||
|
|
||||||
void dap_app_set_config(DapApp* app, DapConfig* config);
|
|
||||||
|
|
||||||
DapConfig* dap_app_get_config(DapApp* app);
|
|
BIN
applications/external/dap_link/dap_link.png
vendored
Before Width: | Height: | Size: 143 B |
92
applications/external/dap_link/gui/dap_gui.c
vendored
|
@ -1,92 +0,0 @@
|
||||||
#include "dap_gui.h"
|
|
||||||
#include "dap_gui_i.h"
|
|
||||||
|
|
||||||
#define DAP_GUI_TICK 250
|
|
||||||
|
|
||||||
static bool dap_gui_custom_event_callback(void* context, uint32_t event) {
|
|
||||||
furi_assert(context);
|
|
||||||
DapGuiApp* app = context;
|
|
||||||
return scene_manager_handle_custom_event(app->scene_manager, event);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool dap_gui_back_event_callback(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
DapGuiApp* app = context;
|
|
||||||
return scene_manager_handle_back_event(app->scene_manager);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dap_gui_tick_event_callback(void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
DapGuiApp* app = context;
|
|
||||||
scene_manager_handle_tick_event(app->scene_manager);
|
|
||||||
}
|
|
||||||
|
|
||||||
DapGuiApp* dap_gui_alloc() {
|
|
||||||
DapGuiApp* app = malloc(sizeof(DapGuiApp));
|
|
||||||
app->gui = furi_record_open(RECORD_GUI);
|
|
||||||
app->view_dispatcher = view_dispatcher_alloc();
|
|
||||||
app->scene_manager = scene_manager_alloc(&dap_scene_handlers, app);
|
|
||||||
view_dispatcher_enable_queue(app->view_dispatcher);
|
|
||||||
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
|
|
||||||
|
|
||||||
view_dispatcher_set_custom_event_callback(app->view_dispatcher, dap_gui_custom_event_callback);
|
|
||||||
view_dispatcher_set_navigation_event_callback(
|
|
||||||
app->view_dispatcher, dap_gui_back_event_callback);
|
|
||||||
view_dispatcher_set_tick_event_callback(
|
|
||||||
app->view_dispatcher, dap_gui_tick_event_callback, DAP_GUI_TICK);
|
|
||||||
|
|
||||||
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
|
||||||
|
|
||||||
app->notifications = furi_record_open(RECORD_NOTIFICATION);
|
|
||||||
|
|
||||||
app->var_item_list = variable_item_list_alloc();
|
|
||||||
view_dispatcher_add_view(
|
|
||||||
app->view_dispatcher,
|
|
||||||
DapGuiAppViewVarItemList,
|
|
||||||
variable_item_list_get_view(app->var_item_list));
|
|
||||||
|
|
||||||
app->main_view = dap_main_view_alloc();
|
|
||||||
view_dispatcher_add_view(
|
|
||||||
app->view_dispatcher, DapGuiAppViewMainView, dap_main_view_get_view(app->main_view));
|
|
||||||
|
|
||||||
app->widget = widget_alloc();
|
|
||||||
view_dispatcher_add_view(
|
|
||||||
app->view_dispatcher, DapGuiAppViewWidget, widget_get_view(app->widget));
|
|
||||||
|
|
||||||
scene_manager_next_scene(app->scene_manager, DapSceneMain);
|
|
||||||
|
|
||||||
return app;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_gui_free(DapGuiApp* app) {
|
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, DapGuiAppViewVarItemList);
|
|
||||||
variable_item_list_free(app->var_item_list);
|
|
||||||
|
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, DapGuiAppViewMainView);
|
|
||||||
dap_main_view_free(app->main_view);
|
|
||||||
|
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, DapGuiAppViewWidget);
|
|
||||||
widget_free(app->widget);
|
|
||||||
|
|
||||||
// View dispatcher
|
|
||||||
view_dispatcher_free(app->view_dispatcher);
|
|
||||||
scene_manager_free(app->scene_manager);
|
|
||||||
|
|
||||||
// Close records
|
|
||||||
furi_record_close(RECORD_GUI);
|
|
||||||
furi_record_close(RECORD_NOTIFICATION);
|
|
||||||
|
|
||||||
free(app);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t dap_gui_thread(void* arg) {
|
|
||||||
DapGuiApp* app = dap_gui_alloc();
|
|
||||||
app->dap_app = arg;
|
|
||||||
|
|
||||||
notification_message_block(app->notifications, &sequence_display_backlight_enforce_on);
|
|
||||||
view_dispatcher_run(app->view_dispatcher);
|
|
||||||
notification_message_block(app->notifications, &sequence_display_backlight_enforce_auto);
|
|
||||||
|
|
||||||
dap_gui_free(app);
|
|
||||||
return 0;
|
|
||||||
}
|
|
4
applications/external/dap_link/gui/dap_gui.h
vendored
|
@ -1,4 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
int32_t dap_gui_thread(void* arg);
|
|
|
@ -1,7 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
DapAppCustomEventConfig,
|
|
||||||
DapAppCustomEventHelp,
|
|
||||||
DapAppCustomEventAbout,
|
|
||||||
} DapAppCustomEvent;
|
|
34
applications/external/dap_link/gui/dap_gui_i.h
vendored
|
@ -1,34 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <gui/gui.h>
|
|
||||||
#include <gui/view_dispatcher.h>
|
|
||||||
#include <gui/scene_manager.h>
|
|
||||||
#include <gui/modules/submenu.h>
|
|
||||||
#include <notification/notification_messages.h>
|
|
||||||
#include <gui/modules/variable_item_list.h>
|
|
||||||
#include <gui/modules/widget.h>
|
|
||||||
|
|
||||||
#include "dap_gui.h"
|
|
||||||
#include "../dap_link.h"
|
|
||||||
#include "scenes/config/dap_scene.h"
|
|
||||||
#include "dap_gui_custom_event.h"
|
|
||||||
#include "views/dap_main_view.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
DapApp* dap_app;
|
|
||||||
|
|
||||||
Gui* gui;
|
|
||||||
NotificationApp* notifications;
|
|
||||||
ViewDispatcher* view_dispatcher;
|
|
||||||
SceneManager* scene_manager;
|
|
||||||
|
|
||||||
VariableItemList* var_item_list;
|
|
||||||
DapMainView* main_view;
|
|
||||||
Widget* widget;
|
|
||||||
} DapGuiApp;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
DapGuiAppViewVarItemList,
|
|
||||||
DapGuiAppViewMainView,
|
|
||||||
DapGuiAppViewWidget,
|
|
||||||
} DapGuiAppView;
|
|
|
@ -1,30 +0,0 @@
|
||||||
#include "dap_scene.h"
|
|
||||||
|
|
||||||
// Generate scene on_enter handlers array
|
|
||||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
|
|
||||||
void (*const dap_scene_on_enter_handlers[])(void*) = {
|
|
||||||
#include "dap_scene_config.h"
|
|
||||||
};
|
|
||||||
#undef ADD_SCENE
|
|
||||||
|
|
||||||
// Generate scene on_event handlers array
|
|
||||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
|
|
||||||
bool (*const dap_scene_on_event_handlers[])(void* context, SceneManagerEvent event) = {
|
|
||||||
#include "dap_scene_config.h"
|
|
||||||
};
|
|
||||||
#undef ADD_SCENE
|
|
||||||
|
|
||||||
// Generate scene on_exit handlers array
|
|
||||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
|
|
||||||
void (*const dap_scene_on_exit_handlers[])(void* context) = {
|
|
||||||
#include "dap_scene_config.h"
|
|
||||||
};
|
|
||||||
#undef ADD_SCENE
|
|
||||||
|
|
||||||
// Initialize scene handlers configuration structure
|
|
||||||
const SceneManagerHandlers dap_scene_handlers = {
|
|
||||||
.on_enter_handlers = dap_scene_on_enter_handlers,
|
|
||||||
.on_event_handlers = dap_scene_on_event_handlers,
|
|
||||||
.on_exit_handlers = dap_scene_on_exit_handlers,
|
|
||||||
.scene_num = DapSceneNum,
|
|
||||||
};
|
|
|
@ -1,29 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <gui/scene_manager.h>
|
|
||||||
|
|
||||||
// Generate scene id and total number
|
|
||||||
#define ADD_SCENE(prefix, name, id) DapScene##id,
|
|
||||||
typedef enum {
|
|
||||||
#include "dap_scene_config.h"
|
|
||||||
DapSceneNum,
|
|
||||||
} DapScene;
|
|
||||||
#undef ADD_SCENE
|
|
||||||
|
|
||||||
extern const SceneManagerHandlers dap_scene_handlers;
|
|
||||||
|
|
||||||
// Generate scene on_enter handlers declaration
|
|
||||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
|
|
||||||
#include "dap_scene_config.h"
|
|
||||||
#undef ADD_SCENE
|
|
||||||
|
|
||||||
// Generate scene on_event handlers declaration
|
|
||||||
#define ADD_SCENE(prefix, name, id) \
|
|
||||||
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
|
|
||||||
#include "dap_scene_config.h"
|
|
||||||
#undef ADD_SCENE
|
|
||||||
|
|
||||||
// Generate scene on_exit handlers declaration
|
|
||||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
|
|
||||||
#include "dap_scene_config.h"
|
|
||||||
#undef ADD_SCENE
|
|
|
@ -1,4 +0,0 @@
|
||||||
ADD_SCENE(dap, main, Main)
|
|
||||||
ADD_SCENE(dap, config, Config)
|
|
||||||
ADD_SCENE(dap, help, Help)
|
|
||||||
ADD_SCENE(dap, about, About)
|
|
|
@ -1,68 +0,0 @@
|
||||||
#include "../dap_gui_i.h"
|
|
||||||
|
|
||||||
#define DAP_VERSION_APP "0.1.0"
|
|
||||||
#define DAP_DEVELOPED "Dr_Zlo"
|
|
||||||
#define DAP_GITHUB "https://github.com/flipperdevices/flipperzero-firmware"
|
|
||||||
|
|
||||||
void dap_scene_about_on_enter(void* context) {
|
|
||||||
DapGuiApp* app = context;
|
|
||||||
|
|
||||||
FuriString* temp_str;
|
|
||||||
temp_str = furi_string_alloc();
|
|
||||||
furi_string_printf(temp_str, "\e#%s\n", "Information");
|
|
||||||
|
|
||||||
furi_string_cat_printf(temp_str, "Version: %s\n", DAP_VERSION_APP);
|
|
||||||
furi_string_cat_printf(temp_str, "Developed by: %s\n", DAP_DEVELOPED);
|
|
||||||
furi_string_cat_printf(temp_str, "Github: %s\n\n", DAP_GITHUB);
|
|
||||||
|
|
||||||
furi_string_cat_printf(temp_str, "\e#%s\n", "Description");
|
|
||||||
furi_string_cat_printf(
|
|
||||||
temp_str, "CMSIS-DAP debugger\nbased on Free-DAP\nThanks to Alex Taradov\n\n");
|
|
||||||
|
|
||||||
furi_string_cat_printf(
|
|
||||||
temp_str,
|
|
||||||
"Supported protocols:\n"
|
|
||||||
"SWD, JTAG, UART\n"
|
|
||||||
"DAP v1 (cmsis_backend hid), DAP v2 (cmsis_backend usb_bulk), VCP\n");
|
|
||||||
|
|
||||||
widget_add_text_box_element(
|
|
||||||
app->widget,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
128,
|
|
||||||
14,
|
|
||||||
AlignCenter,
|
|
||||||
AlignBottom,
|
|
||||||
"\e#\e! \e!\n",
|
|
||||||
false);
|
|
||||||
widget_add_text_box_element(
|
|
||||||
app->widget,
|
|
||||||
0,
|
|
||||||
2,
|
|
||||||
128,
|
|
||||||
14,
|
|
||||||
AlignCenter,
|
|
||||||
AlignBottom,
|
|
||||||
"\e#\e! DAP Link \e!\n",
|
|
||||||
false);
|
|
||||||
widget_add_text_scroll_element(app->widget, 0, 16, 128, 50, furi_string_get_cstr(temp_str));
|
|
||||||
furi_string_free(temp_str);
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, DapGuiAppViewWidget);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dap_scene_about_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
DapGuiApp* app = context;
|
|
||||||
bool consumed = false;
|
|
||||||
UNUSED(app);
|
|
||||||
UNUSED(event);
|
|
||||||
|
|
||||||
return consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_scene_about_on_exit(void* context) {
|
|
||||||
DapGuiApp* app = context;
|
|
||||||
|
|
||||||
// Clear views
|
|
||||||
widget_reset(app->widget);
|
|
||||||
}
|
|
|
@ -1,107 +0,0 @@
|
||||||
#include "../dap_gui_i.h"
|
|
||||||
|
|
||||||
static const char* swd_pins[] = {[DapSwdPinsPA7PA6] = "2,3", [DapSwdPinsPA14PA13] = "10,12"};
|
|
||||||
static const char* uart_pins[] = {[DapUartTypeUSART1] = "13,14", [DapUartTypeLPUART1] = "15,16"};
|
|
||||||
static const char* uart_swap[] = {[DapUartTXRXNormal] = "No", [DapUartTXRXSwap] = "Yes"};
|
|
||||||
|
|
||||||
static void swd_pins_cb(VariableItem* item) {
|
|
||||||
DapGuiApp* app = variable_item_get_context(item);
|
|
||||||
uint8_t index = variable_item_get_current_value_index(item);
|
|
||||||
|
|
||||||
variable_item_set_current_value_text(item, swd_pins[index]);
|
|
||||||
|
|
||||||
DapConfig* config = dap_app_get_config(app->dap_app);
|
|
||||||
config->swd_pins = index;
|
|
||||||
dap_app_set_config(app->dap_app, config);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void uart_pins_cb(VariableItem* item) {
|
|
||||||
DapGuiApp* app = variable_item_get_context(item);
|
|
||||||
uint8_t index = variable_item_get_current_value_index(item);
|
|
||||||
|
|
||||||
variable_item_set_current_value_text(item, uart_pins[index]);
|
|
||||||
|
|
||||||
DapConfig* config = dap_app_get_config(app->dap_app);
|
|
||||||
config->uart_pins = index;
|
|
||||||
dap_app_set_config(app->dap_app, config);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void uart_swap_cb(VariableItem* item) {
|
|
||||||
DapGuiApp* app = variable_item_get_context(item);
|
|
||||||
uint8_t index = variable_item_get_current_value_index(item);
|
|
||||||
|
|
||||||
variable_item_set_current_value_text(item, uart_swap[index]);
|
|
||||||
|
|
||||||
DapConfig* config = dap_app_get_config(app->dap_app);
|
|
||||||
config->uart_swap = index;
|
|
||||||
dap_app_set_config(app->dap_app, config);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ok_cb(void* context, uint32_t index) {
|
|
||||||
DapGuiApp* app = context;
|
|
||||||
switch(index) {
|
|
||||||
case 3:
|
|
||||||
view_dispatcher_send_custom_event(app->view_dispatcher, DapAppCustomEventHelp);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
view_dispatcher_send_custom_event(app->view_dispatcher, DapAppCustomEventAbout);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_scene_config_on_enter(void* context) {
|
|
||||||
DapGuiApp* app = context;
|
|
||||||
VariableItemList* var_item_list = app->var_item_list;
|
|
||||||
VariableItem* item;
|
|
||||||
DapConfig* config = dap_app_get_config(app->dap_app);
|
|
||||||
|
|
||||||
item = variable_item_list_add(
|
|
||||||
var_item_list, "SWC SWD Pins", COUNT_OF(swd_pins), swd_pins_cb, app);
|
|
||||||
variable_item_set_current_value_index(item, config->swd_pins);
|
|
||||||
variable_item_set_current_value_text(item, swd_pins[config->swd_pins]);
|
|
||||||
|
|
||||||
item =
|
|
||||||
variable_item_list_add(var_item_list, "UART Pins", COUNT_OF(uart_pins), uart_pins_cb, app);
|
|
||||||
variable_item_set_current_value_index(item, config->uart_pins);
|
|
||||||
variable_item_set_current_value_text(item, uart_pins[config->uart_pins]);
|
|
||||||
|
|
||||||
item = variable_item_list_add(
|
|
||||||
var_item_list, "Swap TX RX", COUNT_OF(uart_swap), uart_swap_cb, app);
|
|
||||||
variable_item_set_current_value_index(item, config->uart_swap);
|
|
||||||
variable_item_set_current_value_text(item, uart_swap[config->uart_swap]);
|
|
||||||
|
|
||||||
variable_item_list_add(var_item_list, "Help and Pinout", 0, NULL, NULL);
|
|
||||||
variable_item_list_add(var_item_list, "About", 0, NULL, NULL);
|
|
||||||
|
|
||||||
variable_item_list_set_selected_item(
|
|
||||||
var_item_list, scene_manager_get_scene_state(app->scene_manager, DapSceneConfig));
|
|
||||||
|
|
||||||
variable_item_list_set_enter_callback(var_item_list, ok_cb, app);
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, DapGuiAppViewVarItemList);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dap_scene_config_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
DapGuiApp* app = context;
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
if(event.event == DapAppCustomEventHelp) {
|
|
||||||
scene_manager_next_scene(app->scene_manager, DapSceneHelp);
|
|
||||||
return true;
|
|
||||||
} else if(event.event == DapAppCustomEventAbout) {
|
|
||||||
scene_manager_next_scene(app->scene_manager, DapSceneAbout);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_scene_config_on_exit(void* context) {
|
|
||||||
DapGuiApp* app = context;
|
|
||||||
scene_manager_set_scene_state(
|
|
||||||
app->scene_manager,
|
|
||||||
DapSceneConfig,
|
|
||||||
variable_item_list_get_selected_item_index(app->var_item_list));
|
|
||||||
variable_item_list_reset(app->var_item_list);
|
|
||||||
}
|
|
|
@ -1,102 +0,0 @@
|
||||||
#include "../dap_gui_i.h"
|
|
||||||
|
|
||||||
void dap_scene_help_on_enter(void* context) {
|
|
||||||
DapGuiApp* app = context;
|
|
||||||
DapConfig* config = dap_app_get_config(app->dap_app);
|
|
||||||
FuriString* string = furi_string_alloc();
|
|
||||||
|
|
||||||
furi_string_cat(string, "CMSIS DAP/DAP Link v2\r\n");
|
|
||||||
furi_string_cat_printf(string, "Serial: %s\r\n", dap_app_get_serial(app->dap_app));
|
|
||||||
furi_string_cat(
|
|
||||||
string,
|
|
||||||
"Pinout:\r\n"
|
|
||||||
"\e#SWD:\r\n");
|
|
||||||
|
|
||||||
switch(config->swd_pins) {
|
|
||||||
case DapSwdPinsPA7PA6:
|
|
||||||
furi_string_cat(
|
|
||||||
string,
|
|
||||||
" SWC: 2 [A7]\r\n"
|
|
||||||
" SWD: 3 [A6]\r\n");
|
|
||||||
break;
|
|
||||||
case DapSwdPinsPA14PA13:
|
|
||||||
furi_string_cat(
|
|
||||||
string,
|
|
||||||
" SWC: 10 [SWC]\r\n"
|
|
||||||
" SWD: 12 [SIO]\r\n");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
furi_string_cat(string, "\e#JTAG:\r\n");
|
|
||||||
switch(config->swd_pins) {
|
|
||||||
case DapSwdPinsPA7PA6:
|
|
||||||
furi_string_cat(
|
|
||||||
string,
|
|
||||||
" TCK: 2 [A7]\r\n"
|
|
||||||
" TMS: 3 [A6]\r\n"
|
|
||||||
" RST: 4 [A4]\r\n"
|
|
||||||
" TDO: 5 [B3]\r\n"
|
|
||||||
" TDI: 6 [B2]\r\n");
|
|
||||||
break;
|
|
||||||
case DapSwdPinsPA14PA13:
|
|
||||||
furi_string_cat(
|
|
||||||
string,
|
|
||||||
" RST: 4 [A4]\r\n"
|
|
||||||
" TDO: 5 [B3]\r\n"
|
|
||||||
" TDI: 6 [B2]\r\n"
|
|
||||||
" TCK: 10 [SWC]\r\n"
|
|
||||||
" TMS: 12 [SIO]\r\n");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
furi_string_cat(string, "\e#UART:\r\n");
|
|
||||||
switch(config->uart_pins) {
|
|
||||||
case DapUartTypeUSART1:
|
|
||||||
if(config->uart_swap == DapUartTXRXNormal) {
|
|
||||||
furi_string_cat(
|
|
||||||
string,
|
|
||||||
" TX: 13 [TX]\r\n"
|
|
||||||
" RX: 14 [RX]\r\n");
|
|
||||||
} else {
|
|
||||||
furi_string_cat(
|
|
||||||
string,
|
|
||||||
" RX: 13 [TX]\r\n"
|
|
||||||
" TX: 14 [RX]\r\n");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case DapUartTypeLPUART1:
|
|
||||||
if(config->uart_swap == DapUartTXRXNormal) {
|
|
||||||
furi_string_cat(
|
|
||||||
string,
|
|
||||||
" TX: 15 [C1]\r\n"
|
|
||||||
" RX: 16 [C0]\r\n");
|
|
||||||
} else {
|
|
||||||
furi_string_cat(
|
|
||||||
string,
|
|
||||||
" RX: 15 [C1]\r\n"
|
|
||||||
" TX: 16 [C0]\r\n");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
widget_add_text_scroll_element(app->widget, 0, 0, 128, 64, furi_string_get_cstr(string));
|
|
||||||
furi_string_free(string);
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, DapGuiAppViewWidget);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dap_scene_help_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
UNUSED(context);
|
|
||||||
UNUSED(event);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_scene_help_on_exit(void* context) {
|
|
||||||
DapGuiApp* app = context;
|
|
||||||
widget_reset(app->widget);
|
|
||||||
}
|
|
|
@ -1,154 +0,0 @@
|
||||||
#include "../dap_gui_i.h"
|
|
||||||
#include "../../dap_link.h"
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
DapState dap_state;
|
|
||||||
bool dap_active;
|
|
||||||
bool tx_active;
|
|
||||||
bool rx_active;
|
|
||||||
} DapSceneMainState;
|
|
||||||
|
|
||||||
static bool process_dap_state(DapGuiApp* app) {
|
|
||||||
DapSceneMainState* state =
|
|
||||||
(DapSceneMainState*)scene_manager_get_scene_state(app->scene_manager, DapSceneMain);
|
|
||||||
if(state == NULL) return true;
|
|
||||||
|
|
||||||
DapState* prev_state = &state->dap_state;
|
|
||||||
DapState next_state;
|
|
||||||
dap_app_get_state(app->dap_app, &next_state);
|
|
||||||
bool need_to_update = false;
|
|
||||||
|
|
||||||
if(prev_state->dap_mode != next_state.dap_mode) {
|
|
||||||
switch(next_state.dap_mode) {
|
|
||||||
case DapModeDisconnected:
|
|
||||||
dap_main_view_set_mode(app->main_view, DapMainViewModeDisconnected);
|
|
||||||
notification_message(app->notifications, &sequence_blink_stop);
|
|
||||||
break;
|
|
||||||
case DapModeSWD:
|
|
||||||
dap_main_view_set_mode(app->main_view, DapMainViewModeSWD);
|
|
||||||
notification_message(app->notifications, &sequence_blink_start_blue);
|
|
||||||
break;
|
|
||||||
case DapModeJTAG:
|
|
||||||
dap_main_view_set_mode(app->main_view, DapMainViewModeJTAG);
|
|
||||||
notification_message(app->notifications, &sequence_blink_start_magenta);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
need_to_update = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(prev_state->dap_version != next_state.dap_version) {
|
|
||||||
switch(next_state.dap_version) {
|
|
||||||
case DapVersionUnknown:
|
|
||||||
dap_main_view_set_version(app->main_view, DapMainViewVersionUnknown);
|
|
||||||
break;
|
|
||||||
case DapVersionV1:
|
|
||||||
dap_main_view_set_version(app->main_view, DapMainViewVersionV1);
|
|
||||||
break;
|
|
||||||
case DapVersionV2:
|
|
||||||
dap_main_view_set_version(app->main_view, DapMainViewVersionV2);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
need_to_update = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(prev_state->usb_connected != next_state.usb_connected) {
|
|
||||||
dap_main_view_set_usb_connected(app->main_view, next_state.usb_connected);
|
|
||||||
need_to_update = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(prev_state->dap_counter != next_state.dap_counter) {
|
|
||||||
if(!state->dap_active) {
|
|
||||||
state->dap_active = true;
|
|
||||||
dap_main_view_set_dap(app->main_view, state->dap_active);
|
|
||||||
need_to_update = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(state->dap_active) {
|
|
||||||
state->dap_active = false;
|
|
||||||
dap_main_view_set_dap(app->main_view, state->dap_active);
|
|
||||||
need_to_update = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(prev_state->cdc_baudrate != next_state.cdc_baudrate) {
|
|
||||||
dap_main_view_set_baudrate(app->main_view, next_state.cdc_baudrate);
|
|
||||||
need_to_update = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(prev_state->cdc_tx_counter != next_state.cdc_tx_counter) {
|
|
||||||
if(!state->tx_active) {
|
|
||||||
state->tx_active = true;
|
|
||||||
dap_main_view_set_tx(app->main_view, state->tx_active);
|
|
||||||
need_to_update = true;
|
|
||||||
notification_message(app->notifications, &sequence_blink_start_red);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(state->tx_active) {
|
|
||||||
state->tx_active = false;
|
|
||||||
dap_main_view_set_tx(app->main_view, state->tx_active);
|
|
||||||
need_to_update = true;
|
|
||||||
notification_message(app->notifications, &sequence_blink_stop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(prev_state->cdc_rx_counter != next_state.cdc_rx_counter) {
|
|
||||||
if(!state->rx_active) {
|
|
||||||
state->rx_active = true;
|
|
||||||
dap_main_view_set_rx(app->main_view, state->rx_active);
|
|
||||||
need_to_update = true;
|
|
||||||
notification_message(app->notifications, &sequence_blink_start_green);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if(state->rx_active) {
|
|
||||||
state->rx_active = false;
|
|
||||||
dap_main_view_set_rx(app->main_view, state->rx_active);
|
|
||||||
need_to_update = true;
|
|
||||||
notification_message(app->notifications, &sequence_blink_stop);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(need_to_update) {
|
|
||||||
dap_main_view_update(app->main_view);
|
|
||||||
}
|
|
||||||
|
|
||||||
*prev_state = next_state;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void dap_scene_main_on_left(void* context) {
|
|
||||||
DapGuiApp* app = (DapGuiApp*)context;
|
|
||||||
view_dispatcher_send_custom_event(app->view_dispatcher, DapAppCustomEventConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_scene_main_on_enter(void* context) {
|
|
||||||
DapGuiApp* app = context;
|
|
||||||
DapSceneMainState* state = malloc(sizeof(DapSceneMainState));
|
|
||||||
dap_main_view_set_left_callback(app->main_view, dap_scene_main_on_left, app);
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, DapGuiAppViewMainView);
|
|
||||||
scene_manager_set_scene_state(app->scene_manager, DapSceneMain, (uint32_t)state);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool dap_scene_main_on_event(void* context, SceneManagerEvent event) {
|
|
||||||
DapGuiApp* app = context;
|
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
if(event.event == DapAppCustomEventConfig) {
|
|
||||||
scene_manager_next_scene(app->scene_manager, DapSceneConfig);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} else if(event.type == SceneManagerEventTypeTick) {
|
|
||||||
return process_dap_state(app);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_scene_main_on_exit(void* context) {
|
|
||||||
DapGuiApp* app = context;
|
|
||||||
DapSceneMainState* state =
|
|
||||||
(DapSceneMainState*)scene_manager_get_scene_state(app->scene_manager, DapSceneMain);
|
|
||||||
scene_manager_set_scene_state(app->scene_manager, DapSceneMain, (uint32_t)NULL);
|
|
||||||
FURI_SW_MEMBARRIER();
|
|
||||||
free(state);
|
|
||||||
notification_message(app->notifications, &sequence_blink_stop);
|
|
||||||
}
|
|
|
@ -1,189 +0,0 @@
|
||||||
#include "dap_main_view.h"
|
|
||||||
#include "dap_link_icons.h"
|
|
||||||
#include <gui/elements.h>
|
|
||||||
|
|
||||||
// extern const Icon I_ArrowDownEmpty_12x18;
|
|
||||||
// extern const Icon I_ArrowDownFilled_12x18;
|
|
||||||
// extern const Icon I_ArrowUpEmpty_12x18;
|
|
||||||
// extern const Icon I_ArrowUpFilled_12x18;
|
|
||||||
|
|
||||||
struct DapMainView {
|
|
||||||
View* view;
|
|
||||||
DapMainViewButtonCallback cb_left;
|
|
||||||
void* cb_context;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
DapMainViewMode mode;
|
|
||||||
DapMainViewVersion version;
|
|
||||||
bool usb_connected;
|
|
||||||
uint32_t baudrate;
|
|
||||||
bool dap_active;
|
|
||||||
bool tx_active;
|
|
||||||
bool rx_active;
|
|
||||||
} DapMainViewModel;
|
|
||||||
|
|
||||||
static void dap_main_view_draw_callback(Canvas* canvas, void* _model) {
|
|
||||||
DapMainViewModel* model = _model;
|
|
||||||
UNUSED(model);
|
|
||||||
canvas_clear(canvas);
|
|
||||||
elements_button_left(canvas, "Config");
|
|
||||||
|
|
||||||
canvas_set_color(canvas, ColorBlack);
|
|
||||||
canvas_draw_box(canvas, 0, 0, 127, 11);
|
|
||||||
canvas_set_color(canvas, ColorWhite);
|
|
||||||
|
|
||||||
const char* header_string;
|
|
||||||
if(model->usb_connected) {
|
|
||||||
if(model->version == DapMainViewVersionV1) {
|
|
||||||
header_string = "DAP Link V1 Connected";
|
|
||||||
} else if(model->version == DapMainViewVersionV2) {
|
|
||||||
header_string = "DAP Link V2 Connected";
|
|
||||||
} else {
|
|
||||||
header_string = "DAP Link Connected";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
header_string = "DAP Link";
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas_draw_str_aligned(canvas, 64, 9, AlignCenter, AlignBottom, header_string);
|
|
||||||
|
|
||||||
canvas_set_color(canvas, ColorBlack);
|
|
||||||
if(model->dap_active) {
|
|
||||||
canvas_draw_icon(canvas, 14, 16, &I_ArrowUpFilled_12x18);
|
|
||||||
canvas_draw_icon_ex(canvas, 28, 16, &I_ArrowUpFilled_12x18, IconRotation180);
|
|
||||||
} else {
|
|
||||||
canvas_draw_icon(canvas, 14, 16, &I_ArrowUpEmpty_12x18);
|
|
||||||
canvas_draw_icon_ex(canvas, 28, 16, &I_ArrowUpEmpty_12x18, IconRotation180);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(model->mode) {
|
|
||||||
case DapMainViewModeDisconnected:
|
|
||||||
canvas_draw_str_aligned(canvas, 26, 38, AlignCenter, AlignTop, "----");
|
|
||||||
break;
|
|
||||||
case DapMainViewModeSWD:
|
|
||||||
canvas_draw_str_aligned(canvas, 26, 38, AlignCenter, AlignTop, "SWD");
|
|
||||||
break;
|
|
||||||
case DapMainViewModeJTAG:
|
|
||||||
canvas_draw_str_aligned(canvas, 26, 38, AlignCenter, AlignTop, "JTAG");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(model->tx_active) {
|
|
||||||
canvas_draw_icon(canvas, 87, 16, &I_ArrowUpFilled_12x18);
|
|
||||||
} else {
|
|
||||||
canvas_draw_icon(canvas, 87, 16, &I_ArrowUpEmpty_12x18);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(model->rx_active) {
|
|
||||||
canvas_draw_icon_ex(canvas, 101, 16, &I_ArrowUpFilled_12x18, IconRotation180);
|
|
||||||
} else {
|
|
||||||
canvas_draw_icon_ex(canvas, 101, 16, &I_ArrowUpEmpty_12x18, IconRotation180);
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas_draw_str_aligned(canvas, 100, 38, AlignCenter, AlignTop, "UART");
|
|
||||||
|
|
||||||
canvas_draw_line(canvas, 44, 52, 123, 52);
|
|
||||||
if(model->baudrate == 0) {
|
|
||||||
canvas_draw_str(canvas, 45, 62, "Baud: ????");
|
|
||||||
} else {
|
|
||||||
char baudrate_str[18];
|
|
||||||
snprintf(baudrate_str, 18, "Baud: %lu", model->baudrate);
|
|
||||||
canvas_draw_str(canvas, 45, 62, baudrate_str);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool dap_main_view_input_callback(InputEvent* event, void* context) {
|
|
||||||
furi_assert(context);
|
|
||||||
DapMainView* dap_main_view = context;
|
|
||||||
bool consumed = false;
|
|
||||||
|
|
||||||
if(event->type == InputTypeShort) {
|
|
||||||
if(event->key == InputKeyLeft) {
|
|
||||||
if(dap_main_view->cb_left) {
|
|
||||||
dap_main_view->cb_left(dap_main_view->cb_context);
|
|
||||||
}
|
|
||||||
consumed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return consumed;
|
|
||||||
}
|
|
||||||
|
|
||||||
DapMainView* dap_main_view_alloc() {
|
|
||||||
DapMainView* dap_main_view = malloc(sizeof(DapMainView));
|
|
||||||
|
|
||||||
dap_main_view->view = view_alloc();
|
|
||||||
view_allocate_model(dap_main_view->view, ViewModelTypeLocking, sizeof(DapMainViewModel));
|
|
||||||
view_set_context(dap_main_view->view, dap_main_view);
|
|
||||||
view_set_draw_callback(dap_main_view->view, dap_main_view_draw_callback);
|
|
||||||
view_set_input_callback(dap_main_view->view, dap_main_view_input_callback);
|
|
||||||
return dap_main_view;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_main_view_free(DapMainView* dap_main_view) {
|
|
||||||
view_free(dap_main_view->view);
|
|
||||||
free(dap_main_view);
|
|
||||||
}
|
|
||||||
|
|
||||||
View* dap_main_view_get_view(DapMainView* dap_main_view) {
|
|
||||||
return dap_main_view->view;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_main_view_set_left_callback(
|
|
||||||
DapMainView* dap_main_view,
|
|
||||||
DapMainViewButtonCallback callback,
|
|
||||||
void* context) {
|
|
||||||
with_view_model(
|
|
||||||
dap_main_view->view,
|
|
||||||
DapMainViewModel * model,
|
|
||||||
{
|
|
||||||
UNUSED(model);
|
|
||||||
dap_main_view->cb_left = callback;
|
|
||||||
dap_main_view->cb_context = context;
|
|
||||||
},
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_main_view_set_mode(DapMainView* dap_main_view, DapMainViewMode mode) {
|
|
||||||
with_view_model(
|
|
||||||
dap_main_view->view, DapMainViewModel * model, { model->mode = mode; }, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_main_view_set_dap(DapMainView* dap_main_view, bool active) {
|
|
||||||
with_view_model(
|
|
||||||
dap_main_view->view, DapMainViewModel * model, { model->dap_active = active; }, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_main_view_set_tx(DapMainView* dap_main_view, bool active) {
|
|
||||||
with_view_model(
|
|
||||||
dap_main_view->view, DapMainViewModel * model, { model->tx_active = active; }, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_main_view_set_rx(DapMainView* dap_main_view, bool active) {
|
|
||||||
with_view_model(
|
|
||||||
dap_main_view->view, DapMainViewModel * model, { model->rx_active = active; }, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_main_view_set_baudrate(DapMainView* dap_main_view, uint32_t baudrate) {
|
|
||||||
with_view_model(
|
|
||||||
dap_main_view->view, DapMainViewModel * model, { model->baudrate = baudrate; }, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_main_view_update(DapMainView* dap_main_view) {
|
|
||||||
with_view_model(
|
|
||||||
dap_main_view->view, DapMainViewModel * model, { UNUSED(model); }, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_main_view_set_version(DapMainView* dap_main_view, DapMainViewVersion version) {
|
|
||||||
with_view_model(
|
|
||||||
dap_main_view->view, DapMainViewModel * model, { model->version = version; }, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_main_view_set_usb_connected(DapMainView* dap_main_view, bool connected) {
|
|
||||||
with_view_model(
|
|
||||||
dap_main_view->view,
|
|
||||||
DapMainViewModel * model,
|
|
||||||
{ model->usb_connected = connected; },
|
|
||||||
false);
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <gui/view.h>
|
|
||||||
|
|
||||||
typedef struct DapMainView DapMainView;
|
|
||||||
|
|
||||||
typedef void (*DapMainViewButtonCallback)(void* context);
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
DapMainViewVersionUnknown,
|
|
||||||
DapMainViewVersionV1,
|
|
||||||
DapMainViewVersionV2,
|
|
||||||
} DapMainViewVersion;
|
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
DapMainViewModeDisconnected,
|
|
||||||
DapMainViewModeSWD,
|
|
||||||
DapMainViewModeJTAG,
|
|
||||||
} DapMainViewMode;
|
|
||||||
|
|
||||||
DapMainView* dap_main_view_alloc();
|
|
||||||
|
|
||||||
void dap_main_view_free(DapMainView* dap_main_view);
|
|
||||||
|
|
||||||
View* dap_main_view_get_view(DapMainView* dap_main_view);
|
|
||||||
|
|
||||||
void dap_main_view_set_left_callback(
|
|
||||||
DapMainView* dap_main_view,
|
|
||||||
DapMainViewButtonCallback callback,
|
|
||||||
void* context);
|
|
||||||
|
|
||||||
void dap_main_view_set_mode(DapMainView* dap_main_view, DapMainViewMode mode);
|
|
||||||
|
|
||||||
void dap_main_view_set_version(DapMainView* dap_main_view, DapMainViewVersion version);
|
|
||||||
|
|
||||||
void dap_main_view_set_dap(DapMainView* dap_main_view, bool active);
|
|
||||||
|
|
||||||
void dap_main_view_set_tx(DapMainView* dap_main_view, bool active);
|
|
||||||
|
|
||||||
void dap_main_view_set_rx(DapMainView* dap_main_view, bool active);
|
|
||||||
|
|
||||||
void dap_main_view_set_usb_connected(DapMainView* dap_main_view, bool connected);
|
|
||||||
|
|
||||||
void dap_main_view_set_baudrate(DapMainView* dap_main_view, uint32_t baudrate);
|
|
||||||
|
|
||||||
void dap_main_view_update(DapMainView* dap_main_view);
|
|
Before Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 159 B |
Before Width: | Height: | Size: 173 B |
1
applications/external/dap_link/lib/free-dap
vendored
|
@ -1 +0,0 @@
|
||||||
Subproject commit e7752beb5e8a69119af67b70b9179cb3c90f3ac5
|
|
977
applications/external/dap_link/usb/dap_v2_usb.c
vendored
|
@ -1,977 +0,0 @@
|
||||||
#include <furi.h>
|
|
||||||
#include <usb.h>
|
|
||||||
#include <usb_std.h>
|
|
||||||
#include <usb_hid.h>
|
|
||||||
#include <usb_cdc.h>
|
|
||||||
#include <furi_hal_console.h>
|
|
||||||
|
|
||||||
#include "dap_v2_usb.h"
|
|
||||||
|
|
||||||
// #define DAP_USB_LOG
|
|
||||||
|
|
||||||
#define HID_EP_IN 0x80
|
|
||||||
#define HID_EP_OUT 0x00
|
|
||||||
|
|
||||||
#define DAP_HID_EP_SEND 1
|
|
||||||
#define DAP_HID_EP_RECV 2
|
|
||||||
#define DAP_HID_EP_BULK_RECV 3
|
|
||||||
#define DAP_HID_EP_BULK_SEND 4
|
|
||||||
#define DAP_CDC_EP_COMM 5
|
|
||||||
#define DAP_CDC_EP_SEND 6
|
|
||||||
#define DAP_CDC_EP_RECV 7
|
|
||||||
|
|
||||||
#define DAP_HID_EP_IN (HID_EP_IN | DAP_HID_EP_SEND)
|
|
||||||
#define DAP_HID_EP_OUT (HID_EP_OUT | DAP_HID_EP_RECV)
|
|
||||||
#define DAP_HID_EP_BULK_IN (HID_EP_IN | DAP_HID_EP_BULK_SEND)
|
|
||||||
#define DAP_HID_EP_BULK_OUT (HID_EP_OUT | DAP_HID_EP_BULK_RECV)
|
|
||||||
|
|
||||||
#define DAP_HID_EP_SIZE 64
|
|
||||||
#define DAP_CDC_COMM_EP_SIZE 8
|
|
||||||
#define DAP_CDC_EP_SIZE 64
|
|
||||||
|
|
||||||
#define DAP_BULK_INTERVAL 0
|
|
||||||
#define DAP_HID_INTERVAL 1
|
|
||||||
#define DAP_CDC_INTERVAL 0
|
|
||||||
#define DAP_CDC_COMM_INTERVAL 1
|
|
||||||
|
|
||||||
#define DAP_HID_VID 0x0483
|
|
||||||
#define DAP_HID_PID 0x5740
|
|
||||||
|
|
||||||
#define DAP_USB_EP0_SIZE 8
|
|
||||||
|
|
||||||
#define EP_CFG_DECONFIGURE 0
|
|
||||||
#define EP_CFG_CONFIGURE 1
|
|
||||||
|
|
||||||
enum {
|
|
||||||
USB_INTF_HID,
|
|
||||||
USB_INTF_BULK,
|
|
||||||
USB_INTF_CDC_COMM,
|
|
||||||
USB_INTF_CDC_DATA,
|
|
||||||
USB_INTF_COUNT,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
|
||||||
USB_STR_ZERO,
|
|
||||||
USB_STR_MANUFACTURER,
|
|
||||||
USB_STR_PRODUCT,
|
|
||||||
USB_STR_SERIAL_NUMBER,
|
|
||||||
USB_STR_CMSIS_DAP_V1,
|
|
||||||
USB_STR_CMSIS_DAP_V2,
|
|
||||||
USB_STR_COM_PORT,
|
|
||||||
USB_STR_COUNT,
|
|
||||||
};
|
|
||||||
|
|
||||||
// static const char* usb_str[] = {
|
|
||||||
// [USB_STR_MANUFACTURER] = "Flipper Devices Inc.",
|
|
||||||
// [USB_STR_PRODUCT] = "Combined VCP and CMSIS-DAP Adapter",
|
|
||||||
// [USB_STR_COM_PORT] = "Virtual COM-Port",
|
|
||||||
// [USB_STR_CMSIS_DAP_V1] = "CMSIS-DAP v1 Adapter",
|
|
||||||
// [USB_STR_CMSIS_DAP_V2] = "CMSIS-DAP v2 Adapter",
|
|
||||||
// [USB_STR_SERIAL_NUMBER] = "01234567890ABCDEF",
|
|
||||||
// };
|
|
||||||
|
|
||||||
static const struct usb_string_descriptor dev_manuf_descr =
|
|
||||||
USB_STRING_DESC("Flipper Devices Inc.");
|
|
||||||
|
|
||||||
static const struct usb_string_descriptor dev_prod_descr =
|
|
||||||
USB_STRING_DESC("Combined VCP and CMSIS-DAP Adapter");
|
|
||||||
|
|
||||||
static struct usb_string_descriptor* dev_serial_descr = NULL;
|
|
||||||
|
|
||||||
static const struct usb_string_descriptor dev_dap_v1_descr =
|
|
||||||
USB_STRING_DESC("CMSIS-DAP v1 Adapter");
|
|
||||||
|
|
||||||
static const struct usb_string_descriptor dev_dap_v2_descr =
|
|
||||||
USB_STRING_DESC("CMSIS-DAP v2 Adapter");
|
|
||||||
|
|
||||||
static const struct usb_string_descriptor dev_com_descr = USB_STRING_DESC("Virtual COM-Port");
|
|
||||||
|
|
||||||
struct HidConfigDescriptor {
|
|
||||||
struct usb_config_descriptor configuration;
|
|
||||||
|
|
||||||
// CMSIS-DAP v1
|
|
||||||
struct usb_interface_descriptor hid_interface;
|
|
||||||
struct usb_hid_descriptor hid;
|
|
||||||
struct usb_endpoint_descriptor hid_ep_in;
|
|
||||||
struct usb_endpoint_descriptor hid_ep_out;
|
|
||||||
|
|
||||||
// CMSIS-DAP v2
|
|
||||||
struct usb_interface_descriptor bulk_interface;
|
|
||||||
struct usb_endpoint_descriptor bulk_ep_out;
|
|
||||||
struct usb_endpoint_descriptor bulk_ep_in;
|
|
||||||
|
|
||||||
// CDC
|
|
||||||
struct usb_iad_descriptor iad;
|
|
||||||
struct usb_interface_descriptor interface_comm;
|
|
||||||
struct usb_cdc_header_desc cdc_header;
|
|
||||||
struct usb_cdc_call_mgmt_desc cdc_acm;
|
|
||||||
struct usb_cdc_acm_desc cdc_call_mgmt;
|
|
||||||
struct usb_cdc_union_desc cdc_union;
|
|
||||||
struct usb_endpoint_descriptor ep_comm;
|
|
||||||
struct usb_interface_descriptor interface_data;
|
|
||||||
struct usb_endpoint_descriptor ep_in;
|
|
||||||
struct usb_endpoint_descriptor ep_out;
|
|
||||||
|
|
||||||
} __attribute__((packed));
|
|
||||||
|
|
||||||
static const struct usb_device_descriptor hid_device_desc = {
|
|
||||||
.bLength = sizeof(struct usb_device_descriptor),
|
|
||||||
.bDescriptorType = USB_DTYPE_DEVICE,
|
|
||||||
.bcdUSB = VERSION_BCD(2, 1, 0),
|
|
||||||
.bDeviceClass = USB_CLASS_MISC,
|
|
||||||
.bDeviceSubClass = USB_SUBCLASS_IAD,
|
|
||||||
.bDeviceProtocol = USB_PROTO_IAD,
|
|
||||||
.bMaxPacketSize0 = DAP_USB_EP0_SIZE,
|
|
||||||
.idVendor = DAP_HID_VID,
|
|
||||||
.idProduct = DAP_HID_PID,
|
|
||||||
.bcdDevice = VERSION_BCD(1, 0, 0),
|
|
||||||
.iManufacturer = USB_STR_MANUFACTURER,
|
|
||||||
.iProduct = USB_STR_PRODUCT,
|
|
||||||
.iSerialNumber = USB_STR_SERIAL_NUMBER,
|
|
||||||
.bNumConfigurations = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint8_t hid_report_desc[] = {
|
|
||||||
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
|
|
||||||
0x09, 0x00, // Usage (Undefined)
|
|
||||||
0xa1, 0x01, // Collection (Application)
|
|
||||||
0x15, 0x00, // Logical Minimum (0)
|
|
||||||
0x26, 0xff, 0x00, // Logical Maximum (255)
|
|
||||||
0x75, 0x08, // Report Size (8)
|
|
||||||
0x95, 0x40, // Report Count (64)
|
|
||||||
0x09, 0x00, // Usage (Undefined)
|
|
||||||
0x81, 0x82, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
|
|
||||||
0x75, 0x08, // Report Size (8)
|
|
||||||
0x95, 0x40, // Report Count (64)
|
|
||||||
0x09, 0x00, // Usage (Undefined)
|
|
||||||
0x91, 0x82, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile)
|
|
||||||
0xc0, // End Collection
|
|
||||||
};
|
|
||||||
|
|
||||||
static const struct HidConfigDescriptor hid_cfg_desc = {
|
|
||||||
.configuration =
|
|
||||||
{
|
|
||||||
.bLength = sizeof(struct usb_config_descriptor),
|
|
||||||
.bDescriptorType = USB_DTYPE_CONFIGURATION,
|
|
||||||
.wTotalLength = sizeof(struct HidConfigDescriptor),
|
|
||||||
.bNumInterfaces = USB_INTF_COUNT,
|
|
||||||
.bConfigurationValue = 1,
|
|
||||||
.iConfiguration = NO_DESCRIPTOR,
|
|
||||||
.bmAttributes = USB_CFG_ATTR_RESERVED,
|
|
||||||
.bMaxPower = USB_CFG_POWER_MA(500),
|
|
||||||
},
|
|
||||||
|
|
||||||
// CMSIS-DAP v1
|
|
||||||
.hid_interface =
|
|
||||||
{
|
|
||||||
.bLength = sizeof(struct usb_interface_descriptor),
|
|
||||||
.bDescriptorType = USB_DTYPE_INTERFACE,
|
|
||||||
.bInterfaceNumber = USB_INTF_HID,
|
|
||||||
.bAlternateSetting = 0,
|
|
||||||
.bNumEndpoints = 2,
|
|
||||||
.bInterfaceClass = USB_CLASS_HID,
|
|
||||||
.bInterfaceSubClass = USB_HID_SUBCLASS_NONBOOT,
|
|
||||||
.bInterfaceProtocol = USB_HID_PROTO_NONBOOT,
|
|
||||||
.iInterface = USB_STR_CMSIS_DAP_V1,
|
|
||||||
},
|
|
||||||
|
|
||||||
.hid =
|
|
||||||
{
|
|
||||||
.bLength = sizeof(struct usb_hid_descriptor),
|
|
||||||
.bDescriptorType = USB_DTYPE_HID,
|
|
||||||
.bcdHID = VERSION_BCD(1, 1, 1),
|
|
||||||
.bCountryCode = USB_HID_COUNTRY_NONE,
|
|
||||||
.bNumDescriptors = 1,
|
|
||||||
.bDescriptorType0 = USB_DTYPE_HID_REPORT,
|
|
||||||
.wDescriptorLength0 = sizeof(hid_report_desc),
|
|
||||||
},
|
|
||||||
|
|
||||||
.hid_ep_in =
|
|
||||||
{
|
|
||||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
|
||||||
.bDescriptorType = USB_DTYPE_ENDPOINT,
|
|
||||||
.bEndpointAddress = DAP_HID_EP_IN,
|
|
||||||
.bmAttributes = USB_EPTYPE_INTERRUPT,
|
|
||||||
.wMaxPacketSize = DAP_HID_EP_SIZE,
|
|
||||||
.bInterval = DAP_HID_INTERVAL,
|
|
||||||
},
|
|
||||||
|
|
||||||
.hid_ep_out =
|
|
||||||
{
|
|
||||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
|
||||||
.bDescriptorType = USB_DTYPE_ENDPOINT,
|
|
||||||
.bEndpointAddress = DAP_HID_EP_OUT,
|
|
||||||
.bmAttributes = USB_EPTYPE_INTERRUPT,
|
|
||||||
.wMaxPacketSize = DAP_HID_EP_SIZE,
|
|
||||||
.bInterval = DAP_HID_INTERVAL,
|
|
||||||
},
|
|
||||||
|
|
||||||
// CMSIS-DAP v2
|
|
||||||
.bulk_interface =
|
|
||||||
{
|
|
||||||
.bLength = sizeof(struct usb_interface_descriptor),
|
|
||||||
.bDescriptorType = USB_DTYPE_INTERFACE,
|
|
||||||
.bInterfaceNumber = USB_INTF_BULK,
|
|
||||||
.bAlternateSetting = 0,
|
|
||||||
.bNumEndpoints = 2,
|
|
||||||
.bInterfaceClass = USB_CLASS_VENDOR,
|
|
||||||
.bInterfaceSubClass = 0,
|
|
||||||
.bInterfaceProtocol = 0,
|
|
||||||
.iInterface = USB_STR_CMSIS_DAP_V2,
|
|
||||||
},
|
|
||||||
|
|
||||||
.bulk_ep_out =
|
|
||||||
{
|
|
||||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
|
||||||
.bDescriptorType = USB_DTYPE_ENDPOINT,
|
|
||||||
.bEndpointAddress = DAP_HID_EP_BULK_OUT,
|
|
||||||
.bmAttributes = USB_EPTYPE_BULK,
|
|
||||||
.wMaxPacketSize = DAP_HID_EP_SIZE,
|
|
||||||
.bInterval = DAP_BULK_INTERVAL,
|
|
||||||
},
|
|
||||||
|
|
||||||
.bulk_ep_in =
|
|
||||||
{
|
|
||||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
|
||||||
.bDescriptorType = USB_DTYPE_ENDPOINT,
|
|
||||||
.bEndpointAddress = DAP_HID_EP_BULK_IN,
|
|
||||||
.bmAttributes = USB_EPTYPE_BULK,
|
|
||||||
.wMaxPacketSize = DAP_HID_EP_SIZE,
|
|
||||||
.bInterval = DAP_BULK_INTERVAL,
|
|
||||||
},
|
|
||||||
|
|
||||||
// CDC
|
|
||||||
.iad =
|
|
||||||
{
|
|
||||||
.bLength = sizeof(struct usb_iad_descriptor),
|
|
||||||
.bDescriptorType = USB_DTYPE_INTERFASEASSOC,
|
|
||||||
.bFirstInterface = USB_INTF_CDC_COMM,
|
|
||||||
.bInterfaceCount = 2,
|
|
||||||
.bFunctionClass = USB_CLASS_CDC,
|
|
||||||
.bFunctionSubClass = USB_CDC_SUBCLASS_ACM,
|
|
||||||
.bFunctionProtocol = USB_PROTO_NONE,
|
|
||||||
.iFunction = USB_STR_COM_PORT,
|
|
||||||
},
|
|
||||||
.interface_comm =
|
|
||||||
{
|
|
||||||
.bLength = sizeof(struct usb_interface_descriptor),
|
|
||||||
.bDescriptorType = USB_DTYPE_INTERFACE,
|
|
||||||
.bInterfaceNumber = USB_INTF_CDC_COMM,
|
|
||||||
.bAlternateSetting = 0,
|
|
||||||
.bNumEndpoints = 1,
|
|
||||||
.bInterfaceClass = USB_CLASS_CDC,
|
|
||||||
.bInterfaceSubClass = USB_CDC_SUBCLASS_ACM,
|
|
||||||
.bInterfaceProtocol = USB_PROTO_NONE,
|
|
||||||
.iInterface = 0,
|
|
||||||
},
|
|
||||||
|
|
||||||
.cdc_header =
|
|
||||||
{
|
|
||||||
.bFunctionLength = sizeof(struct usb_cdc_header_desc),
|
|
||||||
.bDescriptorType = USB_DTYPE_CS_INTERFACE,
|
|
||||||
.bDescriptorSubType = USB_DTYPE_CDC_HEADER,
|
|
||||||
.bcdCDC = VERSION_BCD(1, 1, 0),
|
|
||||||
},
|
|
||||||
|
|
||||||
.cdc_acm =
|
|
||||||
{
|
|
||||||
.bFunctionLength = sizeof(struct usb_cdc_call_mgmt_desc),
|
|
||||||
.bDescriptorType = USB_DTYPE_CS_INTERFACE,
|
|
||||||
.bDescriptorSubType = USB_DTYPE_CDC_CALL_MANAGEMENT,
|
|
||||||
// .bmCapabilities = USB_CDC_CAP_LINE | USB_CDC_CAP_BRK,
|
|
||||||
.bmCapabilities = 0,
|
|
||||||
},
|
|
||||||
|
|
||||||
.cdc_call_mgmt =
|
|
||||||
{
|
|
||||||
.bFunctionLength = sizeof(struct usb_cdc_acm_desc),
|
|
||||||
.bDescriptorType = USB_DTYPE_CS_INTERFACE,
|
|
||||||
.bDescriptorSubType = USB_DTYPE_CDC_ACM,
|
|
||||||
.bmCapabilities = USB_CDC_CALL_MGMT_CAP_DATA_INTF,
|
|
||||||
// .bDataInterface = USB_INTF_CDC_DATA,
|
|
||||||
},
|
|
||||||
|
|
||||||
.cdc_union =
|
|
||||||
{
|
|
||||||
.bFunctionLength = sizeof(struct usb_cdc_union_desc),
|
|
||||||
.bDescriptorType = USB_DTYPE_CS_INTERFACE,
|
|
||||||
.bDescriptorSubType = USB_DTYPE_CDC_UNION,
|
|
||||||
.bMasterInterface0 = USB_INTF_CDC_COMM,
|
|
||||||
.bSlaveInterface0 = USB_INTF_CDC_DATA,
|
|
||||||
},
|
|
||||||
|
|
||||||
.ep_comm =
|
|
||||||
{
|
|
||||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
|
||||||
.bDescriptorType = USB_DTYPE_ENDPOINT,
|
|
||||||
.bEndpointAddress = HID_EP_IN | DAP_CDC_EP_COMM,
|
|
||||||
.bmAttributes = USB_EPTYPE_INTERRUPT,
|
|
||||||
.wMaxPacketSize = DAP_CDC_COMM_EP_SIZE,
|
|
||||||
.bInterval = DAP_CDC_COMM_INTERVAL,
|
|
||||||
},
|
|
||||||
|
|
||||||
.interface_data =
|
|
||||||
{
|
|
||||||
.bLength = sizeof(struct usb_interface_descriptor),
|
|
||||||
.bDescriptorType = USB_DTYPE_INTERFACE,
|
|
||||||
.bInterfaceNumber = USB_INTF_CDC_DATA,
|
|
||||||
.bAlternateSetting = 0,
|
|
||||||
.bNumEndpoints = 2,
|
|
||||||
.bInterfaceClass = USB_CLASS_CDC_DATA,
|
|
||||||
.bInterfaceSubClass = USB_SUBCLASS_NONE,
|
|
||||||
.bInterfaceProtocol = USB_PROTO_NONE,
|
|
||||||
.iInterface = NO_DESCRIPTOR,
|
|
||||||
},
|
|
||||||
|
|
||||||
.ep_in =
|
|
||||||
{
|
|
||||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
|
||||||
.bDescriptorType = USB_DTYPE_ENDPOINT,
|
|
||||||
.bEndpointAddress = HID_EP_IN | DAP_CDC_EP_SEND,
|
|
||||||
.bmAttributes = USB_EPTYPE_BULK,
|
|
||||||
.wMaxPacketSize = DAP_CDC_EP_SIZE,
|
|
||||||
.bInterval = DAP_CDC_INTERVAL,
|
|
||||||
},
|
|
||||||
|
|
||||||
.ep_out =
|
|
||||||
{
|
|
||||||
.bLength = sizeof(struct usb_endpoint_descriptor),
|
|
||||||
.bDescriptorType = USB_DTYPE_ENDPOINT,
|
|
||||||
.bEndpointAddress = HID_EP_OUT | DAP_CDC_EP_RECV,
|
|
||||||
.bmAttributes = USB_EPTYPE_BULK,
|
|
||||||
.wMaxPacketSize = DAP_CDC_EP_SIZE,
|
|
||||||
.bInterval = DAP_CDC_INTERVAL,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// WinUSB
|
|
||||||
#include "usb_winusb.h"
|
|
||||||
|
|
||||||
typedef struct USB_PACK {
|
|
||||||
usb_binary_object_store_descriptor_t bos;
|
|
||||||
usb_winusb_capability_descriptor_t winusb;
|
|
||||||
} usb_bos_hierarchy_t;
|
|
||||||
|
|
||||||
typedef struct USB_PACK {
|
|
||||||
usb_winusb_subset_header_function_t header;
|
|
||||||
usb_winusb_feature_compatble_id_t comp_id;
|
|
||||||
usb_winusb_feature_reg_property_guids_t property;
|
|
||||||
} usb_msos_descriptor_subset_t;
|
|
||||||
|
|
||||||
typedef struct USB_PACK {
|
|
||||||
usb_winusb_set_header_descriptor_t header;
|
|
||||||
usb_msos_descriptor_subset_t subset;
|
|
||||||
} usb_msos_descriptor_set_t;
|
|
||||||
|
|
||||||
#define USB_DTYPE_BINARY_OBJECT_STORE 15
|
|
||||||
#define USB_DTYPE_DEVICE_CAPABILITY_DESCRIPTOR 16
|
|
||||||
#define USB_DC_TYPE_PLATFORM 5
|
|
||||||
|
|
||||||
const usb_bos_hierarchy_t usb_bos_hierarchy = {
|
|
||||||
.bos =
|
|
||||||
{
|
|
||||||
.bLength = sizeof(usb_binary_object_store_descriptor_t),
|
|
||||||
.bDescriptorType = USB_DTYPE_BINARY_OBJECT_STORE,
|
|
||||||
.wTotalLength = sizeof(usb_bos_hierarchy_t),
|
|
||||||
.bNumDeviceCaps = 1,
|
|
||||||
},
|
|
||||||
.winusb =
|
|
||||||
{
|
|
||||||
.bLength = sizeof(usb_winusb_capability_descriptor_t),
|
|
||||||
.bDescriptorType = USB_DTYPE_DEVICE_CAPABILITY_DESCRIPTOR,
|
|
||||||
.bDevCapabilityType = USB_DC_TYPE_PLATFORM,
|
|
||||||
.bReserved = 0,
|
|
||||||
.PlatformCapabilityUUID = USB_WINUSB_PLATFORM_CAPABILITY_ID,
|
|
||||||
.dwWindowsVersion = USB_WINUSB_WINDOWS_VERSION,
|
|
||||||
.wMSOSDescriptorSetTotalLength = sizeof(usb_msos_descriptor_set_t),
|
|
||||||
.bMS_VendorCode = USB_WINUSB_VENDOR_CODE,
|
|
||||||
.bAltEnumCode = 0,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const usb_msos_descriptor_set_t usb_msos_descriptor_set = {
|
|
||||||
.header =
|
|
||||||
{
|
|
||||||
.wLength = sizeof(usb_winusb_set_header_descriptor_t),
|
|
||||||
.wDescriptorType = USB_WINUSB_SET_HEADER_DESCRIPTOR,
|
|
||||||
.dwWindowsVersion = USB_WINUSB_WINDOWS_VERSION,
|
|
||||||
.wDescriptorSetTotalLength = sizeof(usb_msos_descriptor_set_t),
|
|
||||||
},
|
|
||||||
|
|
||||||
.subset =
|
|
||||||
{
|
|
||||||
.header =
|
|
||||||
{
|
|
||||||
.wLength = sizeof(usb_winusb_subset_header_function_t),
|
|
||||||
.wDescriptorType = USB_WINUSB_SUBSET_HEADER_FUNCTION,
|
|
||||||
.bFirstInterface = USB_INTF_BULK,
|
|
||||||
.bReserved = 0,
|
|
||||||
.wSubsetLength = sizeof(usb_msos_descriptor_subset_t),
|
|
||||||
},
|
|
||||||
|
|
||||||
.comp_id =
|
|
||||||
{
|
|
||||||
.wLength = sizeof(usb_winusb_feature_compatble_id_t),
|
|
||||||
.wDescriptorType = USB_WINUSB_FEATURE_COMPATBLE_ID,
|
|
||||||
.CompatibleID = "WINUSB\0\0",
|
|
||||||
.SubCompatibleID = {0},
|
|
||||||
},
|
|
||||||
|
|
||||||
.property =
|
|
||||||
{
|
|
||||||
.wLength = sizeof(usb_winusb_feature_reg_property_guids_t),
|
|
||||||
.wDescriptorType = USB_WINUSB_FEATURE_REG_PROPERTY,
|
|
||||||
.wPropertyDataType = USB_WINUSB_PROPERTY_DATA_TYPE_MULTI_SZ,
|
|
||||||
.wPropertyNameLength =
|
|
||||||
sizeof(usb_msos_descriptor_set.subset.property.PropertyName),
|
|
||||||
.PropertyName = {'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0, 'I', 0,
|
|
||||||
'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0,
|
|
||||||
'e', 0, 'G', 0, 'U', 0, 'I', 0, 'D', 0, 's', 0, 0, 0},
|
|
||||||
.wPropertyDataLength =
|
|
||||||
sizeof(usb_msos_descriptor_set.subset.property.PropertyData),
|
|
||||||
.PropertyData = {'{', 0, 'C', 0, 'D', 0, 'B', 0, '3', 0, 'B', 0, '5', 0,
|
|
||||||
'A', 0, 'D', 0, '-', 0, '2', 0, '9', 0, '3', 0, 'B', 0,
|
|
||||||
'-', 0, '4', 0, '6', 0, '6', 0, '3', 0, '-', 0, 'A', 0,
|
|
||||||
'A', 0, '3', 0, '6', 0, '-', 0, '1', 0, 'A', 0, 'A', 0,
|
|
||||||
'E', 0, '4', 0, '6', 0, '4', 0, '6', 0, '3', 0, '7', 0,
|
|
||||||
'7', 0, '6', 0, '}', 0, 0, 0, 0, 0},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
FuriSemaphore* semaphore_v1;
|
|
||||||
FuriSemaphore* semaphore_v2;
|
|
||||||
FuriSemaphore* semaphore_cdc;
|
|
||||||
bool connected;
|
|
||||||
usbd_device* usb_dev;
|
|
||||||
DapStateCallback state_callback;
|
|
||||||
DapRxCallback rx_callback_v1;
|
|
||||||
DapRxCallback rx_callback_v2;
|
|
||||||
DapRxCallback rx_callback_cdc;
|
|
||||||
DapCDCControlLineCallback control_line_callback_cdc;
|
|
||||||
DapCDCConfigCallback config_callback_cdc;
|
|
||||||
void* context;
|
|
||||||
void* context_cdc;
|
|
||||||
} DAPState;
|
|
||||||
|
|
||||||
static DAPState dap_state = {
|
|
||||||
.semaphore_v1 = NULL,
|
|
||||||
.semaphore_v2 = NULL,
|
|
||||||
.semaphore_cdc = NULL,
|
|
||||||
.connected = false,
|
|
||||||
.usb_dev = NULL,
|
|
||||||
.state_callback = NULL,
|
|
||||||
.rx_callback_v1 = NULL,
|
|
||||||
.rx_callback_v2 = NULL,
|
|
||||||
.rx_callback_cdc = NULL,
|
|
||||||
.control_line_callback_cdc = NULL,
|
|
||||||
.config_callback_cdc = NULL,
|
|
||||||
.context = NULL,
|
|
||||||
.context_cdc = NULL,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct usb_cdc_line_coding cdc_config = {0};
|
|
||||||
static uint8_t cdc_ctrl_line_state = 0;
|
|
||||||
|
|
||||||
#ifdef DAP_USB_LOG
|
|
||||||
void furi_console_log_printf(const char* format, ...) _ATTRIBUTE((__format__(__printf__, 1, 2)));
|
|
||||||
|
|
||||||
void furi_console_log_printf(const char* format, ...) {
|
|
||||||
char buffer[256];
|
|
||||||
va_list args;
|
|
||||||
va_start(args, format);
|
|
||||||
vsnprintf(buffer, sizeof(buffer), format, args);
|
|
||||||
va_end(args);
|
|
||||||
furi_hal_console_puts(buffer);
|
|
||||||
furi_hal_console_puts("\r\n");
|
|
||||||
UNUSED(format);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#define furi_console_log_printf(...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int32_t dap_v1_usb_tx(uint8_t* buffer, uint8_t size) {
|
|
||||||
if((dap_state.semaphore_v1 == NULL) || (dap_state.connected == false)) return 0;
|
|
||||||
|
|
||||||
furi_check(furi_semaphore_acquire(dap_state.semaphore_v1, FuriWaitForever) == FuriStatusOk);
|
|
||||||
|
|
||||||
if(dap_state.connected) {
|
|
||||||
int32_t len = usbd_ep_write(dap_state.usb_dev, DAP_HID_EP_IN, buffer, size);
|
|
||||||
furi_console_log_printf("v1 tx %ld", len);
|
|
||||||
return len;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t dap_v2_usb_tx(uint8_t* buffer, uint8_t size) {
|
|
||||||
if((dap_state.semaphore_v2 == NULL) || (dap_state.connected == false)) return 0;
|
|
||||||
|
|
||||||
furi_check(furi_semaphore_acquire(dap_state.semaphore_v2, FuriWaitForever) == FuriStatusOk);
|
|
||||||
|
|
||||||
if(dap_state.connected) {
|
|
||||||
int32_t len = usbd_ep_write(dap_state.usb_dev, DAP_HID_EP_BULK_IN, buffer, size);
|
|
||||||
furi_console_log_printf("v2 tx %ld", len);
|
|
||||||
return len;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t dap_cdc_usb_tx(uint8_t* buffer, uint8_t size) {
|
|
||||||
if((dap_state.semaphore_cdc == NULL) || (dap_state.connected == false)) return 0;
|
|
||||||
|
|
||||||
furi_check(furi_semaphore_acquire(dap_state.semaphore_cdc, FuriWaitForever) == FuriStatusOk);
|
|
||||||
|
|
||||||
if(dap_state.connected) {
|
|
||||||
int32_t len = usbd_ep_write(dap_state.usb_dev, HID_EP_IN | DAP_CDC_EP_SEND, buffer, size);
|
|
||||||
furi_console_log_printf("cdc tx %ld", len);
|
|
||||||
return len;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_v1_usb_set_rx_callback(DapRxCallback callback) {
|
|
||||||
dap_state.rx_callback_v1 = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_v2_usb_set_rx_callback(DapRxCallback callback) {
|
|
||||||
dap_state.rx_callback_v2 = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_cdc_usb_set_rx_callback(DapRxCallback callback) {
|
|
||||||
dap_state.rx_callback_cdc = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_cdc_usb_set_control_line_callback(DapCDCControlLineCallback callback) {
|
|
||||||
dap_state.control_line_callback_cdc = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_cdc_usb_set_config_callback(DapCDCConfigCallback callback) {
|
|
||||||
dap_state.config_callback_cdc = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_cdc_usb_set_context(void* context) {
|
|
||||||
dap_state.context_cdc = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_common_usb_set_context(void* context) {
|
|
||||||
dap_state.context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_common_usb_set_state_callback(DapStateCallback callback) {
|
|
||||||
dap_state.state_callback = callback;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void* dap_usb_alloc_string_descr(const char* str) {
|
|
||||||
furi_assert(str);
|
|
||||||
|
|
||||||
size_t len = strlen(str);
|
|
||||||
size_t wlen = (len + 1) * sizeof(uint16_t);
|
|
||||||
struct usb_string_descriptor* dev_str_desc = malloc(wlen);
|
|
||||||
dev_str_desc->bLength = wlen;
|
|
||||||
dev_str_desc->bDescriptorType = USB_DTYPE_STRING;
|
|
||||||
for(size_t i = 0; i < len; i++) {
|
|
||||||
dev_str_desc->wString[i] = str[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
return dev_str_desc;
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_common_usb_alloc_name(const char* name) {
|
|
||||||
dev_serial_descr = dap_usb_alloc_string_descr(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void dap_common_usb_free_name() {
|
|
||||||
free(dev_serial_descr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hid_init(usbd_device* dev, FuriHalUsbInterface* intf, void* ctx);
|
|
||||||
static void hid_deinit(usbd_device* dev);
|
|
||||||
static void hid_on_wakeup(usbd_device* dev);
|
|
||||||
static void hid_on_suspend(usbd_device* dev);
|
|
||||||
|
|
||||||
static usbd_respond hid_ep_config(usbd_device* dev, uint8_t cfg);
|
|
||||||
static usbd_respond hid_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_callback* callback);
|
|
||||||
|
|
||||||
FuriHalUsbInterface dap_v2_usb_hid = {
|
|
||||||
.init = hid_init,
|
|
||||||
.deinit = hid_deinit,
|
|
||||||
.wakeup = hid_on_wakeup,
|
|
||||||
.suspend = hid_on_suspend,
|
|
||||||
.dev_descr = (struct usb_device_descriptor*)&hid_device_desc,
|
|
||||||
.cfg_descr = (void*)&hid_cfg_desc,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void hid_init(usbd_device* dev, FuriHalUsbInterface* intf, void* ctx) {
|
|
||||||
UNUSED(intf);
|
|
||||||
UNUSED(ctx);
|
|
||||||
|
|
||||||
dap_v2_usb_hid.str_manuf_descr = (void*)&dev_manuf_descr;
|
|
||||||
dap_v2_usb_hid.str_prod_descr = (void*)&dev_prod_descr;
|
|
||||||
dap_v2_usb_hid.str_serial_descr = (void*)dev_serial_descr;
|
|
||||||
|
|
||||||
dap_state.usb_dev = dev;
|
|
||||||
if(dap_state.semaphore_v1 == NULL) dap_state.semaphore_v1 = furi_semaphore_alloc(1, 1);
|
|
||||||
if(dap_state.semaphore_v2 == NULL) dap_state.semaphore_v2 = furi_semaphore_alloc(1, 1);
|
|
||||||
if(dap_state.semaphore_cdc == NULL) dap_state.semaphore_cdc = furi_semaphore_alloc(1, 1);
|
|
||||||
|
|
||||||
usbd_reg_config(dev, hid_ep_config);
|
|
||||||
usbd_reg_control(dev, hid_control);
|
|
||||||
|
|
||||||
usbd_connect(dev, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hid_deinit(usbd_device* dev) {
|
|
||||||
dap_state.usb_dev = NULL;
|
|
||||||
|
|
||||||
furi_semaphore_free(dap_state.semaphore_v1);
|
|
||||||
furi_semaphore_free(dap_state.semaphore_v2);
|
|
||||||
furi_semaphore_free(dap_state.semaphore_cdc);
|
|
||||||
dap_state.semaphore_v1 = NULL;
|
|
||||||
dap_state.semaphore_v2 = NULL;
|
|
||||||
dap_state.semaphore_cdc = NULL;
|
|
||||||
|
|
||||||
usbd_reg_config(dev, NULL);
|
|
||||||
usbd_reg_control(dev, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hid_on_wakeup(usbd_device* dev) {
|
|
||||||
UNUSED(dev);
|
|
||||||
if(!dap_state.connected) {
|
|
||||||
dap_state.connected = true;
|
|
||||||
if(dap_state.state_callback != NULL) {
|
|
||||||
dap_state.state_callback(dap_state.connected, dap_state.context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hid_on_suspend(usbd_device* dev) {
|
|
||||||
UNUSED(dev);
|
|
||||||
if(dap_state.connected) {
|
|
||||||
dap_state.connected = false;
|
|
||||||
if(dap_state.state_callback != NULL) {
|
|
||||||
dap_state.state_callback(dap_state.connected, dap_state.context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t dap_v1_usb_rx(uint8_t* buffer, size_t size) {
|
|
||||||
size_t len = 0;
|
|
||||||
|
|
||||||
if(dap_state.connected) {
|
|
||||||
len = usbd_ep_read(dap_state.usb_dev, DAP_HID_EP_OUT, buffer, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t dap_v2_usb_rx(uint8_t* buffer, size_t size) {
|
|
||||||
size_t len = 0;
|
|
||||||
|
|
||||||
if(dap_state.connected) {
|
|
||||||
len = usbd_ep_read(dap_state.usb_dev, DAP_HID_EP_BULK_OUT, buffer, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t dap_cdc_usb_rx(uint8_t* buffer, size_t size) {
|
|
||||||
size_t len = 0;
|
|
||||||
|
|
||||||
if(dap_state.connected) {
|
|
||||||
len = usbd_ep_read(dap_state.usb_dev, HID_EP_OUT | DAP_CDC_EP_RECV, buffer, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hid_txrx_ep_callback(usbd_device* dev, uint8_t event, uint8_t ep) {
|
|
||||||
UNUSED(dev);
|
|
||||||
UNUSED(ep);
|
|
||||||
|
|
||||||
switch(event) {
|
|
||||||
case usbd_evt_eptx:
|
|
||||||
furi_semaphore_release(dap_state.semaphore_v1);
|
|
||||||
furi_console_log_printf("hid tx complete");
|
|
||||||
break;
|
|
||||||
case usbd_evt_eprx:
|
|
||||||
if(dap_state.rx_callback_v1 != NULL) {
|
|
||||||
dap_state.rx_callback_v1(dap_state.context);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
furi_console_log_printf("hid %d, %d", event, ep);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void hid_txrx_ep_bulk_callback(usbd_device* dev, uint8_t event, uint8_t ep) {
|
|
||||||
UNUSED(dev);
|
|
||||||
UNUSED(ep);
|
|
||||||
|
|
||||||
switch(event) {
|
|
||||||
case usbd_evt_eptx:
|
|
||||||
furi_semaphore_release(dap_state.semaphore_v2);
|
|
||||||
furi_console_log_printf("bulk tx complete");
|
|
||||||
break;
|
|
||||||
case usbd_evt_eprx:
|
|
||||||
if(dap_state.rx_callback_v2 != NULL) {
|
|
||||||
dap_state.rx_callback_v2(dap_state.context);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
furi_console_log_printf("bulk %d, %d", event, ep);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void cdc_txrx_ep_callback(usbd_device* dev, uint8_t event, uint8_t ep) {
|
|
||||||
UNUSED(dev);
|
|
||||||
UNUSED(ep);
|
|
||||||
|
|
||||||
switch(event) {
|
|
||||||
case usbd_evt_eptx:
|
|
||||||
furi_semaphore_release(dap_state.semaphore_cdc);
|
|
||||||
furi_console_log_printf("cdc tx complete");
|
|
||||||
break;
|
|
||||||
case usbd_evt_eprx:
|
|
||||||
if(dap_state.rx_callback_cdc != NULL) {
|
|
||||||
dap_state.rx_callback_cdc(dap_state.context_cdc);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
furi_console_log_printf("cdc %d, %d", event, ep);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static usbd_respond hid_ep_config(usbd_device* dev, uint8_t cfg) {
|
|
||||||
switch(cfg) {
|
|
||||||
case EP_CFG_DECONFIGURE:
|
|
||||||
usbd_ep_deconfig(dev, DAP_HID_EP_OUT);
|
|
||||||
usbd_ep_deconfig(dev, DAP_HID_EP_IN);
|
|
||||||
usbd_ep_deconfig(dev, DAP_HID_EP_BULK_IN);
|
|
||||||
usbd_ep_deconfig(dev, DAP_HID_EP_BULK_OUT);
|
|
||||||
usbd_ep_deconfig(dev, HID_EP_IN | DAP_CDC_EP_COMM);
|
|
||||||
usbd_ep_deconfig(dev, HID_EP_IN | DAP_CDC_EP_SEND);
|
|
||||||
usbd_ep_deconfig(dev, HID_EP_OUT | DAP_CDC_EP_RECV);
|
|
||||||
usbd_reg_endpoint(dev, DAP_HID_EP_OUT, NULL);
|
|
||||||
usbd_reg_endpoint(dev, DAP_HID_EP_IN, NULL);
|
|
||||||
usbd_reg_endpoint(dev, DAP_HID_EP_BULK_IN, NULL);
|
|
||||||
usbd_reg_endpoint(dev, DAP_HID_EP_BULK_OUT, NULL);
|
|
||||||
usbd_reg_endpoint(dev, HID_EP_IN | DAP_CDC_EP_SEND, 0);
|
|
||||||
usbd_reg_endpoint(dev, HID_EP_OUT | DAP_CDC_EP_RECV, 0);
|
|
||||||
return usbd_ack;
|
|
||||||
case EP_CFG_CONFIGURE:
|
|
||||||
usbd_ep_config(dev, DAP_HID_EP_IN, USB_EPTYPE_INTERRUPT, DAP_HID_EP_SIZE);
|
|
||||||
usbd_ep_config(dev, DAP_HID_EP_OUT, USB_EPTYPE_INTERRUPT, DAP_HID_EP_SIZE);
|
|
||||||
usbd_ep_config(dev, DAP_HID_EP_BULK_OUT, USB_EPTYPE_BULK, DAP_HID_EP_SIZE);
|
|
||||||
usbd_ep_config(dev, DAP_HID_EP_BULK_IN, USB_EPTYPE_BULK, DAP_HID_EP_SIZE);
|
|
||||||
usbd_ep_config(dev, HID_EP_OUT | DAP_CDC_EP_RECV, USB_EPTYPE_BULK, DAP_CDC_EP_SIZE);
|
|
||||||
usbd_ep_config(dev, HID_EP_IN | DAP_CDC_EP_SEND, USB_EPTYPE_BULK, DAP_CDC_EP_SIZE);
|
|
||||||
usbd_ep_config(dev, HID_EP_IN | DAP_CDC_EP_COMM, USB_EPTYPE_INTERRUPT, DAP_CDC_EP_SIZE);
|
|
||||||
usbd_reg_endpoint(dev, DAP_HID_EP_IN, hid_txrx_ep_callback);
|
|
||||||
usbd_reg_endpoint(dev, DAP_HID_EP_OUT, hid_txrx_ep_callback);
|
|
||||||
usbd_reg_endpoint(dev, DAP_HID_EP_BULK_OUT, hid_txrx_ep_bulk_callback);
|
|
||||||
usbd_reg_endpoint(dev, DAP_HID_EP_BULK_IN, hid_txrx_ep_bulk_callback);
|
|
||||||
usbd_reg_endpoint(dev, HID_EP_OUT | DAP_CDC_EP_RECV, cdc_txrx_ep_callback);
|
|
||||||
usbd_reg_endpoint(dev, HID_EP_IN | DAP_CDC_EP_SEND, cdc_txrx_ep_callback);
|
|
||||||
// usbd_ep_write(dev, DAP_HID_EP_IN, NULL, 0);
|
|
||||||
// usbd_ep_write(dev, DAP_HID_EP_BULK_IN, NULL, 0);
|
|
||||||
// usbd_ep_write(dev, HID_EP_IN | DAP_CDC_EP_SEND, NULL, 0);
|
|
||||||
return usbd_ack;
|
|
||||||
default:
|
|
||||||
return usbd_fail;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef DAP_USB_LOG
|
|
||||||
static void dump_request_type(uint8_t type) {
|
|
||||||
switch(type & USB_REQ_DIRECTION) {
|
|
||||||
case USB_REQ_HOSTTODEV:
|
|
||||||
furi_hal_console_puts("host to dev, ");
|
|
||||||
break;
|
|
||||||
case USB_REQ_DEVTOHOST:
|
|
||||||
furi_hal_console_puts("dev to host, ");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(type & USB_REQ_TYPE) {
|
|
||||||
case USB_REQ_STANDARD:
|
|
||||||
furi_hal_console_puts("standard, ");
|
|
||||||
break;
|
|
||||||
case USB_REQ_CLASS:
|
|
||||||
furi_hal_console_puts("class, ");
|
|
||||||
break;
|
|
||||||
case USB_REQ_VENDOR:
|
|
||||||
furi_hal_console_puts("vendor, ");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch(type & USB_REQ_RECIPIENT) {
|
|
||||||
case USB_REQ_DEVICE:
|
|
||||||
furi_hal_console_puts("device");
|
|
||||||
break;
|
|
||||||
case USB_REQ_INTERFACE:
|
|
||||||
furi_hal_console_puts("interface");
|
|
||||||
break;
|
|
||||||
case USB_REQ_ENDPOINT:
|
|
||||||
furi_hal_console_puts("endpoint");
|
|
||||||
break;
|
|
||||||
case USB_REQ_OTHER:
|
|
||||||
furi_hal_console_puts("other");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
furi_hal_console_puts("\r\n");
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
#define dump_request_type(...)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static usbd_respond hid_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_callback* callback) {
|
|
||||||
UNUSED(callback);
|
|
||||||
|
|
||||||
dump_request_type(req->bmRequestType);
|
|
||||||
furi_console_log_printf(
|
|
||||||
"control: RT %02x, R %02x, V %04x, I %04x, L %04x",
|
|
||||||
req->bmRequestType,
|
|
||||||
req->bRequest,
|
|
||||||
req->wValue,
|
|
||||||
req->wIndex,
|
|
||||||
req->wLength);
|
|
||||||
|
|
||||||
if(((USB_REQ_RECIPIENT | USB_REQ_TYPE | USB_REQ_DIRECTION) & req->bmRequestType) ==
|
|
||||||
(USB_REQ_STANDARD | USB_REQ_VENDOR | USB_REQ_DEVTOHOST)) {
|
|
||||||
// vendor request, device to host
|
|
||||||
furi_console_log_printf("vendor request");
|
|
||||||
if(USB_WINUSB_VENDOR_CODE == req->bRequest) {
|
|
||||||
// WINUSB request
|
|
||||||
if(USB_WINUSB_DESCRIPTOR_INDEX == req->wIndex) {
|
|
||||||
furi_console_log_printf("WINUSB descriptor");
|
|
||||||
uint16_t length = req->wLength;
|
|
||||||
if(length > sizeof(usb_msos_descriptor_set_t)) {
|
|
||||||
length = sizeof(usb_msos_descriptor_set_t);
|
|
||||||
}
|
|
||||||
|
|
||||||
dev->status.data_ptr = (uint8_t*)&usb_msos_descriptor_set;
|
|
||||||
dev->status.data_count = length;
|
|
||||||
return usbd_ack;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) ==
|
|
||||||
(USB_REQ_STANDARD | USB_REQ_DEVICE)) {
|
|
||||||
// device request
|
|
||||||
if(req->bRequest == USB_STD_GET_DESCRIPTOR) {
|
|
||||||
const uint8_t dtype = req->wValue >> 8;
|
|
||||||
const uint8_t dnumber = req->wValue & 0xFF;
|
|
||||||
// get string descriptor
|
|
||||||
if(USB_DTYPE_STRING == dtype) {
|
|
||||||
if(dnumber == USB_STR_CMSIS_DAP_V1) {
|
|
||||||
furi_console_log_printf("str CMSIS-DAP v1");
|
|
||||||
dev->status.data_ptr = (uint8_t*)&dev_dap_v1_descr;
|
|
||||||
dev->status.data_count = dev_dap_v1_descr.bLength;
|
|
||||||
return usbd_ack;
|
|
||||||
} else if(dnumber == USB_STR_CMSIS_DAP_V2) {
|
|
||||||
furi_console_log_printf("str CMSIS-DAP v2");
|
|
||||||
dev->status.data_ptr = (uint8_t*)&dev_dap_v2_descr;
|
|
||||||
dev->status.data_count = dev_dap_v2_descr.bLength;
|
|
||||||
return usbd_ack;
|
|
||||||
} else if(dnumber == USB_STR_COM_PORT) {
|
|
||||||
furi_console_log_printf("str COM port");
|
|
||||||
dev->status.data_ptr = (uint8_t*)&dev_com_descr;
|
|
||||||
dev->status.data_count = dev_com_descr.bLength;
|
|
||||||
return usbd_ack;
|
|
||||||
}
|
|
||||||
} else if(USB_DTYPE_BINARY_OBJECT_STORE == dtype) {
|
|
||||||
furi_console_log_printf("BOS descriptor");
|
|
||||||
uint16_t length = req->wLength;
|
|
||||||
if(length > sizeof(usb_bos_hierarchy_t)) {
|
|
||||||
length = sizeof(usb_bos_hierarchy_t);
|
|
||||||
}
|
|
||||||
dev->status.data_ptr = (uint8_t*)&usb_bos_hierarchy;
|
|
||||||
dev->status.data_count = length;
|
|
||||||
return usbd_ack;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) ==
|
|
||||||
(USB_REQ_INTERFACE | USB_REQ_CLASS) &&
|
|
||||||
req->wIndex == 0) {
|
|
||||||
// class request
|
|
||||||
switch(req->bRequest) {
|
|
||||||
// get hid descriptor
|
|
||||||
case USB_HID_GETREPORT:
|
|
||||||
furi_console_log_printf("get report");
|
|
||||||
return usbd_fail;
|
|
||||||
// set hid idle
|
|
||||||
case USB_HID_SETIDLE:
|
|
||||||
furi_console_log_printf("set idle");
|
|
||||||
return usbd_ack;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) ==
|
|
||||||
(USB_REQ_INTERFACE | USB_REQ_CLASS) &&
|
|
||||||
req->wIndex == 2) {
|
|
||||||
// class request
|
|
||||||
switch(req->bRequest) {
|
|
||||||
// control line state
|
|
||||||
case USB_CDC_SET_CONTROL_LINE_STATE:
|
|
||||||
furi_console_log_printf("set control line state");
|
|
||||||
cdc_ctrl_line_state = req->wValue;
|
|
||||||
if(dap_state.control_line_callback_cdc != NULL) {
|
|
||||||
dap_state.control_line_callback_cdc(cdc_ctrl_line_state, dap_state.context_cdc);
|
|
||||||
}
|
|
||||||
return usbd_ack;
|
|
||||||
// set cdc line coding
|
|
||||||
case USB_CDC_SET_LINE_CODING:
|
|
||||||
furi_console_log_printf("set line coding");
|
|
||||||
memcpy(&cdc_config, req->data, sizeof(cdc_config));
|
|
||||||
if(dap_state.config_callback_cdc != NULL) {
|
|
||||||
dap_state.config_callback_cdc(&cdc_config, dap_state.context_cdc);
|
|
||||||
}
|
|
||||||
return usbd_ack;
|
|
||||||
// get cdc line coding
|
|
||||||
case USB_CDC_GET_LINE_CODING:
|
|
||||||
furi_console_log_printf("get line coding");
|
|
||||||
dev->status.data_ptr = &cdc_config;
|
|
||||||
dev->status.data_count = sizeof(cdc_config);
|
|
||||||
return usbd_ack;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) ==
|
|
||||||
(USB_REQ_INTERFACE | USB_REQ_STANDARD) &&
|
|
||||||
req->wIndex == 0 && req->bRequest == USB_STD_GET_DESCRIPTOR) {
|
|
||||||
// standard request
|
|
||||||
switch(req->wValue >> 8) {
|
|
||||||
// get hid descriptor
|
|
||||||
case USB_DTYPE_HID:
|
|
||||||
furi_console_log_printf("get hid descriptor");
|
|
||||||
dev->status.data_ptr = (uint8_t*)&(hid_cfg_desc.hid);
|
|
||||||
dev->status.data_count = sizeof(hid_cfg_desc.hid);
|
|
||||||
return usbd_ack;
|
|
||||||
// get hid report descriptor
|
|
||||||
case USB_DTYPE_HID_REPORT:
|
|
||||||
furi_console_log_printf("get hid report descriptor");
|
|
||||||
dev->status.data_ptr = (uint8_t*)hid_report_desc;
|
|
||||||
dev->status.data_count = sizeof(hid_report_desc);
|
|
||||||
return usbd_ack;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return usbd_fail;
|
|
||||||
}
|
|
53
applications/external/dap_link/usb/dap_v2_usb.h
vendored
|
@ -1,53 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <furi_hal_usb.h>
|
|
||||||
#include <usb_cdc.h>
|
|
||||||
|
|
||||||
extern FuriHalUsbInterface dap_v2_usb_hid;
|
|
||||||
|
|
||||||
// receive callback type
|
|
||||||
typedef void (*DapRxCallback)(void* context);
|
|
||||||
|
|
||||||
typedef void (*DapStateCallback)(bool state, void* context);
|
|
||||||
|
|
||||||
/************************************ V1 ***************************************/
|
|
||||||
|
|
||||||
int32_t dap_v1_usb_tx(uint8_t* buffer, uint8_t size);
|
|
||||||
|
|
||||||
size_t dap_v1_usb_rx(uint8_t* buffer, size_t size);
|
|
||||||
|
|
||||||
void dap_v1_usb_set_rx_callback(DapRxCallback callback);
|
|
||||||
|
|
||||||
/************************************ V2 ***************************************/
|
|
||||||
|
|
||||||
int32_t dap_v2_usb_tx(uint8_t* buffer, uint8_t size);
|
|
||||||
|
|
||||||
size_t dap_v2_usb_rx(uint8_t* buffer, size_t size);
|
|
||||||
|
|
||||||
void dap_v2_usb_set_rx_callback(DapRxCallback callback);
|
|
||||||
|
|
||||||
/************************************ CDC **************************************/
|
|
||||||
|
|
||||||
typedef void (*DapCDCControlLineCallback)(uint8_t state, void* context);
|
|
||||||
typedef void (*DapCDCConfigCallback)(struct usb_cdc_line_coding* config, void* context);
|
|
||||||
|
|
||||||
int32_t dap_cdc_usb_tx(uint8_t* buffer, uint8_t size);
|
|
||||||
|
|
||||||
size_t dap_cdc_usb_rx(uint8_t* buffer, size_t size);
|
|
||||||
|
|
||||||
void dap_cdc_usb_set_rx_callback(DapRxCallback callback);
|
|
||||||
|
|
||||||
void dap_cdc_usb_set_control_line_callback(DapCDCControlLineCallback callback);
|
|
||||||
|
|
||||||
void dap_cdc_usb_set_config_callback(DapCDCConfigCallback callback);
|
|
||||||
|
|
||||||
void dap_cdc_usb_set_context(void* context);
|
|
||||||
|
|
||||||
/*********************************** Common ************************************/
|
|
||||||
|
|
||||||
void dap_common_usb_set_context(void* context);
|
|
||||||
|
|
||||||
void dap_common_usb_set_state_callback(DapStateCallback callback);
|
|
||||||
|
|
||||||
void dap_common_usb_alloc_name(const char* name);
|
|
||||||
|
|
||||||
void dap_common_usb_free_name();
|
|
143
applications/external/dap_link/usb/usb_winusb.h
vendored
|
@ -1,143 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
/*- Definitions -------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#define USB_PACK __attribute__((packed))
|
|
||||||
|
|
||||||
#define USB_WINUSB_VENDOR_CODE 0x20
|
|
||||||
|
|
||||||
#define USB_WINUSB_WINDOWS_VERSION 0x06030000 // Windows 8.1
|
|
||||||
|
|
||||||
#define USB_WINUSB_PLATFORM_CAPABILITY_ID \
|
|
||||||
{ \
|
|
||||||
0xdf, 0x60, 0xdd, 0xd8, 0x89, 0x45, 0xc7, 0x4c, 0x9c, 0xd2, 0x65, 0x9d, 0x9e, 0x64, 0x8a, \
|
|
||||||
0x9f \
|
|
||||||
}
|
|
||||||
|
|
||||||
enum // WinUSB Microsoft OS 2.0 descriptor request codes
|
|
||||||
{
|
|
||||||
USB_WINUSB_DESCRIPTOR_INDEX = 0x07,
|
|
||||||
USB_WINUSB_SET_ALT_ENUMERATION = 0x08,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum // wDescriptorType
|
|
||||||
{
|
|
||||||
USB_WINUSB_SET_HEADER_DESCRIPTOR = 0x00,
|
|
||||||
USB_WINUSB_SUBSET_HEADER_CONFIGURATION = 0x01,
|
|
||||||
USB_WINUSB_SUBSET_HEADER_FUNCTION = 0x02,
|
|
||||||
USB_WINUSB_FEATURE_COMPATBLE_ID = 0x03,
|
|
||||||
USB_WINUSB_FEATURE_REG_PROPERTY = 0x04,
|
|
||||||
USB_WINUSB_FEATURE_MIN_RESUME_TIME = 0x05,
|
|
||||||
USB_WINUSB_FEATURE_MODEL_ID = 0x06,
|
|
||||||
USB_WINUSB_FEATURE_CCGP_DEVICE = 0x07,
|
|
||||||
USB_WINUSB_FEATURE_VENDOR_REVISION = 0x08,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum // wPropertyDataType
|
|
||||||
{
|
|
||||||
USB_WINUSB_PROPERTY_DATA_TYPE_SZ = 1,
|
|
||||||
USB_WINUSB_PROPERTY_DATA_TYPE_EXPAND_SZ = 2,
|
|
||||||
USB_WINUSB_PROPERTY_DATA_TYPE_BINARY = 3,
|
|
||||||
USB_WINUSB_PROPERTY_DATA_TYPE_DWORD_LITTLE_ENDIAN = 4,
|
|
||||||
USB_WINUSB_PROPERTY_DATA_TYPE_DWORD_BIG_ENDIAN = 5,
|
|
||||||
USB_WINUSB_PROPERTY_DATA_TYPE_LINK = 6,
|
|
||||||
USB_WINUSB_PROPERTY_DATA_TYPE_MULTI_SZ = 7,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*- Types BOS -------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
typedef struct USB_PACK {
|
|
||||||
uint8_t bLength;
|
|
||||||
uint8_t bDescriptorType;
|
|
||||||
uint16_t wTotalLength;
|
|
||||||
uint8_t bNumDeviceCaps;
|
|
||||||
} usb_binary_object_store_descriptor_t;
|
|
||||||
|
|
||||||
/*- Types WinUSB -------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
typedef struct USB_PACK {
|
|
||||||
uint8_t bLength;
|
|
||||||
uint8_t bDescriptorType;
|
|
||||||
uint8_t bDevCapabilityType;
|
|
||||||
uint8_t bReserved;
|
|
||||||
uint8_t PlatformCapabilityUUID[16];
|
|
||||||
uint32_t dwWindowsVersion;
|
|
||||||
uint16_t wMSOSDescriptorSetTotalLength;
|
|
||||||
uint8_t bMS_VendorCode;
|
|
||||||
uint8_t bAltEnumCode;
|
|
||||||
} usb_winusb_capability_descriptor_t;
|
|
||||||
|
|
||||||
typedef struct USB_PACK {
|
|
||||||
uint16_t wLength;
|
|
||||||
uint16_t wDescriptorType;
|
|
||||||
uint32_t dwWindowsVersion;
|
|
||||||
uint16_t wDescriptorSetTotalLength;
|
|
||||||
} usb_winusb_set_header_descriptor_t;
|
|
||||||
|
|
||||||
typedef struct USB_PACK {
|
|
||||||
uint16_t wLength;
|
|
||||||
uint16_t wDescriptorType;
|
|
||||||
uint8_t bConfigurationValue;
|
|
||||||
uint8_t bReserved;
|
|
||||||
uint16_t wTotalLength;
|
|
||||||
} usb_winusb_subset_header_configuration_t;
|
|
||||||
|
|
||||||
typedef struct USB_PACK {
|
|
||||||
uint16_t wLength;
|
|
||||||
uint16_t wDescriptorType;
|
|
||||||
uint8_t bFirstInterface;
|
|
||||||
uint8_t bReserved;
|
|
||||||
uint16_t wSubsetLength;
|
|
||||||
} usb_winusb_subset_header_function_t;
|
|
||||||
|
|
||||||
typedef struct USB_PACK {
|
|
||||||
uint16_t wLength;
|
|
||||||
uint16_t wDescriptorType;
|
|
||||||
uint8_t CompatibleID[8];
|
|
||||||
uint8_t SubCompatibleID[8];
|
|
||||||
} usb_winusb_feature_compatble_id_t;
|
|
||||||
|
|
||||||
typedef struct USB_PACK {
|
|
||||||
uint16_t wLength;
|
|
||||||
uint16_t wDescriptorType;
|
|
||||||
uint16_t wPropertyDataType;
|
|
||||||
//uint16_t wPropertyNameLength;
|
|
||||||
//uint8_t PropertyName[...];
|
|
||||||
//uint16_t wPropertyDataLength
|
|
||||||
//uint8_t PropertyData[...];
|
|
||||||
} usb_winusb_feature_reg_property_t;
|
|
||||||
|
|
||||||
typedef struct USB_PACK {
|
|
||||||
uint16_t wLength;
|
|
||||||
uint16_t wDescriptorType;
|
|
||||||
uint16_t wPropertyDataType;
|
|
||||||
uint16_t wPropertyNameLength;
|
|
||||||
uint8_t PropertyName[42];
|
|
||||||
uint16_t wPropertyDataLength;
|
|
||||||
uint8_t PropertyData[80];
|
|
||||||
} usb_winusb_feature_reg_property_guids_t;
|
|
||||||
|
|
||||||
typedef struct USB_PACK {
|
|
||||||
uint16_t wLength;
|
|
||||||
uint16_t wDescriptorType;
|
|
||||||
uint8_t bResumeRecoveryTime;
|
|
||||||
uint8_t bResumeSignalingTime;
|
|
||||||
} usb_winusb_feature_min_resume_time_t;
|
|
||||||
|
|
||||||
typedef struct USB_PACK {
|
|
||||||
uint16_t wLength;
|
|
||||||
uint16_t wDescriptorType;
|
|
||||||
uint8_t ModelID[16];
|
|
||||||
} usb_winusb_feature_model_id_t;
|
|
||||||
|
|
||||||
typedef struct USB_PACK {
|
|
||||||
uint16_t wLength;
|
|
||||||
uint16_t wDescriptorType;
|
|
||||||
} usb_winusb_feature_ccgp_device_t;
|
|
||||||
|
|
||||||
typedef struct USB_PACK {
|
|
||||||
uint16_t wLength;
|
|
||||||
uint16_t wDescriptorType;
|
|
||||||
uint16_t VendorRevision;
|
|
||||||
} usb_winusb_feature_vendor_revision_t;
|
|
24
applications/external/hid_app/application.fam
vendored
|
@ -1,24 +0,0 @@
|
||||||
App(
|
|
||||||
appid="hid_usb",
|
|
||||||
name="Remote",
|
|
||||||
apptype=FlipperAppType.EXTERNAL,
|
|
||||||
entry_point="hid_usb_app",
|
|
||||||
stack_size=1 * 1024,
|
|
||||||
fap_category="USB",
|
|
||||||
fap_icon="hid_usb_10px.png",
|
|
||||||
fap_icon_assets="assets",
|
|
||||||
fap_icon_assets_symbol="hid",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
App(
|
|
||||||
appid="hid_ble",
|
|
||||||
name="Remote",
|
|
||||||
apptype=FlipperAppType.EXTERNAL,
|
|
||||||
entry_point="hid_ble_app",
|
|
||||||
stack_size=1 * 1024,
|
|
||||||
fap_category="Bluetooth",
|
|
||||||
fap_icon="hid_ble_10px.png",
|
|
||||||
fap_icon_assets="assets",
|
|
||||||
fap_icon_assets_symbol="hid",
|
|
||||||
)
|
|
BIN
applications/external/hid_app/assets/Arr_dwn_7x9.png
vendored
Before Width: | Height: | Size: 3.5 KiB |
BIN
applications/external/hid_app/assets/Arr_up_7x9.png
vendored
Before Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 657 B |
Before Width: | Height: | Size: 102 B |
Before Width: | Height: | Size: 172 B |
Before Width: | Height: | Size: 173 B |
Before Width: | Height: | Size: 180 B |
Before Width: | Height: | Size: 177 B |
Before Width: | Height: | Size: 179 B |
Before Width: | Height: | Size: 178 B |
Before Width: | Height: | Size: 177 B |
Before Width: | Height: | Size: 178 B |
Before Width: | Height: | Size: 177 B |