[FL-2744] SPI Mem Manager C port (#1860)
Co-authored-by: あく <alleteam@gmail.com>
1
.gitignore
vendored
|
@ -1,4 +1,5 @@
|
|||
*.swp
|
||||
*.swo
|
||||
*.gdb_history
|
||||
|
||||
|
||||
|
|
17
applications/plugins/spi_mem_manager/application.fam
Normal file
|
@ -0,0 +1,17 @@
|
|||
App(
|
||||
appid="spi_mem_manager",
|
||||
name="SPI Mem Manager",
|
||||
apptype=FlipperAppType.EXTERNAL,
|
||||
entry_point="spi_mem_app",
|
||||
requires=["gui"],
|
||||
stack_size=1 * 2048,
|
||||
order=30,
|
||||
fap_icon="images/Dip8_10px.png",
|
||||
fap_category="Tools",
|
||||
fap_icon_assets="images",
|
||||
fap_private_libs=[
|
||||
Lib(
|
||||
name="spi",
|
||||
),
|
||||
],
|
||||
)
|
After Width: | Height: | Size: 7.1 KiB |
After Width: | Height: | Size: 6.7 KiB |
After Width: | Height: | Size: 7.1 KiB |
|
@ -0,0 +1 @@
|
|||
2
|
BIN
applications/plugins/spi_mem_manager/images/Dip8_10px.png
Normal file
After Width: | Height: | Size: 195 B |
BIN
applications/plugins/spi_mem_manager/images/Dip8_32x36.png
Normal file
After Width: | Height: | Size: 977 B |
After Width: | Height: | Size: 2.4 KiB |
After Width: | Height: | Size: 2.4 KiB |
BIN
applications/plugins/spi_mem_manager/images/SDQuestion_35x43.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 4.3 KiB |
105
applications/plugins/spi_mem_manager/lib/spi/spi_mem_chip.c
Normal file
|
@ -0,0 +1,105 @@
|
|||
#include "spi_mem_chip_i.h"
|
||||
|
||||
const SPIMemChipVendorName spi_mem_chip_vendor_names[] = {
|
||||
{"Adesto", SPIMemChipVendorADESTO},
|
||||
{"AMIC", SPIMemChipVendorAMIC},
|
||||
{"Boya", SPIMemChipVendorBoya},
|
||||
{"EON", SPIMemChipVendorEON},
|
||||
{"PFlash", SPIMemChipVendorPFLASH},
|
||||
{"Terra", SPIMemChipVendorTERRA},
|
||||
{"Generalplus", SPIMemChipVendorGeneralplus},
|
||||
{"Deutron", SPIMemChipVendorDEUTRON},
|
||||
{"EFST", SPIMemChipVendorEFST},
|
||||
{"Excel Semi.", SPIMemChipVendorEXCELSEMI},
|
||||
{"Fidelix", SPIMemChipVendorFIDELIX},
|
||||
{"GigaDevice", SPIMemChipVendorGIGADEVICE},
|
||||
{"ICE", SPIMemChipVendorICE},
|
||||
{"Intel", SPIMemChipVendorINTEL},
|
||||
{"KHIC", SPIMemChipVendorKHIC},
|
||||
{"Macronix", SPIMemChipVendorMACRONIX},
|
||||
{"Micron", SPIMemChipVendorMICRON},
|
||||
{"Mshine", SPIMemChipVendorMSHINE},
|
||||
{"Nantronics", SPIMemChipVendorNANTRONICS},
|
||||
{"Nexflash", SPIMemChipVendorNEXFLASH},
|
||||
{"Numonyx", SPIMemChipVendorNUMONYX},
|
||||
{"PCT", SPIMemChipVendorPCT},
|
||||
{"Spansion", SPIMemChipVendorSPANSION},
|
||||
{"SST", SPIMemChipVendorSST},
|
||||
{"ST", SPIMemChipVendorST},
|
||||
{"Winbond", SPIMemChipVendorWINBOND},
|
||||
{"Zempro", SPIMemChipVendorZEMPRO},
|
||||
{"Zbit", SPIMemChipVendorZbit},
|
||||
{"Berg Micro.", SPIMemChipVendorBerg_Micro},
|
||||
{"Atmel", SPIMemChipVendorATMEL},
|
||||
{"ACE", SPIMemChipVendorACE},
|
||||
{"ATO", SPIMemChipVendorATO},
|
||||
{"Douqi", SPIMemChipVendorDOUQI},
|
||||
{"Fremont", SPIMemChipVendorFremont},
|
||||
{"Fudan", SPIMemChipVendorFudan},
|
||||
{"Genitop", SPIMemChipVendorGenitop},
|
||||
{"Paragon", SPIMemChipVendorParagon},
|
||||
{"Unknown", SPIMemChipVendorUnknown}};
|
||||
|
||||
static const char* spi_mem_chip_search_vendor_name(SPIMemChipVendor vendor_enum) {
|
||||
const SPIMemChipVendorName* vendor = spi_mem_chip_vendor_names;
|
||||
while(vendor->vendor_enum != SPIMemChipVendorUnknown && vendor->vendor_enum != vendor_enum)
|
||||
vendor++;
|
||||
return vendor->vendor_name;
|
||||
}
|
||||
|
||||
bool spi_mem_chip_find_all(SPIMemChip* chip_info, found_chips_t found_chips) {
|
||||
const SPIMemChip* chip_info_arr;
|
||||
found_chips_reset(found_chips);
|
||||
for(chip_info_arr = SPIMemChips; chip_info_arr->model_name != NULL; chip_info_arr++) {
|
||||
if(chip_info->vendor_id != chip_info_arr->vendor_id) continue;
|
||||
if(chip_info->type_id != chip_info_arr->type_id) continue;
|
||||
if(chip_info->capacity_id != chip_info_arr->capacity_id) continue;
|
||||
found_chips_push_back(found_chips, chip_info_arr);
|
||||
}
|
||||
if(found_chips_size(found_chips)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void spi_mem_chip_copy_chip_info(SPIMemChip* dest, const SPIMemChip* src) {
|
||||
memcpy(dest, src, sizeof(SPIMemChip));
|
||||
}
|
||||
|
||||
size_t spi_mem_chip_get_size(SPIMemChip* chip) {
|
||||
return (chip->size);
|
||||
}
|
||||
|
||||
const char* spi_mem_chip_get_vendor_name(const SPIMemChip* chip) {
|
||||
return (spi_mem_chip_search_vendor_name(chip->vendor_enum));
|
||||
}
|
||||
|
||||
const char* spi_mem_chip_get_vendor_name_by_enum(uint32_t vendor_enum) {
|
||||
return (spi_mem_chip_search_vendor_name(vendor_enum));
|
||||
}
|
||||
|
||||
const char* spi_mem_chip_get_model_name(const SPIMemChip* chip) {
|
||||
return (chip->model_name);
|
||||
}
|
||||
|
||||
uint8_t spi_mem_chip_get_vendor_id(SPIMemChip* chip) {
|
||||
return (chip->vendor_id);
|
||||
}
|
||||
|
||||
uint8_t spi_mem_chip_get_type_id(SPIMemChip* chip) {
|
||||
return (chip->type_id);
|
||||
}
|
||||
|
||||
uint8_t spi_mem_chip_get_capacity_id(SPIMemChip* chip) {
|
||||
return (chip->capacity_id);
|
||||
}
|
||||
|
||||
SPIMemChipWriteMode spi_mem_chip_get_write_mode(SPIMemChip* chip) {
|
||||
return (chip->write_mode);
|
||||
}
|
||||
|
||||
size_t spi_mem_chip_get_page_size(SPIMemChip* chip) {
|
||||
return (chip->page_size);
|
||||
}
|
||||
|
||||
uint32_t spi_mem_chip_get_vendor_enum(const SPIMemChip* chip) {
|
||||
return ((uint32_t)chip->vendor_enum);
|
||||
}
|
34
applications/plugins/spi_mem_manager/lib/spi/spi_mem_chip.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
#pragma once
|
||||
|
||||
#include <furi.h>
|
||||
#include <m-array.h>
|
||||
|
||||
typedef struct SPIMemChip SPIMemChip;
|
||||
|
||||
ARRAY_DEF(found_chips, const SPIMemChip*, M_POD_OPLIST)
|
||||
|
||||
typedef enum {
|
||||
SPIMemChipStatusBusy,
|
||||
SPIMemChipStatusIdle,
|
||||
SPIMemChipStatusError
|
||||
} SPIMemChipStatus;
|
||||
|
||||
typedef enum {
|
||||
SPIMemChipWriteModeUnknown = 0,
|
||||
SPIMemChipWriteModePage = (0x01 << 0),
|
||||
SPIMemChipWriteModeAAIByte = (0x01 << 1),
|
||||
SPIMemChipWriteModeAAIWord = (0x01 << 2),
|
||||
} SPIMemChipWriteMode;
|
||||
|
||||
const char* spi_mem_chip_get_vendor_name(const SPIMemChip* chip);
|
||||
const char* spi_mem_chip_get_model_name(const SPIMemChip* chip);
|
||||
size_t spi_mem_chip_get_size(SPIMemChip* chip);
|
||||
uint8_t spi_mem_chip_get_vendor_id(SPIMemChip* chip);
|
||||
uint8_t spi_mem_chip_get_type_id(SPIMemChip* chip);
|
||||
uint8_t spi_mem_chip_get_capacity_id(SPIMemChip* chip);
|
||||
SPIMemChipWriteMode spi_mem_chip_get_write_mode(SPIMemChip* chip);
|
||||
size_t spi_mem_chip_get_page_size(SPIMemChip* chip);
|
||||
bool spi_mem_chip_find_all(SPIMemChip* chip_info, found_chips_t found_chips);
|
||||
void spi_mem_chip_copy_chip_info(SPIMemChip* dest, const SPIMemChip* src);
|
||||
uint32_t spi_mem_chip_get_vendor_enum(const SPIMemChip* chip);
|
||||
const char* spi_mem_chip_get_vendor_name_by_enum(uint32_t vendor_enum);
|
1399
applications/plugins/spi_mem_manager/lib/spi/spi_mem_chip_arr.c
Normal file
|
@ -0,0 +1,85 @@
|
|||
#pragma once
|
||||
|
||||
#include <furi.h>
|
||||
#include "spi_mem_chip.h"
|
||||
|
||||
typedef enum {
|
||||
SPIMemChipVendorUnknown,
|
||||
SPIMemChipVendorADESTO,
|
||||
SPIMemChipVendorAMIC,
|
||||
SPIMemChipVendorBoya,
|
||||
SPIMemChipVendorEON,
|
||||
SPIMemChipVendorPFLASH,
|
||||
SPIMemChipVendorTERRA,
|
||||
SPIMemChipVendorGeneralplus,
|
||||
SPIMemChipVendorDEUTRON,
|
||||
SPIMemChipVendorEFST,
|
||||
SPIMemChipVendorEXCELSEMI,
|
||||
SPIMemChipVendorFIDELIX,
|
||||
SPIMemChipVendorGIGADEVICE,
|
||||
SPIMemChipVendorICE,
|
||||
SPIMemChipVendorINTEL,
|
||||
SPIMemChipVendorKHIC,
|
||||
SPIMemChipVendorMACRONIX,
|
||||
SPIMemChipVendorMICRON,
|
||||
SPIMemChipVendorMSHINE,
|
||||
SPIMemChipVendorNANTRONICS,
|
||||
SPIMemChipVendorNEXFLASH,
|
||||
SPIMemChipVendorNUMONYX,
|
||||
SPIMemChipVendorPCT,
|
||||
SPIMemChipVendorSPANSION,
|
||||
SPIMemChipVendorSST,
|
||||
SPIMemChipVendorST,
|
||||
SPIMemChipVendorWINBOND,
|
||||
SPIMemChipVendorZEMPRO,
|
||||
SPIMemChipVendorZbit,
|
||||
SPIMemChipVendorBerg_Micro,
|
||||
SPIMemChipVendorATMEL,
|
||||
SPIMemChipVendorACE,
|
||||
SPIMemChipVendorATO,
|
||||
SPIMemChipVendorDOUQI,
|
||||
SPIMemChipVendorFremont,
|
||||
SPIMemChipVendorFudan,
|
||||
SPIMemChipVendorGenitop,
|
||||
SPIMemChipVendorParagon
|
||||
} SPIMemChipVendor;
|
||||
|
||||
typedef enum {
|
||||
SPIMemChipCMDReadJEDECChipID = 0x9F,
|
||||
SPIMemChipCMDReadData = 0x03,
|
||||
SPIMemChipCMDChipErase = 0xC7,
|
||||
SPIMemChipCMDWriteEnable = 0x06,
|
||||
SPIMemChipCMDWriteDisable = 0x04,
|
||||
SPIMemChipCMDReadStatus = 0x05,
|
||||
SPIMemChipCMDWriteData = 0x02,
|
||||
SPIMemChipCMDReleasePowerDown = 0xAB
|
||||
} SPIMemChipCMD;
|
||||
|
||||
enum SPIMemChipStatusBit {
|
||||
SPIMemChipStatusBitBusy = (0x01 << 0),
|
||||
SPIMemChipStatusBitWriteEnabled = (0x01 << 1),
|
||||
SPIMemChipStatusBitBitProtection1 = (0x01 << 2),
|
||||
SPIMemChipStatusBitBitProtection2 = (0x01 << 3),
|
||||
SPIMemChipStatusBitBitProtection3 = (0x01 << 4),
|
||||
SPIMemChipStatusBitTopBottomProtection = (0x01 << 5),
|
||||
SPIMemChipStatusBitSectorProtect = (0x01 << 6),
|
||||
SPIMemChipStatusBitRegisterProtect = (0x01 << 7)
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
const char* vendor_name;
|
||||
SPIMemChipVendor vendor_enum;
|
||||
} SPIMemChipVendorName;
|
||||
|
||||
struct SPIMemChip {
|
||||
uint8_t vendor_id;
|
||||
uint8_t type_id;
|
||||
uint8_t capacity_id;
|
||||
const char* model_name;
|
||||
size_t size;
|
||||
size_t page_size;
|
||||
SPIMemChipVendor vendor_enum;
|
||||
SPIMemChipWriteMode write_mode;
|
||||
};
|
||||
|
||||
extern const SPIMemChip SPIMemChips[];
|
152
applications/plugins/spi_mem_manager/lib/spi/spi_mem_tools.c
Normal file
|
@ -0,0 +1,152 @@
|
|||
#include <furi_hal.h>
|
||||
#include <furi_hal_spi_config.h>
|
||||
#include "spi_mem_chip_i.h"
|
||||
#include "spi_mem_tools.h"
|
||||
|
||||
static uint8_t spi_mem_tools_addr_to_byte_arr(uint32_t addr, uint8_t* cmd) {
|
||||
uint8_t len = 3; // TODO(add support of 4 bytes address mode)
|
||||
for(uint8_t i = 0; i < len; i++) {
|
||||
cmd[i] = (addr >> ((len - (i + 1)) * 8)) & 0xFF;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
static bool spi_mem_tools_trx(
|
||||
SPIMemChipCMD cmd,
|
||||
uint8_t* tx_buf,
|
||||
size_t tx_size,
|
||||
uint8_t* rx_buf,
|
||||
size_t rx_size) {
|
||||
bool success = false;
|
||||
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_external);
|
||||
do {
|
||||
if(!furi_hal_spi_bus_tx(
|
||||
&furi_hal_spi_bus_handle_external, (uint8_t*)&cmd, 1, SPI_MEM_SPI_TIMEOUT))
|
||||
break;
|
||||
if(tx_buf) {
|
||||
if(!furi_hal_spi_bus_tx(
|
||||
&furi_hal_spi_bus_handle_external, tx_buf, tx_size, SPI_MEM_SPI_TIMEOUT))
|
||||
break;
|
||||
}
|
||||
if(rx_buf) {
|
||||
if(!furi_hal_spi_bus_rx(
|
||||
&furi_hal_spi_bus_handle_external, rx_buf, rx_size, SPI_MEM_SPI_TIMEOUT))
|
||||
break;
|
||||
}
|
||||
success = true;
|
||||
} while(0);
|
||||
furi_hal_spi_release(&furi_hal_spi_bus_handle_external);
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool spi_mem_tools_write_buffer(uint8_t* data, size_t size, size_t offset) {
|
||||
furi_hal_spi_acquire(&furi_hal_spi_bus_handle_external);
|
||||
uint8_t cmd = (uint8_t)SPIMemChipCMDWriteData;
|
||||
uint8_t address[4];
|
||||
uint8_t address_size = spi_mem_tools_addr_to_byte_arr(offset, address);
|
||||
bool success = false;
|
||||
do {
|
||||
if(!furi_hal_spi_bus_tx(&furi_hal_spi_bus_handle_external, &cmd, 1, SPI_MEM_SPI_TIMEOUT))
|
||||
break;
|
||||
if(!furi_hal_spi_bus_tx(
|
||||
&furi_hal_spi_bus_handle_external, address, address_size, SPI_MEM_SPI_TIMEOUT))
|
||||
break;
|
||||
if(!furi_hal_spi_bus_tx(&furi_hal_spi_bus_handle_external, data, size, SPI_MEM_SPI_TIMEOUT))
|
||||
break;
|
||||
success = true;
|
||||
} while(0);
|
||||
furi_hal_spi_release(&furi_hal_spi_bus_handle_external);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool spi_mem_tools_read_chip_info(SPIMemChip* chip) {
|
||||
uint8_t rx_buf[3] = {0, 0, 0};
|
||||
do {
|
||||
if(!spi_mem_tools_trx(SPIMemChipCMDReadJEDECChipID, NULL, 0, rx_buf, 3)) break;
|
||||
if(rx_buf[0] == 0 || rx_buf[0] == 255) break;
|
||||
chip->vendor_id = rx_buf[0];
|
||||
chip->type_id = rx_buf[1];
|
||||
chip->capacity_id = rx_buf[2];
|
||||
return true;
|
||||
} while(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool spi_mem_tools_check_chip_info(SPIMemChip* chip) {
|
||||
SPIMemChip new_chip_info;
|
||||
spi_mem_tools_read_chip_info(&new_chip_info);
|
||||
do {
|
||||
if(chip->vendor_id != new_chip_info.vendor_id) break;
|
||||
if(chip->type_id != new_chip_info.type_id) break;
|
||||
if(chip->capacity_id != new_chip_info.capacity_id) break;
|
||||
return true;
|
||||
} while(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool spi_mem_tools_read_block(SPIMemChip* chip, size_t offset, uint8_t* data, size_t block_size) {
|
||||
if(!spi_mem_tools_check_chip_info(chip)) return false;
|
||||
for(size_t i = 0; i < block_size; i += SPI_MEM_MAX_BLOCK_SIZE) {
|
||||
uint8_t cmd[4];
|
||||
if((offset + SPI_MEM_MAX_BLOCK_SIZE) > chip->size) return false;
|
||||
if(!spi_mem_tools_trx(
|
||||
SPIMemChipCMDReadData,
|
||||
cmd,
|
||||
spi_mem_tools_addr_to_byte_arr(offset, cmd),
|
||||
data,
|
||||
SPI_MEM_MAX_BLOCK_SIZE))
|
||||
return false;
|
||||
offset += SPI_MEM_MAX_BLOCK_SIZE;
|
||||
data += SPI_MEM_MAX_BLOCK_SIZE;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t spi_mem_tools_get_file_max_block_size(SPIMemChip* chip) {
|
||||
UNUSED(chip);
|
||||
return (SPI_MEM_FILE_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
SPIMemChipStatus spi_mem_tools_get_chip_status(SPIMemChip* chip) {
|
||||
UNUSED(chip);
|
||||
uint8_t status;
|
||||
if(!spi_mem_tools_trx(SPIMemChipCMDReadStatus, NULL, 0, &status, 1))
|
||||
return SPIMemChipStatusError;
|
||||
if(status & SPIMemChipStatusBitBusy) return SPIMemChipStatusBusy;
|
||||
return SPIMemChipStatusIdle;
|
||||
}
|
||||
|
||||
static bool spi_mem_tools_set_write_enabled(SPIMemChip* chip, bool enable) {
|
||||
UNUSED(chip);
|
||||
uint8_t status;
|
||||
SPIMemChipCMD cmd = SPIMemChipCMDWriteDisable;
|
||||
if(enable) cmd = SPIMemChipCMDWriteEnable;
|
||||
do {
|
||||
if(!spi_mem_tools_trx(cmd, NULL, 0, NULL, 0)) break;
|
||||
if(!spi_mem_tools_trx(SPIMemChipCMDReadStatus, NULL, 0, &status, 1)) break;
|
||||
if(!(status & SPIMemChipStatusBitWriteEnabled) && enable) break;
|
||||
if((status & SPIMemChipStatusBitWriteEnabled) && !enable) break;
|
||||
return true;
|
||||
} while(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool spi_mem_tools_erase_chip(SPIMemChip* chip) {
|
||||
do {
|
||||
if(!spi_mem_tools_set_write_enabled(chip, true)) break;
|
||||
if(!spi_mem_tools_trx(SPIMemChipCMDChipErase, NULL, 0, NULL, 0)) break;
|
||||
return true;
|
||||
} while(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool spi_mem_tools_write_bytes(SPIMemChip* chip, size_t offset, uint8_t* data, size_t block_size) {
|
||||
do {
|
||||
if(!spi_mem_tools_check_chip_info(chip)) break;
|
||||
if(!spi_mem_tools_set_write_enabled(chip, true)) break;
|
||||
if((offset + block_size) > chip->size) break;
|
||||
if(!spi_mem_tools_write_buffer(data, block_size, offset)) break;
|
||||
return true;
|
||||
} while(0);
|
||||
return false;
|
||||
}
|
14
applications/plugins/spi_mem_manager/lib/spi/spi_mem_tools.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include "spi_mem_chip.h"
|
||||
|
||||
#define SPI_MEM_SPI_TIMEOUT 1000
|
||||
#define SPI_MEM_MAX_BLOCK_SIZE 256
|
||||
#define SPI_MEM_FILE_BUFFER_SIZE 4096
|
||||
|
||||
bool spi_mem_tools_read_chip_info(SPIMemChip* chip);
|
||||
bool spi_mem_tools_read_block(SPIMemChip* chip, size_t offset, uint8_t* data, size_t block_size);
|
||||
size_t spi_mem_tools_get_file_max_block_size(SPIMemChip* chip);
|
||||
SPIMemChipStatus spi_mem_tools_get_chip_status(SPIMemChip* chip);
|
||||
bool spi_mem_tools_erase_chip(SPIMemChip* chip);
|
||||
bool spi_mem_tools_write_bytes(SPIMemChip* chip, size_t offset, uint8_t* data, size_t block_size);
|
129
applications/plugins/spi_mem_manager/lib/spi/spi_mem_worker.c
Normal file
|
@ -0,0 +1,129 @@
|
|||
#include "spi_mem_worker_i.h"
|
||||
|
||||
typedef enum {
|
||||
SPIMemEventStopThread = (1 << 0),
|
||||
SPIMemEventChipDetect = (1 << 1),
|
||||
SPIMemEventRead = (1 << 2),
|
||||
SPIMemEventVerify = (1 << 3),
|
||||
SPIMemEventErase = (1 << 4),
|
||||
SPIMemEventWrite = (1 << 5),
|
||||
SPIMemEventAll =
|
||||
(SPIMemEventStopThread | SPIMemEventChipDetect | SPIMemEventRead | SPIMemEventVerify |
|
||||
SPIMemEventErase | SPIMemEventWrite)
|
||||
} SPIMemEventEventType;
|
||||
|
||||
static int32_t spi_mem_worker_thread(void* thread_context);
|
||||
|
||||
SPIMemWorker* spi_mem_worker_alloc() {
|
||||
SPIMemWorker* worker = malloc(sizeof(SPIMemWorker));
|
||||
worker->callback = NULL;
|
||||
worker->thread = furi_thread_alloc();
|
||||
worker->mode_index = SPIMemWorkerModeIdle;
|
||||
furi_thread_set_name(worker->thread, "SPIMemWorker");
|
||||
furi_thread_set_callback(worker->thread, spi_mem_worker_thread);
|
||||
furi_thread_set_context(worker->thread, worker);
|
||||
furi_thread_set_stack_size(worker->thread, 10240);
|
||||
return worker;
|
||||
}
|
||||
|
||||
void spi_mem_worker_free(SPIMemWorker* worker) {
|
||||
furi_thread_free(worker->thread);
|
||||
free(worker);
|
||||
}
|
||||
|
||||
bool spi_mem_worker_check_for_stop(SPIMemWorker* worker) {
|
||||
UNUSED(worker);
|
||||
uint32_t flags = furi_thread_flags_get();
|
||||
return (flags & SPIMemEventStopThread);
|
||||
}
|
||||
|
||||
static int32_t spi_mem_worker_thread(void* thread_context) {
|
||||
SPIMemWorker* worker = thread_context;
|
||||
while(true) {
|
||||
uint32_t flags = furi_thread_flags_wait(SPIMemEventAll, FuriFlagWaitAny, FuriWaitForever);
|
||||
if(flags != (unsigned)FuriFlagErrorTimeout) {
|
||||
if(flags & SPIMemEventStopThread) break;
|
||||
if(flags & SPIMemEventChipDetect) worker->mode_index = SPIMemWorkerModeChipDetect;
|
||||
if(flags & SPIMemEventRead) worker->mode_index = SPIMemWorkerModeRead;
|
||||
if(flags & SPIMemEventVerify) worker->mode_index = SPIMemWorkerModeVerify;
|
||||
if(flags & SPIMemEventErase) worker->mode_index = SPIMemWorkerModeErase;
|
||||
if(flags & SPIMemEventWrite) worker->mode_index = SPIMemWorkerModeWrite;
|
||||
if(spi_mem_worker_modes[worker->mode_index].process) {
|
||||
spi_mem_worker_modes[worker->mode_index].process(worker);
|
||||
}
|
||||
worker->mode_index = SPIMemWorkerModeIdle;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void spi_mem_worker_start_thread(SPIMemWorker* worker) {
|
||||
furi_thread_start(worker->thread);
|
||||
}
|
||||
|
||||
void spi_mem_worker_stop_thread(SPIMemWorker* worker) {
|
||||
furi_thread_flags_set(furi_thread_get_id(worker->thread), SPIMemEventStopThread);
|
||||
furi_thread_join(worker->thread);
|
||||
}
|
||||
|
||||
void spi_mem_worker_chip_detect_start(
|
||||
SPIMemChip* chip_info,
|
||||
found_chips_t* found_chips,
|
||||
SPIMemWorker* worker,
|
||||
SPIMemWorkerCallback callback,
|
||||
void* context) {
|
||||
furi_check(worker->mode_index == SPIMemWorkerModeIdle);
|
||||
worker->callback = callback;
|
||||
worker->cb_ctx = context;
|
||||
worker->chip_info = chip_info;
|
||||
worker->found_chips = found_chips;
|
||||
furi_thread_flags_set(furi_thread_get_id(worker->thread), SPIMemEventChipDetect);
|
||||
}
|
||||
|
||||
void spi_mem_worker_read_start(
|
||||
SPIMemChip* chip_info,
|
||||
SPIMemWorker* worker,
|
||||
SPIMemWorkerCallback callback,
|
||||
void* context) {
|
||||
furi_check(worker->mode_index == SPIMemWorkerModeIdle);
|
||||
worker->callback = callback;
|
||||
worker->cb_ctx = context;
|
||||
worker->chip_info = chip_info;
|
||||
furi_thread_flags_set(furi_thread_get_id(worker->thread), SPIMemEventRead);
|
||||
}
|
||||
|
||||
void spi_mem_worker_verify_start(
|
||||
SPIMemChip* chip_info,
|
||||
SPIMemWorker* worker,
|
||||
SPIMemWorkerCallback callback,
|
||||
void* context) {
|
||||
furi_check(worker->mode_index == SPIMemWorkerModeIdle);
|
||||
worker->callback = callback;
|
||||
worker->cb_ctx = context;
|
||||
worker->chip_info = chip_info;
|
||||
furi_thread_flags_set(furi_thread_get_id(worker->thread), SPIMemEventVerify);
|
||||
}
|
||||
|
||||
void spi_mem_worker_erase_start(
|
||||
SPIMemChip* chip_info,
|
||||
SPIMemWorker* worker,
|
||||
SPIMemWorkerCallback callback,
|
||||
void* context) {
|
||||
furi_check(worker->mode_index == SPIMemWorkerModeIdle);
|
||||
worker->callback = callback;
|
||||
worker->cb_ctx = context;
|
||||
worker->chip_info = chip_info;
|
||||
furi_thread_flags_set(furi_thread_get_id(worker->thread), SPIMemEventErase);
|
||||
}
|
||||
|
||||
void spi_mem_worker_write_start(
|
||||
SPIMemChip* chip_info,
|
||||
SPIMemWorker* worker,
|
||||
SPIMemWorkerCallback callback,
|
||||
void* context) {
|
||||
furi_check(worker->mode_index == SPIMemWorkerModeIdle);
|
||||
worker->callback = callback;
|
||||
worker->cb_ctx = context;
|
||||
worker->chip_info = chip_info;
|
||||
furi_thread_flags_set(furi_thread_get_id(worker->thread), SPIMemEventWrite);
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
#pragma once
|
||||
|
||||
#include <furi.h>
|
||||
#include "spi_mem_chip.h"
|
||||
|
||||
typedef struct SPIMemWorker SPIMemWorker;
|
||||
|
||||
typedef struct {
|
||||
void (*const process)(SPIMemWorker* worker);
|
||||
} SPIMemWorkerModeType;
|
||||
|
||||
typedef enum {
|
||||
SPIMemCustomEventWorkerChipIdentified,
|
||||
SPIMemCustomEventWorkerChipUnknown,
|
||||
SPIMemCustomEventWorkerBlockReaded,
|
||||
SPIMemCustomEventWorkerChipFail,
|
||||
SPIMemCustomEventWorkerFileFail,
|
||||
SPIMemCustomEventWorkerDone,
|
||||
SPIMemCustomEventWorkerVerifyFail,
|
||||
} SPIMemCustomEventWorker;
|
||||
|
||||
typedef void (*SPIMemWorkerCallback)(void* context, SPIMemCustomEventWorker event);
|
||||
|
||||
SPIMemWorker* spi_mem_worker_alloc();
|
||||
void spi_mem_worker_free(SPIMemWorker* worker);
|
||||
void spi_mem_worker_start_thread(SPIMemWorker* worker);
|
||||
void spi_mem_worker_stop_thread(SPIMemWorker* worker);
|
||||
bool spi_mem_worker_check_for_stop(SPIMemWorker* worker);
|
||||
void spi_mem_worker_chip_detect_start(
|
||||
SPIMemChip* chip_info,
|
||||
found_chips_t* found_chips,
|
||||
SPIMemWorker* worker,
|
||||
SPIMemWorkerCallback callback,
|
||||
void* context);
|
||||
void spi_mem_worker_read_start(
|
||||
SPIMemChip* chip_info,
|
||||
SPIMemWorker* worker,
|
||||
SPIMemWorkerCallback callback,
|
||||
void* context);
|
||||
void spi_mem_worker_verify_start(
|
||||
SPIMemChip* chip_info,
|
||||
SPIMemWorker* worker,
|
||||
SPIMemWorkerCallback callback,
|
||||
void* context);
|
||||
void spi_mem_worker_erase_start(
|
||||
SPIMemChip* chip_info,
|
||||
SPIMemWorker* worker,
|
||||
SPIMemWorkerCallback callback,
|
||||
void* context);
|
||||
void spi_mem_worker_write_start(
|
||||
SPIMemChip* chip_info,
|
||||
SPIMemWorker* worker,
|
||||
SPIMemWorkerCallback callback,
|
||||
void* context);
|
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
#include "spi_mem_worker.h"
|
||||
|
||||
typedef enum {
|
||||
SPIMemWorkerModeIdle,
|
||||
SPIMemWorkerModeChipDetect,
|
||||
SPIMemWorkerModeRead,
|
||||
SPIMemWorkerModeVerify,
|
||||
SPIMemWorkerModeErase,
|
||||
SPIMemWorkerModeWrite
|
||||
} SPIMemWorkerMode;
|
||||
|
||||
struct SPIMemWorker {
|
||||
SPIMemChip* chip_info;
|
||||
found_chips_t* found_chips;
|
||||
SPIMemWorkerMode mode_index;
|
||||
SPIMemWorkerCallback callback;
|
||||
void* cb_ctx;
|
||||
FuriThread* thread;
|
||||
FuriString* file_name;
|
||||
};
|
||||
|
||||
extern const SPIMemWorkerModeType spi_mem_worker_modes[];
|
|
@ -0,0 +1,214 @@
|
|||
#include "spi_mem_worker_i.h"
|
||||
#include "spi_mem_chip.h"
|
||||
#include "spi_mem_tools.h"
|
||||
#include "../../spi_mem_files.h"
|
||||
|
||||
static void spi_mem_worker_chip_detect_process(SPIMemWorker* worker);
|
||||
static void spi_mem_worker_read_process(SPIMemWorker* worker);
|
||||
static void spi_mem_worker_verify_process(SPIMemWorker* worker);
|
||||
static void spi_mem_worker_erase_process(SPIMemWorker* worker);
|
||||
static void spi_mem_worker_write_process(SPIMemWorker* worker);
|
||||
|
||||
const SPIMemWorkerModeType spi_mem_worker_modes[] = {
|
||||
[SPIMemWorkerModeIdle] = {.process = NULL},
|
||||
[SPIMemWorkerModeChipDetect] = {.process = spi_mem_worker_chip_detect_process},
|
||||
[SPIMemWorkerModeRead] = {.process = spi_mem_worker_read_process},
|
||||
[SPIMemWorkerModeVerify] = {.process = spi_mem_worker_verify_process},
|
||||
[SPIMemWorkerModeErase] = {.process = spi_mem_worker_erase_process},
|
||||
[SPIMemWorkerModeWrite] = {.process = spi_mem_worker_write_process}};
|
||||
|
||||
static void spi_mem_worker_run_callback(SPIMemWorker* worker, SPIMemCustomEventWorker event) {
|
||||
if(worker->callback) {
|
||||
worker->callback(worker->cb_ctx, event);
|
||||
}
|
||||
}
|
||||
|
||||
static bool spi_mem_worker_await_chip_busy(SPIMemWorker* worker) {
|
||||
while(true) {
|
||||
furi_delay_tick(10); // to give some time to OS
|
||||
if(spi_mem_worker_check_for_stop(worker)) return true;
|
||||
SPIMemChipStatus chip_status = spi_mem_tools_get_chip_status(worker->chip_info);
|
||||
if(chip_status == SPIMemChipStatusError) return false;
|
||||
if(chip_status == SPIMemChipStatusBusy) continue;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static size_t spi_mem_worker_modes_get_total_size(SPIMemWorker* worker) {
|
||||
size_t chip_size = spi_mem_chip_get_size(worker->chip_info);
|
||||
size_t file_size = spi_mem_file_get_size(worker->cb_ctx);
|
||||
size_t total_size = chip_size;
|
||||
if(chip_size > file_size) total_size = file_size;
|
||||
return total_size;
|
||||
}
|
||||
|
||||
// ChipDetect
|
||||
static void spi_mem_worker_chip_detect_process(SPIMemWorker* worker) {
|
||||
SPIMemCustomEventWorker event;
|
||||
while(!spi_mem_tools_read_chip_info(worker->chip_info)) {
|
||||
furi_delay_tick(10); // to give some time to OS
|
||||
if(spi_mem_worker_check_for_stop(worker)) return;
|
||||
}
|
||||
if(spi_mem_chip_find_all(worker->chip_info, *worker->found_chips)) {
|
||||
event = SPIMemCustomEventWorkerChipIdentified;
|
||||
} else {
|
||||
event = SPIMemCustomEventWorkerChipUnknown;
|
||||
}
|
||||
spi_mem_worker_run_callback(worker, event);
|
||||
}
|
||||
|
||||
// Read
|
||||
static bool spi_mem_worker_read(SPIMemWorker* worker, SPIMemCustomEventWorker* event) {
|
||||
uint8_t data_buffer[SPI_MEM_FILE_BUFFER_SIZE];
|
||||
size_t chip_size = spi_mem_chip_get_size(worker->chip_info);
|
||||
size_t offset = 0;
|
||||
bool success = true;
|
||||
while(true) {
|
||||
furi_delay_tick(10); // to give some time to OS
|
||||
size_t block_size = SPI_MEM_FILE_BUFFER_SIZE;
|
||||
if(spi_mem_worker_check_for_stop(worker)) break;
|
||||
if(offset >= chip_size) break;
|
||||
if((offset + block_size) > chip_size) block_size = chip_size - offset;
|
||||
if(!spi_mem_tools_read_block(worker->chip_info, offset, data_buffer, block_size)) {
|
||||
*event = SPIMemCustomEventWorkerChipFail;
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
if(!spi_mem_file_write_block(worker->cb_ctx, data_buffer, block_size)) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
offset += block_size;
|
||||
spi_mem_worker_run_callback(worker, SPIMemCustomEventWorkerBlockReaded);
|
||||
}
|
||||
if(success) *event = SPIMemCustomEventWorkerDone;
|
||||
return success;
|
||||
}
|
||||
|
||||
static void spi_mem_worker_read_process(SPIMemWorker* worker) {
|
||||
SPIMemCustomEventWorker event = SPIMemCustomEventWorkerFileFail;
|
||||
do {
|
||||
if(!spi_mem_worker_await_chip_busy(worker)) break;
|
||||
if(!spi_mem_file_create_open(worker->cb_ctx)) break;
|
||||
if(!spi_mem_worker_read(worker, &event)) break;
|
||||
} while(0);
|
||||
spi_mem_file_close(worker->cb_ctx);
|
||||
spi_mem_worker_run_callback(worker, event);
|
||||
}
|
||||
|
||||
// Verify
|
||||
static bool
|
||||
spi_mem_worker_verify(SPIMemWorker* worker, size_t total_size, SPIMemCustomEventWorker* event) {
|
||||
uint8_t data_buffer_chip[SPI_MEM_FILE_BUFFER_SIZE];
|
||||
uint8_t data_buffer_file[SPI_MEM_FILE_BUFFER_SIZE];
|
||||
size_t offset = 0;
|
||||
bool success = true;
|
||||
while(true) {
|
||||
furi_delay_tick(10); // to give some time to OS
|
||||
size_t block_size = SPI_MEM_FILE_BUFFER_SIZE;
|
||||
if(spi_mem_worker_check_for_stop(worker)) break;
|
||||
if(offset >= total_size) break;
|
||||
if((offset + block_size) > total_size) block_size = total_size - offset;
|
||||
if(!spi_mem_tools_read_block(worker->chip_info, offset, data_buffer_chip, block_size)) {
|
||||
*event = SPIMemCustomEventWorkerChipFail;
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
if(!spi_mem_file_read_block(worker->cb_ctx, data_buffer_file, block_size)) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
if(memcmp(data_buffer_chip, data_buffer_file, block_size) != 0) {
|
||||
*event = SPIMemCustomEventWorkerVerifyFail;
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
offset += block_size;
|
||||
spi_mem_worker_run_callback(worker, SPIMemCustomEventWorkerBlockReaded);
|
||||
}
|
||||
if(success) *event = SPIMemCustomEventWorkerDone;
|
||||
return success;
|
||||
}
|
||||
|
||||
static void spi_mem_worker_verify_process(SPIMemWorker* worker) {
|
||||
SPIMemCustomEventWorker event = SPIMemCustomEventWorkerFileFail;
|
||||
size_t total_size = spi_mem_worker_modes_get_total_size(worker);
|
||||
do {
|
||||
if(!spi_mem_worker_await_chip_busy(worker)) break;
|
||||
if(!spi_mem_file_open(worker->cb_ctx)) break;
|
||||
if(!spi_mem_worker_verify(worker, total_size, &event)) break;
|
||||
} while(0);
|
||||
spi_mem_file_close(worker->cb_ctx);
|
||||
spi_mem_worker_run_callback(worker, event);
|
||||
}
|
||||
|
||||
// Erase
|
||||
static void spi_mem_worker_erase_process(SPIMemWorker* worker) {
|
||||
SPIMemCustomEventWorker event = SPIMemCustomEventWorkerChipFail;
|
||||
do {
|
||||
if(!spi_mem_worker_await_chip_busy(worker)) break;
|
||||
if(!spi_mem_tools_erase_chip(worker->chip_info)) break;
|
||||
if(!spi_mem_worker_await_chip_busy(worker)) break;
|
||||
event = SPIMemCustomEventWorkerDone;
|
||||
} while(0);
|
||||
spi_mem_worker_run_callback(worker, event);
|
||||
}
|
||||
|
||||
// Write
|
||||
static bool spi_mem_worker_write_block_by_page(
|
||||
SPIMemWorker* worker,
|
||||
size_t offset,
|
||||
uint8_t* data,
|
||||
size_t block_size,
|
||||
size_t page_size) {
|
||||
for(size_t i = 0; i < block_size; i += page_size) {
|
||||
if(!spi_mem_worker_await_chip_busy(worker)) return false;
|
||||
if(!spi_mem_tools_write_bytes(worker->chip_info, offset, data, page_size)) return false;
|
||||
offset += page_size;
|
||||
data += page_size;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
spi_mem_worker_write(SPIMemWorker* worker, size_t total_size, SPIMemCustomEventWorker* event) {
|
||||
bool success = true;
|
||||
uint8_t data_buffer[SPI_MEM_FILE_BUFFER_SIZE];
|
||||
size_t page_size = spi_mem_chip_get_page_size(worker->chip_info);
|
||||
size_t offset = 0;
|
||||
while(true) {
|
||||
furi_delay_tick(10); // to give some time to OS
|
||||
size_t block_size = SPI_MEM_FILE_BUFFER_SIZE;
|
||||
if(spi_mem_worker_check_for_stop(worker)) break;
|
||||
if(offset >= total_size) break;
|
||||
if((offset + block_size) > total_size) block_size = total_size - offset;
|
||||
if(!spi_mem_file_read_block(worker->cb_ctx, data_buffer, block_size)) {
|
||||
*event = SPIMemCustomEventWorkerFileFail;
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
if(!spi_mem_worker_write_block_by_page(
|
||||
worker, offset, data_buffer, block_size, page_size)) {
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
offset += block_size;
|
||||
spi_mem_worker_run_callback(worker, SPIMemCustomEventWorkerBlockReaded);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
static void spi_mem_worker_write_process(SPIMemWorker* worker) {
|
||||
SPIMemCustomEventWorker event = SPIMemCustomEventWorkerChipFail;
|
||||
size_t total_size =
|
||||
spi_mem_worker_modes_get_total_size(worker); // need to be executed before opening file
|
||||
do {
|
||||
if(!spi_mem_file_open(worker->cb_ctx)) break;
|
||||
if(!spi_mem_worker_await_chip_busy(worker)) break;
|
||||
if(!spi_mem_worker_write(worker, total_size, &event)) break;
|
||||
if(!spi_mem_worker_await_chip_busy(worker)) break;
|
||||
event = SPIMemCustomEventWorkerDone;
|
||||
} while(0);
|
||||
spi_mem_file_close(worker->cb_ctx);
|
||||
spi_mem_worker_run_callback(worker, event);
|
||||
}
|
30
applications/plugins/spi_mem_manager/scenes/spi_mem_scene.c
Normal file
|
@ -0,0 +1,30 @@
|
|||
#include "spi_mem_scene.h"
|
||||
|
||||
// Generate scene on_enter handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
|
||||
void (*const spi_mem_on_enter_handlers[])(void*) = {
|
||||
#include "spi_mem_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 spi_mem_on_event_handlers[])(void* context, SceneManagerEvent event) = {
|
||||
#include "spi_mem_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 spi_mem_on_exit_handlers[])(void* context) = {
|
||||
#include "spi_mem_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Initialize scene handlers configuration structure
|
||||
const SceneManagerHandlers spi_mem_scene_handlers = {
|
||||
.on_enter_handlers = spi_mem_on_enter_handlers,
|
||||
.on_event_handlers = spi_mem_on_event_handlers,
|
||||
.on_exit_handlers = spi_mem_on_exit_handlers,
|
||||
.scene_num = SPIMemSceneNum,
|
||||
};
|
29
applications/plugins/spi_mem_manager/scenes/spi_mem_scene.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
// Generate scene id and total number
|
||||
#define ADD_SCENE(prefix, name, id) SPIMemScene##id,
|
||||
typedef enum {
|
||||
#include "spi_mem_scene_config.h"
|
||||
SPIMemSceneNum,
|
||||
} SPIMemScene;
|
||||
#undef ADD_SCENE
|
||||
|
||||
extern const SceneManagerHandlers spi_mem_scene_handlers;
|
||||
|
||||
// Generate scene on_enter handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
|
||||
#include "spi_mem_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 "spi_mem_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 "spi_mem_scene_config.h"
|
||||
#undef ADD_SCENE
|
|
@ -0,0 +1,42 @@
|
|||
#include "../spi_mem_app_i.h"
|
||||
#include "../lib/spi/spi_mem_chip.h"
|
||||
|
||||
#define SPI_MEM_VERSION_APP "0.1.0"
|
||||
#define SPI_MEM_DEVELOPER "DrunkBatya"
|
||||
#define SPI_MEM_GITHUB "https://github.com/flipperdevices/flipperzero-firmware"
|
||||
#define SPI_MEM_NAME "\e#\e! SPI Mem Manager \e!\n"
|
||||
#define SPI_MEM_BLANK_INV "\e#\e! \e!\n"
|
||||
|
||||
void spi_mem_scene_about_on_enter(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
FuriString* tmp_string = furi_string_alloc();
|
||||
|
||||
widget_add_text_box_element(
|
||||
app->widget, 0, 0, 128, 14, AlignCenter, AlignBottom, SPI_MEM_BLANK_INV, false);
|
||||
widget_add_text_box_element(
|
||||
app->widget, 0, 2, 128, 14, AlignCenter, AlignBottom, SPI_MEM_NAME, false);
|
||||
furi_string_printf(tmp_string, "\e#%s\n", "Information");
|
||||
furi_string_cat_printf(tmp_string, "Version: %s\n", SPI_MEM_VERSION_APP);
|
||||
furi_string_cat_printf(tmp_string, "Developed by: %s\n", SPI_MEM_DEVELOPER);
|
||||
furi_string_cat_printf(tmp_string, "Github: %s\n\n", SPI_MEM_GITHUB);
|
||||
furi_string_cat_printf(tmp_string, "\e#%s\n", "Description");
|
||||
furi_string_cat_printf(
|
||||
tmp_string,
|
||||
"SPI memory dumper\n"
|
||||
"Originally written by Hedger, ghettorce and x893 at\n"
|
||||
"Flipper Hackathon 2021\n\n");
|
||||
widget_add_text_scroll_element(app->widget, 0, 16, 128, 50, furi_string_get_cstr(tmp_string));
|
||||
|
||||
furi_string_free(tmp_string);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewWidget);
|
||||
}
|
||||
|
||||
bool spi_mem_scene_about_on_event(void* context, SceneManagerEvent event) {
|
||||
UNUSED(context);
|
||||
UNUSED(event);
|
||||
return false;
|
||||
}
|
||||
void spi_mem_scene_about_on_exit(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
widget_reset(app->widget);
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
#include "../spi_mem_app_i.h"
|
||||
|
||||
static void spi_mem_scene_chip_detect_callback(void* context, SPIMemCustomEventWorker event) {
|
||||
SPIMemApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
||||
}
|
||||
|
||||
void spi_mem_scene_chip_detect_on_enter(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
notification_message(app->notifications, &sequence_blink_start_yellow);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewDetect);
|
||||
spi_mem_worker_start_thread(app->worker);
|
||||
spi_mem_worker_chip_detect_start(
|
||||
app->chip_info, &app->found_chips, app->worker, spi_mem_scene_chip_detect_callback, app);
|
||||
}
|
||||
|
||||
bool spi_mem_scene_chip_detect_on_event(void* context, SceneManagerEvent event) {
|
||||
SPIMemApp* app = context;
|
||||
bool success = false;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
success = true;
|
||||
if(event.event == SPIMemCustomEventWorkerChipIdentified) {
|
||||
scene_manager_set_scene_state(app->scene_manager, SPIMemSceneSelectVendor, 0);
|
||||
scene_manager_next_scene(app->scene_manager, SPIMemSceneSelectVendor);
|
||||
} else if(event.event == SPIMemCustomEventWorkerChipUnknown) {
|
||||
scene_manager_next_scene(app->scene_manager, SPIMemSceneChipDetectFail);
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
void spi_mem_scene_chip_detect_on_exit(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
spi_mem_worker_stop_thread(app->worker);
|
||||
notification_message(app->notifications, &sequence_blink_stop);
|
||||
popup_reset(app->popup);
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
#include "../spi_mem_app_i.h"
|
||||
#include "../lib/spi/spi_mem_chip.h"
|
||||
|
||||
static void spi_mem_scene_chip_detect_fail_widget_callback(
|
||||
GuiButtonType result,
|
||||
InputType type,
|
||||
void* context) {
|
||||
SPIMemApp* app = context;
|
||||
if(type == InputTypeShort) {
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
}
|
||||
|
||||
void spi_mem_scene_chip_detect_fail_on_enter(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
FuriString* str = furi_string_alloc();
|
||||
widget_add_button_element(
|
||||
app->widget,
|
||||
GuiButtonTypeCenter,
|
||||
"Retry",
|
||||
spi_mem_scene_chip_detect_fail_widget_callback,
|
||||
app);
|
||||
widget_add_string_element(
|
||||
app->widget, 64, 9, AlignCenter, AlignBottom, FontPrimary, "Detected");
|
||||
widget_add_string_element(
|
||||
app->widget, 64, 20, AlignCenter, AlignBottom, FontPrimary, "unknown SPI chip");
|
||||
furi_string_printf(str, "Vendor\nid: 0x%02X", spi_mem_chip_get_vendor_id(app->chip_info));
|
||||
widget_add_string_multiline_element(
|
||||
app->widget, 16, 44, AlignCenter, AlignBottom, FontSecondary, furi_string_get_cstr(str));
|
||||
furi_string_printf(str, "Type\nid: 0x%02X", spi_mem_chip_get_type_id(app->chip_info));
|
||||
widget_add_string_multiline_element(
|
||||
app->widget, 64, 44, AlignCenter, AlignBottom, FontSecondary, furi_string_get_cstr(str));
|
||||
furi_string_printf(str, "Capacity\nid: 0x%02X", spi_mem_chip_get_capacity_id(app->chip_info));
|
||||
widget_add_string_multiline_element(
|
||||
app->widget, 110, 44, AlignCenter, AlignBottom, FontSecondary, furi_string_get_cstr(str));
|
||||
furi_string_free(str);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewWidget);
|
||||
}
|
||||
|
||||
bool spi_mem_scene_chip_detect_fail_on_event(void* context, SceneManagerEvent event) {
|
||||
SPIMemApp* app = context;
|
||||
bool success = false;
|
||||
if(event.type == SceneManagerEventTypeBack) {
|
||||
success = true;
|
||||
scene_manager_search_and_switch_to_previous_scene(app->scene_manager, SPIMemSceneStart);
|
||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
||||
success = true;
|
||||
if(event.event == GuiButtonTypeCenter) {
|
||||
scene_manager_previous_scene(app->scene_manager);
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
void spi_mem_scene_chip_detect_fail_on_exit(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
widget_reset(app->widget);
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
#include "../spi_mem_app_i.h"
|
||||
|
||||
static void spi_mem_scene_chip_detected_widget_callback(
|
||||
GuiButtonType result,
|
||||
InputType type,
|
||||
void* context) {
|
||||
SPIMemApp* app = context;
|
||||
if(type == InputTypeShort) {
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
}
|
||||
|
||||
static void spi_mem_scene_chip_detected_print_chip_info(Widget* widget, SPIMemChip* chip_info) {
|
||||
FuriString* tmp_string = furi_string_alloc();
|
||||
widget_add_string_element(
|
||||
widget,
|
||||
40,
|
||||
12,
|
||||
AlignLeft,
|
||||
AlignTop,
|
||||
FontSecondary,
|
||||
spi_mem_chip_get_vendor_name(chip_info));
|
||||
widget_add_string_element(
|
||||
widget, 40, 20, AlignLeft, AlignTop, FontSecondary, spi_mem_chip_get_model_name(chip_info));
|
||||
furi_string_printf(tmp_string, "Size: %zu KB", spi_mem_chip_get_size(chip_info) / 1024);
|
||||
widget_add_string_element(
|
||||
widget, 40, 28, AlignLeft, AlignTop, FontSecondary, furi_string_get_cstr(tmp_string));
|
||||
furi_string_free(tmp_string);
|
||||
}
|
||||
|
||||
static void spi_mem_scene_chip_detect_draw_next_button(SPIMemApp* app) {
|
||||
FuriString* str = furi_string_alloc();
|
||||
if(app->mode == SPIMemModeRead) furi_string_printf(str, "%s", "Read");
|
||||
if(app->mode == SPIMemModeWrite) furi_string_printf(str, "%s", "Write");
|
||||
if(app->mode == SPIMemModeErase) furi_string_printf(str, "%s", "Erase");
|
||||
if(app->mode == SPIMemModeCompare) furi_string_printf(str, "%s", "Check");
|
||||
widget_add_button_element(
|
||||
app->widget,
|
||||
GuiButtonTypeRight,
|
||||
furi_string_get_cstr(str),
|
||||
spi_mem_scene_chip_detected_widget_callback,
|
||||
app);
|
||||
furi_string_free(str);
|
||||
}
|
||||
|
||||
static void spi_mem_scene_chip_detected_set_previous_scene(SPIMemApp* app) {
|
||||
uint32_t scene = SPIMemSceneStart;
|
||||
if(app->mode == SPIMemModeCompare || app->mode == SPIMemModeWrite)
|
||||
scene = SPIMemSceneSavedFileMenu;
|
||||
scene_manager_search_and_switch_to_previous_scene(app->scene_manager, scene);
|
||||
}
|
||||
|
||||
static void spi_mem_scene_chip_detected_set_next_scene(SPIMemApp* app) {
|
||||
uint32_t scene = SPIMemSceneStart;
|
||||
if(app->mode == SPIMemModeRead) scene = SPIMemSceneReadFilename;
|
||||
if(app->mode == SPIMemModeWrite) scene = SPIMemSceneErase;
|
||||
if(app->mode == SPIMemModeErase) scene = SPIMemSceneErase;
|
||||
if(app->mode == SPIMemModeCompare) scene = SPIMemSceneVerify;
|
||||
scene_manager_next_scene(app->scene_manager, scene);
|
||||
}
|
||||
|
||||
void spi_mem_scene_chip_detected_on_enter(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
widget_add_button_element(
|
||||
app->widget, GuiButtonTypeLeft, "Retry", spi_mem_scene_chip_detected_widget_callback, app);
|
||||
spi_mem_scene_chip_detect_draw_next_button(app);
|
||||
widget_add_icon_element(app->widget, 0, 12, &I_Dip8_32x36);
|
||||
widget_add_string_element(
|
||||
app->widget, 64, 9, AlignCenter, AlignBottom, FontPrimary, "Detected SPI chip");
|
||||
spi_mem_scene_chip_detected_print_chip_info(app->widget, app->chip_info);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewWidget);
|
||||
}
|
||||
|
||||
bool spi_mem_scene_chip_detected_on_event(void* context, SceneManagerEvent event) {
|
||||
SPIMemApp* app = context;
|
||||
bool success = false;
|
||||
if(event.type == SceneManagerEventTypeBack) {
|
||||
success = true;
|
||||
spi_mem_scene_chip_detected_set_previous_scene(app);
|
||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
||||
success = true;
|
||||
if(event.event == GuiButtonTypeLeft) {
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, SPIMemSceneChipDetect);
|
||||
} else if(event.event == GuiButtonTypeRight) {
|
||||
spi_mem_scene_chip_detected_set_next_scene(app);
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
void spi_mem_scene_chip_detected_on_exit(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
widget_reset(app->widget);
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
#include "../spi_mem_app_i.h"
|
||||
|
||||
static void
|
||||
spi_mem_scene_chip_error_widget_callback(GuiButtonType result, InputType type, void* context) {
|
||||
SPIMemApp* app = context;
|
||||
if(type == InputTypeShort) {
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
}
|
||||
|
||||
void spi_mem_scene_chip_error_on_enter(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
widget_add_button_element(
|
||||
app->widget, GuiButtonTypeLeft, "Back", spi_mem_scene_chip_error_widget_callback, app);
|
||||
widget_add_string_element(
|
||||
app->widget, 85, 15, AlignCenter, AlignBottom, FontPrimary, "SPI chip error");
|
||||
widget_add_string_multiline_element(
|
||||
app->widget,
|
||||
85,
|
||||
52,
|
||||
AlignCenter,
|
||||
AlignBottom,
|
||||
FontSecondary,
|
||||
"Error while\ncommunicating\nwith chip");
|
||||
widget_add_icon_element(app->widget, 5, 6, &I_Dip8_32x36);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewWidget);
|
||||
}
|
||||
|
||||
static void spi_mem_scene_chip_error_set_previous_scene(SPIMemApp* app) {
|
||||
uint32_t scene = SPIMemSceneChipDetect;
|
||||
if(app->mode == SPIMemModeRead || app->mode == SPIMemModeErase) scene = SPIMemSceneStart;
|
||||
scene_manager_search_and_switch_to_previous_scene(app->scene_manager, scene);
|
||||
}
|
||||
|
||||
bool spi_mem_scene_chip_error_on_event(void* context, SceneManagerEvent event) {
|
||||
SPIMemApp* app = context;
|
||||
bool success = false;
|
||||
if(event.type == SceneManagerEventTypeBack) {
|
||||
success = true;
|
||||
spi_mem_scene_chip_error_set_previous_scene(app);
|
||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
||||
success = true;
|
||||
if(event.event == GuiButtonTypeLeft) {
|
||||
spi_mem_scene_chip_error_set_previous_scene(app);
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
void spi_mem_scene_chip_error_on_exit(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
widget_reset(app->widget);
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
ADD_SCENE(spi_mem, start, Start)
|
||||
ADD_SCENE(spi_mem, chip_detect, ChipDetect)
|
||||
ADD_SCENE(spi_mem, chip_detected, ChipDetected)
|
||||
ADD_SCENE(spi_mem, chip_detect_fail, ChipDetectFail)
|
||||
ADD_SCENE(spi_mem, select_file, SelectFile)
|
||||
ADD_SCENE(spi_mem, saved_file_menu, SavedFileMenu)
|
||||
ADD_SCENE(spi_mem, read, Read)
|
||||
ADD_SCENE(spi_mem, read_filename, ReadFilename)
|
||||
ADD_SCENE(spi_mem, delete_confirm, DeleteConfirm)
|
||||
ADD_SCENE(spi_mem, success, Success)
|
||||
ADD_SCENE(spi_mem, about, About)
|
||||
ADD_SCENE(spi_mem, verify, Verify)
|
||||
ADD_SCENE(spi_mem, file_info, FileInfo)
|
||||
ADD_SCENE(spi_mem, erase, Erase)
|
||||
ADD_SCENE(spi_mem, chip_error, ChipError)
|
||||
ADD_SCENE(spi_mem, verify_error, VerifyError)
|
||||
ADD_SCENE(spi_mem, write, Write)
|
||||
ADD_SCENE(spi_mem, storage_error, StorageError)
|
||||
ADD_SCENE(spi_mem, select_vendor, SelectVendor)
|
||||
ADD_SCENE(spi_mem, select_model, SelectModel)
|
||||
ADD_SCENE(spi_mem, wiring, Wiring)
|
|
@ -0,0 +1,62 @@
|
|||
#include "../spi_mem_app_i.h"
|
||||
#include "../spi_mem_files.h"
|
||||
|
||||
static void spi_mem_scene_delete_confirm_widget_callback(
|
||||
GuiButtonType result,
|
||||
InputType type,
|
||||
void* context) {
|
||||
SPIMemApp* app = context;
|
||||
if(type == InputTypeShort) {
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
}
|
||||
|
||||
void spi_mem_scene_delete_confirm_on_enter(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
FuriString* file_name = furi_string_alloc();
|
||||
FuriString* message = furi_string_alloc();
|
||||
path_extract_filename(app->file_path, file_name, true);
|
||||
furi_string_printf(message, "\e#Delete %s?\e#", furi_string_get_cstr(file_name));
|
||||
widget_add_text_box_element(
|
||||
app->widget, 0, 0, 128, 27, AlignCenter, AlignCenter, furi_string_get_cstr(message), true);
|
||||
widget_add_button_element(
|
||||
app->widget,
|
||||
GuiButtonTypeLeft,
|
||||
"Cancel",
|
||||
spi_mem_scene_delete_confirm_widget_callback,
|
||||
app);
|
||||
widget_add_button_element(
|
||||
app->widget,
|
||||
GuiButtonTypeRight,
|
||||
"Delete",
|
||||
spi_mem_scene_delete_confirm_widget_callback,
|
||||
app);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewWidget);
|
||||
furi_string_free(file_name);
|
||||
furi_string_free(message);
|
||||
}
|
||||
|
||||
bool spi_mem_scene_delete_confirm_on_event(void* context, SceneManagerEvent event) {
|
||||
SPIMemApp* app = context;
|
||||
bool success = false;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
success = true;
|
||||
if(event.event == GuiButtonTypeRight) {
|
||||
app->mode = SPIMemModeDelete;
|
||||
if(spi_mem_file_delete(app)) {
|
||||
scene_manager_next_scene(app->scene_manager, SPIMemSceneSuccess);
|
||||
} else {
|
||||
scene_manager_next_scene(app->scene_manager, SPIMemSceneStorageError);
|
||||
}
|
||||
} else if(event.event == GuiButtonTypeLeft) {
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, SPIMemSceneSavedFileMenu);
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
void spi_mem_scene_delete_confirm_on_exit(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
widget_reset(app->widget);
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
#include "../spi_mem_app_i.h"
|
||||
|
||||
static void
|
||||
spi_mem_scene_erase_widget_callback(GuiButtonType result, InputType type, void* context) {
|
||||
SPIMemApp* app = context;
|
||||
if(type == InputTypeShort) {
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
}
|
||||
|
||||
static void spi_mem_scene_erase_callback(void* context, SPIMemCustomEventWorker event) {
|
||||
SPIMemApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
||||
}
|
||||
|
||||
void spi_mem_scene_erase_on_enter(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
widget_add_button_element(
|
||||
app->widget, GuiButtonTypeLeft, "Cancel", spi_mem_scene_erase_widget_callback, app);
|
||||
widget_add_string_element(
|
||||
app->widget, 64, 15, AlignCenter, AlignBottom, FontPrimary, "Erasing SPI chip");
|
||||
widget_add_string_element(
|
||||
app->widget, 64, 27, AlignCenter, AlignBottom, FontSecondary, "Please be patient");
|
||||
notification_message(app->notifications, &sequence_blink_start_magenta);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewWidget);
|
||||
spi_mem_worker_start_thread(app->worker);
|
||||
spi_mem_worker_erase_start(app->chip_info, app->worker, spi_mem_scene_erase_callback, app);
|
||||
}
|
||||
|
||||
static void spi_mem_scene_erase_set_previous_scene(SPIMemApp* app) {
|
||||
uint32_t scene = SPIMemSceneStart;
|
||||
if(app->mode == SPIMemModeWrite) scene = SPIMemSceneSavedFileMenu;
|
||||
scene_manager_search_and_switch_to_previous_scene(app->scene_manager, scene);
|
||||
}
|
||||
|
||||
static void spi_mem_scene_erase_set_next_scene(SPIMemApp* app) {
|
||||
uint32_t scene = SPIMemSceneSuccess;
|
||||
if(app->mode == SPIMemModeWrite) scene = SPIMemSceneWrite;
|
||||
scene_manager_next_scene(app->scene_manager, scene);
|
||||
}
|
||||
|
||||
bool spi_mem_scene_erase_on_event(void* context, SceneManagerEvent event) {
|
||||
SPIMemApp* app = context;
|
||||
bool success = false;
|
||||
if(event.type == SceneManagerEventTypeBack) {
|
||||
success = true;
|
||||
spi_mem_scene_erase_set_previous_scene(app);
|
||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
||||
success = true;
|
||||
if(event.event == GuiButtonTypeLeft) {
|
||||
scene_manager_previous_scene(app->scene_manager);
|
||||
} else if(event.event == SPIMemCustomEventWorkerDone) {
|
||||
spi_mem_scene_erase_set_next_scene(app);
|
||||
} else if(event.event == SPIMemCustomEventWorkerChipFail) {
|
||||
scene_manager_next_scene(app->scene_manager, SPIMemSceneChipError);
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
void spi_mem_scene_erase_on_exit(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
spi_mem_worker_stop_thread(app->worker);
|
||||
notification_message(app->notifications, &sequence_blink_stop);
|
||||
widget_reset(app->widget);
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
#include "../spi_mem_app_i.h"
|
||||
#include "../spi_mem_files.h"
|
||||
|
||||
void spi_mem_scene_file_info_on_enter(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
FuriString* str = furi_string_alloc();
|
||||
furi_string_printf(str, "Size: %zu KB", spi_mem_file_get_size(app) / 1024);
|
||||
widget_add_string_element(
|
||||
app->widget, 64, 9, AlignCenter, AlignBottom, FontPrimary, "File info");
|
||||
widget_add_string_element(
|
||||
app->widget, 64, 20, AlignCenter, AlignBottom, FontSecondary, furi_string_get_cstr(str));
|
||||
furi_string_free(str);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewWidget);
|
||||
}
|
||||
|
||||
bool spi_mem_scene_file_info_on_event(void* context, SceneManagerEvent event) {
|
||||
SPIMemApp* app = context;
|
||||
bool success = false;
|
||||
if(event.type == SceneManagerEventTypeBack) {
|
||||
success = true;
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, SPIMemSceneSavedFileMenu);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
void spi_mem_scene_file_info_on_exit(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
widget_reset(app->widget);
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
#include "../spi_mem_app_i.h"
|
||||
#include "../spi_mem_files.h"
|
||||
#include "../lib/spi/spi_mem_chip.h"
|
||||
#include "../lib/spi/spi_mem_tools.h"
|
||||
|
||||
void spi_mem_scene_read_progress_view_result_callback(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SPIMemCustomEventViewReadCancel);
|
||||
}
|
||||
|
||||
static void spi_mem_scene_read_callback(void* context, SPIMemCustomEventWorker event) {
|
||||
SPIMemApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
||||
}
|
||||
|
||||
void spi_mem_scene_read_on_enter(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
spi_mem_view_progress_set_read_callback(
|
||||
app->view_progress, spi_mem_scene_read_progress_view_result_callback, app);
|
||||
notification_message(app->notifications, &sequence_blink_start_blue);
|
||||
spi_mem_view_progress_set_chip_size(app->view_progress, spi_mem_chip_get_size(app->chip_info));
|
||||
spi_mem_view_progress_set_block_size(
|
||||
app->view_progress, spi_mem_tools_get_file_max_block_size(app->chip_info));
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewProgress);
|
||||
spi_mem_worker_start_thread(app->worker);
|
||||
spi_mem_worker_read_start(app->chip_info, app->worker, spi_mem_scene_read_callback, app);
|
||||
}
|
||||
|
||||
bool spi_mem_scene_read_on_event(void* context, SceneManagerEvent event) {
|
||||
SPIMemApp* app = context;
|
||||
UNUSED(app);
|
||||
bool success = false;
|
||||
if(event.type == SceneManagerEventTypeBack) {
|
||||
success = true;
|
||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
||||
success = true;
|
||||
if(event.event == SPIMemCustomEventViewReadCancel) {
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, SPIMemSceneChipDetect);
|
||||
} else if(event.event == SPIMemCustomEventWorkerBlockReaded) {
|
||||
spi_mem_view_progress_inc_progress(app->view_progress);
|
||||
} else if(event.event == SPIMemCustomEventWorkerDone) {
|
||||
scene_manager_next_scene(app->scene_manager, SPIMemSceneVerify);
|
||||
} else if(event.event == SPIMemCustomEventWorkerChipFail) {
|
||||
scene_manager_next_scene(app->scene_manager, SPIMemSceneChipError);
|
||||
} else if(event.event == SPIMemCustomEventWorkerFileFail) {
|
||||
scene_manager_next_scene(app->scene_manager, SPIMemSceneStorageError);
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
void spi_mem_scene_read_on_exit(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
spi_mem_worker_stop_thread(app->worker);
|
||||
spi_mem_view_progress_reset(app->view_progress);
|
||||
notification_message(app->notifications, &sequence_blink_stop);
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
#include "../spi_mem_app_i.h"
|
||||
#include "../spi_mem_files.h"
|
||||
|
||||
void spi_mem_scene_read_filename_view_result_callback(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SPIMemCustomEventTextEditResult);
|
||||
}
|
||||
|
||||
void spi_mem_scene_read_set_random_filename(SPIMemApp* app) {
|
||||
if(furi_string_end_with(app->file_path, SPI_MEM_FILE_EXTENSION)) {
|
||||
size_t filename_start = furi_string_search_rchar(app->file_path, '/');
|
||||
furi_string_left(app->file_path, filename_start);
|
||||
}
|
||||
set_random_name(app->text_buffer, SPI_MEM_TEXT_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
void spi_mem_scene_read_filename_on_enter(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
spi_mem_scene_read_set_random_filename(app);
|
||||
text_input_set_header_text(app->text_input, "Name the dump");
|
||||
text_input_set_result_callback(
|
||||
app->text_input,
|
||||
spi_mem_scene_read_filename_view_result_callback,
|
||||
app,
|
||||
app->text_buffer,
|
||||
SPI_MEM_FILE_NAME_SIZE,
|
||||
true);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewTextInput);
|
||||
}
|
||||
|
||||
bool spi_mem_scene_read_filename_on_event(void* context, SceneManagerEvent event) {
|
||||
SPIMemApp* app = context;
|
||||
UNUSED(app);
|
||||
bool success = false;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
success = true;
|
||||
if(event.event == SPIMemCustomEventTextEditResult) {
|
||||
scene_manager_next_scene(app->scene_manager, SPIMemSceneRead);
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
void spi_mem_scene_read_filename_on_exit(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
text_input_reset(app->text_input);
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
#include "../spi_mem_app_i.h"
|
||||
|
||||
typedef enum {
|
||||
SPIMemSceneSavedFileMenuSubmenuIndexWrite,
|
||||
SPIMemSceneSavedFileMenuSubmenuIndexCompare,
|
||||
SPIMemSceneSavedFileMenuSubmenuIndexInfo,
|
||||
SPIMemSceneSavedFileMenuSubmenuIndexDelete,
|
||||
} SPIMemSceneSavedFileMenuSubmenuIndex;
|
||||
|
||||
static void spi_mem_scene_saved_file_menu_submenu_callback(void* context, uint32_t index) {
|
||||
SPIMemApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void spi_mem_scene_saved_file_menu_on_enter(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
submenu_add_item(
|
||||
app->submenu,
|
||||
"Write",
|
||||
SPIMemSceneSavedFileMenuSubmenuIndexWrite,
|
||||
spi_mem_scene_saved_file_menu_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
app->submenu,
|
||||
"Compare",
|
||||
SPIMemSceneSavedFileMenuSubmenuIndexCompare,
|
||||
spi_mem_scene_saved_file_menu_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
app->submenu,
|
||||
"Info",
|
||||
SPIMemSceneSavedFileMenuSubmenuIndexInfo,
|
||||
spi_mem_scene_saved_file_menu_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
app->submenu,
|
||||
"Delete",
|
||||
SPIMemSceneSavedFileMenuSubmenuIndexDelete,
|
||||
spi_mem_scene_saved_file_menu_submenu_callback,
|
||||
app);
|
||||
submenu_set_selected_item(
|
||||
app->submenu, scene_manager_get_scene_state(app->scene_manager, SPIMemSceneSavedFileMenu));
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewSubmenu);
|
||||
}
|
||||
|
||||
bool spi_mem_scene_saved_file_menu_on_event(void* context, SceneManagerEvent event) {
|
||||
SPIMemApp* app = context;
|
||||
bool success = false;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
scene_manager_set_scene_state(app->scene_manager, SPIMemSceneSavedFileMenu, event.event);
|
||||
if(event.event == SPIMemSceneSavedFileMenuSubmenuIndexWrite) {
|
||||
app->mode = SPIMemModeWrite;
|
||||
scene_manager_next_scene(app->scene_manager, SPIMemSceneChipDetect);
|
||||
success = true;
|
||||
}
|
||||
if(event.event == SPIMemSceneSavedFileMenuSubmenuIndexCompare) {
|
||||
app->mode = SPIMemModeCompare;
|
||||
scene_manager_next_scene(app->scene_manager, SPIMemSceneChipDetect);
|
||||
success = true;
|
||||
}
|
||||
if(event.event == SPIMemSceneSavedFileMenuSubmenuIndexDelete) {
|
||||
scene_manager_next_scene(app->scene_manager, SPIMemSceneDeleteConfirm);
|
||||
success = true;
|
||||
}
|
||||
if(event.event == SPIMemSceneSavedFileMenuSubmenuIndexInfo) {
|
||||
scene_manager_next_scene(app->scene_manager, SPIMemSceneFileInfo);
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
void spi_mem_scene_saved_file_menu_on_exit(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
submenu_reset(app->submenu);
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
#include "../spi_mem_app_i.h"
|
||||
#include "../spi_mem_files.h"
|
||||
|
||||
void spi_mem_scene_select_file_on_enter(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
if(spi_mem_file_select(app)) {
|
||||
scene_manager_set_scene_state(app->scene_manager, SPIMemSceneSavedFileMenu, 0);
|
||||
scene_manager_next_scene(app->scene_manager, SPIMemSceneSavedFileMenu);
|
||||
} else {
|
||||
scene_manager_search_and_switch_to_previous_scene(app->scene_manager, SPIMemSceneStart);
|
||||
}
|
||||
}
|
||||
|
||||
bool spi_mem_scene_select_file_on_event(void* context, SceneManagerEvent event) {
|
||||
UNUSED(context);
|
||||
UNUSED(event);
|
||||
return false;
|
||||
}
|
||||
|
||||
void spi_mem_scene_select_file_on_exit(void* context) {
|
||||
UNUSED(context);
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
#include "../spi_mem_app_i.h"
|
||||
|
||||
static void spi_mem_scene_select_model_submenu_callback(void* context, uint32_t index) {
|
||||
SPIMemApp* app = context;
|
||||
spi_mem_chip_copy_chip_info(app->chip_info, *found_chips_get(app->found_chips, index));
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void spi_mem_scene_select_model_on_enter(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
size_t models_on_vendor = 0;
|
||||
for(size_t index = 0; index < found_chips_size(app->found_chips); index++) {
|
||||
if(spi_mem_chip_get_vendor_enum(*found_chips_get(app->found_chips, index)) !=
|
||||
app->chip_vendor_enum)
|
||||
continue;
|
||||
submenu_add_item(
|
||||
app->submenu,
|
||||
spi_mem_chip_get_model_name(*found_chips_get(app->found_chips, index)),
|
||||
index,
|
||||
spi_mem_scene_select_model_submenu_callback,
|
||||
app);
|
||||
models_on_vendor++;
|
||||
}
|
||||
if(models_on_vendor == 1) spi_mem_scene_select_model_submenu_callback(context, 0);
|
||||
submenu_set_header(app->submenu, "Choose chip model");
|
||||
submenu_set_selected_item(
|
||||
app->submenu, scene_manager_get_scene_state(app->scene_manager, SPIMemSceneSelectVendor));
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewSubmenu);
|
||||
}
|
||||
|
||||
bool spi_mem_scene_select_model_on_event(void* context, SceneManagerEvent event) {
|
||||
SPIMemApp* app = context;
|
||||
bool success = false;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
scene_manager_set_scene_state(app->scene_manager, SPIMemSceneSelectVendor, event.event);
|
||||
scene_manager_next_scene(app->scene_manager, SPIMemSceneChipDetected);
|
||||
success = true;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
void spi_mem_scene_select_model_on_exit(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
submenu_reset(app->submenu);
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
#include "../spi_mem_app_i.h"
|
||||
#include <m-array.h>
|
||||
#include <m-algo.h>
|
||||
|
||||
ARRAY_DEF(vendors, uint32_t)
|
||||
ALGO_DEF(vendors, ARRAY_OPLIST(vendors))
|
||||
|
||||
static void spi_mem_scene_select_vendor_submenu_callback(void* context, uint32_t index) {
|
||||
SPIMemApp* app = context;
|
||||
app->chip_vendor_enum = index;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
||||
}
|
||||
|
||||
static void spi_mem_scene_select_vendor_sort_vendors(SPIMemApp* app, vendors_t vendors_arr) {
|
||||
for(size_t index = 0; index < found_chips_size(app->found_chips); index++) {
|
||||
vendors_push_back(
|
||||
vendors_arr, spi_mem_chip_get_vendor_enum(*found_chips_get(app->found_chips, index)));
|
||||
}
|
||||
vendors_uniq(vendors_arr);
|
||||
}
|
||||
|
||||
void spi_mem_scene_select_vendor_on_enter(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
vendors_t vendors_arr;
|
||||
vendors_init(vendors_arr);
|
||||
spi_mem_scene_select_vendor_sort_vendors(app, vendors_arr);
|
||||
size_t vendors_arr_size = vendors_size(vendors_arr);
|
||||
if(vendors_arr_size == 1)
|
||||
spi_mem_scene_select_vendor_submenu_callback(context, *vendors_get(vendors_arr, 0));
|
||||
for(size_t index = 0; index < vendors_arr_size; index++) {
|
||||
uint32_t vendor_enum = *vendors_get(vendors_arr, index);
|
||||
submenu_add_item(
|
||||
app->submenu,
|
||||
spi_mem_chip_get_vendor_name_by_enum(vendor_enum),
|
||||
vendor_enum,
|
||||
spi_mem_scene_select_vendor_submenu_callback,
|
||||
app);
|
||||
}
|
||||
vendors_clear(vendors_arr);
|
||||
submenu_set_header(app->submenu, "Choose chip vendor");
|
||||
submenu_set_selected_item(
|
||||
app->submenu, scene_manager_get_scene_state(app->scene_manager, SPIMemSceneSelectVendor));
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewSubmenu);
|
||||
}
|
||||
|
||||
static void spi_mem_scene_select_vendor_set_previous_scene(SPIMemApp* app) {
|
||||
uint32_t scene = SPIMemSceneStart;
|
||||
if(app->mode == SPIMemModeCompare || app->mode == SPIMemModeWrite)
|
||||
scene = SPIMemSceneSavedFileMenu;
|
||||
scene_manager_search_and_switch_to_previous_scene(app->scene_manager, scene);
|
||||
}
|
||||
|
||||
bool spi_mem_scene_select_vendor_on_event(void* context, SceneManagerEvent event) {
|
||||
SPIMemApp* app = context;
|
||||
bool success = false;
|
||||
if(event.type == SceneManagerEventTypeBack) {
|
||||
success = true;
|
||||
spi_mem_scene_select_vendor_set_previous_scene(app);
|
||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
||||
scene_manager_set_scene_state(app->scene_manager, SPIMemSceneSelectVendor, event.event);
|
||||
scene_manager_next_scene(app->scene_manager, SPIMemSceneSelectModel);
|
||||
success = true;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
void spi_mem_scene_select_vendor_on_exit(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
submenu_reset(app->submenu);
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
#include "../spi_mem_app_i.h"
|
||||
|
||||
typedef enum {
|
||||
SPIMemSceneStartSubmenuIndexRead,
|
||||
SPIMemSceneStartSubmenuIndexSaved,
|
||||
SPIMemSceneStartSubmenuIndexErase,
|
||||
SPIMemSceneStartSubmenuIndexWiring,
|
||||
SPIMemSceneStartSubmenuIndexAbout
|
||||
} SPIMemSceneStartSubmenuIndex;
|
||||
|
||||
static void spi_mem_scene_start_submenu_callback(void* context, uint32_t index) {
|
||||
SPIMemApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void spi_mem_scene_start_on_enter(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
submenu_add_item(
|
||||
app->submenu,
|
||||
"Read",
|
||||
SPIMemSceneStartSubmenuIndexRead,
|
||||
spi_mem_scene_start_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
app->submenu,
|
||||
"Saved",
|
||||
SPIMemSceneStartSubmenuIndexSaved,
|
||||
spi_mem_scene_start_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
app->submenu,
|
||||
"Erase",
|
||||
SPIMemSceneStartSubmenuIndexErase,
|
||||
spi_mem_scene_start_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
app->submenu,
|
||||
"Wiring",
|
||||
SPIMemSceneStartSubmenuIndexWiring,
|
||||
spi_mem_scene_start_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
app->submenu,
|
||||
"About",
|
||||
SPIMemSceneStartSubmenuIndexAbout,
|
||||
spi_mem_scene_start_submenu_callback,
|
||||
app);
|
||||
submenu_set_selected_item(
|
||||
app->submenu, scene_manager_get_scene_state(app->scene_manager, SPIMemSceneStart));
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewSubmenu);
|
||||
}
|
||||
|
||||
bool spi_mem_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
SPIMemApp* app = context;
|
||||
bool success = false;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
scene_manager_set_scene_state(app->scene_manager, SPIMemSceneStart, event.event);
|
||||
if(event.event == SPIMemSceneStartSubmenuIndexRead) {
|
||||
app->mode = SPIMemModeRead;
|
||||
scene_manager_next_scene(app->scene_manager, SPIMemSceneChipDetect);
|
||||
success = true;
|
||||
} else if(event.event == SPIMemSceneStartSubmenuIndexSaved) {
|
||||
furi_string_set(app->file_path, SPI_MEM_FILE_FOLDER);
|
||||
scene_manager_next_scene(app->scene_manager, SPIMemSceneSelectFile);
|
||||
success = true;
|
||||
} else if(event.event == SPIMemSceneStartSubmenuIndexErase) {
|
||||
app->mode = SPIMemModeErase;
|
||||
scene_manager_next_scene(app->scene_manager, SPIMemSceneChipDetect);
|
||||
success = true;
|
||||
} else if(event.event == SPIMemSceneStartSubmenuIndexWiring) {
|
||||
scene_manager_next_scene(app->scene_manager, SPIMemSceneWiring);
|
||||
success = true;
|
||||
} else if(event.event == SPIMemSceneStartSubmenuIndexAbout) {
|
||||
scene_manager_next_scene(app->scene_manager, SPIMemSceneAbout);
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
void spi_mem_scene_start_on_exit(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
submenu_reset(app->submenu);
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
#include "../spi_mem_app_i.h"
|
||||
|
||||
static void spi_mem_scene_storage_error_widget_callback(
|
||||
GuiButtonType result,
|
||||
InputType type,
|
||||
void* context) {
|
||||
SPIMemApp* app = context;
|
||||
if(type == InputTypeShort) {
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
}
|
||||
|
||||
void spi_mem_scene_storage_error_on_enter(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
widget_add_button_element(
|
||||
app->widget, GuiButtonTypeLeft, "Back", spi_mem_scene_storage_error_widget_callback, app);
|
||||
widget_add_string_element(
|
||||
app->widget, 85, 15, AlignCenter, AlignBottom, FontPrimary, "Storage error");
|
||||
widget_add_string_multiline_element(
|
||||
app->widget,
|
||||
85,
|
||||
52,
|
||||
AlignCenter,
|
||||
AlignBottom,
|
||||
FontSecondary,
|
||||
"Error while\nworking with\nfilesystem");
|
||||
widget_add_icon_element(app->widget, 5, 6, &I_SDQuestion_35x43);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewWidget);
|
||||
}
|
||||
|
||||
static void spi_mem_scene_storage_error_set_previous_scene(SPIMemApp* app) {
|
||||
uint32_t scene = SPIMemSceneChipDetect;
|
||||
if(app->mode == SPIMemModeRead) scene = SPIMemSceneStart;
|
||||
if(app->mode == SPIMemModeErase) scene = SPIMemSceneStart;
|
||||
if(app->mode == SPIMemModeDelete) scene = SPIMemSceneStart;
|
||||
scene_manager_search_and_switch_to_previous_scene(app->scene_manager, scene);
|
||||
}
|
||||
|
||||
bool spi_mem_scene_storage_error_on_event(void* context, SceneManagerEvent event) {
|
||||
SPIMemApp* app = context;
|
||||
bool success = false;
|
||||
if(event.type == SceneManagerEventTypeBack) {
|
||||
success = true;
|
||||
spi_mem_scene_storage_error_set_previous_scene(app);
|
||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
||||
success = true;
|
||||
if(event.event == GuiButtonTypeLeft) {
|
||||
spi_mem_scene_storage_error_set_previous_scene(app);
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
void spi_mem_scene_storage_error_on_exit(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
widget_reset(app->widget);
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
#include "../spi_mem_app_i.h"
|
||||
|
||||
static void spi_mem_scene_success_popup_callback(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SPIMemCustomEventPopupBack);
|
||||
}
|
||||
|
||||
void spi_mem_scene_success_on_enter(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
popup_set_icon(app->popup, 32, 5, &I_DolphinNice_96x59);
|
||||
popup_set_header(app->popup, "Success!", 5, 7, AlignLeft, AlignTop);
|
||||
popup_set_callback(app->popup, spi_mem_scene_success_popup_callback);
|
||||
popup_set_context(app->popup, app);
|
||||
popup_set_timeout(app->popup, 1500);
|
||||
popup_enable_timeout(app->popup);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewPopup);
|
||||
}
|
||||
|
||||
static void spi_mem_scene_success_set_previous_scene(SPIMemApp* app) {
|
||||
uint32_t scene = SPIMemSceneSelectFile;
|
||||
if(app->mode == SPIMemModeErase) scene = SPIMemSceneStart;
|
||||
scene_manager_search_and_switch_to_another_scene(app->scene_manager, scene);
|
||||
}
|
||||
|
||||
bool spi_mem_scene_success_on_event(void* context, SceneManagerEvent event) {
|
||||
SPIMemApp* app = context;
|
||||
bool success = false;
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
success = true;
|
||||
if(event.event == SPIMemCustomEventPopupBack) {
|
||||
spi_mem_scene_success_set_previous_scene(app);
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
void spi_mem_scene_success_on_exit(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
popup_reset(app->popup);
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
#include "../spi_mem_app_i.h"
|
||||
#include "../spi_mem_files.h"
|
||||
#include "../lib/spi/spi_mem_chip.h"
|
||||
#include "../lib/spi/spi_mem_tools.h"
|
||||
|
||||
void spi_mem_scene_verify_view_result_callback(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SPIMemCustomEventViewVerifySkip);
|
||||
}
|
||||
|
||||
static void spi_mem_scene_verify_callback(void* context, SPIMemCustomEventWorker event) {
|
||||
SPIMemApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
||||
}
|
||||
|
||||
void spi_mem_scene_verify_on_enter(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
spi_mem_view_progress_set_verify_callback(
|
||||
app->view_progress, spi_mem_scene_verify_view_result_callback, app);
|
||||
notification_message(app->notifications, &sequence_blink_start_cyan);
|
||||
spi_mem_view_progress_set_chip_size(app->view_progress, spi_mem_chip_get_size(app->chip_info));
|
||||
spi_mem_view_progress_set_file_size(app->view_progress, spi_mem_file_get_size(app));
|
||||
spi_mem_view_progress_set_block_size(
|
||||
app->view_progress, spi_mem_tools_get_file_max_block_size(app->chip_info));
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewProgress);
|
||||
spi_mem_worker_start_thread(app->worker);
|
||||
spi_mem_worker_verify_start(app->chip_info, app->worker, spi_mem_scene_verify_callback, app);
|
||||
}
|
||||
|
||||
bool spi_mem_scene_verify_on_event(void* context, SceneManagerEvent event) {
|
||||
SPIMemApp* app = context;
|
||||
UNUSED(app);
|
||||
bool success = false;
|
||||
if(event.type == SceneManagerEventTypeBack) {
|
||||
success = true;
|
||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
||||
success = true;
|
||||
if(event.event == SPIMemCustomEventViewVerifySkip) {
|
||||
scene_manager_next_scene(app->scene_manager, SPIMemSceneSuccess);
|
||||
} else if(event.event == SPIMemCustomEventWorkerBlockReaded) {
|
||||
spi_mem_view_progress_inc_progress(app->view_progress);
|
||||
} else if(event.event == SPIMemCustomEventWorkerChipFail) {
|
||||
scene_manager_next_scene(app->scene_manager, SPIMemSceneChipError);
|
||||
} else if(event.event == SPIMemCustomEventWorkerFileFail) {
|
||||
scene_manager_next_scene(app->scene_manager, SPIMemSceneStorageError);
|
||||
} else if(event.event == SPIMemCustomEventWorkerDone) {
|
||||
scene_manager_next_scene(app->scene_manager, SPIMemSceneSuccess);
|
||||
} else if(event.event == SPIMemCustomEventWorkerVerifyFail) {
|
||||
scene_manager_next_scene(app->scene_manager, SPIMemSceneVerifyError);
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
void spi_mem_scene_verify_on_exit(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
spi_mem_worker_stop_thread(app->worker);
|
||||
spi_mem_view_progress_reset(app->view_progress);
|
||||
notification_message(app->notifications, &sequence_blink_stop);
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
#include "../spi_mem_app_i.h"
|
||||
|
||||
static void spi_mem_scene_verify_error_widget_callback(
|
||||
GuiButtonType result,
|
||||
InputType type,
|
||||
void* context) {
|
||||
SPIMemApp* app = context;
|
||||
if(type == InputTypeShort) {
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
}
|
||||
|
||||
void spi_mem_scene_verify_error_on_enter(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
widget_add_button_element(
|
||||
app->widget, GuiButtonTypeLeft, "Back", spi_mem_scene_verify_error_widget_callback, app);
|
||||
widget_add_string_element(
|
||||
app->widget, 64, 9, AlignCenter, AlignBottom, FontPrimary, "Verification error");
|
||||
widget_add_string_element(
|
||||
app->widget, 64, 21, AlignCenter, AlignBottom, FontSecondary, "Data mismatch");
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewWidget);
|
||||
}
|
||||
|
||||
bool spi_mem_scene_verify_error_on_event(void* context, SceneManagerEvent event) {
|
||||
SPIMemApp* app = context;
|
||||
bool success = false;
|
||||
if(event.type == SceneManagerEventTypeBack) {
|
||||
success = true;
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, SPIMemSceneChipDetect);
|
||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
||||
success = true;
|
||||
if(event.event == GuiButtonTypeLeft) {
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, SPIMemSceneChipDetect);
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
void spi_mem_scene_verify_error_on_exit(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
widget_reset(app->widget);
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#include "../spi_mem_app_i.h"
|
||||
#include "../lib/spi/spi_mem_chip.h"
|
||||
|
||||
void spi_mem_scene_wiring_on_enter(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
widget_add_icon_element(app->widget, 0, 0, &I_Wiring_SPI_128x64);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewWidget);
|
||||
}
|
||||
|
||||
bool spi_mem_scene_wiring_on_event(void* context, SceneManagerEvent event) {
|
||||
UNUSED(context);
|
||||
UNUSED(event);
|
||||
return false;
|
||||
}
|
||||
void spi_mem_scene_wiring_on_exit(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
widget_reset(app->widget);
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
#include "../spi_mem_app_i.h"
|
||||
#include "../spi_mem_files.h"
|
||||
#include "../lib/spi/spi_mem_chip.h"
|
||||
#include "../lib/spi/spi_mem_tools.h"
|
||||
|
||||
void spi_mem_scene_write_progress_view_result_callback(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SPIMemCustomEventViewReadCancel);
|
||||
}
|
||||
|
||||
static void spi_mem_scene_write_callback(void* context, SPIMemCustomEventWorker event) {
|
||||
SPIMemApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, event);
|
||||
}
|
||||
|
||||
void spi_mem_scene_write_on_enter(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
spi_mem_view_progress_set_write_callback(
|
||||
app->view_progress, spi_mem_scene_write_progress_view_result_callback, app);
|
||||
notification_message(app->notifications, &sequence_blink_start_cyan);
|
||||
spi_mem_view_progress_set_chip_size(app->view_progress, spi_mem_chip_get_size(app->chip_info));
|
||||
spi_mem_view_progress_set_file_size(app->view_progress, spi_mem_file_get_size(app));
|
||||
spi_mem_view_progress_set_block_size(
|
||||
app->view_progress, spi_mem_tools_get_file_max_block_size(app->chip_info));
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SPIMemViewProgress);
|
||||
spi_mem_worker_start_thread(app->worker);
|
||||
spi_mem_worker_write_start(app->chip_info, app->worker, spi_mem_scene_write_callback, app);
|
||||
}
|
||||
|
||||
bool spi_mem_scene_write_on_event(void* context, SceneManagerEvent event) {
|
||||
SPIMemApp* app = context;
|
||||
UNUSED(app);
|
||||
bool success = false;
|
||||
if(event.type == SceneManagerEventTypeBack) {
|
||||
success = true;
|
||||
} else if(event.type == SceneManagerEventTypeCustom) {
|
||||
success = true;
|
||||
if(event.event == SPIMemCustomEventViewReadCancel) {
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, SPIMemSceneChipDetect);
|
||||
} else if(event.event == SPIMemCustomEventWorkerBlockReaded) {
|
||||
spi_mem_view_progress_inc_progress(app->view_progress);
|
||||
} else if(event.event == SPIMemCustomEventWorkerDone) {
|
||||
scene_manager_next_scene(app->scene_manager, SPIMemSceneVerify);
|
||||
} else if(event.event == SPIMemCustomEventWorkerChipFail) {
|
||||
scene_manager_next_scene(app->scene_manager, SPIMemSceneChipError);
|
||||
} else if(event.event == SPIMemCustomEventWorkerFileFail) {
|
||||
scene_manager_next_scene(app->scene_manager, SPIMemSceneStorageError);
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
void spi_mem_scene_write_on_exit(void* context) {
|
||||
SPIMemApp* app = context;
|
||||
spi_mem_worker_stop_thread(app->worker);
|
||||
spi_mem_view_progress_reset(app->view_progress);
|
||||
notification_message(app->notifications, &sequence_blink_stop);
|
||||
}
|
112
applications/plugins/spi_mem_manager/spi_mem_app.c
Normal file
|
@ -0,0 +1,112 @@
|
|||
#include <furi_hal.h>
|
||||
#include "spi_mem_app_i.h"
|
||||
#include "spi_mem_files.h"
|
||||
#include "lib/spi/spi_mem_chip_i.h"
|
||||
|
||||
static bool spi_mem_custom_event_callback(void* context, uint32_t event) {
|
||||
furi_assert(context);
|
||||
SPIMemApp* app = context;
|
||||
return scene_manager_handle_custom_event(app->scene_manager, event);
|
||||
}
|
||||
|
||||
static bool spi_mem_back_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
SPIMemApp* app = context;
|
||||
return scene_manager_handle_back_event(app->scene_manager);
|
||||
}
|
||||
|
||||
SPIMemApp* spi_mem_alloc(void) {
|
||||
SPIMemApp* instance = malloc(sizeof(SPIMemApp));
|
||||
|
||||
instance->file_path = furi_string_alloc();
|
||||
instance->gui = furi_record_open(RECORD_GUI);
|
||||
instance->notifications = furi_record_open(RECORD_NOTIFICATION);
|
||||
instance->view_dispatcher = view_dispatcher_alloc();
|
||||
instance->scene_manager = scene_manager_alloc(&spi_mem_scene_handlers, instance);
|
||||
instance->submenu = submenu_alloc();
|
||||
instance->dialog_ex = dialog_ex_alloc();
|
||||
instance->popup = popup_alloc();
|
||||
instance->worker = spi_mem_worker_alloc();
|
||||
instance->dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
instance->storage = furi_record_open(RECORD_STORAGE);
|
||||
instance->widget = widget_alloc();
|
||||
instance->chip_info = malloc(sizeof(SPIMemChip));
|
||||
found_chips_init(instance->found_chips);
|
||||
instance->view_progress = spi_mem_view_progress_alloc();
|
||||
instance->view_detect = spi_mem_view_detect_alloc();
|
||||
instance->text_input = text_input_alloc();
|
||||
instance->mode = SPIMemModeUnknown;
|
||||
|
||||
furi_string_set(instance->file_path, SPI_MEM_FILE_FOLDER);
|
||||
|
||||
view_dispatcher_enable_queue(instance->view_dispatcher);
|
||||
view_dispatcher_set_event_callback_context(instance->view_dispatcher, instance);
|
||||
view_dispatcher_set_custom_event_callback(
|
||||
instance->view_dispatcher, spi_mem_custom_event_callback);
|
||||
view_dispatcher_set_navigation_event_callback(
|
||||
instance->view_dispatcher, spi_mem_back_event_callback);
|
||||
view_dispatcher_attach_to_gui(
|
||||
instance->view_dispatcher, instance->gui, ViewDispatcherTypeFullscreen);
|
||||
view_dispatcher_add_view(
|
||||
instance->view_dispatcher, SPIMemViewSubmenu, submenu_get_view(instance->submenu));
|
||||
view_dispatcher_add_view(
|
||||
instance->view_dispatcher, SPIMemViewDialogEx, dialog_ex_get_view(instance->dialog_ex));
|
||||
view_dispatcher_add_view(
|
||||
instance->view_dispatcher, SPIMemViewPopup, popup_get_view(instance->popup));
|
||||
view_dispatcher_add_view(
|
||||
instance->view_dispatcher, SPIMemViewWidget, widget_get_view(instance->widget));
|
||||
view_dispatcher_add_view(
|
||||
instance->view_dispatcher,
|
||||
SPIMemViewProgress,
|
||||
spi_mem_view_progress_get_view(instance->view_progress));
|
||||
view_dispatcher_add_view(
|
||||
instance->view_dispatcher,
|
||||
SPIMemViewDetect,
|
||||
spi_mem_view_detect_get_view(instance->view_detect));
|
||||
view_dispatcher_add_view(
|
||||
instance->view_dispatcher, SPIMemViewTextInput, text_input_get_view(instance->text_input));
|
||||
|
||||
furi_hal_power_enable_otg();
|
||||
furi_hal_spi_bus_handle_init(&furi_hal_spi_bus_handle_external);
|
||||
scene_manager_next_scene(instance->scene_manager, SPIMemSceneStart);
|
||||
return instance;
|
||||
}
|
||||
|
||||
void spi_mem_free(SPIMemApp* instance) {
|
||||
view_dispatcher_remove_view(instance->view_dispatcher, SPIMemViewSubmenu);
|
||||
view_dispatcher_remove_view(instance->view_dispatcher, SPIMemViewDialogEx);
|
||||
view_dispatcher_remove_view(instance->view_dispatcher, SPIMemViewPopup);
|
||||
view_dispatcher_remove_view(instance->view_dispatcher, SPIMemViewWidget);
|
||||
view_dispatcher_remove_view(instance->view_dispatcher, SPIMemViewProgress);
|
||||
view_dispatcher_remove_view(instance->view_dispatcher, SPIMemViewDetect);
|
||||
view_dispatcher_remove_view(instance->view_dispatcher, SPIMemViewTextInput);
|
||||
spi_mem_view_progress_free(instance->view_progress);
|
||||
spi_mem_view_detect_free(instance->view_detect);
|
||||
submenu_free(instance->submenu);
|
||||
dialog_ex_free(instance->dialog_ex);
|
||||
popup_free(instance->popup);
|
||||
widget_free(instance->widget);
|
||||
text_input_free(instance->text_input);
|
||||
view_dispatcher_free(instance->view_dispatcher);
|
||||
scene_manager_free(instance->scene_manager);
|
||||
spi_mem_worker_free(instance->worker);
|
||||
free(instance->chip_info);
|
||||
found_chips_clear(instance->found_chips);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
furi_record_close(RECORD_DIALOGS);
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
furi_record_close(RECORD_GUI);
|
||||
furi_string_free(instance->file_path);
|
||||
furi_hal_spi_bus_handle_deinit(&furi_hal_spi_bus_handle_external);
|
||||
furi_hal_power_disable_otg();
|
||||
free(instance);
|
||||
}
|
||||
|
||||
int32_t spi_mem_app(void* p) {
|
||||
UNUSED(p);
|
||||
SPIMemApp* instance = spi_mem_alloc();
|
||||
spi_mem_file_create_folder(instance);
|
||||
view_dispatcher_run(instance->view_dispatcher);
|
||||
spi_mem_free(instance);
|
||||
return 0;
|
||||
}
|
3
applications/plugins/spi_mem_manager/spi_mem_app.h
Normal file
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
typedef struct SPIMemApp SPIMemApp;
|
79
applications/plugins/spi_mem_manager/spi_mem_app_i.h
Normal file
|
@ -0,0 +1,79 @@
|
|||
#pragma once
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal_spi.h>
|
||||
#include <furi_hal_spi_config.h>
|
||||
#include "spi_mem_app.h"
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/modules/submenu.h>
|
||||
#include <gui/modules/dialog_ex.h>
|
||||
#include <gui/modules/popup.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <dialogs/dialogs.h>
|
||||
#include <gui/modules/widget.h>
|
||||
#include <gui/modules/text_input.h>
|
||||
#include <storage/storage.h>
|
||||
#include <toolbox/path.h>
|
||||
#include <toolbox/random_name.h>
|
||||
#include "scenes/spi_mem_scene.h"
|
||||
#include "lib/spi/spi_mem_worker.h"
|
||||
#include "spi_mem_manager_icons.h"
|
||||
#include "views/spi_mem_view_progress.h"
|
||||
#include "views/spi_mem_view_detect.h"
|
||||
|
||||
#define TAG "SPIMem"
|
||||
#define SPI_MEM_FILE_EXTENSION ".bin"
|
||||
#define SPI_MEM_FILE_FOLDER EXT_PATH("spimem")
|
||||
#define SPI_MEM_FILE_NAME_SIZE 100
|
||||
#define SPI_MEM_TEXT_BUFFER_SIZE 128
|
||||
|
||||
typedef enum {
|
||||
SPIMemModeRead,
|
||||
SPIMemModeWrite,
|
||||
SPIMemModeCompare,
|
||||
SPIMemModeErase,
|
||||
SPIMemModeDelete,
|
||||
SPIMemModeUnknown
|
||||
} SPIMemMode;
|
||||
|
||||
struct SPIMemApp {
|
||||
Gui* gui;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
SceneManager* scene_manager;
|
||||
Submenu* submenu;
|
||||
DialogEx* dialog_ex;
|
||||
Popup* popup;
|
||||
NotificationApp* notifications;
|
||||
FuriString* file_path;
|
||||
DialogsApp* dialogs;
|
||||
Storage* storage;
|
||||
File* file;
|
||||
Widget* widget;
|
||||
SPIMemWorker* worker;
|
||||
SPIMemChip* chip_info;
|
||||
found_chips_t found_chips;
|
||||
uint32_t chip_vendor_enum;
|
||||
SPIMemProgressView* view_progress;
|
||||
SPIMemDetectView* view_detect;
|
||||
TextInput* text_input;
|
||||
SPIMemMode mode;
|
||||
char text_buffer[SPI_MEM_TEXT_BUFFER_SIZE + 1];
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
SPIMemViewSubmenu,
|
||||
SPIMemViewDialogEx,
|
||||
SPIMemViewPopup,
|
||||
SPIMemViewWidget,
|
||||
SPIMemViewTextInput,
|
||||
SPIMemViewProgress,
|
||||
SPIMemViewDetect
|
||||
} SPIMemView;
|
||||
|
||||
typedef enum {
|
||||
SPIMemCustomEventViewReadCancel,
|
||||
SPIMemCustomEventViewVerifySkip,
|
||||
SPIMemCustomEventTextEditResult,
|
||||
SPIMemCustomEventPopupBack
|
||||
} SPIMemCustomEvent;
|
74
applications/plugins/spi_mem_manager/spi_mem_files.c
Normal file
|
@ -0,0 +1,74 @@
|
|||
#include "spi_mem_app_i.h"
|
||||
|
||||
void spi_mem_file_create_folder(SPIMemApp* app) {
|
||||
if(!storage_simply_mkdir(app->storage, SPI_MEM_FILE_FOLDER)) {
|
||||
dialog_message_show_storage_error(app->dialogs, "Cannot create\napp folder");
|
||||
}
|
||||
}
|
||||
|
||||
bool spi_mem_file_delete(SPIMemApp* app) {
|
||||
return (storage_simply_remove(app->storage, furi_string_get_cstr(app->file_path)));
|
||||
}
|
||||
|
||||
bool spi_mem_file_select(SPIMemApp* app) {
|
||||
DialogsFileBrowserOptions browser_options;
|
||||
dialog_file_browser_set_basic_options(&browser_options, SPI_MEM_FILE_EXTENSION, &I_Dip8_10px);
|
||||
browser_options.base_path = SPI_MEM_FILE_FOLDER;
|
||||
bool success =
|
||||
dialog_file_browser_show(app->dialogs, app->file_path, app->file_path, &browser_options);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool spi_mem_file_create_open(SPIMemApp* app) {
|
||||
bool success = false;
|
||||
app->file = storage_file_alloc(app->storage);
|
||||
do {
|
||||
if(furi_string_end_with(app->file_path, SPI_MEM_FILE_EXTENSION)) {
|
||||
if(!spi_mem_file_delete(app)) break;
|
||||
size_t filename_start = furi_string_search_rchar(app->file_path, '/');
|
||||
furi_string_left(app->file_path, filename_start);
|
||||
}
|
||||
furi_string_cat_printf(app->file_path, "/%s%s", app->text_buffer, SPI_MEM_FILE_EXTENSION);
|
||||
if(!storage_file_open(
|
||||
app->file, furi_string_get_cstr(app->file_path), FSAM_WRITE, FSOM_CREATE_NEW))
|
||||
break;
|
||||
success = true;
|
||||
} while(0);
|
||||
if(!success) { //-V547
|
||||
dialog_message_show_storage_error(app->dialogs, "Cannot save\nfile");
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool spi_mem_file_open(SPIMemApp* app) {
|
||||
app->file = storage_file_alloc(app->storage);
|
||||
if(!storage_file_open(
|
||||
app->file, furi_string_get_cstr(app->file_path), FSAM_READ_WRITE, FSOM_OPEN_EXISTING)) {
|
||||
dialog_message_show_storage_error(app->dialogs, "Cannot save\nfile");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool spi_mem_file_write_block(SPIMemApp* app, uint8_t* data, size_t size) {
|
||||
if(storage_file_write(app->file, data, size) != size) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool spi_mem_file_read_block(SPIMemApp* app, uint8_t* data, size_t size) {
|
||||
if(storage_file_read(app->file, data, size) != size) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void spi_mem_file_close(SPIMemApp* app) {
|
||||
storage_file_close(app->file);
|
||||
storage_file_free(app->file);
|
||||
}
|
||||
|
||||
size_t spi_mem_file_get_size(SPIMemApp* app) {
|
||||
FileInfo file_info;
|
||||
if(storage_common_stat(app->storage, furi_string_get_cstr(app->file_path), &file_info) !=
|
||||
FSE_OK)
|
||||
return 0;
|
||||
return file_info.size;
|
||||
}
|
14
applications/plugins/spi_mem_manager/spi_mem_files.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
#include "spi_mem_app.h"
|
||||
|
||||
void spi_mem_file_create_folder(SPIMemApp* app);
|
||||
bool spi_mem_file_select(SPIMemApp* app);
|
||||
bool spi_mem_file_create(SPIMemApp* app, const char* file_name);
|
||||
bool spi_mem_file_delete(SPIMemApp* app);
|
||||
bool spi_mem_file_create_open(SPIMemApp* app);
|
||||
bool spi_mem_file_open(SPIMemApp* app);
|
||||
bool spi_mem_file_write_block(SPIMemApp* app, uint8_t* data, size_t size);
|
||||
bool spi_mem_file_read_block(SPIMemApp* app, uint8_t* data, size_t size);
|
||||
void spi_mem_file_close(SPIMemApp* app);
|
||||
void spi_mem_file_show_storage_error(SPIMemApp* app, const char* error_text);
|
||||
size_t spi_mem_file_get_size(SPIMemApp* app);
|
7
applications/plugins/spi_mem_manager/tools/README.md
Normal file
|
@ -0,0 +1,7 @@
|
|||
This utility can convert nofeletru's UsbAsp-flash's chiplist.xml to C array
|
||||
|
||||
Usage:
|
||||
```bash
|
||||
./chiplist_convert.py chiplist/chiplist.xml
|
||||
mv spi_mem_chip_arr.c ../lib/spi/spi_mem_chip_arr.c
|
||||
```
|
22
applications/plugins/spi_mem_manager/tools/chiplist/LICENSE
Normal file
|
@ -0,0 +1,22 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 nofeletru
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
984
applications/plugins/spi_mem_manager/tools/chiplist/chiplist.xml
Normal file
|
@ -0,0 +1,984 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!---
|
||||
This file is downloaded from nofeletru's UsbAsp-flash repository
|
||||
https://github.com/nofeletru/UsbAsp-flash/blob/master/chiplist.xml
|
||||
And distributed under MIT license
|
||||
-->
|
||||
<!---
|
||||
size - размер данных микросхемы памяти в байтах(DEC)
|
||||
page - размер страницы микросхемы памяти в байтах(DEC). Для SST AAI Word programm - SSTW. Для SST AAI Byte programm - SSTB.
|
||||
id - индефикатор микросхемы памяти(HEX). Поддерживаются опкоды 9F, 90, AB, 15
|
||||
spicmd - команды для серий микросхем памяти 25, 45, 95(EEPROM)
|
||||
script - имя файла скрипта из папки scripts
|
||||
-->
|
||||
<chiplist>
|
||||
<SPI>
|
||||
<KB90XX>
|
||||
<KB9012 id="0" page="128" size="131072" spicmd="KB"/>
|
||||
</KB90XX>
|
||||
<ADESTO>
|
||||
<AT25DN256 id="1F4000" page="256" size="32768"/>
|
||||
</ADESTO>
|
||||
<AMIC>
|
||||
<A25L05PT id="372020" page="256" size="65536"/>
|
||||
<A25L05PU id="372010" page="256" size="65536"/>
|
||||
<A25L10PT id="372021" page="256" size="131072"/>
|
||||
<A25L10PU id="372011" page="256" size="131072"/>
|
||||
<A25L20PT id="372022" page="256" size="262144"/>
|
||||
<A25L20PU id="372012" page="256" size="262144"/>
|
||||
<A25L40PT id="372023" page="256" size="524288"/>
|
||||
<A25L40PU id="372013" page="256" size="524288"/>
|
||||
<A25L80PT id="372024" page="256" size="1048576"/>
|
||||
<A25L80PU id="372014" page="256" size="1048576"/>
|
||||
<A25L16PT id="372025" page="256" size="2097152"/>
|
||||
<A25L16PU id="372015" page="256" size="2097152"/>
|
||||
<A25L512 id="373010" page="256" size="65536"/>
|
||||
<A25L010 id="373011" page="256" size="131072"/>
|
||||
<A25L020 id="373012" page="256" size="262144"/>
|
||||
<A25L040 id="373013" page="256" size="524288"/>
|
||||
<A25L080 id="373014" page="256" size="1048576"/>
|
||||
<A25L016 id="373015" page="256" size="2097152"/>
|
||||
<A25L032 id="373016" page="256" size="4194304"/>
|
||||
<A25LQ16 id="374015" page="256" size="2097152"/>
|
||||
<A25LQ32A id="374016" page="256" size="4194304"/>
|
||||
</AMIC>
|
||||
<APLUS>
|
||||
<AF25BC08 page="32" size="1024" spicmd="95"/>
|
||||
<AF25BC16 page="32" size="2048" spicmd="95"/>
|
||||
<AF25BC32 page="32" size="4096" spicmd="95"/>
|
||||
<AF25BC64 page="32" size="8192" spicmd="95"/>
|
||||
<AF25BC128 page="64" size="16384" spicmd="95"/>
|
||||
<AF25BC256 page="64" size="32768" spicmd="95"/>
|
||||
</APLUS>
|
||||
<Boya>
|
||||
<BY25D80 id="684014" page="256" size="1048576"/>
|
||||
</Boya>
|
||||
<CATALYST_CSI>
|
||||
<CAT25010 page="16" size="128" spicmd="95"/>
|
||||
<CAT25020 page="16" size="256" spicmd="95"/>
|
||||
<CAT25040 page="16" size="512" spicmd="95"/>
|
||||
<CAT25080 page="32" size="1024" spicmd="95"/>
|
||||
<CAT25160 page="32" size="2048" spicmd="95"/>
|
||||
<CAT25320 page="32" size="4096" spicmd="95"/>
|
||||
<CAT25640 page="64" size="8192" spicmd="95"/>
|
||||
<CAT25128 page="64" size="16384" spicmd="95"/>
|
||||
<CAT25256 page="64" size="32768" spicmd="95"/>
|
||||
<CAT25C01 page="16" size="128" spicmd="95"/>
|
||||
<CAT25C02 page="16" size="256" spicmd="95"/>
|
||||
<CAT25C03 page="16" size="256" spicmd="95"/>
|
||||
<CAT25C04 page="16" size="512" spicmd="95"/>
|
||||
<CAT25C05 page="16" size="512" spicmd="95"/>
|
||||
<CAT25C08 page="32" size="1024" spicmd="95"/>
|
||||
<CAT25C09 page="32" size="1024" spicmd="95"/>
|
||||
<CAT25C16 page="32" size="2048" spicmd="95"/>
|
||||
<CAT25C17 page="32" size="2048" spicmd="95"/>
|
||||
<CAT25C32 page="32" size="4096" spicmd="95"/>
|
||||
<CAT25C33 page="32" size="4096" spicmd="95"/>
|
||||
<CAT25C64 page="64" size="8192" spicmd="95"/>
|
||||
<CAT25C65 page="64" size="8192" spicmd="95"/>
|
||||
<CAT25C128 page="64" size="16384" spicmd="95"/>
|
||||
<CAT25C256 page="64" size="32768" spicmd="95"/>
|
||||
</CATALYST_CSI>
|
||||
<EON>
|
||||
<EN25B05 id="1C2010" page="256" size="65536"/>
|
||||
<EN25B05T id="1C2010" page="256" size="65536"/>
|
||||
<EN25B10 id="1C2011" page="256" size="131072"/>
|
||||
<EN25B10T id="1C2011" page="256" size="131072"/>
|
||||
<EN25B20 id="1C2012" page="256" size="262144"/>
|
||||
<EN25B20T id="1C2012" page="256" size="262144"/>
|
||||
<EN25B40 id="1C2013" page="256" size="524288"/>
|
||||
<EN25B40T id="1C2013" page="256" size="524288"/>
|
||||
<EN25B80 id="1C2014" page="256" size="1048576"/>
|
||||
<EN25B80T id="1C2014" page="256" size="1048576"/>
|
||||
<EN25B16 id="1C2015" page="256" size="2097152"/>
|
||||
<EN25B16T id="1C2015" page="256" size="2097152"/>
|
||||
<EN25B32 id="1C2016" page="256" size="4194304"/>
|
||||
<EN25B32T id="1C2016" page="256" size="4194304"/>
|
||||
<EN25B64 id="1C2017" page="256" size="8388608"/>
|
||||
<EN25B64T id="1C2017" page="256" size="8388608"/>
|
||||
<EN25F05 id="1C3110" otp="240" page="256" size="65536"/>
|
||||
<EN25F10 id="1C3111" otp="496" page="256" size="131072"/>
|
||||
<EN25F20 id="1C3112" otp="1008" page="256" size="262144"/>
|
||||
<EN25F40 id="1C3113" otp="2032" page="256" size="524288"/>
|
||||
<EN25F80 id="1C3114" otp="4080" page="256" size="1048576"/>
|
||||
<EN25F16 id="1C3115" otp="8176" page="256" size="2097152"/>
|
||||
<EN25F32 id="1C3116" otp="16368" page="256" size="4194304"/>
|
||||
<EN25LF05 id="1C3110" page="256" size="65536"/>
|
||||
<EN25LF10 id="1C3111" page="256" size="131072"/>
|
||||
<EN25LF20 id="1C3112" page="256" size="262144"/>
|
||||
<EN25LF40 id="1C3113" page="256" size="524288"/>
|
||||
<EN25P05 id="1C2010" page="256" size="65536"/>
|
||||
<EN25P10 id="1C2011" page="256" size="131072"/>
|
||||
<EN25P20 id="1C2012" page="256" size="262144"/>
|
||||
<EN25P40 id="1C2013" page="256" size="524288"/>
|
||||
<EN25P80 id="1C2014" page="256" size="1048576"/>
|
||||
<EN25P16 id="1C2015" page="256" size="2097152"/>
|
||||
<EN25P32 id="1C2016" page="256" size="4194304"/>
|
||||
<EN25P64 id="1C2017" page="256" size="8388608"/>
|
||||
<EN25Q40 id="1C3013" otp="2032" page="256" size="524288"/>
|
||||
<EN25Q80A id="1C3014" otp="4080" page="256" size="1048576"/>
|
||||
<EN25Q16A id="1C3015" otp="8176" page="256" size="2097152"/>
|
||||
<EN25Q32A id="1C3016" otp="16368" page="256" size="4194304"/>
|
||||
<EN25Q32A id="1C7016" otp="16368" page="256" size="4194304"/>
|
||||
<EN25Q32B id="1C3016" otp="16368" page="256" size="4194304"/>
|
||||
<EN25Q64 id="1C3017" otp="32752" page="256" size="8388608"/>
|
||||
<EN25Q128 id="1C3018" otp="65520" page="256" size="16777216"/>
|
||||
<EN25QH16 id="1C7015" otp="8176" page="256" size="2097152"/>
|
||||
<EN25QH32 id="1C7016" otp="16368" page="256" size="4194304"/>
|
||||
<EN25QH64 id="1C7017" otp="32752" page="256" size="8388608"/>
|
||||
<EN25QH128 id="1C7018" otp="65520" page="256" size="16777216"/>
|
||||
<EN25QH256 id="1C7019" otp="0" page="256" size="33554432"/>
|
||||
<EN25T80 id="1C5114" otp="4080" page="256" size="1048576"/>
|
||||
<EN25T16 id="1C5115" otp="8176" page="256" size="2097152"/>
|
||||
<EN25F64 id="1C3117" otp="32752" page="256" size="8388608"/>
|
||||
</EON>
|
||||
<PMC>
|
||||
<PM25LD256C id="9D2F" page="256" size="32768"/>
|
||||
<PM25LD512 id="9D20" page="256" size="65536"/>
|
||||
<PM25LD512C id="9D20" page="256" size="65536"/>
|
||||
<PM25LD010 id="9D21" page="256" size="131072"/>
|
||||
<PM25LD010C id="9D21" page="256" size="131072"/>
|
||||
<PM25LD020 id="9D22" page="256" size="262144"/>
|
||||
<PM25LD020C id="9D22" page="256" size="262144"/>
|
||||
<PM25LD040 id="9D7E" page="256" size="524288"/>
|
||||
<PM25LD040C id="9D7E" page="256" size="524288"/>
|
||||
<PM25LV512 id="9D7B" page="256" size="65536"/>
|
||||
<PM25LV512A id="9D7B" page="256" size="65536"/>
|
||||
<PM25LV010 id="9D7C" page="256" size="131072"/>
|
||||
<PM25LV010A id="9D7C" page="256" size="131072"/>
|
||||
<PM25LV020 id="9D7D" page="256" size="262144"/>
|
||||
<PM25LV040 id="9D7E" page="256" size="524288"/>
|
||||
<PM25LV080B id="9D13" page="256" size="1048576"/>
|
||||
<PM25LV016B id="9D14" page="256" size="2097152"/>
|
||||
<PM25WD020 id="9D32" page="256" size="262144"/>
|
||||
<PM25WD040 id="9D33" page="256" size="524288"/>
|
||||
</PMC>
|
||||
<PFLASH>
|
||||
<Pm25LV010 id="7F9D7C" page="256" size="131072"/>
|
||||
<Pm25LD010 id="7F9D21" page="256" size="131072"/>
|
||||
<Pm25LV020 id="7F9D22" page="256" size="262144"/>
|
||||
<Pm25W020 id="7F9D7D" page="256" size="262144"/>
|
||||
<Pm25LV040 id="7F9D7E" page="256" size="524288"/>
|
||||
</PFLASH>
|
||||
<TERRA>
|
||||
<TS25L512A id="373010" page="256" size="65536"/>
|
||||
<TS25L010A id="373011" page="256" size="131072"/>
|
||||
<TS25L020A id="373012" page="256" size="262144"/>
|
||||
<TS25L16AP id="202015" page="256" size="2097152"/>
|
||||
<TS25L16BP id="202015" page="256" size="2097152"/>
|
||||
<ZP25L16P id="202015" page="256" size="2097152"/>
|
||||
<TS25L16PE id="208015" page="256" size="2097152"/>
|
||||
<TS25L80PE id="208014" page="256" size="1048576"/>
|
||||
<TS25L032A id="373016" page="256" size="4194304"/>
|
||||
<TS25L40P id="202013" page="256" size="524288"/>
|
||||
</TERRA>
|
||||
<Generalplus>
|
||||
<GPR25L005E id="C22010" page="256" size="65536"/>
|
||||
<GPR25L161B id="C22015" page="256" size="262144"/>
|
||||
<GPR25L020B id="C22012" page="256" size="262144"/>
|
||||
<GPR25L3203F id="C22016" page="256" size="4194304" script="GPR25L3203F_OTP.pas"/>
|
||||
</Generalplus>
|
||||
<DEUTRON>
|
||||
<AC25LV512 id="9D7B00" page="256" size="65536"/>
|
||||
<AC25LV010 id="9D7C00" page="256" size="131072"/>
|
||||
</DEUTRON>
|
||||
<EFST>
|
||||
<EM25LV512 id="9D7B00" page="256" size="65536"/>
|
||||
<EM25LV010 id="9D7C00" page="256" size="131072"/>
|
||||
<F25L004A id="8C2013" page="256" size="524288"/>
|
||||
<F25L008A id="8C2014" page="256" size="1048576"/>
|
||||
<F25L016A id="8C2015" page="256" size="2097152"/>
|
||||
<F25L04UA id="8C8C8C" page="256" size="524288"/>
|
||||
<F25L04P id="8C2013" page="256" size="524288"/>
|
||||
<F25S04P id="8C3013" page="256" size="524288"/>
|
||||
<F25L08P id="8C2014" page="256" size="1048576"/>
|
||||
<F25L16P id="8C2015" page="256" size="2097152"/>
|
||||
<F25L32P id="8C2016" page="256" size="4194304"/>
|
||||
<F25L32Q id="8C4016" page="256" size="4194304"/>
|
||||
</EFST>
|
||||
<EXCELSEMI>
|
||||
<ES25P10 id="4A2011" page="256" size="131072"/>
|
||||
<ES25P20 id="4A2012" page="256" size="262144"/>
|
||||
<ES25P40 id="4A2013" page="256" size="524288"/>
|
||||
<ES25P80 id="4A2014" page="256" size="1048576"/>
|
||||
<ES25P16 id="4A2015" page="256" size="2097152"/>
|
||||
<ES25P32 id="4A2016" page="256" size="4194304"/>
|
||||
<ES25M40A id="4A3213" page="256" size="524288"/>
|
||||
<ES25M80A id="4A3214" page="256" size="1048576"/>
|
||||
<ES25M16A id="4A3215" page="256" size="2097152"/>
|
||||
</EXCELSEMI>
|
||||
<FIDELIX>
|
||||
<FM25Q08A id="F83214" page="256" size="1048576"/>
|
||||
<FM25Q16A id="F83215" page="256" size="2097152"/>
|
||||
<FM25Q16B id="F83215" page="256" size="2097152"/>
|
||||
<FM25Q32A id="F83216" page="256" size="4194304"/>
|
||||
<FM25Q64A id="F83217" page="256" size="8388608"/>
|
||||
</FIDELIX>
|
||||
<GIANTEC>
|
||||
<GT25C01 page="8" size="128" spicmd="95"/>
|
||||
<GT25C02 page="8" size="256" spicmd="95"/>
|
||||
<GT25C04 page="8" size="512" spicmd="95"/>
|
||||
<GT25C08 page="32" size="1024" spicmd="95"/>
|
||||
<GT25C16 page="32" size="2048" spicmd="95"/>
|
||||
<GT25C32 page="32" size="4096" spicmd="95"/>
|
||||
<GT25C32A page="32" size="4096" spicmd="95"/>
|
||||
<GT25C64 page="32" size="8192" spicmd="95"/>
|
||||
<GT25C128 page="64" size="16384" spicmd="95"/>
|
||||
<GT25C128A page="64" size="16384" spicmd="95"/>
|
||||
<GT25C256 page="64" size="32768" spicmd="95"/>
|
||||
</GIANTEC>
|
||||
<GIGADEVICE>
|
||||
<GD25D40 id="C83013" page="256" size="524288"/>
|
||||
<GD25D80 id="C83014" page="256" size="1048576"/>
|
||||
<GD25F40 id="C82013" page="256" size="524288"/>
|
||||
<GD25F80 id="C82014" page="256" size="1048576"/>
|
||||
<GD25Q512 id="C84010" page="256" size="65536"/>
|
||||
<GD25Q10 id="C84011" page="256" size="131072"/>
|
||||
<GD25Q20 id="C84012" page="256" size="262144"/>
|
||||
<GD25LQ20C_1.8V id="C86012" page="256" size="262144"/>
|
||||
<GD25Q40 id="C84013" page="256" size="524288"/>
|
||||
<GD25Q80 id="C84014" page="256" size="1048576"/>
|
||||
<GD25Q80B id="C84014" page="256" size="1048576"/>
|
||||
<GD25Q80C id="C84014" page="256" size="1048576"/>
|
||||
<GD25Q16 id="C84015" page="256" size="2097152"/>
|
||||
<GD25Q16B id="C84015" page="256" size="2097152"/>
|
||||
<GD25Q32 id="C84016" page="256" size="4194304"/>
|
||||
<GD25Q32B id="C84016" page="256" size="4194304"/>
|
||||
<GD25Q64 id="C84017" page="256" size="8388608"/>
|
||||
<GD25Q64B id="C84017" page="256" size="8388608"/>
|
||||
<GD25B64C id="C84017" page="256" size="8388608"/>
|
||||
<GD25Q128B id="C84018" page="256" size="16777216"/>
|
||||
<GD25Q128C id="C84018" page="256" size="16777216"/>
|
||||
<GD25LQ064C_1.8V id="C86017" page="256" size="8388608"/>
|
||||
<GD25LQ128C_1.8V id="C86018" page="256" size="16777216"/>
|
||||
<GD25LQ256C_1.8V id="C86019" page="256" size="33554432"/>
|
||||
<MD25T80 id="C83114" page="256" size="1048576"/>
|
||||
<MD25D20 id="514012" page="256" size="262144"/>
|
||||
<MD25D40 id="514013" page="256" size="524288"/>
|
||||
<MD25D80 id="514014" page="256" size="1048576"/>
|
||||
<MD25D16 id="514015" page="256" size="2097152"/>
|
||||
</GIGADEVICE>
|
||||
<ICE>
|
||||
<ICE25P05 id="1C2010" page="128" size="65536"/>
|
||||
</ICE>
|
||||
<ICMIC>
|
||||
<X25020 page="4" size="256" spicmd="95"/>
|
||||
<X25021 page="4" size="256" spicmd="95"/>
|
||||
<X25040 page="4" size="512" spicmd="95"/>
|
||||
<X25041 page="4" size="512" spicmd="95"/>
|
||||
<X25080 page="32" size="1024" spicmd="95"/>
|
||||
<X25128 page="32" size="16384" spicmd="95"/>
|
||||
<X25160 page="32" size="2048" spicmd="95"/>
|
||||
<X25170 page="32" size="2048" spicmd="95"/>
|
||||
<X25320 page="32" size="4096" spicmd="95"/>
|
||||
<X25330 page="32" size="4096" spicmd="95"/>
|
||||
<X25640 page="32" size="8192" spicmd="95"/>
|
||||
<X25642 page="32" size="8192" spicmd="95"/>
|
||||
<X25650 page="32" size="8192" spicmd="95"/>
|
||||
</ICMIC>
|
||||
<INTEGRAL>
|
||||
<IN25AA020 page="16" size="256" spicmd="95"/>
|
||||
<IN25AA040 page="16" size="512" spicmd="95"/>
|
||||
<IN25AA080 page="16" size="1024" spicmd="95"/>
|
||||
<IN25AA160 page="16" size="2048" spicmd="95"/>
|
||||
</INTEGRAL>
|
||||
<INTEL>
|
||||
<QB25F016S33B id="898911" page="256" size="2097152"/>
|
||||
<QB25F160S33B id="898911" page="256" size="2097152"/>
|
||||
<QB25F320S33B id="898912" page="256" size="4194304"/>
|
||||
<QB25F640S33B id="898913" page="256" size="8388608"/>
|
||||
<QH25F016S33B id="898911" page="256" size="2097152"/>
|
||||
<QH25F160S33B id="898911" page="256" size="2097152"/>
|
||||
<QH25F320S33B id="898912" page="256" size="4194304"/>
|
||||
</INTEL>
|
||||
<ISSI>
|
||||
<IS25C01 page="8" size="128" spicmd="95"/>
|
||||
<IS25C02 page="16" size="256" spicmd="95"/>
|
||||
<IS25C04 page="16" size="512" spicmd="95"/>
|
||||
<IS25C08 page="16" size="1024" spicmd="95"/>
|
||||
<IS25C16 page="16" size="2048" spicmd="95"/>
|
||||
<IS25C32 page="32" size="4096" spicmd="95"/>
|
||||
<IS25C32A page="32" size="4096" spicmd="95"/>
|
||||
<IS25C64 page="64" size="8192" spicmd="95"/>
|
||||
<IS25C128 page="64" size="16384" spicmd="95"/>
|
||||
<IS25C256 page="64" size="32768" spicmd="95"/>
|
||||
</ISSI>
|
||||
<KHIC>
|
||||
<KH25L1005 id="C22011" page="256" size="131072"/>
|
||||
<KH25L1005A id="C22011" page="256" size="131072"/>
|
||||
<KH25L2005 id="C22012" page="256" size="262144"/>
|
||||
<KH25L4005 id="C22013" page="256" size="524288"/>
|
||||
<KH25L4005A id="C22013" page="256" size="524288"/>
|
||||
<KH25L512 id="C22010" page="256" size="65536"/>
|
||||
<KH25L512A id="C22010" page="256" size="65536"/>
|
||||
<KH25L8005 id="C22014" page="256" size="1048576"/>
|
||||
<KH25L8036D id="C22615" page="256" size="1048576"/>
|
||||
</KHIC>
|
||||
<MACRONIX>
|
||||
<MX25L1005 id="C22011" page="256" size="131072"/>
|
||||
<MX25L1005A id="C22011" page="256" size="131072"/>
|
||||
<MX25L1005C id="C22011" page="256" size="131072"/>
|
||||
<MX25L1006E id="C22011" page="256" size="131072"/>
|
||||
<MX25L1021E id="C22211" page="32" size="131072"/>
|
||||
<MX25L1025C id="C22011" page="256" size="131072"/>
|
||||
<MX25L1026E id="C22011" page="256" size="131072"/>
|
||||
<MX25L12805D id="C22018" page="256" size="16777216"/>
|
||||
<MX25L12835E id="C22018" page="256" size="16777216"/>
|
||||
<MX25L12835F id="C22018" page="256" size="16777216"/>
|
||||
<MX25L12836E id="C22018" page="256" size="16777216"/>
|
||||
<MX25L12839F id="C22018" page="256" size="16777216"/>
|
||||
<MX25L12845E id="C22018" page="256" size="16777216"/>
|
||||
<MX25L12845G id="C22018" page="256" size="16777216"/>
|
||||
<MX25L12845F id="C22018" page="256" size="16777216"/>
|
||||
<MX25L12865E id="C22018" page="256" size="16777216"/>
|
||||
<MX25L12865F id="C22018" page="256" size="16777216"/>
|
||||
<MX25L12873F id="C22018" page="256" size="16777216"/>
|
||||
<MX25L12875F id="C22018" page="256" size="16777216"/>
|
||||
<MX25L25635E id="C22019" page="256" size="33554432"/>
|
||||
<MX25L1605 id="C22015" page="256" size="2097152"/>
|
||||
<MX25L1605A id="C22015" page="256" size="2097152"/>
|
||||
<MX25L1605D id="C22015" page="256" size="2097152"/>
|
||||
<MX25L1606E id="C22015" page="256" size="2097152"/>
|
||||
<MX25L1633E id="C22415" page="256" size="2097152"/>
|
||||
<MX25L1635D id="C22415" page="256" size="2097152"/>
|
||||
<MX25L1635E id="C22515" page="256" size="2097152"/>
|
||||
<MX25L1636D id="C22415" page="256" size="2097152"/>
|
||||
<MX25L1636E id="C22515" page="256" size="2097152"/>
|
||||
<MX25L1673E id="C22415" page="256" size="2097152"/>
|
||||
<MX25L1675E id="C22415" page="256" size="2097152"/>
|
||||
<MX25L2005 id="C22012" page="256" size="262144"/>
|
||||
<MX25L2005C id="C22012" page="256" size="262144"/>
|
||||
<MX25L2006E id="C22012" page="256" size="262144"/>
|
||||
<MX25L2026C id="C22012" page="256" size="262144"/>
|
||||
<MX25L2026E id="C22012" page="256" size="262144"/>
|
||||
<MX25L3205 id="C22016" page="256" size="4194304"/>
|
||||
<MX25L3205A id="C22016" page="256" size="4194304"/>
|
||||
<MX25L3205D id="C22016" page="256" size="4194304"/>
|
||||
<MX25L3206E id="C22016" page="256" size="4194304"/>
|
||||
<MX25L3208E id="C22016" page="256" size="4194304"/>
|
||||
<MX25L3225D id="C25E16" page="256" size="4194304"/>
|
||||
<MX25L3233F id="C22016" page="256" size="4194304"/>
|
||||
<MX25L3235D id="C25E16" page="256" size="4194304"/>
|
||||
<MX25L3235E id="C22016" page="256" size="4194304"/>
|
||||
<MX25L3236D id="C25E16" page="256" size="4194304"/>
|
||||
<MX25L3237D id="C25E16" page="256" size="4194304"/>
|
||||
<MX25L3239E id="C22536" page="256" size="4194304"/>
|
||||
<MX25L3273E id="C22016" page="256" size="4194304"/>
|
||||
<MX25L3273F id="C22016" page="256" size="4194304"/>
|
||||
<MX25L3275E id="C22016" page="256" size="4194304"/>
|
||||
<MX25L4005 id="C22013" page="256" size="524288"/>
|
||||
<MX25L4005A id="C22013" page="256" size="524288"/>
|
||||
<MX25L4005C id="C22013" page="256" size="524288"/>
|
||||
<MX25L4006E id="C22013" page="256" size="524288"/>
|
||||
<MX25L4026E id="C22013" page="256" size="524288"/>
|
||||
<MX25L512 id="C22010" page="256" size="65536"/>
|
||||
<MX25L512A id="C22010" page="256" size="65536"/>
|
||||
<MX25L512C id="C22010" page="256" size="65536"/>
|
||||
<MX25L5121E id="C22210" page="32" size="65536"/>
|
||||
<MX25L6405 id="C22017" page="256" size="8388608"/>
|
||||
<MX25L6405D id="C22017" page="256" size="8388608"/>
|
||||
<MX25L6406E id="C22017" page="256" size="8388608"/>
|
||||
<MX25L6408E id="C22017" page="256" size="8388608"/>
|
||||
<MX25L6433F id="C22017" page="256" size="8388608"/>
|
||||
<MX25L6435E id="C22017" page="256" size="8388608"/>
|
||||
<MX25L6436E id="C22017" page="256" size="8388608"/>
|
||||
<MX25L6436F id="C22017" page="256" size="8388608"/>
|
||||
<MX25L6439E id="C22537" page="256" size="8388608"/>
|
||||
<MX25L6445E id="C22017" page="256" size="8388608"/>
|
||||
<MX25L6465E id="C22017" page="256" size="8388608"/>
|
||||
<MX25L6473E id="C22017" page="256" size="8388608"/>
|
||||
<MX25L6473F id="C22017" page="256" size="8388608"/>
|
||||
<MX25L6475E id="C22017" page="256" size="8388608"/>
|
||||
<MX25L8005 id="C22014" page="256" size="1048576"/>
|
||||
<MX25L8006E id="C22014" page="256" size="1048576"/>
|
||||
<MX25L8008E id="C22014" page="256" size="1048576"/>
|
||||
<MX25L8035E id="C22014" page="256" size="1048576"/>
|
||||
<MX25L8036E id="C22014" page="256" size="1048576"/>
|
||||
<MX25L8073E id="C22014" page="256" size="1048576"/>
|
||||
<MX25L8075E id="C22014" page="256" size="1048576"/>
|
||||
<MX25L25673G id="C22019" page="256" size="33554432"/>
|
||||
<MX25R512F id="C22810" page="256" size="65536"/>
|
||||
<MX25R1035F id="C22811" page="256" size="131072"/>
|
||||
<MX25R1635F id="C22815" page="256" size="2097152"/>
|
||||
<MX25R2035F id="C22812" page="256" size="262144"/>
|
||||
<MX25R3235F id="C22816" page="256" size="4194304"/>
|
||||
<MX25R4035F id="C22813" page="256" size="524288"/>
|
||||
<MX25R6435F id="C22817" page="256" size="8388608"/>
|
||||
<MX25R8035F id="C22814" page="256" size="1048576"/>
|
||||
<MX25U1001E_1.8V id="C22531" page="256" size="131072"/>
|
||||
<MX25U12835F_1.8V id="C22518" page="256" size="16777216"/>
|
||||
<MX25U25673G_1.8V id="C22539" page="256" size="33554432"/>
|
||||
<MX25U25645G_1.8V id="C22539" page="256" size="33554432"/>
|
||||
<MX25U1635E_1.8V id="C22535" page="256" size="2097152"/>
|
||||
<MX25U1635F_1.8V id="C22535" page="256" size="2097152"/>
|
||||
<MX25U2032E_1.8V id="C22532" page="256" size="262144"/>
|
||||
<MX25U2033E_1.8V id="C22532" page="256" size="262144"/>
|
||||
<MX25U3235E_1.8V id="C22536" page="256" size="4194304"/>
|
||||
<MX25U3235F_1.8V id="C22536" page="256" size="4194304"/>
|
||||
<MX25U4032E_1.8V id="C22533" page="256" size="524288"/>
|
||||
<MX25U4033E_1.8V id="C22533" page="256" size="524288"/>
|
||||
<MX25U4035_1.8V id="C22533" page="256" size="524288"/>
|
||||
<MX25U5121E_1.8V id="C22530" page="256" size="65536"/>
|
||||
<MX25U6435F_1.8V id="C22537" page="256" size="8388608"/>
|
||||
<MX25U6473F_1.8V id="C22537" page="256" size="8388608"/>
|
||||
<MX25U8032E_1.8V id="C22534" page="256" size="1048576"/>
|
||||
<MX25U8033E_1.8V id="C22534" page="256" size="1048576"/>
|
||||
<MX25U8035_1.8V id="C22534" page="256" size="1048576"/>
|
||||
<MX25U8035E_1.8V id="C22534" page="256" size="1048576"/>
|
||||
<MX25U12873F_1.8V id="C22538" page="256" size="16777216"/>
|
||||
<MX25V1006E id="C22011" page="256" size="131072"/>
|
||||
<MX25V1035F id="C22311" page="256" size="131072"/>
|
||||
<MX25V2006E id="C22012" page="256" size="262144"/>
|
||||
<MX25V2035F id="C22312" page="256" size="262144"/>
|
||||
<MX25V512 id="C22010" page="256" size="65536"/>
|
||||
<MX25V512C id="C22010" page="256" size="65536"/>
|
||||
<MX25V512E id="C22010" page="256" size="65536"/>
|
||||
<MX25V512F id="C22310" page="256" size="65536"/>
|
||||
<MX25V4005 id="C22013" page="256" size="524288"/>
|
||||
<MX25V4006E id="C22013" page="256" size="524288"/>
|
||||
<MX25V4035 id="C22553" page="256" size="524288"/>
|
||||
<MX25V4035F id="C22313" page="256" size="524288"/>
|
||||
<MX25V8005 id="C22014" page="256" size="1048576"/>
|
||||
<MX25V8006E id="C22014" page="256" size="1048576"/>
|
||||
<MX25V8035 id="C22554" page="256" size="1048576"/>
|
||||
<MX25V8035F id="C22314" page="256" size="1048576"/>
|
||||
<MX66U51235F_1.8V id="C2253A" page="256" size="67108864"/>
|
||||
<MX66U1G45G_1.8V id="C2253B" page="256" size="134217728"/>
|
||||
</MACRONIX>
|
||||
<MICROCHIP>
|
||||
<_25AA010A page="16" size="128" spicmd="95"/>
|
||||
<_25AA020A page="16" size="256" spicmd="95"/>
|
||||
<_25AA040 page="16" size="512" spicmd="95"/>
|
||||
<_25AA040A page="16" size="512" spicmd="95"/>
|
||||
<_25AA080 page="16" size="1024" spicmd="95"/>
|
||||
<_25AA080A page="16" size="1024" spicmd="95"/>
|
||||
<_25AA080B page="32" size="1024" spicmd="95"/>
|
||||
<_25AA080C page="16" size="1024" spicmd="95"/>
|
||||
<_25AA080D page="32" size="1024" spicmd="95"/>
|
||||
<_25AA1024 page="256" size="131072" spicmd="95"/>
|
||||
<_25AA128 page="64" size="16384" spicmd="95"/>
|
||||
<_25AA160 page="16" size="2048" spicmd="95"/>
|
||||
<_25AA160A page="16" size="2048" spicmd="95"/>
|
||||
<_25AA160B page="32" size="2048" spicmd="95"/>
|
||||
<_25AA256 page="64" size="32768" spicmd="95"/>
|
||||
<_25AA320 page="32" size="4096" spicmd="95"/>
|
||||
<_25AA512 page="128" size="65536" spicmd="95"/>
|
||||
<_25AA640 page="32" size="8192" spicmd="95"/>
|
||||
<_25C040 page="16" size="512" spicmd="95"/>
|
||||
<_25C080 page="16" size="1024" spicmd="95"/>
|
||||
<_25C160 page="16" size="2048" spicmd="95"/>
|
||||
<_25C320 page="32" size="4096" spicmd="95"/>
|
||||
<_25C640 page="32" size="8192" spicmd="95"/>
|
||||
<_25LC010A page="16" size="128" spicmd="95"/>
|
||||
<_25LC020A page="16" size="256" spicmd="95"/>
|
||||
<_25LC040 page="16" size="512" spicmd="95"/>
|
||||
<_25LC040A page="16" size="512" spicmd="95"/>
|
||||
<_25LC080 page="16" size="1024" spicmd="95"/>
|
||||
<_25LC080A page="16" size="1024" spicmd="95"/>
|
||||
<_25LC080B page="32" size="1024" spicmd="95"/>
|
||||
<_25LC080C page="16" size="1024" spicmd="95"/>
|
||||
<_25LC080D page="32" size="1024" spicmd="95"/>
|
||||
<_25LC1024 page="256" size="131072" spicmd="95"/>
|
||||
<_25LC128 page="64" size="16384" spicmd="95"/>
|
||||
<_25LC160 page="16" size="2048" spicmd="95"/>
|
||||
<_25LC160A page="16" size="2048" spicmd="95"/>
|
||||
<_25LC160B page="32" size="2048" spicmd="95"/>
|
||||
<_25LC256 page="64" size="32768" spicmd="95"/>
|
||||
<_25LC320 page="32" size="4096" spicmd="95"/>
|
||||
<_25LC512 page="128" size="65536" spicmd="95"/>
|
||||
<_25LC640 page="32" size="8192" spicmd="95"/>
|
||||
</MICROCHIP>
|
||||
<MICRON>
|
||||
<N25Q032A id="20BA16" page="256" size="4194304"/>
|
||||
<N25Q064A id="20BA17" page="256" size="8388608"/>
|
||||
<N25Q256A13 id="20BA19" page="256" size="33554432"/>
|
||||
<N25Q512A83 id="20BA20" page="256" size="67108864"/>
|
||||
<N25W256A11 id="2CCB19" page="256" size="33554432"/>
|
||||
<MT25QL128AB id="20BA18" page="256" size="16777216"/>
|
||||
<MT25QL256A id="20BA19" page="256" size="33554432"/>
|
||||
<MT25QL512A id="20BA20" page="256" size="67108864"/>
|
||||
<MT25QL02GC id="20BA22" page="256" size="268435456"/>
|
||||
<MT25QU256 id="20BB19" page="256" size="33554432"/>
|
||||
<N25Q00AA13G id="20BA21" page="256" size="134217728"/>
|
||||
</MICRON>
|
||||
<MSHINE>
|
||||
<MS25X512 id="373010" page="256" size="65536"/>
|
||||
<MS25X10 id="373011" page="256" size="131072"/>
|
||||
<MS25X20 id="373012" page="256" size="262144"/>
|
||||
<MS25X40 id="373013" page="256" size="524288"/>
|
||||
<MS25X80 id="373014" page="256" size="1048576"/>
|
||||
<MS25X16 id="373015" page="256" size="2097152"/>
|
||||
<MS25X32 id="373016" page="256" size="4194304"/>
|
||||
</MSHINE>
|
||||
<NANTRONICS>
|
||||
<N25S10 id="D53011" page="256" size="131072"/>
|
||||
<N25S20 id="D53012" page="256" size="262144"/>
|
||||
<N25S40 id="D53013" page="256" size="524288"/>
|
||||
<N25S16 id="D53015" page="256" size="2097152"/>
|
||||
<N25S32 id="D53016" page="256" size="4194304"/>
|
||||
<N25S80 id="D53014" page="256" size="1048576"/>
|
||||
</NANTRONICS>
|
||||
<NEXFLASH>
|
||||
<NX25P10 id="9D7F7C" page="256" size="131072"/>
|
||||
<NX25P16 id="EF2015" page="256" size="2097152"/>
|
||||
<NX25P20 id="9D7F7D" page="256" size="262144"/>
|
||||
<NX25P32 id="EF2016" page="256" size="4194304"/>
|
||||
<NX25P40 id="9D7F7E" page="256" size="524288"/>
|
||||
<NX25P80 id="9D7F13" page="256" size="1048576"/>
|
||||
</NEXFLASH>
|
||||
<NUMONYX>
|
||||
<M45PE16 id="204015" page="256" size="2097152" script="blockerase.pas"/>
|
||||
<M25P05 id="202010" page="128" size="65536"/>
|
||||
<M25P05A id="202010" page="256" size="65536"/>
|
||||
<M25P10 id="202011" page="128" size="131072"/>
|
||||
<M25P10A id="202011" page="256" size="131072"/>
|
||||
<M25P20 id="202012" page="256" size="262144"/>
|
||||
<M25P40 id="202013" page="256" size="524288"/>
|
||||
<M25P80 id="202014" page="256" size="1048576"/>
|
||||
<M25P16 id="202015" page="256" size="2097152"/>
|
||||
<M25P32 id="202016" page="256" size="4194304"/>
|
||||
<M25P64 id="202017" page="256" size="8388608"/>
|
||||
<M25P128_ST25P28V6G id="202018" page="256" size="16777216"/>
|
||||
<M25PE10 id="208011" page="256" size="131072"/>
|
||||
<M25PE16 id="208015" page="256" size="2097152"/>
|
||||
<M25PE20 id="208012" page="256" size="262144"/>
|
||||
<M25PE40 id="208013" page="256" size="524288"/>
|
||||
<M25PE80 id="208014" page="256" size="1048576"/>
|
||||
</NUMONYX>
|
||||
<PCT>
|
||||
<PCT25LF020A id="BF4300" page="256" size="262144"/>
|
||||
<PCT25VF010A id="BF4900" page="256" size="131072"/>
|
||||
<PCT25VF016B id="BF2541" page="256" size="2097152"/>
|
||||
<PCT25VF020A id="BF4300" page="256" size="262144"/>
|
||||
<PCT25VF032B id="BF254A" page="256" size="4194304"/>
|
||||
<PCT25VF040A id="BF4400" page="256" size="524288"/>
|
||||
<PCT25VF040B id="BF258D" page="256" size="524288"/>
|
||||
<PCT25VF080B id="BF258E" page="256" size="1048576"/>
|
||||
</PCT>
|
||||
<RAMTRON>
|
||||
<FM25040 page="32" size="512" spicmd="95"/>
|
||||
<FM25C160 page="32" size="2048" spicmd="95"/>
|
||||
<FM25640 page="32" size="8192" spicmd="95"/>
|
||||
<FM25CL04 page="32" size="512" spicmd="95"/>
|
||||
<FM25CL64 page="32" size="8192" spicmd="95"/>
|
||||
<FM25L16 page="32" size="2048" spicmd="95"/>
|
||||
<FM25L256 page="32" size="32768" spicmd="95"/>
|
||||
<FM25L512 page="32" size="65536" spicmd="95"/>
|
||||
<FM25W256 page="32" size="32768" spicmd="95"/>
|
||||
</RAMTRON>
|
||||
<RENESAS>
|
||||
<HN58X2502 page="16" size="256" spicmd="95"/>
|
||||
<HN58X2504 page="16" size="512" spicmd="95"/>
|
||||
<HN58X2508 page="16" size="1024" spicmd="95"/>
|
||||
<HN58X25128 page="64" size="16384" spicmd="95"/>
|
||||
<HN58X2516 page="16" size="2048" spicmd="95"/>
|
||||
<HN58X25256 page="64" size="32768" spicmd="95"/>
|
||||
<HN58X2532 page="32" size="4096" spicmd="95"/>
|
||||
<HN58X2564 page="32" size="8192" spicmd="95"/>
|
||||
<R1EX25002A page="16" size="256" spicmd="95"/>
|
||||
<R1EX25004A page="16" size="512" spicmd="95"/>
|
||||
<R1EX25008A page="16" size="1024" spicmd="95"/>
|
||||
<R1EX25016A page="16" size="2048" spicmd="95"/>
|
||||
<R1EX25032A page="32" size="4096" spicmd="95"/>
|
||||
<R1EX25064A page="32" size="8192" spicmd="95"/>
|
||||
</RENESAS>
|
||||
<ROHM>
|
||||
<BR25010 page="16" size="128" spicmd="95"/>
|
||||
<BR25020 page="16" size="256" spicmd="95"/>
|
||||
<BR25040 page="16" size="512" spicmd="95"/>
|
||||
<BR25080 page="16" size="1024" spicmd="95"/>
|
||||
<BR25160 page="16" size="2048" spicmd="95"/>
|
||||
<BR25320 page="32" size="4096" spicmd="95"/>
|
||||
<BR25H010 page="16" size="128" spicmd="95"/>
|
||||
<BR25H020 page="16" size="256" spicmd="95"/>
|
||||
<BR25H040 page="16" size="512" spicmd="95"/>
|
||||
<BR25H080 page="16" size="1024" spicmd="95"/>
|
||||
<BR25H160 page="16" size="2048" spicmd="95"/>
|
||||
<BR25H320 page="32" size="4096" spicmd="95"/>
|
||||
<BR25L010 page="16" size="128" spicmd="95"/>
|
||||
<BR25L010 page="16" size="128" spicmd="95"/>
|
||||
<BR25L020 page="16" size="256" spicmd="95"/>
|
||||
<BR25L040 page="16" size="512" spicmd="95"/>
|
||||
<BR25L080 page="16" size="1024" spicmd="95"/>
|
||||
<BR25L160 page="16" size="2048" spicmd="95"/>
|
||||
<BR25L320 page="32" size="4096" spicmd="95"/>
|
||||
<BR25L640 page="32" size="8192" spicmd="95"/>
|
||||
<BR25S320 page="32" size="4096" spicmd="95"/>
|
||||
<BR25S640 page="32" size="8192" spicmd="95"/>
|
||||
<BR25S128 page="64" size="16384" spicmd="95"/>
|
||||
<BR25S256 page="64" size="32768" spicmd="95"/>
|
||||
<BR95010 page="8" size="128" spicmd="95"/>
|
||||
<BR95020 page="8" size="256" spicmd="95"/>
|
||||
<BR95040 page="8" size="512" spicmd="95"/>
|
||||
<BR95080 page="32" size="1024" spicmd="95"/>
|
||||
<BR95160 page="32" size="2048" spicmd="95"/>
|
||||
</ROHM>
|
||||
<SAIFUN>
|
||||
<SA25C1024H page="128" size="131072" spicmd="95"/>
|
||||
<SA25C1024L page="128" size="131072" spicmd="95"/>
|
||||
<SA25C512H page="128" size="65536" spicmd="95"/>
|
||||
<SA25C512L page="128" size="65536" spicmd="95"/>
|
||||
</SAIFUN>
|
||||
<SANYO>
|
||||
<LE25FU106BMA id="621D" page="256" size="131072"/>
|
||||
<LE25FU206MA id="6244" page="256" size="262144"/>
|
||||
<LE25FU406BMA id="621E" page="256" size="524288"/>
|
||||
<LE25FW206M id="6226" page="256" size="262144"/>
|
||||
<LE25FW406M id="6207" page="256" size="524288"/>
|
||||
<LE25FW406AM id="621A" page="256" size="524288"/>
|
||||
<LE25FW806M id="6226" page="256" size="1048576"/>
|
||||
</SANYO>
|
||||
<SEIKO>
|
||||
<S-25A010A page="8" size="128" spicmd="95"/>
|
||||
<S-25A020A page="8" size="256" spicmd="95"/>
|
||||
<S-25A040A page="8" size="512" spicmd="95"/>
|
||||
<S-25A080A page="32" size="1024" spicmd="95"/>
|
||||
<S-25A160A page="32" size="2048" spicmd="95"/>
|
||||
<S-25A320A page="32" size="4096" spicmd="95"/>
|
||||
<S-25A640A page="32" size="8192" spicmd="95"/>
|
||||
<S-25C010A page="8" size="128" spicmd="95"/>
|
||||
<S-25C020A page="8" size="256" spicmd="95"/>
|
||||
<S-25C040A page="8" size="512" spicmd="95"/>
|
||||
<S-25C080A page="32" size="1024" spicmd="95"/>
|
||||
<S-25C160A page="32" size="2048" spicmd="95"/>
|
||||
<S-25C320A page="32" size="4096" spicmd="95"/>
|
||||
<S-25C640A page="32" size="8192" spicmd="95"/>
|
||||
</SEIKO>
|
||||
<SIEMENS>
|
||||
<SLA25010 page="16" size="128" spicmd="95"/>
|
||||
<SLA25020 page="16" size="256" spicmd="95"/>
|
||||
<SLA25040 page="16" size="512" spicmd="95"/>
|
||||
<SLA25080 page="32" size="1024" spicmd="95"/>
|
||||
<SLA25160 page="32" size="2048" spicmd="95"/>
|
||||
<SLA25320 page="32" size="4096" spicmd="95"/>
|
||||
<SLE25010 page="16" size="128" spicmd="95"/>
|
||||
<SLE25020 page="16" size="256" spicmd="95"/>
|
||||
<SLE25040 page="16" size="512" spicmd="95"/>
|
||||
<SLE25080 page="32" size="1024" spicmd="95"/>
|
||||
<SLE25160 page="32" size="2048" spicmd="95"/>
|
||||
<SLE25320 page="32" size="4096" spicmd="95"/>
|
||||
</SIEMENS>
|
||||
<SPANSION>
|
||||
<S25FL001D id="010210" page="256" size="131072"/>
|
||||
<S25FL002D id="010211" page="256" size="262144"/>
|
||||
<S25FL004A id="010212" page="256" size="524288"/>
|
||||
<S25FL004D id="010212" page="256" size="524288"/>
|
||||
<S25FL004K id="EF4013" page="256" size="524288"/>
|
||||
<S25FL008A id="010213" page="256" size="1048576"/>
|
||||
<S25FL008D id="010213" page="256" size="1048576"/>
|
||||
<S25FL008K id="EF4014" page="256" size="1048576"/>
|
||||
<S25FL016A id="010214" page="256" size="2097152"/>
|
||||
<S25FL016K id="EF4015" page="256" size="2097152"/>
|
||||
<S25FL032A id="010215" page="256" size="4194304"/>
|
||||
<S25FL032K id="EF4016" page="256" size="4194304"/>
|
||||
<S25FL032P id="010215" page="256" size="4194304"/>
|
||||
<S25FL040A id="010212" page="256" size="524288"/>
|
||||
<S25FL040A_BOT id="010226" page="256" size="524288"/>
|
||||
<S25FL040A_TOP id="010225" page="256" size="524288"/>
|
||||
<S25FL064A id="010216" page="256" size="8388608"/>
|
||||
<S25FL064K id="EF4017" page="256" size="8388608"/>
|
||||
<S25FL064P id="010216" page="256" size="8388608"/>
|
||||
<S25FL116K id="014015" page="256" size="2097152"/>
|
||||
<S25FL128K id="EF4018" page="256" size="16777216"/>
|
||||
<S25FL128P id="012018" page="256" size="16777216"/>
|
||||
<S25FL128S id="012018" page="256" size="16777216"/>
|
||||
<S25FL132K id="014016" page="256" size="4194304"/>
|
||||
<S25FL164K id="014017" page="256" size="8388608"/>
|
||||
<S25FL256S id="010219" page="256" size="33554432"/>
|
||||
</SPANSION>
|
||||
<SST>
|
||||
<SST25LF020A id="BF43" page="SSTB" size="262144"/>
|
||||
<SST25LF040A id="BF44" page="SSTB" size="524288"/>
|
||||
<SST25LF080A id="BF80" page="SSTB" size="1048576"/>
|
||||
<SST25VF010 id="BF49" page="SSTB" size="131072"/>
|
||||
<SST25VF010A id="BF49" page="SSTB" size="131072"/>
|
||||
<SST25VF016B id="BF2541" page="SSTW" size="2097152"/>
|
||||
<SST25VF020 id="BF43" page="SSTB" size="262144"/>
|
||||
<SST25VF020A id="BF43" page="SSTB" size="262144"/>
|
||||
<SST25VF020B id="BF258C" page="SSTW" size="262144"/>
|
||||
<SST25VF032B id="BF254A" page="SSTW" size="4194304"/>
|
||||
<SST25VF064C id="BF254B" page="256" size="8388608"/>
|
||||
<SST25VF040 id="BF44" page="SSTB" size="524288"/>
|
||||
<SST25VF040A id="BF44" page="SSTB" size="524288"/>
|
||||
<SST25VF040B id="BF258D" page="SSTW" size="524288"/>
|
||||
<SST25VF080B id="BF258E" page="SSTW" size="1048576"/>
|
||||
<SST25VF512 id="BF48" page="SSTB" size="65536"/>
|
||||
<SST25VF512A id="BF48" page="SSTB" size="65536"/>
|
||||
</SST>
|
||||
<ST>
|
||||
<M25C16 page="16" size="2048" spicmd="95"/>
|
||||
<M25PX16 id="207115" page="256" size="2097152"/>
|
||||
<M25PX32 id="207116" page="256" size="4194304"/>
|
||||
<M25PX64 id="207117" page="256" size="8388608"/>
|
||||
<M25PX80 id="207114" page="256" size="1048576"/>
|
||||
<M25W16 page="16" size="2048" spicmd="95"/>
|
||||
<M35080-3 page="32" size="1024" spicmd="95"/>
|
||||
<M35080-6 page="32" size="1024" spicmd="95"/>
|
||||
<M35080V6 page="32" size="1024" spicmd="95"/>
|
||||
<M35080VP page="32" size="1024" spicmd="95"/>
|
||||
<M95010 page="8" size="128" spicmd="95"/>
|
||||
<M95010R page="8" size="128" spicmd="95"/>
|
||||
<M95010W page="8" size="128" spicmd="95"/>
|
||||
<M95020 page="8" size="256" spicmd="95"/>
|
||||
<M95020R page="8" size="256" spicmd="95"/>
|
||||
<M95020W page="8" size="256" spicmd="95"/>
|
||||
<M95040 page="8" size="512" spicmd="95"/>
|
||||
<M95040R page="8" size="512" spicmd="95"/>
|
||||
<M95040W page="8" size="512" spicmd="95"/>
|
||||
<M95080 page="32" size="1024" spicmd="95"/>
|
||||
<M95080R page="32" size="1024" spicmd="95"/>
|
||||
<M95080W page="32" size="1024" spicmd="95"/>
|
||||
<M95128 page="64" size="16384" spicmd="95"/>
|
||||
<M95128R page="64" size="16384" spicmd="95"/>
|
||||
<M95128W page="64" size="16384" spicmd="95"/>
|
||||
<M95160 page="32" size="2048" spicmd="95"/>
|
||||
<M95160R page="32" size="2048" spicmd="95"/>
|
||||
<M95160W page="32" size="2048" spicmd="95"/>
|
||||
<M95256 page="64" size="32768" spicmd="95"/>
|
||||
<M95256R page="64" size="32768" spicmd="95"/>
|
||||
<M95256W page="64" size="32768" spicmd="95"/>
|
||||
<M95320 page="32" size="4096" spicmd="95"/>
|
||||
<M95320R page="32" size="4096" spicmd="95"/>
|
||||
<M95320W page="32" size="4096" spicmd="95"/>
|
||||
<M95512R page="128" size="65536" spicmd="95"/>
|
||||
<M95512W page="128" size="65536" spicmd="95"/>
|
||||
<M95640 page="32" size="8192" spicmd="95"/>
|
||||
<M95640R page="32" size="8192" spicmd="95"/>
|
||||
<M95640W page="32" size="8192" spicmd="95"/>
|
||||
<M95M01R page="256" size="131072" spicmd="95"/>
|
||||
<M95M01W page="256" size="131072" spicmd="95"/>
|
||||
<ST25C16 page="16" size="2048" spicmd="95"/>
|
||||
<ST25P05 id="202010" page="128" size="65536"/>
|
||||
<ST25P05A id="202010" page="256" size="65536"/>
|
||||
<ST25P10 id="202011" page="128" size="131072"/>
|
||||
<ST25P10A id="202011" page="256" size="131072"/>
|
||||
<ST25P16 id="202015" page="256" size="2097152"/>
|
||||
<ST25P20 id="202012" page="256" size="262144"/>
|
||||
<ST25P32 id="202016" page="256" size="4194304"/>
|
||||
<ST25P40 id="202013" page="256" size="524288"/>
|
||||
<ST25P64 id="202017" page="256" size="8388608"/>
|
||||
<ST25P80 id="202014" page="256" size="1048576"/>
|
||||
</ST>
|
||||
<WINBOND>
|
||||
<W25P10 id="EF1000" page="256" size="131072"/>
|
||||
<W25P16 id="EF2015" page="256" size="2097152"/>
|
||||
<W25P20 id="EF1100" page="256" size="262144"/>
|
||||
<W25P32 id="EF2016" page="256" size="4194304"/>
|
||||
<W25P40 id="EF1200" page="256" size="524288"/>
|
||||
<W25P64 id="EF2017" page="256" size="8388608"/>
|
||||
<W25P80 id="EF2014" page="256" size="1048576"/>
|
||||
<W25Q10EW_1.8V id="EF6011" page="256" size="131072"/>
|
||||
<W25Q128BV id="EF4018" page="256" size="16777216"/>
|
||||
<W25Q128FV id="EF4018" page="256" size="16777216"/>
|
||||
<W25Q128JV id="EF7018" page="256" size="16777216"/>
|
||||
<W25Q256FV id="EF4019" page="256" size="33554432"/>
|
||||
<W25Q256JV id="EF4019" page="256" size="33554432"/>
|
||||
<W25Q256JV id="EF7019" page="256" size="33554432"/>
|
||||
<W25Q128FW_1.8V id="EF6018" page="256" size="16777216"/>
|
||||
<W25Q16 id="EF4015" page="256" size="2097152"/>
|
||||
<W25Q16BV id="EF4015" page="256" size="2097152"/>
|
||||
<W25Q16CL id="EF4015" page="256" size="2097152"/>
|
||||
<W25Q16CV id="EF4015" page="256" size="2097152"/>
|
||||
<W25Q16DV id="EF4015" page="256" size="2097152"/>
|
||||
<W25Q16FW_1.8V id="EF6015" page="256" size="2097152"/>
|
||||
<W25Q16V id="EF4015" page="256" size="2097152"/>
|
||||
<W25Q20CL id="EF4012" page="256" size="262144"/>
|
||||
<W25Q20EW_1.8V id="EF6012" page="256" size="262144"/>
|
||||
<W25Q32 id="EF4016" page="256" size="4194304"/>
|
||||
<W25Q32BV id="EF4016" page="256" size="4194304"/>
|
||||
<W25Q32FV id="EF4016" page="256" size="4194304"/>
|
||||
<W25Q32FW_1.8V id="EF6016" page="256" size="4194304"/>
|
||||
<W25Q32V id="EF4016" page="256" size="4194304"/>
|
||||
<W25Q40BL id="EF4013" page="256" size="524288"/>
|
||||
<W25Q40BV id="EF4013" page="256" size="524288"/>
|
||||
<W25Q40CL id="EF4013" page="256" size="524288"/>
|
||||
<W25Q40EW_1.8V id="EF6013" page="256" size="524288"/>
|
||||
<W25Q64BV id="EF4017" page="256" size="8388608"/>
|
||||
<W25Q64CV id="EF4017" page="256" size="8388608"/>
|
||||
<W25Q64FV id="EF4017" page="256" size="8388608"/>
|
||||
<W25Q64JV id="EF4017" page="256" size="8388608"/>
|
||||
<W25Q64FW_1.8V id="EF6017" page="256" size="8388608"/>
|
||||
<W25Q80BL id="EF4014" page="256" size="1048576"/>
|
||||
<W25Q80BV id="EF4014" page="256" size="1048576"/>
|
||||
<W25Q80BW_1.8V id="EF5014" page="256" size="1048576"/>
|
||||
<W25Q80DV id="EF4014" page="256" size="1048576"/>
|
||||
<W25Q80EW_1.8V id="EF6014" page="256" size="1048576"/>
|
||||
<W25X05 id="EF3010" page="256" size="65536"/>
|
||||
<W25X05CL id="EF3010" page="256" size="65536"/>
|
||||
<W25X10AV id="EF3011" page="256" size="131072"/>
|
||||
<W25X10BL id="EF3011" page="256" size="131072"/>
|
||||
<W25X10BV id="EF3011" page="256" size="131072"/>
|
||||
<W25X10CL id="EF3011" page="256" size="131072"/>
|
||||
<W25X10L id="EF3011" page="256" size="131072"/>
|
||||
<W25X10V id="EF3011" page="256" size="131072"/>
|
||||
<W25X16 id="EF3015" page="256" size="2097152"/>
|
||||
<W25X16AL id="EF3015" page="256" size="2097152"/>
|
||||
<W25X16AV id="EF3015" page="256" size="2097152"/>
|
||||
<W25X16BV id="EF3015" page="256" size="2097152"/>
|
||||
<W25X16V id="EF3015" page="256" size="2097152"/>
|
||||
<W25X20AL id="EF3012" page="256" size="262144"/>
|
||||
<W25X20AV id="EF3012" page="256" size="262144"/>
|
||||
<W25X20BL id="EF3012" page="256" size="262144"/>
|
||||
<W25X20BV id="EF3012" page="256" size="262144"/>
|
||||
<W25X20CL id="EF3012" page="256" size="262144"/>
|
||||
<W25X20L id="EF3012" page="256" size="262144"/>
|
||||
<W25X20V id="EF3012" page="256" size="262144"/>
|
||||
<W25X32 id="EF3016" page="256" size="4194304"/>
|
||||
<W25X32AV id="EF3016" page="256" size="4194304"/>
|
||||
<W25X32BV id="EF3016" page="256" size="4194304"/>
|
||||
<W25X32V id="EF3016" page="256" size="4194304"/>
|
||||
<W25X40AL id="EF3013" page="256" size="524288"/>
|
||||
<W25X40AV id="EF3013" page="256" size="524288"/>
|
||||
<W25X40BL id="EF3013" page="256" size="524288"/>
|
||||
<W25X40BV id="EF3013" page="256" size="524288"/>
|
||||
<W25X40CL id="EF3013" page="256" size="524288"/>
|
||||
<W25X40L id="EF3013" page="256" size="524288"/>
|
||||
<W25X40V id="EF3013" page="256" size="524288"/>
|
||||
<W25X64 id="EF3017" page="256" size="8388608"/>
|
||||
<W25X64BV id="EF3017" page="256" size="8388608"/>
|
||||
<W25X64V id="EF3017" page="256" size="8388608"/>
|
||||
<W25X80AL id="EF3014" page="256" size="1048576"/>
|
||||
<W25X80AV id="EF3014" page="256" size="1048576"/>
|
||||
<W25X80BV id="EF3014" page="256" size="1048576"/>
|
||||
<W25X80L id="EF3014" page="256" size="1048576"/>
|
||||
<W25X80V id="EF3014" page="256" size="1048576"/>
|
||||
<W25M512JV id="EF7119" page="256" size="67108864"/>
|
||||
<W25R256JV id="EF4019" page="256" size="33554432"/>
|
||||
</WINBOND>
|
||||
<XICOR>
|
||||
<X25010 page="4" size="128" spicmd="95"/>
|
||||
<X25043 page="4" size="512" spicmd="95"/>
|
||||
<X25045 page="4" size="512" spicmd="95"/>
|
||||
<X25F008 page="32" size="1024" spicmd="95"/>
|
||||
<X25F016 page="32" size="2048" spicmd="95"/>
|
||||
<X25F032 page="32" size="4096" spicmd="95"/>
|
||||
<X25F064 page="32" size="8192" spicmd="95"/>
|
||||
<X5043 page="16" size="512" spicmd="95"/>
|
||||
<X5045 page="16" size="512" spicmd="95"/>
|
||||
</XICOR>
|
||||
<ZEMPRO>
|
||||
<TS25L512A id="372010" page="256" size="65536"/>
|
||||
<TS25L010A id="373011" page="256" size="131072"/>
|
||||
<TS25L020A id="373012" page="256" size="262144"/>
|
||||
<TS25L16AP id="202015" page="256" size="2097152"/>
|
||||
<TS25L16BP id="202015" page="256" size="2097152"/>
|
||||
<TS25L16P id="372015" page="256" size="2097152"/>
|
||||
</ZEMPRO>
|
||||
<Zbit>
|
||||
<ZB25D16 id="5E4015" page="256" size="2097152"/>
|
||||
</Zbit>
|
||||
<Berg_Micro>
|
||||
<BG25Q40A id="E04013" page="256" size="524288"/>
|
||||
<BG25Q80A id="E04014" page="256" size="1048576"/>
|
||||
<BG25Q16A id="E04015" page="256" size="2097152"/>
|
||||
<BG25Q32A id="E04016" page="256" size="4194304"/>
|
||||
</Berg_Micro>
|
||||
<ATMEL>
|
||||
<AT45DB021D id="1F2300" page="264" size="270336" spicmd="45"/>
|
||||
<AT45DB041D id="1F2400" page="264" size="540672" spicmd="45"/>
|
||||
<AT45DB161D id="1F2600" page="528" size="2162688" spicmd="45"/>
|
||||
<AT45DB321D id="1F2701" page="528" size="4325376" spicmd="45"/>
|
||||
<AT25010 page="8" size="128" spicmd="95"/>
|
||||
<AT25010A page="8" size="128" spicmd="95"/>
|
||||
<AT25020 page="8" size="256" spicmd="95"/>
|
||||
<AT25020A page="8" size="256" spicmd="95"/>
|
||||
<AT25040 page="8" size="512" spicmd="95"/>
|
||||
<AT25040A page="8" size="512" spicmd="95"/>
|
||||
<AT25080 page="32" size="1024" spicmd="95"/>
|
||||
<AT25080A page="32" size="1024" spicmd="95"/>
|
||||
<AT25080B page="32" size="1024" spicmd="95"/>
|
||||
<AT25160 page="32" size="2048" spicmd="95"/>
|
||||
<AT25160A page="32" size="2048" spicmd="95"/>
|
||||
<AT25160B page="32" size="2048" spicmd="95"/>
|
||||
<AT25320 page="32" size="4096" spicmd="95"/>
|
||||
<AT25320A page="32" size="4096" spicmd="95"/>
|
||||
<AT25320B page="32" size="4096" spicmd="95"/>
|
||||
<AT25640 page="32" size="8192" spicmd="95"/>
|
||||
<AT25640A page="32" size="8192" spicmd="95"/>
|
||||
<AT25640B page="32" size="8192" spicmd="95"/>
|
||||
<AT25128 page="64" size="16384" spicmd="95"/>
|
||||
<AT25128A page="64" size="16384" spicmd="95"/>
|
||||
<AT25128B page="64" size="16384" spicmd="95"/>
|
||||
<AT25256 page="64" size="32768" spicmd="95"/>
|
||||
<AT25256A page="64" size="32768" spicmd="95"/>
|
||||
<AT25256B page="64" size="32768" spicmd="95"/>
|
||||
<AT25512 page="128" size="65536" spicmd="95"/>
|
||||
<AT25DF021 id="1F4300" page="256" size="262144"/>
|
||||
<AT25DF041 id="1F4400" page="256" size="524288"/>
|
||||
<AT25DF041A id="1F4400" page="256" size="524288"/>
|
||||
<AT25SF041 id="1F8400" page="256" size="524288"/>
|
||||
<AT25DF081 id="1F4500" page="256" size="1048576"/>
|
||||
<AT25DF081A id="1F4500" page="256" size="1048576"/>
|
||||
<AT25DF161 id="1F4600" page="256" size="2097152"/>
|
||||
<AT25DF321 id="1F4700" page="256" size="4194304"/>
|
||||
<AT25DF321A id="1F4700" page="256" size="4194304"/>
|
||||
<AT25DF641 id="1F4800" page="256" size="8388608"/>
|
||||
<AT25F512 id="1F65" page="256" size="65536"/>
|
||||
<AT25F512A id="1F65" page="128" size="65536"/>
|
||||
<AT25F512B id="1F6500" page="256" size="65536"/>
|
||||
<AT25F1024 id="1F60" page="256" size="131072"/>
|
||||
<AT25F1024A id="1F60" page="256" size="131072"/>
|
||||
<AT25F2048 id="1F63" page="256" size="262144"/>
|
||||
<AT25F2048A id="1F63" page="256" size="262144"/>
|
||||
<AT25F4096 id="1F64" page="256" size="524288"/>
|
||||
<AT25F4096A id="1F64" page="256" size="524288"/>
|
||||
<AT25HP256 page="128" size="32768" spicmd="95"/>
|
||||
<AT25HP512 page="128" size="65536" spicmd="95"/>
|
||||
<AT26DF081 id="1F4500" page="256" size="1048576"/>
|
||||
<AT26DF081A id="1F4500" page="256" size="1048576"/>
|
||||
<AT26DF161 id="1F4600" page="256" size="2097152"/>
|
||||
<AT26DF161A id="1F4600" page="256" size="2097152"/>
|
||||
<AT26DF321 id="1F4700" page="256" size="4194304"/>
|
||||
<AT26DF321A id="1F4700" page="256" size="4194304"/>
|
||||
<AT26F004 id="1F0400" page="256" size="524288"/>
|
||||
</ATMEL>
|
||||
<ACE>
|
||||
<ACE25A128G_1.8V id="E06018" page="256" size="16777216"/>
|
||||
</ACE>
|
||||
<ATO>
|
||||
<ATO25Q32 id="9B3216" page="256" size="4194304"/>
|
||||
</ATO>
|
||||
<DOUQI>
|
||||
<DQ25Q64A id="544017" page="256" size="8388608"/>
|
||||
</DOUQI>
|
||||
<Fremont>
|
||||
<FT25H16 id="0E4015" page="256" size="2097152"/>
|
||||
</Fremont>
|
||||
<Fudan>
|
||||
<FM25Q04A id="A14013" page="256" size="524288"/>
|
||||
<FM25Q32 id="A14016" page="256" size="4194304"/>
|
||||
</Fudan>
|
||||
<Genitop>
|
||||
<GT25Q80A id="E04014" page="256" size="1048576"/>
|
||||
</Genitop>
|
||||
<Paragon>
|
||||
<PN25F04A id="E04013" page="256" size="524288"/>
|
||||
</Paragon>
|
||||
</SPI>
|
||||
<I2C>
|
||||
<_24Cxxx>
|
||||
<AT24C01 page="1" size="128" addrtype="0"/>
|
||||
<_24C01 page="1" size="128" addrtype="1"/>
|
||||
<_24C02 page="1" size="256" addrtype="1"/>
|
||||
<_24C04 page="1" size="512" addrtype="2"/>
|
||||
<_24C08 page="16" size="1024" addrtype="3"/>
|
||||
<_24C16 page="16" size="2048" addrtype="4"/>
|
||||
<_24C32 page="32" size="4096" addrtype="5"/>
|
||||
<_24C64 page="32" size="8192" addrtype="5"/>
|
||||
<_24C128 page="64" size="16384" addrtype="5"/>
|
||||
<_24C256 page="64" size="32768" addrtype="5"/>
|
||||
<_24C512 page="128" size="65536" addrtype="5"/>
|
||||
<_24C1024 page="128" size="131072" addrtype="6"/>
|
||||
</_24Cxxx>
|
||||
</I2C>
|
||||
<Microwire>
|
||||
<Microchip>
|
||||
<M93C86 size="2048" addrbitlen="10"/>
|
||||
<M93C76 size="1024" addrbitlen="10"/>
|
||||
<M93C66 size="512" addrbitlen="8"/>
|
||||
<M93C56 size="256" addrbitlen="8"/>
|
||||
<M93C46 size="128" addrbitlen="6"/>
|
||||
<M93C06 size="16" addrbitlen="6"/>
|
||||
</Microchip>
|
||||
</Microwire>
|
||||
</chiplist>
|
109
applications/plugins/spi_mem_manager/tools/chiplist_convert.py
Executable file
|
@ -0,0 +1,109 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import xml.etree.ElementTree as XML
|
||||
import sys
|
||||
|
||||
|
||||
def getArgs():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="chiplist.xml to C array converter",
|
||||
)
|
||||
parser.add_argument("file", help="chiplist.xml file")
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
def getXML(file):
|
||||
tree = XML.parse(file)
|
||||
root = tree.getroot()
|
||||
return root
|
||||
|
||||
|
||||
def parseChip(cur, arr, vendor, vendorCodeArr):
|
||||
chip = {}
|
||||
chipAttr = cur.attrib
|
||||
if "page" not in chipAttr: # chip without page size not supported
|
||||
return
|
||||
if "id" not in chipAttr: # I2C not supported yet
|
||||
return
|
||||
if len(chipAttr["id"]) < 6: # ID wihout capacity id not supported yet
|
||||
return
|
||||
chip["modelName"] = cur.tag
|
||||
chip["vendorEnum"] = "SPIMemChipVendor" + vendor
|
||||
chip["vendorID"] = "0x" + chipAttr["id"][0] + chipAttr["id"][1]
|
||||
chip["typeID"] = chipAttr["id"][2] + chipAttr["id"][3]
|
||||
chip["capacityID"] = chipAttr["id"][4] + chipAttr["id"][5]
|
||||
chip["size"] = chipAttr["size"]
|
||||
if chipAttr["page"] == "SSTW":
|
||||
chip["writeMode"] = "SPIMemChipWriteModeAAIWord"
|
||||
chip["pageSize"] = "1"
|
||||
elif chipAttr["page"] == "SSTB":
|
||||
chip["writeMode"] = "SPIMemChipWriteModeAAIByte"
|
||||
chip["pageSize"] = "1"
|
||||
else:
|
||||
chip["writeMode"] = "SPIMemChipWriteModePage"
|
||||
chip["pageSize"] = chipAttr["page"]
|
||||
arr.append(chip)
|
||||
vendorCodeArr[vendor].add(chip["vendorID"])
|
||||
|
||||
|
||||
def cleanEmptyVendors(vendors):
|
||||
for cur in list(vendors):
|
||||
if not vendors[cur]:
|
||||
vendors.pop(cur)
|
||||
|
||||
|
||||
def getVendors(xml, interface):
|
||||
arr = {}
|
||||
for cur in xml.find(interface):
|
||||
arr[cur.tag] = set()
|
||||
return arr
|
||||
|
||||
|
||||
def parseXML(xml, interface, vendorCodeArr):
|
||||
arr = []
|
||||
for vendor in xml.find(interface):
|
||||
for cur in vendor:
|
||||
parseChip(cur, arr, vendor.tag, vendorCodeArr)
|
||||
return arr
|
||||
|
||||
|
||||
def getVendorNameEnum(vendorID):
|
||||
try:
|
||||
return vendors[vendorID]
|
||||
except:
|
||||
print("Unknown vendor: " + vendorID)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def generateCArr(arr, filename):
|
||||
with open(filename, "w") as out:
|
||||
print('#include "spi_mem_chip_i.h"', file=out)
|
||||
print("const SPIMemChip SPIMemChips[] = {", file=out)
|
||||
for cur in arr:
|
||||
print(" {" + cur["vendorID"] + ",", file=out, end="")
|
||||
print(" 0x" + cur["typeID"] + ",", file=out, end="")
|
||||
print(" 0x" + cur["capacityID"] + ",", file=out, end="")
|
||||
print(' "' + cur["modelName"] + '",', file=out, end="")
|
||||
print(" " + cur["size"] + ",", file=out, end="")
|
||||
print(" " + cur["pageSize"] + ",", file=out, end="")
|
||||
print(" " + cur["vendorEnum"] + ",", file=out, end="")
|
||||
if cur == arr[-1]:
|
||||
print(" " + cur["writeMode"] + "}};", file=out)
|
||||
else:
|
||||
print(" " + cur["writeMode"] + "},", file=out)
|
||||
|
||||
def main():
|
||||
filename = "spi_mem_chip_arr.c"
|
||||
args = getArgs()
|
||||
xml = getXML(args.file)
|
||||
vendors = getVendors(xml, "SPI")
|
||||
chipArr = parseXML(xml, "SPI", vendors)
|
||||
cleanEmptyVendors(vendors)
|
||||
for cur in vendors:
|
||||
print(' {"' + cur + '", SPIMemChipVendor' + cur + "},")
|
||||
generateCArr(chipArr, filename)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -0,0 +1,64 @@
|
|||
#include "spi_mem_view_detect.h"
|
||||
#include "spi_mem_manager_icons.h"
|
||||
#include <gui/elements.h>
|
||||
|
||||
struct SPIMemDetectView {
|
||||
View* view;
|
||||
IconAnimation* icon;
|
||||
SPIMemDetectViewCallback callback;
|
||||
void* cb_ctx;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
IconAnimation* icon;
|
||||
} SPIMemDetectViewModel;
|
||||
|
||||
View* spi_mem_view_detect_get_view(SPIMemDetectView* app) {
|
||||
return app->view;
|
||||
}
|
||||
|
||||
static void spi_mem_view_detect_draw_callback(Canvas* canvas, void* context) {
|
||||
SPIMemDetectViewModel* model = context;
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_icon_animation(canvas, 0, 0, model->icon);
|
||||
canvas_draw_str_aligned(canvas, 64, 26, AlignLeft, AlignCenter, "Detecting");
|
||||
canvas_draw_str_aligned(canvas, 64, 36, AlignLeft, AlignCenter, "SPI chip...");
|
||||
}
|
||||
|
||||
static void spi_mem_view_detect_enter_callback(void* context) {
|
||||
SPIMemDetectView* app = context;
|
||||
with_view_model(
|
||||
app->view, SPIMemDetectViewModel * model, { icon_animation_start(model->icon); }, false);
|
||||
}
|
||||
|
||||
static void spi_mem_view_detect_exit_callback(void* context) {
|
||||
SPIMemDetectView* app = context;
|
||||
with_view_model(
|
||||
app->view, SPIMemDetectViewModel * model, { icon_animation_stop(model->icon); }, false);
|
||||
}
|
||||
|
||||
SPIMemDetectView* spi_mem_view_detect_alloc() {
|
||||
SPIMemDetectView* app = malloc(sizeof(SPIMemDetectView));
|
||||
app->view = view_alloc();
|
||||
view_set_context(app->view, app);
|
||||
view_allocate_model(app->view, ViewModelTypeLocking, sizeof(SPIMemDetectViewModel));
|
||||
with_view_model(
|
||||
app->view,
|
||||
SPIMemDetectViewModel * model,
|
||||
{
|
||||
model->icon = icon_animation_alloc(&A_ChipLooking_64x64);
|
||||
view_tie_icon_animation(app->view, model->icon);
|
||||
},
|
||||
false);
|
||||
view_set_draw_callback(app->view, spi_mem_view_detect_draw_callback);
|
||||
view_set_enter_callback(app->view, spi_mem_view_detect_enter_callback);
|
||||
view_set_exit_callback(app->view, spi_mem_view_detect_exit_callback);
|
||||
return app;
|
||||
}
|
||||
|
||||
void spi_mem_view_detect_free(SPIMemDetectView* app) {
|
||||
with_view_model(
|
||||
app->view, SPIMemDetectViewModel * model, { icon_animation_free(model->icon); }, false);
|
||||
view_free(app->view);
|
||||
free(app);
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
#include <gui/view.h>
|
||||
|
||||
typedef struct SPIMemDetectView SPIMemDetectView;
|
||||
typedef void (*SPIMemDetectViewCallback)(void* context);
|
||||
|
||||
View* spi_mem_view_detect_get_view(SPIMemDetectView* app);
|
||||
SPIMemDetectView* spi_mem_view_detect_alloc();
|
||||
void spi_mem_view_detect_free(SPIMemDetectView* app);
|
|
@ -0,0 +1,230 @@
|
|||
#include "spi_mem_view_progress.h"
|
||||
#include <gui/elements.h>
|
||||
|
||||
struct SPIMemProgressView {
|
||||
View* view;
|
||||
SPIMemProgressViewCallback callback;
|
||||
void* cb_ctx;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
SPIMemProgressViewTypeRead,
|
||||
SPIMemProgressViewTypeVerify,
|
||||
SPIMemProgressViewTypeWrite,
|
||||
SPIMemProgressViewTypeUnknown
|
||||
} SPIMemProgressViewType;
|
||||
|
||||
typedef struct {
|
||||
size_t chip_size;
|
||||
size_t file_size;
|
||||
size_t blocks_written;
|
||||
size_t block_size;
|
||||
float progress;
|
||||
SPIMemProgressViewType view_type;
|
||||
} SPIMemProgressViewModel;
|
||||
|
||||
View* spi_mem_view_progress_get_view(SPIMemProgressView* app) {
|
||||
return app->view;
|
||||
}
|
||||
|
||||
static void spi_mem_view_progress_draw_progress(Canvas* canvas, float progress) {
|
||||
FuriString* progress_str = furi_string_alloc();
|
||||
if(progress > 1.0) progress = 1.0;
|
||||
furi_string_printf(progress_str, "%d %%", (int)(progress * 100));
|
||||
elements_progress_bar(canvas, 13, 35, 100, progress);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 64, 25, AlignCenter, AlignTop, furi_string_get_cstr(progress_str));
|
||||
furi_string_free(progress_str);
|
||||
}
|
||||
|
||||
static void
|
||||
spi_mem_view_progress_read_draw_callback(Canvas* canvas, SPIMemProgressViewModel* model) {
|
||||
canvas_draw_str_aligned(canvas, 64, 4, AlignCenter, AlignTop, "Reading dump");
|
||||
spi_mem_view_progress_draw_progress(canvas, model->progress);
|
||||
elements_button_left(canvas, "Cancel");
|
||||
}
|
||||
|
||||
static void
|
||||
spi_mem_view_progress_draw_size_warning(Canvas* canvas, SPIMemProgressViewModel* model) {
|
||||
if(model->file_size > model->chip_size) {
|
||||
canvas_draw_str_aligned(canvas, 64, 13, AlignCenter, AlignTop, "Size clamped to chip!");
|
||||
}
|
||||
if(model->chip_size > model->file_size) {
|
||||
canvas_draw_str_aligned(canvas, 64, 13, AlignCenter, AlignTop, "Size clamped to file!");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
spi_mem_view_progress_verify_draw_callback(Canvas* canvas, SPIMemProgressViewModel* model) {
|
||||
canvas_draw_str_aligned(canvas, 64, 2, AlignCenter, AlignTop, "Verifying dump");
|
||||
spi_mem_view_progress_draw_size_warning(canvas, model);
|
||||
spi_mem_view_progress_draw_progress(canvas, model->progress);
|
||||
elements_button_center(canvas, "Skip");
|
||||
}
|
||||
|
||||
static void
|
||||
spi_mem_view_progress_write_draw_callback(Canvas* canvas, SPIMemProgressViewModel* model) {
|
||||
canvas_draw_str_aligned(canvas, 64, 4, AlignCenter, AlignTop, "Writing dump");
|
||||
spi_mem_view_progress_draw_size_warning(canvas, model);
|
||||
spi_mem_view_progress_draw_progress(canvas, model->progress);
|
||||
elements_button_left(canvas, "Cancel");
|
||||
}
|
||||
|
||||
static void spi_mem_view_progress_draw_callback(Canvas* canvas, void* context) {
|
||||
SPIMemProgressViewModel* model = context;
|
||||
SPIMemProgressViewType view_type = model->view_type;
|
||||
if(view_type == SPIMemProgressViewTypeRead) {
|
||||
spi_mem_view_progress_read_draw_callback(canvas, model);
|
||||
} else if(view_type == SPIMemProgressViewTypeVerify) {
|
||||
spi_mem_view_progress_verify_draw_callback(canvas, model);
|
||||
} else if(view_type == SPIMemProgressViewTypeWrite) {
|
||||
spi_mem_view_progress_write_draw_callback(canvas, model);
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
spi_mem_view_progress_read_write_input_callback(InputEvent* event, SPIMemProgressView* app) {
|
||||
bool success = false;
|
||||
if(event->type == InputTypeShort && event->key == InputKeyLeft) {
|
||||
if(app->callback) {
|
||||
app->callback(app->cb_ctx);
|
||||
}
|
||||
success = true;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool
|
||||
spi_mem_view_progress_verify_input_callback(InputEvent* event, SPIMemProgressView* app) {
|
||||
bool success = false;
|
||||
if(event->type == InputTypeShort && event->key == InputKeyOk) {
|
||||
if(app->callback) {
|
||||
app->callback(app->cb_ctx);
|
||||
}
|
||||
success = true;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool spi_mem_view_progress_input_callback(InputEvent* event, void* context) {
|
||||
SPIMemProgressView* app = context;
|
||||
bool success = false;
|
||||
SPIMemProgressViewType view_type;
|
||||
with_view_model(
|
||||
app->view, SPIMemProgressViewModel * model, { view_type = model->view_type; }, true);
|
||||
if(view_type == SPIMemProgressViewTypeRead) {
|
||||
success = spi_mem_view_progress_read_write_input_callback(event, app);
|
||||
} else if(view_type == SPIMemProgressViewTypeVerify) {
|
||||
success = spi_mem_view_progress_verify_input_callback(event, app);
|
||||
} else if(view_type == SPIMemProgressViewTypeWrite) {
|
||||
success = spi_mem_view_progress_read_write_input_callback(event, app);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
SPIMemProgressView* spi_mem_view_progress_alloc() {
|
||||
SPIMemProgressView* app = malloc(sizeof(SPIMemProgressView));
|
||||
app->view = view_alloc();
|
||||
view_allocate_model(app->view, ViewModelTypeLocking, sizeof(SPIMemProgressViewModel));
|
||||
view_set_context(app->view, app);
|
||||
view_set_draw_callback(app->view, spi_mem_view_progress_draw_callback);
|
||||
view_set_input_callback(app->view, spi_mem_view_progress_input_callback);
|
||||
spi_mem_view_progress_reset(app);
|
||||
return app;
|
||||
}
|
||||
|
||||
void spi_mem_view_progress_free(SPIMemProgressView* app) {
|
||||
view_free(app->view);
|
||||
free(app);
|
||||
}
|
||||
|
||||
void spi_mem_view_progress_set_read_callback(
|
||||
SPIMemProgressView* app,
|
||||
SPIMemProgressViewCallback callback,
|
||||
void* cb_ctx) {
|
||||
app->callback = callback;
|
||||
app->cb_ctx = cb_ctx;
|
||||
with_view_model(
|
||||
app->view,
|
||||
SPIMemProgressViewModel * model,
|
||||
{ model->view_type = SPIMemProgressViewTypeRead; },
|
||||
true);
|
||||
}
|
||||
|
||||
void spi_mem_view_progress_set_verify_callback(
|
||||
SPIMemProgressView* app,
|
||||
SPIMemProgressViewCallback callback,
|
||||
void* cb_ctx) {
|
||||
app->callback = callback;
|
||||
app->cb_ctx = cb_ctx;
|
||||
with_view_model(
|
||||
app->view,
|
||||
SPIMemProgressViewModel * model,
|
||||
{ model->view_type = SPIMemProgressViewTypeVerify; },
|
||||
true);
|
||||
}
|
||||
|
||||
void spi_mem_view_progress_set_write_callback(
|
||||
SPIMemProgressView* app,
|
||||
SPIMemProgressViewCallback callback,
|
||||
void* cb_ctx) {
|
||||
app->callback = callback;
|
||||
app->cb_ctx = cb_ctx;
|
||||
with_view_model(
|
||||
app->view,
|
||||
SPIMemProgressViewModel * model,
|
||||
{ model->view_type = SPIMemProgressViewTypeWrite; },
|
||||
true);
|
||||
}
|
||||
|
||||
void spi_mem_view_progress_set_chip_size(SPIMemProgressView* app, size_t chip_size) {
|
||||
with_view_model(
|
||||
app->view, SPIMemProgressViewModel * model, { model->chip_size = chip_size; }, true);
|
||||
}
|
||||
|
||||
void spi_mem_view_progress_set_file_size(SPIMemProgressView* app, size_t file_size) {
|
||||
with_view_model(
|
||||
app->view, SPIMemProgressViewModel * model, { model->file_size = file_size; }, true);
|
||||
}
|
||||
|
||||
void spi_mem_view_progress_set_block_size(SPIMemProgressView* app, size_t block_size) {
|
||||
with_view_model(
|
||||
app->view, SPIMemProgressViewModel * model, { model->block_size = block_size; }, true);
|
||||
}
|
||||
|
||||
static size_t spi_mem_view_progress_set_total_size(SPIMemProgressViewModel* model) {
|
||||
size_t total_size = model->chip_size;
|
||||
if((model->chip_size > model->file_size) && model->view_type != SPIMemProgressViewTypeRead) {
|
||||
total_size = model->file_size;
|
||||
}
|
||||
return total_size;
|
||||
}
|
||||
|
||||
void spi_mem_view_progress_inc_progress(SPIMemProgressView* app) {
|
||||
with_view_model(
|
||||
app->view,
|
||||
SPIMemProgressViewModel * model,
|
||||
{
|
||||
size_t total_size = spi_mem_view_progress_set_total_size(model);
|
||||
if(total_size == 0) total_size = 1;
|
||||
model->blocks_written++;
|
||||
model->progress =
|
||||
((float)model->block_size * (float)model->blocks_written) / ((float)total_size);
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
void spi_mem_view_progress_reset(SPIMemProgressView* app) {
|
||||
with_view_model(
|
||||
app->view,
|
||||
SPIMemProgressViewModel * model,
|
||||
{
|
||||
model->blocks_written = 0;
|
||||
model->block_size = 0;
|
||||
model->chip_size = 0;
|
||||
model->file_size = 0;
|
||||
model->progress = 0;
|
||||
model->view_type = SPIMemProgressViewTypeUnknown;
|
||||
},
|
||||
true);
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
#include <gui/view.h>
|
||||
|
||||
typedef struct SPIMemProgressView SPIMemProgressView;
|
||||
typedef void (*SPIMemProgressViewCallback)(void* context);
|
||||
|
||||
View* spi_mem_view_progress_get_view(SPIMemProgressView* app);
|
||||
SPIMemProgressView* spi_mem_view_progress_alloc();
|
||||
void spi_mem_view_progress_free(SPIMemProgressView* app);
|
||||
void spi_mem_view_progress_set_read_callback(
|
||||
SPIMemProgressView* app,
|
||||
SPIMemProgressViewCallback callback,
|
||||
void* cb_ctx);
|
||||
void spi_mem_view_progress_set_verify_callback(
|
||||
SPIMemProgressView* app,
|
||||
SPIMemProgressViewCallback callback,
|
||||
void* cb_ctx);
|
||||
void spi_mem_view_progress_set_write_callback(
|
||||
SPIMemProgressView* app,
|
||||
SPIMemProgressViewCallback callback,
|
||||
void* cb_ctx);
|
||||
void spi_mem_view_progress_set_chip_size(SPIMemProgressView* app, size_t chip_size);
|
||||
void spi_mem_view_progress_set_file_size(SPIMemProgressView* app, size_t file_size);
|
||||
void spi_mem_view_progress_set_block_size(SPIMemProgressView* app, size_t block_size);
|
||||
void spi_mem_view_progress_inc_progress(SPIMemProgressView* app);
|
||||
void spi_mem_view_progress_reset(SPIMemProgressView* app);
|