diff --git a/SConstruct b/SConstruct index 62e37dfdc..81ff67790 100644 --- a/SConstruct +++ b/SConstruct @@ -139,7 +139,7 @@ if GetOption("fullenv") or any( basic_dist = distenv.DistCommand("fw_dist", distenv["DIST_DEPENDS"]) distenv.Default(basic_dist) -dist_dir = distenv.GetProjetDirName() +dist_dir = distenv.GetProjectDirName() fap_dist = [ distenv.Install( distenv.Dir(f"#/dist/{dist_dir}/apps/debug_elf"), diff --git a/applications/main/infrared/views/infrared_progress_view.h b/applications/main/infrared/views/infrared_progress_view.h index e8f76ba1f..4f3c3a875 100644 --- a/applications/main/infrared/views/infrared_progress_view.h +++ b/applications/main/infrared/views/infrared_progress_view.h @@ -10,7 +10,7 @@ extern "C" { #endif -/** Anonumous instance */ +/** Anonymous instance */ typedef struct InfraredProgressView InfraredProgressView; /** Callback for back button handling */ diff --git a/applications/main/lfrfid/scenes/lfrfid_scene_clear_t5577.c b/applications/main/lfrfid/scenes/lfrfid_scene_clear_t5577.c index 888288a31..a950de708 100644 --- a/applications/main/lfrfid/scenes/lfrfid_scene_clear_t5577.c +++ b/applications/main/lfrfid/scenes/lfrfid_scene_clear_t5577.c @@ -16,7 +16,7 @@ static void lfrfid_clear_t5577_password_and_config_to_EM(LfRfid* app) { Popup* popup = app->popup; char curr_buf[32] = {}; - //TODO: use .txt file in resourses for passwords. + //TODO: use .txt file in resources for passwords. const uint32_t default_passwords[] = { 0x51243648, 0x000D8787, 0x19920427, 0x50524F58, 0xF9DCEBA0, 0x65857569, 0x05D73B9F, 0x89A69E60, 0x314159E0, 0xAA55BBBB, 0xA5B4C3D2, 0x1C0B5848, 0x00434343, 0x444E4752, diff --git a/applications/main/nfc/helpers/nfc_emv_parser.h b/applications/main/nfc/helpers/nfc_emv_parser.h index abe57f470..c636ca77d 100644 --- a/applications/main/nfc/helpers/nfc_emv_parser.h +++ b/applications/main/nfc/helpers/nfc_emv_parser.h @@ -9,7 +9,7 @@ * @param aid - AID number array * @param aid_len - AID length * @param aid_name - string to keep AID name - * @return - true if AID found, false otherwies + * @return - true if AID found, false otherwise */ bool nfc_emv_parser_get_aid_name( Storage* storage, @@ -21,7 +21,7 @@ bool nfc_emv_parser_get_aid_name( * @param storage Storage instance * @param country_code - ISO 3166 country code * @param country_name - string to keep country name - * @return - true if country found, false otherwies + * @return - true if country found, false otherwise */ bool nfc_emv_parser_get_country_name( Storage* storage, @@ -32,7 +32,7 @@ bool nfc_emv_parser_get_country_name( * @param storage Storage instance * @param currency_code - ISO 3166 currency code * @param currency_name - string to keep currency name - * @return - true if currency found, false otherwies + * @return - true if currency found, false otherwise */ bool nfc_emv_parser_get_currency_name( Storage* storage, diff --git a/applications/main/nfc/scenes/nfc_scene_config.h b/applications/main/nfc/scenes/nfc_scene_config.h index 045080fea..ef257b76e 100644 --- a/applications/main/nfc/scenes/nfc_scene_config.h +++ b/applications/main/nfc/scenes/nfc_scene_config.h @@ -34,6 +34,7 @@ ADD_SCENE(nfc, mf_desfire_menu, MfDesfireMenu) ADD_SCENE(nfc, mf_desfire_data, MfDesfireData) ADD_SCENE(nfc, mf_desfire_app, MfDesfireApp) ADD_SCENE(nfc, mf_classic_read_success, MfClassicReadSuccess) +ADD_SCENE(nfc, mf_classic_data, MfClassicData) ADD_SCENE(nfc, mf_classic_menu, MfClassicMenu) ADD_SCENE(nfc, mf_classic_emulate, MfClassicEmulate) ADD_SCENE(nfc, mf_classic_keys, MfClassicKeys) diff --git a/applications/main/nfc/scenes/nfc_scene_mf_classic_data.c b/applications/main/nfc/scenes/nfc_scene_mf_classic_data.c new file mode 100644 index 000000000..dcb02d364 --- /dev/null +++ b/applications/main/nfc/scenes/nfc_scene_mf_classic_data.c @@ -0,0 +1,106 @@ +#include "../nfc_i.h" + +void nfc_scene_mf_classic_data_on_enter(void* context) { + Nfc* nfc = context; + MfClassicType type = nfc->dev->dev_data.mf_classic_data.type; + MfClassicData* data = &nfc->dev->dev_data.mf_classic_data; + TextBox* text_box = nfc->text_box; + + text_box_set_font(text_box, TextBoxFontHex); + + int card_blocks = 0; + if(type == MfClassicType1k) { + card_blocks = MF_CLASSIC_1K_TOTAL_SECTORS_NUM * 4; + } else if(type == MfClassicType4k) { + // 16 sectors of 4 blocks each plus 8 sectors of 16 blocks each + card_blocks = MF_CLASSIC_1K_TOTAL_SECTORS_NUM * 4 + 8 * 16; + } else if(type == MfClassicTypeMini) { + card_blocks = MF_MINI_TOTAL_SECTORS_NUM * 4; + } + + int bytes_written = 0; + for(int block_num = 0; block_num < card_blocks; block_num++) { + bool is_sec_trailer = mf_classic_is_sector_trailer(block_num); + if(is_sec_trailer) { + uint8_t sector_num = mf_classic_get_sector_by_block(block_num); + MfClassicSectorTrailer* sec_tr = + mf_classic_get_sector_trailer_by_sector(data, sector_num); + // Key A + for(size_t i = 0; i < sizeof(sec_tr->key_a); i += 2) { + if((bytes_written % 8 == 0) && (bytes_written != 0)) { + furi_string_push_back(nfc->text_box_store, '\n'); + } + if(mf_classic_is_key_found(data, sector_num, MfClassicKeyA)) { + furi_string_cat_printf( + nfc->text_box_store, "%02X%02X ", sec_tr->key_a[i], sec_tr->key_a[i + 1]); + } else { + furi_string_cat_printf(nfc->text_box_store, "???? "); + } + bytes_written += 2; + } + // Access bytes + for(size_t i = 0; i < MF_CLASSIC_ACCESS_BYTES_SIZE; i += 2) { + if((bytes_written % 8 == 0) && (bytes_written != 0)) { + furi_string_push_back(nfc->text_box_store, '\n'); + } + if(mf_classic_is_block_read(data, block_num)) { + furi_string_cat_printf( + nfc->text_box_store, + "%02X%02X ", + sec_tr->access_bits[i], + sec_tr->access_bits[i + 1]); + } else { + furi_string_cat_printf(nfc->text_box_store, "???? "); + } + bytes_written += 2; + } + // Key B + for(size_t i = 0; i < sizeof(sec_tr->key_b); i += 2) { + if((bytes_written % 8 == 0) && (bytes_written != 0)) { + furi_string_push_back(nfc->text_box_store, '\n'); + } + if(mf_classic_is_key_found(data, sector_num, MfClassicKeyB)) { + furi_string_cat_printf( + nfc->text_box_store, "%02X%02X ", sec_tr->key_b[i], sec_tr->key_b[i + 1]); + } else { + furi_string_cat_printf(nfc->text_box_store, "???? "); + } + bytes_written += 2; + } + } else { + // Write data block + for(size_t i = 0; i < MF_CLASSIC_BLOCK_SIZE; i += 2) { + if((bytes_written % 8 == 0) && (bytes_written != 0)) { + furi_string_push_back(nfc->text_box_store, '\n'); + } + if(mf_classic_is_block_read(data, block_num)) { + furi_string_cat_printf( + nfc->text_box_store, + "%02X%02X ", + data->block[block_num].value[i], + data->block[block_num].value[i + 1]); + } else { + furi_string_cat_printf(nfc->text_box_store, "???? "); + } + bytes_written += 2; + } + } + } + text_box_set_text(text_box, furi_string_get_cstr(nfc->text_box_store)); + + view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox); +} + +bool nfc_scene_mf_classic_data_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + return false; +} + +void nfc_scene_mf_classic_data_on_exit(void* context) { + Nfc* nfc = context; + + // Clean view + text_box_reset(nfc->text_box); + furi_string_reset(nfc->text_box_store); +} diff --git a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c index 372da8860..bcc8a2122 100644 --- a/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c +++ b/applications/main/nfc/scenes/nfc_scene_nfc_data_info.c @@ -26,7 +26,8 @@ void nfc_scene_nfc_data_info_on_enter(void* context) { NfcProtocol protocol = dev_data->protocol; uint8_t text_scroll_height = 0; if((protocol == NfcDeviceProtocolMifareDesfire) || (protocol == NfcDeviceProtocolMifareUl) || - (protocol == NfcDeviceProtocolNfcV)) { + (protocol == NfcDeviceProtocolNfcV) || + (protocol == NfcDeviceProtocolMifareClassic)) { widget_add_button_element( widget, GuiButtonTypeRight, "More", nfc_scene_nfc_data_info_widget_callback, nfc); text_scroll_height = 52; @@ -290,6 +291,9 @@ bool nfc_scene_nfc_data_info_on_event(void* context, SceneManagerEvent event) { } else if(protocol == NfcDeviceProtocolNfcV) { scene_manager_next_scene(nfc->scene_manager, NfcSceneNfcVMenu); consumed = true; + } else if(protocol == NfcDeviceProtocolMifareClassic) { + scene_manager_next_scene(nfc->scene_manager, NfcSceneMfClassicData); + consumed = true; } } } diff --git a/applications/main/nfc/scenes/nfc_scene_saved_menu.c b/applications/main/nfc/scenes/nfc_scene_saved_menu.c index 616dc0ef7..2fb4dcec4 100644 --- a/applications/main/nfc/scenes/nfc_scene_saved_menu.c +++ b/applications/main/nfc/scenes/nfc_scene_saved_menu.c @@ -153,6 +153,8 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) { application_info_present = nfc_supported_card_verify_and_parse(dev_data); } + FURI_LOG_I("nfc", "application_info_present: %d", application_info_present); + if(application_info_present) { scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo); } else { diff --git a/applications/main/subghz/helpers/subghz_chat.c b/applications/main/subghz/helpers/subghz_chat.c index dbf34c970..b589ba5d5 100644 --- a/applications/main/subghz/helpers/subghz_chat.c +++ b/applications/main/subghz/helpers/subghz_chat.c @@ -9,7 +9,7 @@ struct SubGhzChatWorker { SubGhzTxRxWorker* subghz_txrx; volatile bool worker_running; - volatile bool worker_stoping; + volatile bool worker_stopping; FuriMessageQueue* event_queue; uint32_t last_time_rx_data; diff --git a/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c b/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c index fc9603744..d4e719792 100644 --- a/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c +++ b/applications/main/subghz/helpers/subghz_frequency_analyzer_worker.c @@ -117,15 +117,15 @@ static int32_t subghz_frequency_analyzer_worker_thread(void* context) { // First stage: coarse scan for(size_t i = 0; i < subghz_setting_get_frequency_count(instance->setting); i++) { - uint32_t current_frequnecy = subghz_setting_get_frequency(instance->setting, i); - if(furi_hal_subghz_is_frequency_valid(current_frequnecy) && - (current_frequnecy != 467750000) && + uint32_t current_frequency = subghz_setting_get_frequency(instance->setting, i); + if(furi_hal_subghz_is_frequency_valid(current_frequency) && + (current_frequency != 467750000) && !((furi_hal_subghz.radio_type == SubGhzRadioExternal) && - (current_frequnecy >= 311900000 && current_frequnecy <= 312200000))) { + (current_frequency >= 311900000 && current_frequency <= 312200000))) { furi_hal_spi_acquire(furi_hal_subghz.spi_bus_handle); cc1101_switch_to_idle(furi_hal_subghz.spi_bus_handle); frequency = - cc1101_set_frequency(furi_hal_subghz.spi_bus_handle, current_frequnecy); + cc1101_set_frequency(furi_hal_subghz.spi_bus_handle, current_frequency); cc1101_calibrate(furi_hal_subghz.spi_bus_handle); do { diff --git a/applications/main/subghz/helpers/subghz_types.h b/applications/main/subghz/helpers/subghz_types.h index 7d63ba6b9..6e42c1523 100644 --- a/applications/main/subghz/helpers/subghz_types.h +++ b/applications/main/subghz/helpers/subghz_types.h @@ -23,7 +23,7 @@ typedef enum { /** SubGhzHopperState state */ typedef enum { SubGhzHopperStateOFF, - SubGhzHopperStateRunnig, + SubGhzHopperStateRunning, SubGhzHopperStatePause, SubGhzHopperStateRSSITimeOut, } SubGhzHopperState; diff --git a/applications/main/subghz/scenes/subghz_scene_read_raw.c b/applications/main/subghz/scenes/subghz_scene_read_raw.c index e396527cc..1e3d6a9c0 100644 --- a/applications/main/subghz/scenes/subghz_scene_read_raw.c +++ b/applications/main/subghz/scenes/subghz_scene_read_raw.c @@ -368,7 +368,7 @@ bool subghz_scene_read_raw_on_event(void* context, SceneManagerEvent event) { float rssi = furi_hal_subghz_get_rssi(); - if(float_is_equal(subghz->txrx->raw_threshold_rssi, SUBGHZ_RAW_TRESHOLD_MIN)) { + if(float_is_equal(subghz->txrx->raw_threshold_rssi, SUBGHZ_RAW_THRESHOLD_MIN)) { subghz_read_raw_add_data_rssi(subghz->subghz_read_raw, rssi, true); subghz_protocol_raw_save_to_file_pause( (SubGhzProtocolDecoderRAW*)subghz->txrx->decoder_result, false); @@ -421,4 +421,4 @@ void subghz_scene_read_raw_on_exit(void* context) { //filter restoration subghz_receiver_set_filter(subghz->txrx->receiver, subghz->txrx->filter); -} \ No newline at end of file +} diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_config.c b/applications/main/subghz/scenes/subghz_scene_receiver_config.c index af4c6aca3..ff51e2f4d 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_config.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_config.c @@ -8,11 +8,11 @@ enum SubGhzSettingIndex { SubGhzSettingIndexBinRAW, SubGhzSettingIndexSound, SubGhzSettingIndexLock, - SubGhzSettingIndexRAWThesholdRSSI, + SubGhzSettingIndexRAWThresholdRSSI, }; #define RAW_THRESHOLD_RSSI_COUNT 11 -const char* const raw_theshold_rssi_text[RAW_THRESHOLD_RSSI_COUNT] = { +const char* const raw_threshold_rssi_text[RAW_THRESHOLD_RSSI_COUNT] = { "-----", "-85.0", "-80.0", @@ -26,7 +26,7 @@ const char* const raw_theshold_rssi_text[RAW_THRESHOLD_RSSI_COUNT] = { "-40.0", }; -const float raw_theshold_rssi_value[RAW_THRESHOLD_RSSI_COUNT] = { +const float raw_threshold_rssi_value[RAW_THRESHOLD_RSSI_COUNT] = { -90.0f, -85.0f, -80.0f, @@ -47,7 +47,7 @@ const char* const hopping_text[HOPPING_COUNT] = { }; const uint32_t hopping_value[HOPPING_COUNT] = { SubGhzHopperStateOFF, - SubGhzHopperStateRunnig, + SubGhzHopperStateRunning, }; #define SPEAKER_COUNT 2 @@ -213,8 +213,8 @@ static void subghz_scene_receiver_config_set_raw_threshold_rssi(VariableItem* it SubGhz* subghz = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); - variable_item_set_current_value_text(item, raw_theshold_rssi_text[index]); - subghz->txrx->raw_threshold_rssi = raw_theshold_rssi_value[index]; + variable_item_set_current_value_text(item, raw_threshold_rssi_text[index]); + subghz->txrx->raw_threshold_rssi = raw_threshold_rssi_value[index]; } static void subghz_scene_receiver_config_var_list_enter_callback(void* context, uint32_t index) { @@ -320,9 +320,9 @@ void subghz_scene_receiver_config_on_enter(void* context) { subghz_scene_receiver_config_set_raw_threshold_rssi, subghz); value_index = value_index_float( - subghz->txrx->raw_threshold_rssi, raw_theshold_rssi_value, RAW_THRESHOLD_RSSI_COUNT); + subghz->txrx->raw_threshold_rssi, raw_threshold_rssi_value, RAW_THRESHOLD_RSSI_COUNT); variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, raw_theshold_rssi_text[value_index]); + variable_item_set_current_value_text(item, raw_threshold_rssi_text[value_index]); } view_dispatcher_switch_to_view(subghz->view_dispatcher, SubGhzViewIdVariableItemList); } diff --git a/applications/main/subghz/scenes/subghz_scene_receiver_info.c b/applications/main/subghz/scenes/subghz_scene_receiver_info.c index 0b265cca2..e5b037f2e 100644 --- a/applications/main/subghz/scenes/subghz_scene_receiver_info.c +++ b/applications/main/subghz/scenes/subghz_scene_receiver_info.c @@ -148,7 +148,7 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) subghz_rx(subghz, subghz->txrx->preset->frequency); } if(subghz->txrx->hopper_state == SubGhzHopperStatePause) { - subghz->txrx->hopper_state = SubGhzHopperStateRunnig; + subghz->txrx->hopper_state = SubGhzHopperStateRunning; } subghz->state_notifications = SubGhzNotificationStateRx; } else { @@ -175,7 +175,7 @@ bool subghz_scene_receiver_info_on_event(void* context, SceneManagerEvent event) subghz_rx(subghz, subghz->txrx->preset->frequency); } if(subghz->txrx->hopper_state == SubGhzHopperStatePause) { - subghz->txrx->hopper_state = SubGhzHopperStateRunnig; + subghz->txrx->hopper_state = SubGhzHopperStateRunning; } subghz->state_notifications = SubGhzNotificationStateRx; } diff --git a/applications/main/subghz/scenes/subghz_scene_set_seed_bft.c b/applications/main/subghz/scenes/subghz_scene_set_seed_bft.c index 1d6f9d70b..2c48462ef 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_seed_bft.c +++ b/applications/main/subghz/scenes/subghz_scene_set_seed_bft.c @@ -14,7 +14,7 @@ void subghz_scene_set_seed_bft_on_enter(void* context) { SubGhz* subghz = context; // Setup view - // roguemaster don't steal!!! + // RogueMaster don't steal!!! ByteInput* byte_input = subghz->byte_input; byte_input_set_header_text(byte_input, "Enter SEED in hex"); byte_input_set_result_callback( diff --git a/applications/main/subghz/scenes/subghz_scene_set_seed_faac.c b/applications/main/subghz/scenes/subghz_scene_set_seed_faac.c index 8e955e4b7..55387a0a5 100644 --- a/applications/main/subghz/scenes/subghz_scene_set_seed_faac.c +++ b/applications/main/subghz/scenes/subghz_scene_set_seed_faac.c @@ -65,7 +65,7 @@ bool subghz_scene_set_seed_faac_on_event(void* context, SceneManagerEvent event) seed, "FAAC_SLH", subghz->txrx->preset); - // rogueemaster dont steal! + // RogueMaster dont steal! uint8_t seed_data[sizeof(uint32_t)] = {0}; for(size_t i = 0; i < sizeof(uint32_t); i++) { seed_data[sizeof(uint32_t) - i - 1] = (seed >> i * 8) & 0xFF; diff --git a/applications/main/subghz/subghz.c b/applications/main/subghz/subghz.c index 78295f08c..ac9270114 100644 --- a/applications/main/subghz/subghz.c +++ b/applications/main/subghz/subghz.c @@ -275,7 +275,7 @@ SubGhz* subghz_alloc(bool alloc_for_tx_only) { subghz->txrx->history = subghz_history_alloc(); } - subghz->txrx->raw_threshold_rssi = SUBGHZ_RAW_TRESHOLD_MIN; + subghz->txrx->raw_threshold_rssi = SUBGHZ_RAW_THRESHOLD_MIN; subghz->txrx->worker = subghz_worker_alloc(); subghz->txrx->fff_data = flipper_format_string_alloc(); diff --git a/applications/main/subghz/subghz_history.h b/applications/main/subghz/subghz_history.h index 607dbeae2..4b01f5aef 100644 --- a/applications/main/subghz/subghz_history.h +++ b/applications/main/subghz/subghz_history.h @@ -80,7 +80,7 @@ void subghz_history_get_text_item_menu(SubGhzHistory* instance, FuriString* outp * * @param instance - SubGhzHistory instance * @param output - FuriString* output - * @return bool - is FUUL + * @return bool - is FULL */ bool subghz_history_get_text_space_left(SubGhzHistory* instance, FuriString* output); diff --git a/applications/main/subghz/subghz_history_private.h b/applications/main/subghz/subghz_history_private.h index 7c554621b..12ce28fff 100644 --- a/applications/main/subghz/subghz_history_private.h +++ b/applications/main/subghz/subghz_history_private.h @@ -92,7 +92,7 @@ uint32_t subghz_history_rand_range(uint32_t min, uint32_t max); * * @param file - Stream* * @param is_negative_start - first value is negative or positive? - * @param current_position - 0 if started from begining + * @param current_position - 0 if started from beginning * @param empty_line - add RAW_Data to this line * @return true * @return false @@ -160,4 +160,4 @@ bool subghz_history_stream_seek_to_key(Stream* stream, const char* key, bool str * @return true * @return false */ -bool subghz_history_stream_read_value(Stream* stream, FuriString* value, bool* last); \ No newline at end of file +bool subghz_history_stream_read_value(Stream* stream, FuriString* value, bool* last); diff --git a/applications/main/subghz/subghz_i.c b/applications/main/subghz/subghz_i.c index 9f9a4be8f..c1a1a92ae 100644 --- a/applications/main/subghz/subghz_i.c +++ b/applications/main/subghz/subghz_i.c @@ -575,7 +575,7 @@ void subghz_hopper_update(SubGhz* subghz) { return; } } else { - subghz->txrx->hopper_state = SubGhzHopperStateRunnig; + subghz->txrx->hopper_state = SubGhzHopperStateRunning; } // Select next frequency if(subghz->txrx->hopper_idx_frequency < diff --git a/applications/main/subghz/views/receiver.c b/applications/main/subghz/views/receiver.c index 943fdf815..f5c48598b 100644 --- a/applications/main/subghz/views/receiver.c +++ b/applications/main/subghz/views/receiver.c @@ -14,7 +14,7 @@ #define MENU_ITEMS 4u #define UNLOCK_CNT 3 -#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f +#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f typedef struct { FuriString* item_str; @@ -82,10 +82,10 @@ void subghz_receiver_rssi(SubGhzViewReceiver* instance, float rssi) { instance->view, SubGhzViewReceiverModel * model, { - if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) { + if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) { model->u_rssi = 0; } else { - model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_TRESHOLD_MIN); + model->u_rssi = (uint8_t)(rssi - SUBGHZ_RAW_THRESHOLD_MIN); } }, true); diff --git a/applications/main/subghz/views/subghz_read_raw.c b/applications/main/subghz/views/subghz_read_raw.c index 7ba2f4434..fcc077efa 100644 --- a/applications/main/subghz/views/subghz_read_raw.c +++ b/applications/main/subghz/views/subghz_read_raw.c @@ -23,7 +23,7 @@ typedef struct { FuriString* sample_write; FuriString* file_name; uint8_t* rssi_history; - uint8_t rssi_curret; + uint8_t rssi_current; bool rssi_history_end; uint8_t ind_write; uint8_t ind_sin; @@ -62,17 +62,17 @@ void subghz_read_raw_add_data_rssi(SubGhzReadRAW* instance, float rssi, bool tra furi_assert(instance); uint8_t u_rssi = 0; - if(rssi < SUBGHZ_RAW_TRESHOLD_MIN) { + if(rssi < SUBGHZ_RAW_THRESHOLD_MIN) { u_rssi = 0; } else { - u_rssi = (uint8_t)((rssi - SUBGHZ_RAW_TRESHOLD_MIN) / 2.7); + u_rssi = (uint8_t)((rssi - SUBGHZ_RAW_THRESHOLD_MIN) / 2.7); } with_view_model( instance->view, SubGhzReadRAWModel * model, { - model->rssi_curret = u_rssi; + model->rssi_current = u_rssi; if(trace) { model->rssi_history[model->ind_write++] = u_rssi; } else { @@ -206,10 +206,10 @@ void subghz_read_raw_draw_rssi(Canvas* canvas, SubGhzReadRAWModel* model) { canvas_draw_line(canvas, i, 47, i, 47 - model->rssi_history[i]); } canvas_draw_line( - canvas, model->ind_write + 1, 47, model->ind_write + 1, 47 - model->rssi_curret); + canvas, model->ind_write + 1, 47, model->ind_write + 1, 47 - model->rssi_current); if(model->ind_write > 3) { canvas_draw_line( - canvas, model->ind_write - 1, 47, model->ind_write - 1, 47 - model->rssi_curret); + canvas, model->ind_write - 1, 47, model->ind_write - 1, 47 - model->rssi_current); for(uint8_t i = 13; i < 47; i += width * 2) { canvas_draw_line(canvas, model->ind_write, i, model->ind_write, i + width); @@ -231,13 +231,13 @@ void subghz_read_raw_draw_rssi(Canvas* canvas, SubGhzReadRAWModel* model) { SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE - 1, 47, SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE - 1, - 47 - model->rssi_curret); + 47 - model->rssi_current); canvas_draw_line( canvas, SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE + 1, 47, SUBGHZ_READ_RAW_RSSI_HISTORY_SIZE + 1, - 47 - model->rssi_curret); + 47 - model->rssi_current); for(uint8_t i = 13; i < 47; i += width * 2) { canvas_draw_line( @@ -266,9 +266,9 @@ void subghz_read_raw_draw_threshold_rssi(Canvas* canvas, SubGhzReadRAWModel* mod uint8_t x = 118; uint8_t y = 48; - if(model->raw_threshold_rssi > SUBGHZ_RAW_TRESHOLD_MIN) { + if(model->raw_threshold_rssi > SUBGHZ_RAW_THRESHOLD_MIN) { uint8_t x = 118; - y -= (uint8_t)((model->raw_threshold_rssi - SUBGHZ_RAW_TRESHOLD_MIN) / 2.7); + y -= (uint8_t)((model->raw_threshold_rssi - SUBGHZ_RAW_THRESHOLD_MIN) / 2.7); uint8_t width = 3; for(uint8_t i = 0; i < x; i += width * 2) { diff --git a/applications/main/subghz/views/subghz_read_raw.h b/applications/main/subghz/views/subghz_read_raw.h index 43afac427..9d63870d5 100644 --- a/applications/main/subghz/views/subghz_read_raw.h +++ b/applications/main/subghz/views/subghz_read_raw.h @@ -3,7 +3,7 @@ #include #include "../helpers/subghz_custom_event.h" -#define SUBGHZ_RAW_TRESHOLD_MIN -90.0f +#define SUBGHZ_RAW_THRESHOLD_MIN -90.0f typedef struct SubGhzReadRAW SubGhzReadRAW; diff --git a/applications/main/u2f/u2f_data.c b/applications/main/u2f/u2f_data.c index 66604d166..217733c94 100644 --- a/applications/main/u2f/u2f_data.c +++ b/applications/main/u2f/u2f_data.c @@ -178,7 +178,7 @@ bool u2f_data_cert_key_load(uint8_t* cert_key) { uint8_t key_slot = 0; uint32_t version = 0; - // Check if unique key exists in secure eclave and generate it if missing + // Check if unique key exists in secure eclave(typo?) and generate it if missing if(!furi_hal_crypto_verify_key(U2F_DATA_FILE_ENCRYPTION_KEY_SLOT_UNIQUE)) return false; FuriString* filetype; diff --git a/applications/main/unirfremix/unirfremix_app.c b/applications/main/unirfremix/unirfremix_app.c index a0e131882..a4e5249fa 100644 --- a/applications/main/unirfremix/unirfremix_app.c +++ b/applications/main/unirfremix/unirfremix_app.c @@ -640,7 +640,7 @@ static void render_callback(Canvas* canvas, void* ctx) { //canvas_draw_str(canvas, 0, 40, "D: "); //canvas_draw_str(canvas, 0, 50, "Ok: "); - //PNGs are located in assets/icons/UniRFRemix before compiliation + //PNGs are located in assets/icons/UniRFRemix before compilation //Icons for Labels //canvas_draw_icon(canvas, 0, 0, &I_UniRFRemix_LeftAlignedButtons_9x64); diff --git a/applications/plugins/swd_probe/.gitignore b/applications/plugins/swd_probe/.gitignore new file mode 100644 index 000000000..c6127b38c --- /dev/null +++ b/applications/plugins/swd_probe/.gitignore @@ -0,0 +1,52 @@ +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf diff --git a/applications/plugins/swd_probe/LICENSE.txt b/applications/plugins/swd_probe/LICENSE.txt new file mode 100644 index 000000000..f288702d2 --- /dev/null +++ b/applications/plugins/swd_probe/LICENSE.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/applications/plugins/swd_probe/README.md b/applications/plugins/swd_probe/README.md new file mode 100644 index 000000000..e69de29bb diff --git a/applications/plugins/swd_probe/adi.c b/applications/plugins/swd_probe/adi.c new file mode 100644 index 000000000..95456fcd0 --- /dev/null +++ b/applications/plugins/swd_probe/adi.c @@ -0,0 +1,1016 @@ + +#include +#include + +#include "adi.h" +#include "swd_probe_app.h" + +/* https://github.com/openocd-org/openocd/blob/master/src/target/arm_adi_v5.c */ + +/* +static const char* class_description[16] = { + [0x0] = "Generic verification component", + [0x1] = "(ROM Table)", + [0x2] = "Reserved", + [0x3] = "Reserved", + [0x4] = "Reserved", + [0x5] = "Reserved", + [0x6] = "Reserved", + [0x7] = "Reserved", + [0x8] = "Reserved", + [0x9] = "CoreSight component", + [0xA] = "Reserved", + [0xB] = "Peripheral Test Block", + [0xC] = "Reserved", + [0xD] = "OptimoDE DESS", + [0xE] = "Generic IP component", + [0xF] = "CoreLink, PrimeCell or System component", +}; +*/ + +static const struct { + uint32_t arch_id; + const char* description; +} class0x9_devarch[] = { + /* keep same unsorted order as in ARM IHI0029E */ + {ARCH_ID(ARM_ID, 0x0A00), "RAS architecture"}, + {ARCH_ID(ARM_ID, 0x1A01), "Instrumentation Trace Macrocell (ITM) architecture"}, + {ARCH_ID(ARM_ID, 0x1A02), "DWT architecture"}, + {ARCH_ID(ARM_ID, 0x1A03), "Flash Patch and Breakpoint unit (FPB) architecture"}, + {ARCH_ID(ARM_ID, 0x2A04), "Processor debug architecture (ARMv8-M)"}, + {ARCH_ID(ARM_ID, 0x6A05), "Processor debug architecture (ARMv8-R)"}, + {ARCH_ID(ARM_ID, 0x0A10), "PC sample-based profiling"}, + {ARCH_ID(ARM_ID, 0x4A13), "Embedded Trace Macrocell (ETM) architecture"}, + {ARCH_ID(ARM_ID, 0x1A14), "Cross Trigger Interface (CTI) architecture"}, + {ARCH_ID(ARM_ID, 0x6A15), "Processor debug architecture (v8.0-A)"}, + {ARCH_ID(ARM_ID, 0x7A15), "Processor debug architecture (v8.1-A)"}, + {ARCH_ID(ARM_ID, 0x8A15), "Processor debug architecture (v8.2-A)"}, + {ARCH_ID(ARM_ID, 0x2A16), "Processor Performance Monitor (PMU) architecture"}, + {ARCH_ID(ARM_ID, 0x0A17), "Memory Access Port v2 architecture"}, + {ARCH_ID(ARM_ID, 0x0A27), "JTAG Access Port v2 architecture"}, + {ARCH_ID(ARM_ID, 0x0A31), "Basic trace router"}, + {ARCH_ID(ARM_ID, 0x0A37), "Power requestor"}, + {ARCH_ID(ARM_ID, 0x0A47), "Unknown Access Port v2 architecture"}, + {ARCH_ID(ARM_ID, 0x0A50), "HSSTP architecture"}, + {ARCH_ID(ARM_ID, 0x0A63), "System Trace Macrocell (STM) architecture"}, + {ARCH_ID(ARM_ID, 0x0A75), "CoreSight ELA architecture"}, + {ARCH_ID(ARM_ID, 0x0AF7), "CoreSight ROM architecture"}, +}; + +/* Part number interpretations are from Cortex + * core specs, the CoreSight components TRM + * (ARM DDI 0314H), CoreSight System Design + * Guide (ARM DGI 0012D) and ETM specs; also + * from chip observation (e.g. TI SDTI). + */ + +static const struct dap_part_nums { + uint16_t designer_id; + uint16_t part_num; + const char* type; + const char* full; +} dap_part_nums[] = { + { + ARM_ID, + 0x000, + "Cortex-M3 SCS", + "(System Control Space)", + }, + { + ARM_ID, + 0x001, + "Cortex-M3 ITM", + "(Instrumentation Trace Module)", + }, + { + ARM_ID, + 0x002, + "Cortex-M3 DWT", + "(Data Watchpoint and Trace)", + }, + { + ARM_ID, + 0x003, + "Cortex-M3 FPB", + "(Flash Patch and Breakpoint)", + }, + { + ARM_ID, + 0x008, + "Cortex-M0 SCS", + "(System Control Space)", + }, + { + ARM_ID, + 0x00a, + "Cortex-M0 DWT", + "(Data Watchpoint and Trace)", + }, + { + ARM_ID, + 0x00b, + "Cortex-M0 BPU", + "(Breakpoint Unit)", + }, + { + ARM_ID, + 0x00c, + "Cortex-M4 SCS", + "(System Control Space)", + }, + { + ARM_ID, + 0x00d, + "CoreSight ETM11", + "(Embedded Trace)", + }, + { + ARM_ID, + 0x00e, + "Cortex-M7 FPB", + "(Flash Patch and Breakpoint)", + }, + { + ARM_ID, + 0x193, + "SoC-600 TSGEN", + "(Timestamp Generator)", + }, + { + ARM_ID, + 0x470, + "Cortex-M1 ROM", + "(ROM Table)", + }, + { + ARM_ID, + 0x471, + "Cortex-M0 ROM", + "(ROM Table)", + }, + { + ARM_ID, + 0x490, + "Cortex-A15 GIC", + "(Generic Interrupt Controller)", + }, + { + ARM_ID, + 0x492, + "Cortex-R52 GICD", + "(Distributor)", + }, + { + ARM_ID, + 0x493, + "Cortex-R52 GICR", + "(Redistributor)", + }, + { + ARM_ID, + 0x4a1, + "Cortex-A53 ROM", + "(v8 Memory Map ROM Table)", + }, + { + ARM_ID, + 0x4a2, + "Cortex-A57 ROM", + "(ROM Table)", + }, + { + ARM_ID, + 0x4a3, + "Cortex-A53 ROM", + "(v7 Memory Map ROM Table)", + }, + { + ARM_ID, + 0x4a4, + "Cortex-A72 ROM", + "(ROM Table)", + }, + { + ARM_ID, + 0x4a9, + "Cortex-A9 ROM", + "(ROM Table)", + }, + { + ARM_ID, + 0x4aa, + "Cortex-A35 ROM", + "(v8 Memory Map ROM Table)", + }, + { + ARM_ID, + 0x4af, + "Cortex-A15 ROM", + "(ROM Table)", + }, + { + ARM_ID, + 0x4b5, + "Cortex-R5 ROM", + "(ROM Table)", + }, + { + ARM_ID, + 0x4b8, + "Cortex-R52 ROM", + "(ROM Table)", + }, + { + ARM_ID, + 0x4c0, + "Cortex-M0+ ROM", + "(ROM Table)", + }, + { + ARM_ID, + 0x4c3, + "Cortex-M3 ROM", + "(ROM Table)", + }, + { + ARM_ID, + 0x4c4, + "Cortex-M4 ROM", + "(ROM Table)", + }, + { + ARM_ID, + 0x4c7, + "Cortex-M7 PPB ROM", + "(Private Peripheral Bus ROM Table)", + }, + { + ARM_ID, + 0x4c8, + "Cortex-M7 ROM", + "(ROM Table)", + }, + { + ARM_ID, + 0x4e0, + "Cortex-A35 ROM", + "(v7 Memory Map ROM Table)", + }, + { + ARM_ID, + 0x4e4, + "Cortex-A76 ROM", + "(ROM Table)", + }, + { + ARM_ID, + 0x906, + "CoreSight CTI", + "(Cross Trigger)", + }, + { + ARM_ID, + 0x907, + "CoreSight ETB", + "(Trace Buffer)", + }, + { + ARM_ID, + 0x908, + "CoreSight CSTF", + "(Trace Funnel)", + }, + { + ARM_ID, + 0x909, + "CoreSight ATBR", + "(Advanced Trace Bus Replicator)", + }, + { + ARM_ID, + 0x910, + "CoreSight ETM9", + "(Embedded Trace)", + }, + { + ARM_ID, + 0x912, + "CoreSight TPIU", + "(Trace Port Interface Unit)", + }, + { + ARM_ID, + 0x913, + "CoreSight ITM", + "(Instrumentation Trace Macrocell)", + }, + { + ARM_ID, + 0x914, + "CoreSight SWO", + "(Single Wire Output)", + }, + { + ARM_ID, + 0x917, + "CoreSight HTM", + "(AHB Trace Macrocell)", + }, + { + ARM_ID, + 0x920, + "CoreSight ETM11", + "(Embedded Trace)", + }, + { + ARM_ID, + 0x921, + "Cortex-A8 ETM", + "(Embedded Trace)", + }, + { + ARM_ID, + 0x922, + "Cortex-A8 CTI", + "(Cross Trigger)", + }, + { + ARM_ID, + 0x923, + "Cortex-M3 TPIU", + "(Trace Port Interface Unit)", + }, + { + ARM_ID, + 0x924, + "Cortex-M3 ETM", + "(Embedded Trace)", + }, + { + ARM_ID, + 0x925, + "Cortex-M4 ETM", + "(Embedded Trace)", + }, + { + ARM_ID, + 0x930, + "Cortex-R4 ETM", + "(Embedded Trace)", + }, + { + ARM_ID, + 0x931, + "Cortex-R5 ETM", + "(Embedded Trace)", + }, + { + ARM_ID, + 0x932, + "CoreSight MTB-M0+", + "(Micro Trace Buffer)", + }, + { + ARM_ID, + 0x941, + "CoreSight TPIU-Lite", + "(Trace Port Interface Unit)", + }, + { + ARM_ID, + 0x950, + "Cortex-A9 PTM", + "(Program Trace Macrocell)", + }, + { + ARM_ID, + 0x955, + "Cortex-A5 ETM", + "(Embedded Trace)", + }, + { + ARM_ID, + 0x95a, + "Cortex-A72 ETM", + "(Embedded Trace)", + }, + { + ARM_ID, + 0x95b, + "Cortex-A17 PTM", + "(Program Trace Macrocell)", + }, + { + ARM_ID, + 0x95d, + "Cortex-A53 ETM", + "(Embedded Trace)", + }, + { + ARM_ID, + 0x95e, + "Cortex-A57 ETM", + "(Embedded Trace)", + }, + { + ARM_ID, + 0x95f, + "Cortex-A15 PTM", + "(Program Trace Macrocell)", + }, + { + ARM_ID, + 0x961, + "CoreSight TMC", + "(Trace Memory Controller)", + }, + { + ARM_ID, + 0x962, + "CoreSight STM", + "(System Trace Macrocell)", + }, + { + ARM_ID, + 0x975, + "Cortex-M7 ETM", + "(Embedded Trace)", + }, + { + ARM_ID, + 0x9a0, + "CoreSight PMU", + "(Performance Monitoring Unit)", + }, + { + ARM_ID, + 0x9a1, + "Cortex-M4 TPIU", + "(Trace Port Interface Unit)", + }, + { + ARM_ID, + 0x9a4, + "CoreSight GPR", + "(Granular Power Requester)", + }, + { + ARM_ID, + 0x9a5, + "Cortex-A5 PMU", + "(Performance Monitor Unit)", + }, + { + ARM_ID, + 0x9a7, + "Cortex-A7 PMU", + "(Performance Monitor Unit)", + }, + { + ARM_ID, + 0x9a8, + "Cortex-A53 CTI", + "(Cross Trigger)", + }, + { + ARM_ID, + 0x9a9, + "Cortex-M7 TPIU", + "(Trace Port Interface Unit)", + }, + { + ARM_ID, + 0x9ae, + "Cortex-A17 PMU", + "(Performance Monitor Unit)", + }, + { + ARM_ID, + 0x9af, + "Cortex-A15 PMU", + "(Performance Monitor Unit)", + }, + { + ARM_ID, + 0x9b6, + "Cortex-R52 PMU/CTI/ETM", + "(Performance Monitor Unit/Cross Trigger/ETM)", + }, + { + ARM_ID, + 0x9b7, + "Cortex-R7 PMU", + "(Performance Monitor Unit)", + }, + { + ARM_ID, + 0x9d3, + "Cortex-A53 PMU", + "(Performance Monitor Unit)", + }, + { + ARM_ID, + 0x9d7, + "Cortex-A57 PMU", + "(Performance Monitor Unit)", + }, + { + ARM_ID, + 0x9d8, + "Cortex-A72 PMU", + "(Performance Monitor Unit)", + }, + { + ARM_ID, + 0x9da, + "Cortex-A35 PMU/CTI/ETM", + "(Performance Monitor Unit/Cross Trigger/ETM)", + }, + { + ARM_ID, + 0x9e2, + "SoC-600 APB-AP", + "(APB4 Memory Access Port)", + }, + { + ARM_ID, + 0x9e3, + "SoC-600 AHB-AP", + "(AHB5 Memory Access Port)", + }, + { + ARM_ID, + 0x9e4, + "SoC-600 AXI-AP", + "(AXI Memory Access Port)", + }, + { + ARM_ID, + 0x9e5, + "SoC-600 APv1 Adapter", + "(Access Port v1 Adapter)", + }, + { + ARM_ID, + 0x9e6, + "SoC-600 JTAG-AP", + "(JTAG Access Port)", + }, + { + ARM_ID, + 0x9e7, + "SoC-600 TPIU", + "(Trace Port Interface Unit)", + }, + { + ARM_ID, + 0x9e8, + "SoC-600 TMC ETR/ETS", + "(Embedded Trace Router/Streamer)", + }, + { + ARM_ID, + 0x9e9, + "SoC-600 TMC ETB", + "(Embedded Trace Buffer)", + }, + { + ARM_ID, + 0x9ea, + "SoC-600 TMC ETF", + "(Embedded Trace FIFO)", + }, + { + ARM_ID, + 0x9eb, + "SoC-600 ATB Funnel", + "(Trace Funnel)", + }, + { + ARM_ID, + 0x9ec, + "SoC-600 ATB Replicator", + "(Trace Replicator)", + }, + { + ARM_ID, + 0x9ed, + "SoC-600 CTI", + "(Cross Trigger)", + }, + { + ARM_ID, + 0x9ee, + "SoC-600 CATU", + "(Address Translation Unit)", + }, + { + ARM_ID, + 0xc05, + "Cortex-A5 Debug", + "(Debug Unit)", + }, + { + ARM_ID, + 0xc07, + "Cortex-A7 Debug", + "(Debug Unit)", + }, + { + ARM_ID, + 0xc08, + "Cortex-A8 Debug", + "(Debug Unit)", + }, + { + ARM_ID, + 0xc09, + "Cortex-A9 Debug", + "(Debug Unit)", + }, + { + ARM_ID, + 0xc0e, + "Cortex-A17 Debug", + "(Debug Unit)", + }, + { + ARM_ID, + 0xc0f, + "Cortex-A15 Debug", + "(Debug Unit)", + }, + { + ARM_ID, + 0xc14, + "Cortex-R4 Debug", + "(Debug Unit)", + }, + { + ARM_ID, + 0xc15, + "Cortex-R5 Debug", + "(Debug Unit)", + }, + { + ARM_ID, + 0xc17, + "Cortex-R7 Debug", + "(Debug Unit)", + }, + { + ARM_ID, + 0xd03, + "Cortex-A53 Debug", + "(Debug Unit)", + }, + { + ARM_ID, + 0xd04, + "Cortex-A35 Debug", + "(Debug Unit)", + }, + { + ARM_ID, + 0xd07, + "Cortex-A57 Debug", + "(Debug Unit)", + }, + { + ARM_ID, + 0xd08, + "Cortex-A72 Debug", + "(Debug Unit)", + }, + { + ARM_ID, + 0xd0b, + "Cortex-A76 Debug", + "(Debug Unit)", + }, + { + ARM_ID, + 0xd0c, + "Neoverse N1", + "(Debug Unit)", + }, + { + ARM_ID, + 0xd13, + "Cortex-R52 Debug", + "(Debug Unit)", + }, + { + ARM_ID, + 0xd49, + "Neoverse N2", + "(Debug Unit)", + }, + { + 0x017, + 0x120, + "TI SDTI", + "(System Debug Trace Interface)", + }, /* from OMAP3 memmap */ + { + 0x017, + 0x343, + "TI DAPCTL", + "", + }, /* from OMAP3 memmap */ + {0x017, 0x9af, "MSP432 ROM", "(ROM Table)"}, + {0x01f, 0xcd0, "Atmel CPU with DSU", "(CPU)"}, + {0x041, 0x1db, "XMC4500 ROM", "(ROM Table)"}, + {0x041, 0x1df, "XMC4700/4800 ROM", "(ROM Table)"}, + {0x041, 0x1ed, "XMC1000 ROM", "(ROM Table)"}, + { + 0x065, + 0x000, + "SHARC+/Blackfin+", + "", + }, + { + 0x070, + 0x440, + "Qualcomm QDSS Component v1", + "(Qualcomm Designed CoreSight Component v1)", + }, + { + 0x0bf, + 0x100, + "Brahma-B53 Debug", + "(Debug Unit)", + }, + { + 0x0bf, + 0x9d3, + "Brahma-B53 PMU", + "(Performance Monitor Unit)", + }, + { + 0x0bf, + 0x4a1, + "Brahma-B53 ROM", + "(ROM Table)", + }, + { + 0x0bf, + 0x721, + "Brahma-B53 ROM", + "(ROM Table)", + }, + { + 0x1eb, + 0x181, + "Tegra 186 ROM", + "(ROM Table)", + }, + { + 0x1eb, + 0x202, + "Denver ETM", + "(Denver Embedded Trace)", + }, + { + 0x1eb, + 0x211, + "Tegra 210 ROM", + "(ROM Table)", + }, + { + 0x1eb, + 0x302, + "Denver Debug", + "(Debug Unit)", + }, + { + 0x1eb, + 0x402, + "Denver PMU", + "(Performance Monitor Unit)", + }, + {0x20, 0x410, "STM32F10 (med)", "(ROM Table)"}, + {0x20, 0x411, "STM32F2", "(ROM Table)"}, + {0x20, 0x412, "STM32F10 (low)", "(ROM Table)"}, + {0x20, 0x413, "STM32F40/41", "(ROM Table)"}, + {0x20, 0x414, "STM32F10 (high)", "(ROM Table)"}, + {0x20, 0x415, "STM32L47/48", "(ROM Table)"}, + {0x20, 0x416, "STM32L1xxx6/8/B", "(ROM Table)"}, + {0x20, 0x417, "STM32L05/06", "(ROM Table)"}, + {0x20, 0x418, "STM32F105xx/107", "(ROM Table)"}, + {0x20, 0x419, "STM32F42/43", "(ROM Table)"}, + {0x20, 0x420, "STM32F10 (med)", "(ROM Table)"}, + {0x20, 0x421, "STM32F446xx", "(ROM Table)"}, + {0x20, 0x422, "STM32FF358/02/03", "(ROM Table)"}, + {0x20, 0x423, "STM32F401xB/C", "(ROM Table)"}, + {0x20, 0x425, "STM32L031/41", "(ROM Table)"}, + {0x20, 0x427, "STM32L1xxxC", "(ROM Table)"}, + {0x20, 0x428, "STM32F10 (high)", "(ROM Table)"}, + {0x20, 0x429, "STM32L1xxx6A/8A/BA", "(ROM Table)"}, + {0x20, 0x430, "STM32F10 (xl)", "(ROM Table)"}, + {0x20, 0x431, "STM32F411xx", "(ROM Table)"}, + {0x20, 0x432, "STM32F373/8", "(ROM Table)"}, + {0x20, 0x433, "STM32F401xD/E", "(ROM Table)"}, + {0x20, 0x434, "STM32F469/79", "(ROM Table)"}, + {0x20, 0x435, "STM32L43/44", "(ROM Table)"}, + {0x20, 0x436, "STM32L1xxxD", "(ROM Table)"}, + {0x20, 0x437, "STM32L1xxxE", "(ROM Table)"}, + {0x20, 0x438, "STM32F303/34/28", "(ROM Table)"}, + {0x20, 0x439, "STM32F301/02/18 ", "(ROM Table)"}, + {0x20, 0x440, "STM32F03/5", "(ROM Table)"}, + {0x20, 0x441, "STM32F412xx", "(ROM Table)"}, + {0x20, 0x442, "STM32F03/9", "(ROM Table)"}, + {0x20, 0x444, "STM32F03xx4", "(ROM Table)"}, + {0x20, 0x445, "STM32F04/7", "(ROM Table)"}, + {0x20, 0x446, "STM32F302/03/98", "(ROM Table)"}, + {0x20, 0x447, "STM32L07/08", "(ROM Table)"}, + {0x20, 0x448, "STM32F070/1/2", "(ROM Table)"}, + {0x20, 0x449, "STM32F74/5", "(ROM Table)"}, + {0x20, 0x450, "STM32H74/5", "(ROM Table)"}, + {0x20, 0x451, "STM32F76/7", "(ROM Table)"}, + {0x20, 0x452, "STM32F72/3", "(ROM Table)"}, + {0x20, 0x457, "STM32L01/2", "(ROM Table)"}, + {0x20, 0x458, "STM32F410xx", "(ROM Table)"}, + {0x20, 0x460, "STM32G07/8", "(ROM Table)"}, + {0x20, 0x461, "STM32L496/A6", "(ROM Table)"}, + {0x20, 0x462, "STM32L45/46", "(ROM Table)"}, + {0x20, 0x463, "STM32F413/23", "(ROM Table)"}, + {0x20, 0x464, "STM32L412/22", "(ROM Table)"}, + {0x20, 0x466, "STM32G03/04", "(ROM Table)"}, + {0x20, 0x468, "STM32G431/41", "(ROM Table)"}, + {0x20, 0x469, "STM32G47/48", "(ROM Table)"}, + {0x20, 0x470, "STM32L4R/S", "(ROM Table)"}, + {0x20, 0x471, "STM32L4P5/Q5", "(ROM Table)"}, + {0x20, 0x479, "STM32G491xx", "(ROM Table)"}, + {0x20, 0x480, "STM32H7A/B", "(ROM Table)"}, + {0x20, 0x495, "STM32WB50/55", "(ROM Table)"}, + {0x20, 0x497, "STM32WLE5xx", "(ROM Table)"}}; + +const char* adi_devarch_desc(uint32_t devarch) { + if(!(devarch & ARM_CS_C9_DEVARCH_PRESENT)) { + return "not present"; + } + + for(unsigned int i = 0; i < ARRAY_SIZE(class0x9_devarch); i++) { + if((devarch & DEVARCH_ID_MASK) == class0x9_devarch[i].arch_id) { + return class0x9_devarch[i].description; + } + } + + return "unknown"; +} + +const struct dap_part_nums* adi_part_num(unsigned int des, unsigned int part) { + static char buf[32]; + static struct dap_part_nums unknown = { + .type = "Unrecognized", + .full = "", + }; + + for(unsigned int i = 0; i < ARRAY_SIZE(dap_part_nums); i++) { + if(dap_part_nums[i].designer_id == des && dap_part_nums[i].part_num == part) { + return &dap_part_nums[i]; + } + } + + snprintf(buf, sizeof(buf), "D:%x P:%x", des, part); + unknown.full = buf; + + return &unknown; +} + +bool adi_get_pidr(AppFSM* const ctx, uint32_t base, pidr_data_t* data) { + uint32_t pidrs[7]; + uint32_t offsets[] = {0xFE0, 0xFE4, 0xFE8, 0xFEC, 0xFD0, 0xFD4, 0xFD8, 0xFDC}; + + furi_mutex_acquire(ctx->swd_mutex, FuriWaitForever); + for(size_t pos = 0; pos < COUNT(pidrs); pos++) { + uint8_t ret = swd_read_memory(ctx, ctx->ap_pos, base + offsets[pos], &pidrs[pos]); + if(ret != 1) { + DBGS("Read failed"); + furi_mutex_release(ctx->swd_mutex); + return false; + } + } + furi_mutex_release(ctx->swd_mutex); + + data->designer = ((pidrs[4] & 0x0F) << 7) | ((pidrs[2] & 0x07) << 4) | + ((pidrs[1] >> 4) & 0x0F); + data->part = (pidrs[0] & 0xFF) | ((pidrs[1] & 0x0F) << 8); + data->revand = ((pidrs[3] >> 4) & 0x0F); + data->cmod = (pidrs[3] & 0x0F); + data->revision = ((pidrs[2] >> 4) & 0x0F); + data->size = ((pidrs[2] >> 4) & 0x0F); + + return true; +} + +bool adi_get_class(AppFSM* const ctx, uint32_t base, uint8_t* class) { + uint32_t cidrs[4]; + uint32_t offsets[] = {0xFF0, 0xFF4, 0xFF8, 0xFFC}; + + furi_mutex_acquire(ctx->swd_mutex, FuriWaitForever); + for(size_t pos = 0; pos < COUNT(cidrs); pos++) { + uint8_t ret = swd_read_memory(ctx, ctx->ap_pos, base + offsets[pos], &cidrs[pos]); + if(ret != 1) { + DBGS("Read failed"); + furi_mutex_release(ctx->swd_mutex); + return false; + } + } + furi_mutex_release(ctx->swd_mutex); + + if((cidrs[0] & 0xFF) != 0x0D) { + return false; + } + if((cidrs[1] & 0x0F) != 0x00) { + return false; + } + if((cidrs[2] & 0xFF) != 0x05) { + return false; + } + if((cidrs[3] & 0xFF) != 0xB1) { + return false; + } + + *class = ((cidrs[1] >> 4) & 0x0F); + + return true; +} + +const char* adi_romtable_type(AppFSM* const ctx, uint32_t base) { + pidr_data_t data; + + if(!adi_get_pidr(ctx, base, &data)) { + return "fail"; + } + const struct dap_part_nums* info = adi_part_num(data.designer, data.part); + + return info->type; +} + +const char* adi_romtable_full(AppFSM* const ctx, uint32_t base) { + pidr_data_t data; + + if(!adi_get_pidr(ctx, base, &data)) { + return "fail"; + } + const struct dap_part_nums* info = adi_part_num(data.designer, data.part); + + return info->full; +} + +uint32_t adi_romtable_entry_count(AppFSM* const ctx, uint32_t base) { + uint32_t count = 0; + uint32_t entry = 0; + + furi_mutex_acquire(ctx->swd_mutex, FuriWaitForever); + for(size_t pos = 0; pos < 960; pos++) { + uint8_t ret = 0; + for(int tries = 0; tries < 10 && ret != 1; tries++) { + ret = swd_read_memory(ctx, ctx->ap_pos, base + pos * 4, &entry); + } + if(ret != 1) { + DBGS("Read failed"); + break; + } + if(!(entry & 1)) { + break; + } + if(entry & 0x00000FFC) { + break; + } + count++; + } + furi_mutex_release(ctx->swd_mutex); + return count; +} + +uint32_t adi_romtable_get(AppFSM* const ctx, uint32_t base, uint32_t pos) { + uint32_t entry = 0; + + furi_mutex_acquire(ctx->swd_mutex, FuriWaitForever); + uint8_t ret = swd_read_memory(ctx, ctx->ap_pos, base + pos * 4, &entry); + if(ret != 1) { + DBGS("Read failed"); + furi_mutex_release(ctx->swd_mutex); + return 0; + } + furi_mutex_release(ctx->swd_mutex); + + return base + (entry & 0xFFFFF000); +} + +bool adi_is_romtable(AppFSM* const ctx, uint32_t base) { + uint8_t class = 0; + + if(!adi_get_class(ctx, base, &class)) { + return false; + } + + if(class != CIDR_CLASS_ROMTABLE) { + return false; + } + + return true; +} diff --git a/applications/plugins/swd_probe/adi.h b/applications/plugins/swd_probe/adi.h new file mode 100644 index 000000000..bade7736a --- /dev/null +++ b/applications/plugins/swd_probe/adi.h @@ -0,0 +1,34 @@ + +#ifndef __ADI_H__ +#define __ADI_H__ + +#include "swd_probe_app.h" + +#define ARM_ID 0x23B + +#define ARCH_ID(architect, archid) ((architect) << 21) | (archid) + +#define BIT(nr) (1UL << (nr)) +#define ARM_CS_C9_DEVARCH_PRESENT BIT(20) +#define ARM_CS_C9_DEVARCH_ARCHITECT_MASK (0xFFE00000) +#define ARM_CS_C9_DEVARCH_ARCHID_MASK (0x0000FFFF) +#define DEVARCH_ID_MASK (ARM_CS_C9_DEVARCH_ARCHITECT_MASK | ARM_CS_C9_DEVARCH_ARCHID_MASK) + +typedef struct { + uint16_t designer; + uint16_t part; + uint8_t revision; + uint8_t cmod; + uint8_t revand; + uint8_t size; +} pidr_data_t; + +typedef enum { CIDR_CLASS_ROMTABLE = 0x01, CIDR_CLASS_CORESIGHT = 0x09 } cidr_classes_t; + +uint32_t adi_romtable_entry_count(AppFSM* const ctx, uint32_t base); +uint32_t adi_romtable_get(AppFSM* const ctx, uint32_t base, uint32_t pos); +bool adi_is_romtable(AppFSM* const ctx, uint32_t base); +const char* adi_romtable_type(AppFSM* const ctx, uint32_t base); +const char* adi_romtable_full(AppFSM* const ctx, uint32_t base); + +#endif diff --git a/applications/plugins/swd_probe/application.fam b/applications/plugins/swd_probe/application.fam new file mode 100644 index 000000000..64140d130 --- /dev/null +++ b/applications/plugins/swd_probe/application.fam @@ -0,0 +1,13 @@ +App( + appid="swd_probe", + name="SWD Probe", + apptype=FlipperAppType.PLUGIN, + entry_point="swd_probe_app_main", + cdefines=["APP_SWD_PROBE"], + requires=["notification", "gui", "storage", "dialogs", "cli"], + stack_size=2 * 1024, + order=10, + fap_icon="icons/app.png", + fap_category="Tools", + fap_icon_assets="icons" +) diff --git a/applications/plugins/swd_probe/icons/ButtonDown_7x4.png b/applications/plugins/swd_probe/icons/ButtonDown_7x4.png new file mode 100644 index 000000000..2954bb6a6 Binary files /dev/null and b/applications/plugins/swd_probe/icons/ButtonDown_7x4.png differ diff --git a/applications/plugins/swd_probe/icons/ButtonUp_7x4.png b/applications/plugins/swd_probe/icons/ButtonUp_7x4.png new file mode 100644 index 000000000..1be79328b Binary files /dev/null and b/applications/plugins/swd_probe/icons/ButtonUp_7x4.png differ diff --git a/applications/plugins/swd_probe/icons/app.png b/applications/plugins/swd_probe/icons/app.png new file mode 100644 index 000000000..6949ce78d Binary files /dev/null and b/applications/plugins/swd_probe/icons/app.png differ diff --git a/applications/plugins/swd_probe/icons/swd.png b/applications/plugins/swd_probe/icons/swd.png new file mode 100644 index 000000000..c8cb5831b Binary files /dev/null and b/applications/plugins/swd_probe/icons/swd.png differ diff --git a/applications/plugins/swd_probe/jep106.c b/applications/plugins/swd_probe/jep106.c new file mode 100644 index 000000000..65df94dba --- /dev/null +++ b/applications/plugins/swd_probe/jep106.c @@ -0,0 +1,26 @@ +/* https://github.com/openocd-org/openocd/blob/master/src/helper/ */ +// SPDX-License-Identifier: GPL-2.0-or-later + +/*************************************************************************** + * Copyright (C) 2015 Andreas Fritiofson * + * andreas.fritiofson@gmail.com * + ***************************************************************************/ + +#include "jep106.h" + +static const char* const jep106[][126] = { +#include "jep106.inc" +}; + +const char* jep106_table_manufacturer(unsigned int bank, unsigned int id) { + if(id < 1 || id > 126) { + return ""; + } + + /* index is zero based */ + id--; + + if(bank >= 14 || jep106[bank][id] == 0) return ""; + + return jep106[bank][id]; +} diff --git a/applications/plugins/swd_probe/jep106.h b/applications/plugins/swd_probe/jep106.h new file mode 100644 index 000000000..17c87feaa --- /dev/null +++ b/applications/plugins/swd_probe/jep106.h @@ -0,0 +1,26 @@ +/* https://github.com/openocd-org/openocd/blob/master/src/helper/ */ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/*************************************************************************** + * Copyright (C) 2015 Andreas Fritiofson * + * andreas.fritiofson@gmail.com * + ***************************************************************************/ + +#ifndef OPENOCD_HELPER_JEP106_H +#define OPENOCD_HELPER_JEP106_H + +/** + * Get the manufacturer name associated with a JEP106 ID. + * @param bank The bank (number of continuation codes) of the manufacturer ID. + * @param id The 7-bit manufacturer ID (i.e. with parity stripped). + * @return A pointer to static const storage containing the name of the + * manufacturer associated with bank and id, or one of the strings + * "" and "". + */ +const char* jep106_table_manufacturer(unsigned int bank, unsigned int id); + +static inline const char* jep106_manufacturer(unsigned int manufacturer) { + return jep106_table_manufacturer(manufacturer >> 7, manufacturer & 0x7f); +} + +#endif /* OPENOCD_HELPER_JEP106_H */ diff --git a/applications/plugins/swd_probe/jep106.inc b/applications/plugins/swd_probe/jep106.inc new file mode 100644 index 000000000..3adc131be --- /dev/null +++ b/applications/plugins/swd_probe/jep106.inc @@ -0,0 +1,1791 @@ +/* https://github.com/openocd-org/openocd/blob/master/src/helper/ */ + +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +/* + * The manufacturer's standard identification code list appears in JEP106. + * Copyright (c) 2022 JEDEC. All rights reserved. + * + * JEP106 is regularly updated. For the current manufacturer's standard + * identification code list, please visit the JEDEC website at www.jedec.org . + */ + +/* This file is aligned to revision JEP106BF.01 October 2022. */ + +[0][0x01 - 1] = "AMD", +[0][0x02 - 1] = "AMI", +[0][0x03 - 1] = "Fairchild", +[0][0x04 - 1] = "Fujitsu", +[0][0x05 - 1] = "GTE", +[0][0x06 - 1] = "Harris", +[0][0x07 - 1] = "Hitachi", +[0][0x08 - 1] = "Inmos", +[0][0x09 - 1] = "Intel", +[0][0x0a - 1] = "I.T.T.", +[0][0x0b - 1] = "Intersil", +[0][0x0c - 1] = "Monolithic Memories", +[0][0x0d - 1] = "Mostek", +[0][0x0e - 1] = "Freescale (Motorola)", +[0][0x0f - 1] = "National", +[0][0x10 - 1] = "NEC", +[0][0x11 - 1] = "RCA", +[0][0x12 - 1] = "Raytheon", +[0][0x13 - 1] = "Conexant (Rockwell)", +[0][0x14 - 1] = "Seeq", +[0][0x15 - 1] = "NXP (Philips)", +[0][0x16 - 1] = "Synertek", +[0][0x17 - 1] = "Texas Instruments", +[0][0x18 - 1] = "Kioxia Corporation", +[0][0x19 - 1] = "Xicor", +[0][0x1a - 1] = "Zilog", +[0][0x1b - 1] = "Eurotechnique", +[0][0x1c - 1] = "Mitsubishi", +[0][0x1d - 1] = "Lucent (AT&T)", +[0][0x1e - 1] = "Exel", +[0][0x1f - 1] = "Atmel", +[0][0x20 - 1] = "STMicroelectronics", +[0][0x21 - 1] = "Lattice Semi.", +[0][0x22 - 1] = "NCR", +[0][0x23 - 1] = "Wafer Scale Integration", +[0][0x24 - 1] = "IBM", +[0][0x25 - 1] = "Tristar", +[0][0x26 - 1] = "Visic", +[0][0x27 - 1] = "Intl. CMOS Technology", +[0][0x28 - 1] = "SSSI", +[0][0x29 - 1] = "Microchip Technology", +[0][0x2a - 1] = "Ricoh Ltd", +[0][0x2b - 1] = "VLSI", +[0][0x2c - 1] = "Micron Technology", +[0][0x2d - 1] = "SK Hynix", +[0][0x2e - 1] = "OKI Semiconductor", +[0][0x2f - 1] = "ACTEL", +[0][0x30 - 1] = "Sharp", +[0][0x31 - 1] = "Catalyst", +[0][0x32 - 1] = "Panasonic", +[0][0x33 - 1] = "IDT", +[0][0x34 - 1] = "Cypress", +[0][0x35 - 1] = "DEC", +[0][0x36 - 1] = "LSI Logic", +[0][0x37 - 1] = "Zarlink (Plessey)", +[0][0x38 - 1] = "UTMC", +[0][0x39 - 1] = "Thinking Machine", +[0][0x3a - 1] = "Thomson CSF", +[0][0x3b - 1] = "Integrated CMOS (Vertex)", +[0][0x3c - 1] = "Honeywell", +[0][0x3d - 1] = "Tektronix", +[0][0x3e - 1] = "Oracle Corporation", +[0][0x3f - 1] = "Silicon Storage Technology", +[0][0x40 - 1] = "ProMos/Mosel Vitelic", +[0][0x41 - 1] = "Infineon (Siemens)", +[0][0x42 - 1] = "Macronix", +[0][0x43 - 1] = "Xerox", +[0][0x44 - 1] = "Plus Logic", +[0][0x45 - 1] = "Western Digital Technologies Inc", +[0][0x46 - 1] = "Elan Circuit Tech.", +[0][0x47 - 1] = "European Silicon Str.", +[0][0x48 - 1] = "Apple Computer", +[0][0x49 - 1] = "Xilinx", +[0][0x4a - 1] = "Compaq", +[0][0x4b - 1] = "Protocol Engines", +[0][0x4c - 1] = "SCI", +[0][0x4d - 1] = "Seiko Instruments", +[0][0x4e - 1] = "Samsung", +[0][0x4f - 1] = "I3 Design System", +[0][0x50 - 1] = "Klic", +[0][0x51 - 1] = "Crosspoint Solutions", +[0][0x52 - 1] = "Alliance Memory Inc", +[0][0x53 - 1] = "Tandem", +[0][0x54 - 1] = "Hewlett-Packard", +[0][0x55 - 1] = "Integrated Silicon Solutions", +[0][0x56 - 1] = "Brooktree", +[0][0x57 - 1] = "New Media", +[0][0x58 - 1] = "MHS Electronic", +[0][0x59 - 1] = "Performance Semi.", +[0][0x5a - 1] = "Winbond Electronic", +[0][0x5b - 1] = "Kawasaki Steel", +[0][0x5c - 1] = "Bright Micro", +[0][0x5d - 1] = "TECMAR", +[0][0x5e - 1] = "Exar", +[0][0x5f - 1] = "PCMCIA", +[0][0x60 - 1] = "LG Semi (Goldstar)", +[0][0x61 - 1] = "Northern Telecom", +[0][0x62 - 1] = "Sanyo", +[0][0x63 - 1] = "Array Microsystems", +[0][0x64 - 1] = "Crystal Semiconductor", +[0][0x65 - 1] = "Analog Devices", +[0][0x66 - 1] = "PMC-Sierra", +[0][0x67 - 1] = "Asparix", +[0][0x68 - 1] = "Convex Computer", +[0][0x69 - 1] = "Quality Semiconductor", +[0][0x6a - 1] = "Nimbus Technology", +[0][0x6b - 1] = "Transwitch", +[0][0x6c - 1] = "Micronas (ITT Intermetall)", +[0][0x6d - 1] = "Cannon", +[0][0x6e - 1] = "Altera", +[0][0x6f - 1] = "NEXCOM", +[0][0x70 - 1] = "Qualcomm", +[0][0x71 - 1] = "Sony", +[0][0x72 - 1] = "Cray Research", +[0][0x73 - 1] = "AMS(Austria Micro)", +[0][0x74 - 1] = "Vitesse", +[0][0x75 - 1] = "Aster Electronics", +[0][0x76 - 1] = "Bay Networks (Synoptic)", +[0][0x77 - 1] = "Zentrum/ZMD", +[0][0x78 - 1] = "TRW", +[0][0x79 - 1] = "Thesys", +[0][0x7a - 1] = "Solbourne Computer", +[0][0x7b - 1] = "Allied-Signal", +[0][0x7c - 1] = "Dialog Semiconductor", +[0][0x7d - 1] = "Media Vision", +[0][0x7e - 1] = "Numonyx Corporation", +[1][0x01 - 1] = "Cirrus Logic", +[1][0x02 - 1] = "National Instruments", +[1][0x03 - 1] = "ILC Data Device", +[1][0x04 - 1] = "Alcatel Mietec", +[1][0x05 - 1] = "Micro Linear", +[1][0x06 - 1] = "Univ. of NC", +[1][0x07 - 1] = "JTAG Technologies", +[1][0x08 - 1] = "BAE Systems (Loral)", +[1][0x09 - 1] = "Nchip", +[1][0x0a - 1] = "Galileo Tech", +[1][0x0b - 1] = "Bestlink Systems", +[1][0x0c - 1] = "Graychip", +[1][0x0d - 1] = "GENNUM", +[1][0x0e - 1] = "Imagination Technologies Limited", +[1][0x0f - 1] = "Robert Bosch", +[1][0x10 - 1] = "Chip Express", +[1][0x11 - 1] = "DATARAM", +[1][0x12 - 1] = "United Microelectronics Corp", +[1][0x13 - 1] = "TCSI", +[1][0x14 - 1] = "Smart Modular", +[1][0x15 - 1] = "Hughes Aircraft", +[1][0x16 - 1] = "Lanstar Semiconductor", +[1][0x17 - 1] = "Qlogic", +[1][0x18 - 1] = "Kingston", +[1][0x19 - 1] = "Music Semi", +[1][0x1a - 1] = "Ericsson Components", +[1][0x1b - 1] = "SpaSE", +[1][0x1c - 1] = "Eon Silicon Devices", +[1][0x1d - 1] = "Integrated Silicon Solution (ISSI)", +[1][0x1e - 1] = "DoD", +[1][0x1f - 1] = "Integ. Memories Tech.", +[1][0x20 - 1] = "Corollary Inc", +[1][0x21 - 1] = "Dallas Semiconductor", +[1][0x22 - 1] = "Omnivision", +[1][0x23 - 1] = "EIV(Switzerland)", +[1][0x24 - 1] = "Novatel Wireless", +[1][0x25 - 1] = "Zarlink (Mitel)", +[1][0x26 - 1] = "Clearpoint", +[1][0x27 - 1] = "Cabletron", +[1][0x28 - 1] = "STEC (Silicon Tech)", +[1][0x29 - 1] = "Vanguard", +[1][0x2a - 1] = "Hagiwara Sys-Com", +[1][0x2b - 1] = "Vantis", +[1][0x2c - 1] = "Celestica", +[1][0x2d - 1] = "Century", +[1][0x2e - 1] = "Hal Computers", +[1][0x2f - 1] = "Rohm Company Ltd", +[1][0x30 - 1] = "Juniper Networks", +[1][0x31 - 1] = "Libit Signal Processing", +[1][0x32 - 1] = "Mushkin Enhanced Memory", +[1][0x33 - 1] = "Tundra Semiconductor", +[1][0x34 - 1] = "Adaptec Inc", +[1][0x35 - 1] = "LightSpeed Semi.", +[1][0x36 - 1] = "ZSP Corp", +[1][0x37 - 1] = "AMIC Technology", +[1][0x38 - 1] = "Adobe Systems", +[1][0x39 - 1] = "Dynachip", +[1][0x3a - 1] = "PNY Technologies Inc", +[1][0x3b - 1] = "Newport Digital", +[1][0x3c - 1] = "MMC Networks", +[1][0x3d - 1] = "T Square", +[1][0x3e - 1] = "Seiko Epson", +[1][0x3f - 1] = "Broadcom", +[1][0x40 - 1] = "Viking Components", +[1][0x41 - 1] = "V3 Semiconductor", +[1][0x42 - 1] = "Flextronics (Orbit Semiconductor)", +[1][0x43 - 1] = "Suwa Electronics", +[1][0x44 - 1] = "Transmeta", +[1][0x45 - 1] = "Micron CMS", +[1][0x46 - 1] = "American Computer & Digital Components Inc", +[1][0x47 - 1] = "Enhance 3000 Inc", +[1][0x48 - 1] = "Tower Semiconductor", +[1][0x49 - 1] = "CPU Design", +[1][0x4a - 1] = "Price Point", +[1][0x4b - 1] = "Maxim Integrated Product", +[1][0x4c - 1] = "Tellabs", +[1][0x4d - 1] = "Centaur Technology", +[1][0x4e - 1] = "Unigen Corporation", +[1][0x4f - 1] = "Transcend Information", +[1][0x50 - 1] = "Memory Card Technology", +[1][0x51 - 1] = "CKD Corporation Ltd", +[1][0x52 - 1] = "Capital Instruments Inc", +[1][0x53 - 1] = "Aica Kogyo Ltd", +[1][0x54 - 1] = "Linvex Technology", +[1][0x55 - 1] = "MSC Vertriebs GmbH", +[1][0x56 - 1] = "AKM Company Ltd", +[1][0x57 - 1] = "Dynamem Inc", +[1][0x58 - 1] = "NERA ASA", +[1][0x59 - 1] = "GSI Technology", +[1][0x5a - 1] = "Dane-Elec (C Memory)", +[1][0x5b - 1] = "Acorn Computers", +[1][0x5c - 1] = "Lara Technology", +[1][0x5d - 1] = "Oak Technology Inc", +[1][0x5e - 1] = "Itec Memory", +[1][0x5f - 1] = "Tanisys Technology", +[1][0x60 - 1] = "Truevision", +[1][0x61 - 1] = "Wintec Industries", +[1][0x62 - 1] = "Super PC Memory", +[1][0x63 - 1] = "MGV Memory", +[1][0x64 - 1] = "Galvantech", +[1][0x65 - 1] = "Gadzoox Networks", +[1][0x66 - 1] = "Multi Dimensional Cons.", +[1][0x67 - 1] = "GateField", +[1][0x68 - 1] = "Integrated Memory System", +[1][0x69 - 1] = "Triscend", +[1][0x6a - 1] = "XaQti", +[1][0x6b - 1] = "Goldenram", +[1][0x6c - 1] = "Clear Logic", +[1][0x6d - 1] = "Cimaron Communications", +[1][0x6e - 1] = "Nippon Steel Semi. Corp", +[1][0x6f - 1] = "Advantage Memory", +[1][0x70 - 1] = "AMCC", +[1][0x71 - 1] = "LeCroy", +[1][0x72 - 1] = "Yamaha Corporation", +[1][0x73 - 1] = "Digital Microwave", +[1][0x74 - 1] = "NetLogic Microsystems", +[1][0x75 - 1] = "MIMOS Semiconductor", +[1][0x76 - 1] = "Advanced Fibre", +[1][0x77 - 1] = "BF Goodrich Data.", +[1][0x78 - 1] = "Epigram", +[1][0x79 - 1] = "Acbel Polytech Inc", +[1][0x7a - 1] = "Apacer Technology", +[1][0x7b - 1] = "Admor Memory", +[1][0x7c - 1] = "FOXCONN", +[1][0x7d - 1] = "Quadratics Superconductor", +[1][0x7e - 1] = "3COM", +[2][0x01 - 1] = "Camintonn Corporation", +[2][0x02 - 1] = "ISOA Incorporated", +[2][0x03 - 1] = "Agate Semiconductor", +[2][0x04 - 1] = "ADMtek Incorporated", +[2][0x05 - 1] = "HYPERTEC", +[2][0x06 - 1] = "Adhoc Technologies", +[2][0x07 - 1] = "MOSAID Technologies", +[2][0x08 - 1] = "Ardent Technologies", +[2][0x09 - 1] = "Switchcore", +[2][0x0a - 1] = "Cisco Systems Inc", +[2][0x0b - 1] = "Allayer Technologies", +[2][0x0c - 1] = "WorkX AG (Wichman)", +[2][0x0d - 1] = "Oasis Semiconductor", +[2][0x0e - 1] = "Novanet Semiconductor", +[2][0x0f - 1] = "E-M Solutions", +[2][0x10 - 1] = "Power General", +[2][0x11 - 1] = "Advanced Hardware Arch.", +[2][0x12 - 1] = "Inova Semiconductors GmbH", +[2][0x13 - 1] = "Telocity", +[2][0x14 - 1] = "Delkin Devices", +[2][0x15 - 1] = "Symagery Microsystems", +[2][0x16 - 1] = "C-Port Corporation", +[2][0x17 - 1] = "SiberCore Technologies", +[2][0x18 - 1] = "Southland Microsystems", +[2][0x19 - 1] = "Malleable Technologies", +[2][0x1a - 1] = "Kendin Communications", +[2][0x1b - 1] = "Great Technology Microcomputer", +[2][0x1c - 1] = "Sanmina Corporation", +[2][0x1d - 1] = "HADCO Corporation", +[2][0x1e - 1] = "Corsair", +[2][0x1f - 1] = "Actrans System Inc", +[2][0x20 - 1] = "ALPHA Technologies", +[2][0x21 - 1] = "Silicon Laboratories Inc (Cygnal)", +[2][0x22 - 1] = "Artesyn Technologies", +[2][0x23 - 1] = "Align Manufacturing", +[2][0x24 - 1] = "Peregrine Semiconductor", +[2][0x25 - 1] = "Chameleon Systems", +[2][0x26 - 1] = "Aplus Flash Technology", +[2][0x27 - 1] = "MIPS Technologies", +[2][0x28 - 1] = "Chrysalis ITS", +[2][0x29 - 1] = "ADTEC Corporation", +[2][0x2a - 1] = "Kentron Technologies", +[2][0x2b - 1] = "Win Technologies", +[2][0x2c - 1] = "Tezzaron Semiconductor", +[2][0x2d - 1] = "Extreme Packet Devices", +[2][0x2e - 1] = "RF Micro Devices", +[2][0x2f - 1] = "Siemens AG", +[2][0x30 - 1] = "Sarnoff Corporation", +[2][0x31 - 1] = "Itautec SA", +[2][0x32 - 1] = "Radiata Inc", +[2][0x33 - 1] = "Benchmark Elect. (AVEX)", +[2][0x34 - 1] = "Legend", +[2][0x35 - 1] = "SpecTek Incorporated", +[2][0x36 - 1] = "Hi/fn", +[2][0x37 - 1] = "Enikia Incorporated", +[2][0x38 - 1] = "SwitchOn Networks", +[2][0x39 - 1] = "AANetcom Incorporated", +[2][0x3a - 1] = "Micro Memory Bank", +[2][0x3b - 1] = "ESS Technology", +[2][0x3c - 1] = "Virata Corporation", +[2][0x3d - 1] = "Excess Bandwidth", +[2][0x3e - 1] = "West Bay Semiconductor", +[2][0x3f - 1] = "DSP Group", +[2][0x40 - 1] = "Newport Communications", +[2][0x41 - 1] = "Chip2Chip Incorporated", +[2][0x42 - 1] = "Phobos Corporation", +[2][0x43 - 1] = "Intellitech Corporation", +[2][0x44 - 1] = "Nordic VLSI ASA", +[2][0x45 - 1] = "Ishoni Networks", +[2][0x46 - 1] = "Silicon Spice", +[2][0x47 - 1] = "Alchemy Semiconductor", +[2][0x48 - 1] = "Agilent Technologies", +[2][0x49 - 1] = "Centillium Communications", +[2][0x4a - 1] = "W.L. Gore", +[2][0x4b - 1] = "HanBit Electronics", +[2][0x4c - 1] = "GlobeSpan", +[2][0x4d - 1] = "Element 14", +[2][0x4e - 1] = "Pycon", +[2][0x4f - 1] = "Saifun Semiconductors", +[2][0x50 - 1] = "Sibyte Incorporated", +[2][0x51 - 1] = "MetaLink Technologies", +[2][0x52 - 1] = "Feiya Technology", +[2][0x53 - 1] = "I & C Technology", +[2][0x54 - 1] = "Shikatronics", +[2][0x55 - 1] = "Elektrobit", +[2][0x56 - 1] = "Megic", +[2][0x57 - 1] = "Com-Tier", +[2][0x58 - 1] = "Malaysia Micro Solutions", +[2][0x59 - 1] = "Hyperchip", +[2][0x5a - 1] = "Gemstone Communications", +[2][0x5b - 1] = "Anadigm (Anadyne)", +[2][0x5c - 1] = "3ParData", +[2][0x5d - 1] = "Mellanox Technologies", +[2][0x5e - 1] = "Tenx Technologies", +[2][0x5f - 1] = "Helix AG", +[2][0x60 - 1] = "Domosys", +[2][0x61 - 1] = "Skyup Technology", +[2][0x62 - 1] = "HiNT Corporation", +[2][0x63 - 1] = "Chiaro", +[2][0x64 - 1] = "MDT Technologies GmbH", +[2][0x65 - 1] = "Exbit Technology A/S", +[2][0x66 - 1] = "Integrated Technology Express", +[2][0x67 - 1] = "AVED Memory", +[2][0x68 - 1] = "Legerity", +[2][0x69 - 1] = "Jasmine Networks", +[2][0x6a - 1] = "Caspian Networks", +[2][0x6b - 1] = "nCUBE", +[2][0x6c - 1] = "Silicon Access Networks", +[2][0x6d - 1] = "FDK Corporation", +[2][0x6e - 1] = "High Bandwidth Access", +[2][0x6f - 1] = "MultiLink Technology", +[2][0x70 - 1] = "BRECIS", +[2][0x71 - 1] = "World Wide Packets", +[2][0x72 - 1] = "APW", +[2][0x73 - 1] = "Chicory Systems", +[2][0x74 - 1] = "Xstream Logic", +[2][0x75 - 1] = "Fast-Chip", +[2][0x76 - 1] = "Zucotto Wireless", +[2][0x77 - 1] = "Realchip", +[2][0x78 - 1] = "Galaxy Power", +[2][0x79 - 1] = "eSilicon", +[2][0x7a - 1] = "Morphics Technology", +[2][0x7b - 1] = "Accelerant Networks", +[2][0x7c - 1] = "Silicon Wave", +[2][0x7d - 1] = "SandCraft", +[2][0x7e - 1] = "Elpida", +[3][0x01 - 1] = "Solectron", +[3][0x02 - 1] = "Optosys Technologies", +[3][0x03 - 1] = "Buffalo (Formerly Melco)", +[3][0x04 - 1] = "TriMedia Technologies", +[3][0x05 - 1] = "Cyan Technologies", +[3][0x06 - 1] = "Global Locate", +[3][0x07 - 1] = "Optillion", +[3][0x08 - 1] = "Terago Communications", +[3][0x09 - 1] = "Ikanos Communications", +[3][0x0a - 1] = "Princeton Technology", +[3][0x0b - 1] = "Nanya Technology", +[3][0x0c - 1] = "Elite Flash Storage", +[3][0x0d - 1] = "Mysticom", +[3][0x0e - 1] = "LightSand Communications", +[3][0x0f - 1] = "ATI Technologies", +[3][0x10 - 1] = "Agere Systems", +[3][0x11 - 1] = "NeoMagic", +[3][0x12 - 1] = "AuroraNetics", +[3][0x13 - 1] = "Golden Empire", +[3][0x14 - 1] = "Mushkin", +[3][0x15 - 1] = "Tioga Technologies", +[3][0x16 - 1] = "Netlist", +[3][0x17 - 1] = "TeraLogic", +[3][0x18 - 1] = "Cicada Semiconductor", +[3][0x19 - 1] = "Centon Electronics", +[3][0x1a - 1] = "Tyco Electronics", +[3][0x1b - 1] = "Magis Works", +[3][0x1c - 1] = "Zettacom", +[3][0x1d - 1] = "Cogency Semiconductor", +[3][0x1e - 1] = "Chipcon AS", +[3][0x1f - 1] = "Aspex Technology", +[3][0x20 - 1] = "F5 Networks", +[3][0x21 - 1] = "Programmable Silicon Solutions", +[3][0x22 - 1] = "ChipWrights", +[3][0x23 - 1] = "Acorn Networks", +[3][0x24 - 1] = "Quicklogic", +[3][0x25 - 1] = "Kingmax Semiconductor", +[3][0x26 - 1] = "BOPS", +[3][0x27 - 1] = "Flasys", +[3][0x28 - 1] = "BitBlitz Communications", +[3][0x29 - 1] = "eMemory Technology", +[3][0x2a - 1] = "Procket Networks", +[3][0x2b - 1] = "Purple Ray", +[3][0x2c - 1] = "Trebia Networks", +[3][0x2d - 1] = "Delta Electronics", +[3][0x2e - 1] = "Onex Communications", +[3][0x2f - 1] = "Ample Communications", +[3][0x30 - 1] = "Memory Experts Intl", +[3][0x31 - 1] = "Astute Networks", +[3][0x32 - 1] = "Azanda Network Devices", +[3][0x33 - 1] = "Dibcom", +[3][0x34 - 1] = "Tekmos", +[3][0x35 - 1] = "API NetWorks", +[3][0x36 - 1] = "Bay Microsystems", +[3][0x37 - 1] = "Firecron Ltd", +[3][0x38 - 1] = "Resonext Communications", +[3][0x39 - 1] = "Tachys Technologies", +[3][0x3a - 1] = "Equator Technology", +[3][0x3b - 1] = "Concept Computer", +[3][0x3c - 1] = "SILCOM", +[3][0x3d - 1] = "3Dlabs", +[3][0x3e - 1] = "c't Magazine", +[3][0x3f - 1] = "Sanera Systems", +[3][0x40 - 1] = "Silicon Packets", +[3][0x41 - 1] = "Viasystems Group", +[3][0x42 - 1] = "Simtek", +[3][0x43 - 1] = "Semicon Devices Singapore", +[3][0x44 - 1] = "Satron Handelsges", +[3][0x45 - 1] = "Improv Systems", +[3][0x46 - 1] = "INDUSYS GmbH", +[3][0x47 - 1] = "Corrent", +[3][0x48 - 1] = "Infrant Technologies", +[3][0x49 - 1] = "Ritek Corp", +[3][0x4a - 1] = "empowerTel Networks", +[3][0x4b - 1] = "Hypertec", +[3][0x4c - 1] = "Cavium Networks", +[3][0x4d - 1] = "PLX Technology", +[3][0x4e - 1] = "Massana Design", +[3][0x4f - 1] = "Intrinsity", +[3][0x50 - 1] = "Valence Semiconductor", +[3][0x51 - 1] = "Terawave Communications", +[3][0x52 - 1] = "IceFyre Semiconductor", +[3][0x53 - 1] = "Primarion", +[3][0x54 - 1] = "Picochip Designs Ltd", +[3][0x55 - 1] = "Silverback Systems", +[3][0x56 - 1] = "Jade Star Technologies", +[3][0x57 - 1] = "Pijnenburg Securealink", +[3][0x58 - 1] = "takeMS - Ultron AG", +[3][0x59 - 1] = "Cambridge Silicon Radio", +[3][0x5a - 1] = "Swissbit", +[3][0x5b - 1] = "Nazomi Communications", +[3][0x5c - 1] = "eWave System", +[3][0x5d - 1] = "Rockwell Collins", +[3][0x5e - 1] = "Picocel Co Ltd (Paion)", +[3][0x5f - 1] = "Alphamosaic Ltd", +[3][0x60 - 1] = "Sandburst", +[3][0x61 - 1] = "SiCon Video", +[3][0x62 - 1] = "NanoAmp Solutions", +[3][0x63 - 1] = "Ericsson Technology", +[3][0x64 - 1] = "PrairieComm", +[3][0x65 - 1] = "Mitac International", +[3][0x66 - 1] = "Layer N Networks", +[3][0x67 - 1] = "MtekVision (Atsana)", +[3][0x68 - 1] = "Allegro Networks", +[3][0x69 - 1] = "Marvell Semiconductors", +[3][0x6a - 1] = "Netergy Microelectronic", +[3][0x6b - 1] = "NVIDIA", +[3][0x6c - 1] = "Internet Machines", +[3][0x6d - 1] = "Memorysolution GmbH", +[3][0x6e - 1] = "Litchfield Communication", +[3][0x6f - 1] = "Accton Technology", +[3][0x70 - 1] = "Teradiant Networks", +[3][0x71 - 1] = "Scaleo Chip", +[3][0x72 - 1] = "Cortina Systems", +[3][0x73 - 1] = "RAM Components", +[3][0x74 - 1] = "Raqia Networks", +[3][0x75 - 1] = "ClearSpeed", +[3][0x76 - 1] = "Matsushita Battery", +[3][0x77 - 1] = "Xelerated", +[3][0x78 - 1] = "SimpleTech", +[3][0x79 - 1] = "Utron Technology", +[3][0x7a - 1] = "Astec International", +[3][0x7b - 1] = "AVM gmbH", +[3][0x7c - 1] = "Redux Communications", +[3][0x7d - 1] = "Dot Hill Systems", +[3][0x7e - 1] = "TeraChip", +[4][0x01 - 1] = "T-RAM Incorporated", +[4][0x02 - 1] = "Innovics Wireless", +[4][0x03 - 1] = "Teknovus", +[4][0x04 - 1] = "KeyEye Communications", +[4][0x05 - 1] = "Runcom Technologies", +[4][0x06 - 1] = "RedSwitch", +[4][0x07 - 1] = "Dotcast", +[4][0x08 - 1] = "Silicon Mountain Memory", +[4][0x09 - 1] = "Signia Technologies", +[4][0x0a - 1] = "Pixim", +[4][0x0b - 1] = "Galazar Networks", +[4][0x0c - 1] = "White Electronic Designs", +[4][0x0d - 1] = "Patriot Scientific", +[4][0x0e - 1] = "Neoaxiom Corporation", +[4][0x0f - 1] = "3Y Power Technology", +[4][0x10 - 1] = "Scaleo Chip", +[4][0x11 - 1] = "Potentia Power Systems", +[4][0x12 - 1] = "C-guys Incorporated", +[4][0x13 - 1] = "Digital Communications Technology Inc", +[4][0x14 - 1] = "Silicon-Based Technology", +[4][0x15 - 1] = "Fulcrum Microsystems", +[4][0x16 - 1] = "Positivo Informatica Ltd", +[4][0x17 - 1] = "XIOtech Corporation", +[4][0x18 - 1] = "PortalPlayer", +[4][0x19 - 1] = "Zhiying Software", +[4][0x1a - 1] = "ParkerVision Inc", +[4][0x1b - 1] = "Phonex Broadband", +[4][0x1c - 1] = "Skyworks Solutions", +[4][0x1d - 1] = "Entropic Communications", +[4][0x1e - 1] = "I'M Intelligent Memory Ltd", +[4][0x1f - 1] = "Zensys A/S", +[4][0x20 - 1] = "Legend Silicon Corp", +[4][0x21 - 1] = "Sci-worx GmbH", +[4][0x22 - 1] = "SMSC (Standard Microsystems)", +[4][0x23 - 1] = "Renesas Electronics", +[4][0x24 - 1] = "Raza Microelectronics", +[4][0x25 - 1] = "Phyworks", +[4][0x26 - 1] = "MediaTek", +[4][0x27 - 1] = "Non-cents Productions", +[4][0x28 - 1] = "US Modular", +[4][0x29 - 1] = "Wintegra Ltd", +[4][0x2a - 1] = "Mathstar", +[4][0x2b - 1] = "StarCore", +[4][0x2c - 1] = "Oplus Technologies", +[4][0x2d - 1] = "Mindspeed", +[4][0x2e - 1] = "Just Young Computer", +[4][0x2f - 1] = "Radia Communications", +[4][0x30 - 1] = "OCZ", +[4][0x31 - 1] = "Emuzed", +[4][0x32 - 1] = "LOGIC Devices", +[4][0x33 - 1] = "Inphi Corporation", +[4][0x34 - 1] = "Quake Technologies", +[4][0x35 - 1] = "Vixel", +[4][0x36 - 1] = "SolusTek", +[4][0x37 - 1] = "Kongsberg Maritime", +[4][0x38 - 1] = "Faraday Technology", +[4][0x39 - 1] = "Altium Ltd", +[4][0x3a - 1] = "Insyte", +[4][0x3b - 1] = "ARM Ltd", +[4][0x3c - 1] = "DigiVision", +[4][0x3d - 1] = "Vativ Technologies", +[4][0x3e - 1] = "Endicott Interconnect Technologies", +[4][0x3f - 1] = "Pericom", +[4][0x40 - 1] = "Bandspeed", +[4][0x41 - 1] = "LeWiz Communications", +[4][0x42 - 1] = "CPU Technology", +[4][0x43 - 1] = "Ramaxel Technology", +[4][0x44 - 1] = "DSP Group", +[4][0x45 - 1] = "Axis Communications", +[4][0x46 - 1] = "Legacy Electronics", +[4][0x47 - 1] = "Chrontel", +[4][0x48 - 1] = "Powerchip Semiconductor", +[4][0x49 - 1] = "MobilEye Technologies", +[4][0x4a - 1] = "Excel Semiconductor", +[4][0x4b - 1] = "A-DATA Technology", +[4][0x4c - 1] = "VirtualDigm", +[4][0x4d - 1] = "G Skill Intl", +[4][0x4e - 1] = "Quanta Computer", +[4][0x4f - 1] = "Yield Microelectronics", +[4][0x50 - 1] = "Afa Technologies", +[4][0x51 - 1] = "KINGBOX Technology Co Ltd", +[4][0x52 - 1] = "Ceva", +[4][0x53 - 1] = "iStor Networks", +[4][0x54 - 1] = "Advance Modules", +[4][0x55 - 1] = "Microsoft", +[4][0x56 - 1] = "Open-Silicon", +[4][0x57 - 1] = "Goal Semiconductor", +[4][0x58 - 1] = "ARC International", +[4][0x59 - 1] = "Simmtec", +[4][0x5a - 1] = "Metanoia", +[4][0x5b - 1] = "Key Stream", +[4][0x5c - 1] = "Lowrance Electronics", +[4][0x5d - 1] = "Adimos", +[4][0x5e - 1] = "SiGe Semiconductor", +[4][0x5f - 1] = "Fodus Communications", +[4][0x60 - 1] = "Credence Systems Corp", +[4][0x61 - 1] = "Genesis Microchip Inc", +[4][0x62 - 1] = "Vihana Inc", +[4][0x63 - 1] = "WIS Technologies", +[4][0x64 - 1] = "GateChange Technologies", +[4][0x65 - 1] = "High Density Devices AS", +[4][0x66 - 1] = "Synopsys", +[4][0x67 - 1] = "Gigaram", +[4][0x68 - 1] = "Enigma Semiconductor Inc", +[4][0x69 - 1] = "Century Micro Inc", +[4][0x6a - 1] = "Icera Semiconductor", +[4][0x6b - 1] = "Mediaworks Integrated Systems", +[4][0x6c - 1] = "O'Neil Product Development", +[4][0x6d - 1] = "Supreme Top Technology Ltd", +[4][0x6e - 1] = "MicroDisplay Corporation", +[4][0x6f - 1] = "Team Group Inc", +[4][0x70 - 1] = "Sinett Corporation", +[4][0x71 - 1] = "Toshiba Corporation", +[4][0x72 - 1] = "Tensilica", +[4][0x73 - 1] = "SiRF Technology", +[4][0x74 - 1] = "Bacoc Inc", +[4][0x75 - 1] = "SMaL Camera Technologies", +[4][0x76 - 1] = "Thomson SC", +[4][0x77 - 1] = "Airgo Networks", +[4][0x78 - 1] = "Wisair Ltd", +[4][0x79 - 1] = "SigmaTel", +[4][0x7a - 1] = "Arkados", +[4][0x7b - 1] = "Compete IT gmbH Co KG", +[4][0x7c - 1] = "Eudar Technology Inc", +[4][0x7d - 1] = "Focus Enhancements", +[4][0x7e - 1] = "Xyratex", +[5][0x01 - 1] = "Specular Networks", +[5][0x02 - 1] = "Patriot Memory (PDP Systems)", +[5][0x03 - 1] = "U-Chip Technology Corp", +[5][0x04 - 1] = "Silicon Optix", +[5][0x05 - 1] = "Greenfield Networks", +[5][0x06 - 1] = "CompuRAM GmbH", +[5][0x07 - 1] = "Stargen Inc", +[5][0x08 - 1] = "NetCell Corporation", +[5][0x09 - 1] = "Excalibrus Technologies Ltd", +[5][0x0a - 1] = "SCM Microsystems", +[5][0x0b - 1] = "Xsigo Systems Inc", +[5][0x0c - 1] = "CHIPS & Systems Inc", +[5][0x0d - 1] = "Tier 1 Multichip Solutions", +[5][0x0e - 1] = "CWRL Labs", +[5][0x0f - 1] = "Teradici", +[5][0x10 - 1] = "Gigaram Inc", +[5][0x11 - 1] = "g2 Microsystems", +[5][0x12 - 1] = "PowerFlash Semiconductor", +[5][0x13 - 1] = "P.A. Semi Inc", +[5][0x14 - 1] = "NovaTech Solutions S.A.", +[5][0x15 - 1] = "c2 Microsystems Inc", +[5][0x16 - 1] = "Level5 Networks", +[5][0x17 - 1] = "COS Memory AG", +[5][0x18 - 1] = "Innovasic Semiconductor", +[5][0x19 - 1] = "02IC Co Ltd", +[5][0x1a - 1] = "Tabula Inc", +[5][0x1b - 1] = "Crucial Technology", +[5][0x1c - 1] = "Chelsio Communications", +[5][0x1d - 1] = "Solarflare Communications", +[5][0x1e - 1] = "Xambala Inc", +[5][0x1f - 1] = "EADS Astrium", +[5][0x20 - 1] = "Terra Semiconductor Inc", +[5][0x21 - 1] = "Imaging Works Inc", +[5][0x22 - 1] = "Astute Networks Inc", +[5][0x23 - 1] = "Tzero", +[5][0x24 - 1] = "Emulex", +[5][0x25 - 1] = "Power-One", +[5][0x26 - 1] = "Pulse~LINK Inc", +[5][0x27 - 1] = "Hon Hai Precision Industry", +[5][0x28 - 1] = "White Rock Networks Inc", +[5][0x29 - 1] = "Telegent Systems USA Inc", +[5][0x2a - 1] = "Atrua Technologies Inc", +[5][0x2b - 1] = "Acbel Polytech Inc", +[5][0x2c - 1] = "eRide Inc", +[5][0x2d - 1] = "ULi Electronics Inc", +[5][0x2e - 1] = "Magnum Semiconductor Inc", +[5][0x2f - 1] = "neoOne Technology Inc", +[5][0x30 - 1] = "Connex Technology Inc", +[5][0x31 - 1] = "Stream Processors Inc", +[5][0x32 - 1] = "Focus Enhancements", +[5][0x33 - 1] = "Telecis Wireless Inc", +[5][0x34 - 1] = "uNav Microelectronics", +[5][0x35 - 1] = "Tarari Inc", +[5][0x36 - 1] = "Ambric Inc", +[5][0x37 - 1] = "Newport Media Inc", +[5][0x38 - 1] = "VMTS", +[5][0x39 - 1] = "Enuclia Semiconductor Inc", +[5][0x3a - 1] = "Virtium Technology Inc", +[5][0x3b - 1] = "Solid State System Co Ltd", +[5][0x3c - 1] = "Kian Tech LLC", +[5][0x3d - 1] = "Artimi", +[5][0x3e - 1] = "Power Quotient International", +[5][0x3f - 1] = "Avago Technologies", +[5][0x40 - 1] = "ADTechnology", +[5][0x41 - 1] = "Sigma Designs", +[5][0x42 - 1] = "SiCortex Inc", +[5][0x43 - 1] = "Ventura Technology Group", +[5][0x44 - 1] = "eASIC", +[5][0x45 - 1] = "M.H.S. SAS", +[5][0x46 - 1] = "Micro Star International", +[5][0x47 - 1] = "Rapport Inc", +[5][0x48 - 1] = "Makway International", +[5][0x49 - 1] = "Broad Reach Engineering Co", +[5][0x4a - 1] = "Semiconductor Mfg Intl Corp", +[5][0x4b - 1] = "SiConnect", +[5][0x4c - 1] = "FCI USA Inc", +[5][0x4d - 1] = "Validity Sensors", +[5][0x4e - 1] = "Coney Technology Co Ltd", +[5][0x4f - 1] = "Spans Logic", +[5][0x50 - 1] = "Neterion Inc", +[5][0x51 - 1] = "Qimonda", +[5][0x52 - 1] = "New Japan Radio Co Ltd", +[5][0x53 - 1] = "Velogix", +[5][0x54 - 1] = "Montalvo Systems", +[5][0x55 - 1] = "iVivity Inc", +[5][0x56 - 1] = "Walton Chaintech", +[5][0x57 - 1] = "AENEON", +[5][0x58 - 1] = "Lorom Industrial Co Ltd", +[5][0x59 - 1] = "Radiospire Networks", +[5][0x5a - 1] = "Sensio Technologies Inc", +[5][0x5b - 1] = "Nethra Imaging", +[5][0x5c - 1] = "Hexon Technology Pte Ltd", +[5][0x5d - 1] = "CompuStocx (CSX)", +[5][0x5e - 1] = "Methode Electronics Inc", +[5][0x5f - 1] = "Connect One Ltd", +[5][0x60 - 1] = "Opulan Technologies", +[5][0x61 - 1] = "Septentrio NV", +[5][0x62 - 1] = "Goldenmars Technology Inc", +[5][0x63 - 1] = "Kreton Corporation", +[5][0x64 - 1] = "Cochlear Ltd", +[5][0x65 - 1] = "Altair Semiconductor", +[5][0x66 - 1] = "NetEffect Inc", +[5][0x67 - 1] = "Spansion Inc", +[5][0x68 - 1] = "Taiwan Semiconductor Mfg", +[5][0x69 - 1] = "Emphany Systems Inc", +[5][0x6a - 1] = "ApaceWave Technologies", +[5][0x6b - 1] = "Mobilygen Corporation", +[5][0x6c - 1] = "Tego", +[5][0x6d - 1] = "Cswitch Corporation", +[5][0x6e - 1] = "Haier (Beijing) IC Design Co", +[5][0x6f - 1] = "MetaRAM", +[5][0x70 - 1] = "Axel Electronics Co Ltd", +[5][0x71 - 1] = "Tilera Corporation", +[5][0x72 - 1] = "Aquantia", +[5][0x73 - 1] = "Vivace Semiconductor", +[5][0x74 - 1] = "Redpine Signals", +[5][0x75 - 1] = "Octalica", +[5][0x76 - 1] = "InterDigital Communications", +[5][0x77 - 1] = "Avant Technology", +[5][0x78 - 1] = "Asrock Inc", +[5][0x79 - 1] = "Availink", +[5][0x7a - 1] = "Quartics Inc", +[5][0x7b - 1] = "Element CXI", +[5][0x7c - 1] = "Innovaciones Microelectronicas", +[5][0x7d - 1] = "VeriSilicon Microelectronics", +[5][0x7e - 1] = "W5 Networks", +[6][0x01 - 1] = "MOVEKING", +[6][0x02 - 1] = "Mavrix Technology Inc", +[6][0x03 - 1] = "CellGuide Ltd", +[6][0x04 - 1] = "Faraday Technology", +[6][0x05 - 1] = "Diablo Technologies Inc", +[6][0x06 - 1] = "Jennic", +[6][0x07 - 1] = "Octasic", +[6][0x08 - 1] = "Molex Incorporated", +[6][0x09 - 1] = "3Leaf Networks", +[6][0x0a - 1] = "Bright Micron Technology", +[6][0x0b - 1] = "Netxen", +[6][0x0c - 1] = "NextWave Broadband Inc", +[6][0x0d - 1] = "DisplayLink", +[6][0x0e - 1] = "ZMOS Technology", +[6][0x0f - 1] = "Tec-Hill", +[6][0x10 - 1] = "Multigig Inc", +[6][0x11 - 1] = "Amimon", +[6][0x12 - 1] = "Euphonic Technologies Inc", +[6][0x13 - 1] = "BRN Phoenix", +[6][0x14 - 1] = "InSilica", +[6][0x15 - 1] = "Ember Corporation", +[6][0x16 - 1] = "Avexir Technologies Corporation", +[6][0x17 - 1] = "Echelon Corporation", +[6][0x18 - 1] = "Edgewater Computer Systems", +[6][0x19 - 1] = "XMOS Semiconductor Ltd", +[6][0x1a - 1] = "GENUSION Inc", +[6][0x1b - 1] = "Memory Corp NV", +[6][0x1c - 1] = "SiliconBlue Technologies", +[6][0x1d - 1] = "Rambus Inc", +[6][0x1e - 1] = "Andes Technology Corporation", +[6][0x1f - 1] = "Coronis Systems", +[6][0x20 - 1] = "Achronix Semiconductor", +[6][0x21 - 1] = "Siano Mobile Silicon Ltd", +[6][0x22 - 1] = "Semtech Corporation", +[6][0x23 - 1] = "Pixelworks Inc", +[6][0x24 - 1] = "Gaisler Research AB", +[6][0x25 - 1] = "Teranetics", +[6][0x26 - 1] = "Toppan Printing Co Ltd", +[6][0x27 - 1] = "Kingxcon", +[6][0x28 - 1] = "Silicon Integrated Systems", +[6][0x29 - 1] = "I-O Data Device Inc", +[6][0x2a - 1] = "NDS Americas Inc", +[6][0x2b - 1] = "Solomon Systech Limited", +[6][0x2c - 1] = "On Demand Microelectronics", +[6][0x2d - 1] = "Amicus Wireless Inc", +[6][0x2e - 1] = "SMARDTV SNC", +[6][0x2f - 1] = "Comsys Communication Ltd", +[6][0x30 - 1] = "Movidia Ltd", +[6][0x31 - 1] = "Javad GNSS Inc", +[6][0x32 - 1] = "Montage Technology Group", +[6][0x33 - 1] = "Trident Microsystems", +[6][0x34 - 1] = "Super Talent", +[6][0x35 - 1] = "Optichron Inc", +[6][0x36 - 1] = "Future Waves UK Ltd", +[6][0x37 - 1] = "SiBEAM Inc", +[6][0x38 - 1] = "InicoreInc", +[6][0x39 - 1] = "Virident Systems", +[6][0x3a - 1] = "M2000 Inc", +[6][0x3b - 1] = "ZeroG Wireless Inc", +[6][0x3c - 1] = "Gingle Technology Co Ltd", +[6][0x3d - 1] = "Space Micro Inc", +[6][0x3e - 1] = "Wilocity", +[6][0x3f - 1] = "Novafora Inc", +[6][0x40 - 1] = "iKoa Corporation", +[6][0x41 - 1] = "ASint Technology", +[6][0x42 - 1] = "Ramtron", +[6][0x43 - 1] = "Plato Networks Inc", +[6][0x44 - 1] = "IPtronics AS", +[6][0x45 - 1] = "Infinite-Memories", +[6][0x46 - 1] = "Parade Technologies Inc", +[6][0x47 - 1] = "Dune Networks", +[6][0x48 - 1] = "GigaDevice Semiconductor", +[6][0x49 - 1] = "Modu Ltd", +[6][0x4a - 1] = "CEITEC", +[6][0x4b - 1] = "Northrop Grumman", +[6][0x4c - 1] = "XRONET Corporation", +[6][0x4d - 1] = "Sicon Semiconductor AB", +[6][0x4e - 1] = "Atla Electronics Co Ltd", +[6][0x4f - 1] = "TOPRAM Technology", +[6][0x50 - 1] = "Silego Technology Inc", +[6][0x51 - 1] = "Kinglife", +[6][0x52 - 1] = "Ability Industries Ltd", +[6][0x53 - 1] = "Silicon Power Computer & Communications", +[6][0x54 - 1] = "Augusta Technology Inc", +[6][0x55 - 1] = "Nantronics Semiconductors", +[6][0x56 - 1] = "Hilscher Gesellschaft", +[6][0x57 - 1] = "Quixant Ltd", +[6][0x58 - 1] = "Percello Ltd", +[6][0x59 - 1] = "NextIO Inc", +[6][0x5a - 1] = "Scanimetrics Inc", +[6][0x5b - 1] = "FS-Semi Company Ltd", +[6][0x5c - 1] = "Infinera Corporation", +[6][0x5d - 1] = "SandForce Inc", +[6][0x5e - 1] = "Lexar Media", +[6][0x5f - 1] = "Teradyne Inc", +[6][0x60 - 1] = "Memory Exchange Corp", +[6][0x61 - 1] = "Suzhou Smartek Electronics", +[6][0x62 - 1] = "Avantium Corporation", +[6][0x63 - 1] = "ATP Electronics Inc", +[6][0x64 - 1] = "Valens Semiconductor Ltd", +[6][0x65 - 1] = "Agate Logic Inc", +[6][0x66 - 1] = "Netronome", +[6][0x67 - 1] = "Zenverge Inc", +[6][0x68 - 1] = "N-trig Ltd", +[6][0x69 - 1] = "SanMax Technologies Inc", +[6][0x6a - 1] = "Contour Semiconductor Inc", +[6][0x6b - 1] = "TwinMOS", +[6][0x6c - 1] = "Silicon Systems Inc", +[6][0x6d - 1] = "V-Color Technology Inc", +[6][0x6e - 1] = "Certicom Corporation", +[6][0x6f - 1] = "JSC ICC Milandr", +[6][0x70 - 1] = "PhotoFast Global Inc", +[6][0x71 - 1] = "InnoDisk Corporation", +[6][0x72 - 1] = "Muscle Power", +[6][0x73 - 1] = "Energy Micro", +[6][0x74 - 1] = "Innofidei", +[6][0x75 - 1] = "CopperGate Communications", +[6][0x76 - 1] = "Holtek Semiconductor Inc", +[6][0x77 - 1] = "Myson Century Inc", +[6][0x78 - 1] = "FIDELIX", +[6][0x79 - 1] = "Red Digital Cinema", +[6][0x7a - 1] = "Densbits Technology", +[6][0x7b - 1] = "Zempro", +[6][0x7c - 1] = "MoSys", +[6][0x7d - 1] = "Provigent", +[6][0x7e - 1] = "Triad Semiconductor Inc", +[7][0x01 - 1] = "Siklu Communication Ltd", +[7][0x02 - 1] = "A Force Manufacturing Ltd", +[7][0x03 - 1] = "Strontium", +[7][0x04 - 1] = "ALi Corp (Abilis Systems)", +[7][0x05 - 1] = "Siglead Inc", +[7][0x06 - 1] = "Ubicom Inc", +[7][0x07 - 1] = "Unifosa Corporation", +[7][0x08 - 1] = "Stretch Inc", +[7][0x09 - 1] = "Lantiq Deutschland GmbH", +[7][0x0a - 1] = "Visipro.", +[7][0x0b - 1] = "EKMemory", +[7][0x0c - 1] = "Microelectronics Institute ZTE", +[7][0x0d - 1] = "u-blox AG", +[7][0x0e - 1] = "Carry Technology Co Ltd", +[7][0x0f - 1] = "Nokia", +[7][0x10 - 1] = "King Tiger Technology", +[7][0x11 - 1] = "Sierra Wireless", +[7][0x12 - 1] = "HT Micron", +[7][0x13 - 1] = "Albatron Technology Co Ltd", +[7][0x14 - 1] = "Leica Geosystems AG", +[7][0x15 - 1] = "BroadLight", +[7][0x16 - 1] = "AEXEA", +[7][0x17 - 1] = "ClariPhy Communications Inc", +[7][0x18 - 1] = "Green Plug", +[7][0x19 - 1] = "Design Art Networks", +[7][0x1a - 1] = "Mach Xtreme Technology Ltd", +[7][0x1b - 1] = "ATO Solutions Co Ltd", +[7][0x1c - 1] = "Ramsta", +[7][0x1d - 1] = "Greenliant Systems Ltd", +[7][0x1e - 1] = "Teikon", +[7][0x1f - 1] = "Antec Hadron", +[7][0x20 - 1] = "NavCom Technology Inc", +[7][0x21 - 1] = "Shanghai Fudan Microelectronics", +[7][0x22 - 1] = "Calxeda Inc", +[7][0x23 - 1] = "JSC EDC Electronics", +[7][0x24 - 1] = "Kandit Technology Co Ltd", +[7][0x25 - 1] = "Ramos Technology", +[7][0x26 - 1] = "Goldenmars Technology", +[7][0x27 - 1] = "XeL Technology Inc", +[7][0x28 - 1] = "Newzone Corporation", +[7][0x29 - 1] = "ShenZhen MercyPower Tech", +[7][0x2a - 1] = "Nanjing Yihuo Technology", +[7][0x2b - 1] = "Nethra Imaging Inc", +[7][0x2c - 1] = "SiTel Semiconductor BV", +[7][0x2d - 1] = "SolidGear Corporation", +[7][0x2e - 1] = "Topower Computer Ind Co Ltd", +[7][0x2f - 1] = "Wilocity", +[7][0x30 - 1] = "Profichip GmbH", +[7][0x31 - 1] = "Gerad Technologies", +[7][0x32 - 1] = "Ritek Corporation", +[7][0x33 - 1] = "Gomos Technology Limited", +[7][0x34 - 1] = "Memoright Corporation", +[7][0x35 - 1] = "D-Broad Inc", +[7][0x36 - 1] = "HiSilicon Technologies", +[7][0x37 - 1] = "Syndiant Inc.", +[7][0x38 - 1] = "Enverv Inc", +[7][0x39 - 1] = "Cognex", +[7][0x3a - 1] = "Xinnova Technology Inc", +[7][0x3b - 1] = "Ultron AG", +[7][0x3c - 1] = "Concord Idea Corporation", +[7][0x3d - 1] = "AIM Corporation", +[7][0x3e - 1] = "Lifetime Memory Products", +[7][0x3f - 1] = "Ramsway", +[7][0x40 - 1] = "Recore Systems B.V.", +[7][0x41 - 1] = "Haotian Jinshibo Science Tech", +[7][0x42 - 1] = "Being Advanced Memory", +[7][0x43 - 1] = "Adesto Technologies", +[7][0x44 - 1] = "Giantec Semiconductor Inc", +[7][0x45 - 1] = "HMD Electronics AG", +[7][0x46 - 1] = "Gloway International (HK)", +[7][0x47 - 1] = "Kingcore", +[7][0x48 - 1] = "Anucell Technology Holding", +[7][0x49 - 1] = "Accord Software & Systems Pvt. Ltd", +[7][0x4a - 1] = "Active-Semi Inc", +[7][0x4b - 1] = "Denso Corporation", +[7][0x4c - 1] = "TLSI Inc", +[7][0x4d - 1] = "Qidan", +[7][0x4e - 1] = "Mustang", +[7][0x4f - 1] = "Orca Systems", +[7][0x50 - 1] = "Passif Semiconductor", +[7][0x51 - 1] = "GigaDevice Semiconductor (Beijing) Inc", +[7][0x52 - 1] = "Memphis Electronic", +[7][0x53 - 1] = "Beckhoff Automation GmbH", +[7][0x54 - 1] = "Harmony Semiconductor Corp", +[7][0x55 - 1] = "Air Computers SRL", +[7][0x56 - 1] = "TMT Memory", +[7][0x57 - 1] = "Eorex Corporation", +[7][0x58 - 1] = "Xingtera", +[7][0x59 - 1] = "Netsol", +[7][0x5a - 1] = "Bestdon Technology Co Ltd", +[7][0x5b - 1] = "Baysand Inc", +[7][0x5c - 1] = "Uroad Technology Co Ltd", +[7][0x5d - 1] = "Wilk Elektronik S.A.", +[7][0x5e - 1] = "AAI", +[7][0x5f - 1] = "Harman", +[7][0x60 - 1] = "Berg Microelectronics Inc", +[7][0x61 - 1] = "ASSIA Inc", +[7][0x62 - 1] = "Visiontek Products LLC", +[7][0x63 - 1] = "OCMEMORY", +[7][0x64 - 1] = "Welink Solution Inc", +[7][0x65 - 1] = "Shark Gaming", +[7][0x66 - 1] = "Avalanche Technology", +[7][0x67 - 1] = "R&D Center ELVEES OJSC", +[7][0x68 - 1] = "KingboMars Technology Co Ltd", +[7][0x69 - 1] = "High Bridge Solutions Industria Eletronica", +[7][0x6a - 1] = "Transcend Technology Co Ltd", +[7][0x6b - 1] = "Everspin Technologies", +[7][0x6c - 1] = "Hon-Hai Precision", +[7][0x6d - 1] = "Smart Storage Systems", +[7][0x6e - 1] = "Toumaz Group", +[7][0x6f - 1] = "Zentel Electronics Corporation", +[7][0x70 - 1] = "Panram International Corporation", +[7][0x71 - 1] = "Silicon Space Technology", +[7][0x72 - 1] = "LITE-ON IT Corporation", +[7][0x73 - 1] = "Inuitive", +[7][0x74 - 1] = "HMicro", +[7][0x75 - 1] = "BittWare Inc", +[7][0x76 - 1] = "GLOBALFOUNDRIES", +[7][0x77 - 1] = "ACPI Digital Co Ltd", +[7][0x78 - 1] = "Annapurna Labs", +[7][0x79 - 1] = "AcSiP Technology Corporation", +[7][0x7a - 1] = "Idea! Electronic Systems", +[7][0x7b - 1] = "Gowe Technology Co Ltd", +[7][0x7c - 1] = "Hermes Testing Solutions Inc", +[7][0x7d - 1] = "Positivo BGH", +[7][0x7e - 1] = "Intelligence Silicon Technology", +[8][0x01 - 1] = "3D PLUS", +[8][0x02 - 1] = "Diehl Aerospace", +[8][0x03 - 1] = "Fairchild", +[8][0x04 - 1] = "Mercury Systems", +[8][0x05 - 1] = "Sonics Inc", +[8][0x06 - 1] = "Emerson Automation Solutions", +[8][0x07 - 1] = "Shenzhen Jinge Information Co Ltd", +[8][0x08 - 1] = "SCWW", +[8][0x09 - 1] = "Silicon Motion Inc", +[8][0x0a - 1] = "Anurag", +[8][0x0b - 1] = "King Kong", +[8][0x0c - 1] = "FROM30 Co Ltd", +[8][0x0d - 1] = "Gowin Semiconductor Corp", +[8][0x0e - 1] = "Fremont Micro Devices Ltd", +[8][0x0f - 1] = "Ericsson Modems", +[8][0x10 - 1] = "Exelis", +[8][0x11 - 1] = "Satixfy Ltd", +[8][0x12 - 1] = "Galaxy Microsystems Ltd", +[8][0x13 - 1] = "Gloway International Co Ltd", +[8][0x14 - 1] = "Lab", +[8][0x15 - 1] = "Smart Energy Instruments", +[8][0x16 - 1] = "Approved Memory Corporation", +[8][0x17 - 1] = "Axell Corporation", +[8][0x18 - 1] = "Essencore Limited", +[8][0x19 - 1] = "Phytium", +[8][0x1a - 1] = "Xi'an UniIC Semiconductors Co Ltd", +[8][0x1b - 1] = "Ambiq Micro", +[8][0x1c - 1] = "eveRAM Technology Inc", +[8][0x1d - 1] = "Infomax", +[8][0x1e - 1] = "Butterfly Network Inc", +[8][0x1f - 1] = "Shenzhen City Gcai Electronics", +[8][0x20 - 1] = "Stack Devices Corporation", +[8][0x21 - 1] = "ADK Media Group", +[8][0x22 - 1] = "TSP Global Co Ltd", +[8][0x23 - 1] = "HighX", +[8][0x24 - 1] = "Shenzhen Elicks Technology", +[8][0x25 - 1] = "XinKai/Silicon Kaiser", +[8][0x26 - 1] = "Google Inc", +[8][0x27 - 1] = "Dasima International Development", +[8][0x28 - 1] = "Leahkinn Technology Limited", +[8][0x29 - 1] = "HIMA Paul Hildebrandt GmbH Co KG", +[8][0x2a - 1] = "Keysight Technologies", +[8][0x2b - 1] = "Techcomp International (Fastable)", +[8][0x2c - 1] = "Ancore Technology Corporation", +[8][0x2d - 1] = "Nuvoton", +[8][0x2e - 1] = "Korea Uhbele International Group Ltd", +[8][0x2f - 1] = "Ikegami Tsushinki Co Ltd", +[8][0x30 - 1] = "RelChip Inc", +[8][0x31 - 1] = "Baikal Electronics", +[8][0x32 - 1] = "Nemostech Inc", +[8][0x33 - 1] = "Memorysolution GmbH", +[8][0x34 - 1] = "Silicon Integrated Systems Corporation", +[8][0x35 - 1] = "Xiede", +[8][0x36 - 1] = "BRC", +[8][0x37 - 1] = "Flash Chi", +[8][0x38 - 1] = "Jone", +[8][0x39 - 1] = "GCT Semiconductor Inc", +[8][0x3a - 1] = "Hong Kong Zetta Device Technology", +[8][0x3b - 1] = "Unimemory Technology(s) Pte Ltd", +[8][0x3c - 1] = "Cuso", +[8][0x3d - 1] = "Kuso", +[8][0x3e - 1] = "Uniquify Inc", +[8][0x3f - 1] = "Skymedi Corporation", +[8][0x40 - 1] = "Core Chance Co Ltd", +[8][0x41 - 1] = "Tekism Co Ltd", +[8][0x42 - 1] = "Seagate Technology PLC", +[8][0x43 - 1] = "Hong Kong Gaia Group Co Limited", +[8][0x44 - 1] = "Gigacom Semiconductor LLC", +[8][0x45 - 1] = "V2 Technologies", +[8][0x46 - 1] = "TLi", +[8][0x47 - 1] = "Neotion", +[8][0x48 - 1] = "Lenovo", +[8][0x49 - 1] = "Shenzhen Zhongteng Electronic Corp Ltd", +[8][0x4a - 1] = "Compound Photonics", +[8][0x4b - 1] = "in2H2 inc", +[8][0x4c - 1] = "Shenzhen Pango Microsystems Co Ltd", +[8][0x4d - 1] = "Vasekey", +[8][0x4e - 1] = "Cal-Comp Industria de Semicondutores", +[8][0x4f - 1] = "Eyenix Co Ltd", +[8][0x50 - 1] = "Heoriady", +[8][0x51 - 1] = "Accelerated Memory Production Inc", +[8][0x52 - 1] = "INVECAS Inc", +[8][0x53 - 1] = "AP Memory", +[8][0x54 - 1] = "Douqi Technology", +[8][0x55 - 1] = "Etron Technology Inc", +[8][0x56 - 1] = "Indie Semiconductor", +[8][0x57 - 1] = "Socionext Inc", +[8][0x58 - 1] = "HGST", +[8][0x59 - 1] = "EVGA", +[8][0x5a - 1] = "Audience Inc", +[8][0x5b - 1] = "EpicGear", +[8][0x5c - 1] = "Vitesse Enterprise Co", +[8][0x5d - 1] = "Foxtronn International Corporation", +[8][0x5e - 1] = "Bretelon Inc", +[8][0x5f - 1] = "Graphcore", +[8][0x60 - 1] = "Eoplex Inc", +[8][0x61 - 1] = "MaxLinear Inc", +[8][0x62 - 1] = "ETA Devices", +[8][0x63 - 1] = "LOKI", +[8][0x64 - 1] = "IMS Electronics Co Ltd", +[8][0x65 - 1] = "Dosilicon Co Ltd", +[8][0x66 - 1] = "Dolphin Integration", +[8][0x67 - 1] = "Shenzhen Mic Electronics Technolog", +[8][0x68 - 1] = "Boya Microelectronics Inc", +[8][0x69 - 1] = "Geniachip (Roche)", +[8][0x6a - 1] = "Axign", +[8][0x6b - 1] = "Kingred Electronic Technology Ltd", +[8][0x6c - 1] = "Chao Yue Zhuo Computer Business Dept.", +[8][0x6d - 1] = "Guangzhou Si Nuo Electronic Technology.", +[8][0x6e - 1] = "Crocus Technology Inc", +[8][0x6f - 1] = "Creative Chips GmbH", +[8][0x70 - 1] = "GE Aviation Systems LLC.", +[8][0x71 - 1] = "Asgard", +[8][0x72 - 1] = "Good Wealth Technology Ltd", +[8][0x73 - 1] = "TriCor Technologies", +[8][0x74 - 1] = "Nova-Systems GmbH", +[8][0x75 - 1] = "JUHOR", +[8][0x76 - 1] = "Zhuhai Douke Commerce Co Ltd", +[8][0x77 - 1] = "DSL Memory", +[8][0x78 - 1] = "Anvo-Systems Dresden GmbH", +[8][0x79 - 1] = "Realtek", +[8][0x7a - 1] = "AltoBeam", +[8][0x7b - 1] = "Wave Computing", +[8][0x7c - 1] = "Beijing TrustNet Technology Co Ltd", +[8][0x7d - 1] = "Innovium Inc", +[8][0x7e - 1] = "Starsway Technology Limited", +[9][0x01 - 1] = "Weltronics Co LTD", +[9][0x02 - 1] = "VMware Inc", +[9][0x03 - 1] = "Hewlett Packard Enterprise", +[9][0x04 - 1] = "INTENSO", +[9][0x05 - 1] = "Puya Semiconductor", +[9][0x06 - 1] = "MEMORFI", +[9][0x07 - 1] = "MSC Technologies GmbH", +[9][0x08 - 1] = "Txrui", +[9][0x09 - 1] = "SiFive Inc", +[9][0x0a - 1] = "Spreadtrum Communications", +[9][0x0b - 1] = "XTX Technology Limited", +[9][0x0c - 1] = "UMAX Technology", +[9][0x0d - 1] = "Shenzhen Yong Sheng Technology", +[9][0x0e - 1] = "SNOAMOO (Shenzhen Kai Zhuo Yue)", +[9][0x0f - 1] = "Daten Tecnologia LTDA", +[9][0x10 - 1] = "Shenzhen XinRuiYan Electronics", +[9][0x11 - 1] = "Eta Compute", +[9][0x12 - 1] = "Energous", +[9][0x13 - 1] = "Raspberry Pi Trading Ltd", +[9][0x14 - 1] = "Shenzhen Chixingzhe Tech Co Ltd", +[9][0x15 - 1] = "Silicon Mobility", +[9][0x16 - 1] = "IQ-Analog Corporation", +[9][0x17 - 1] = "Uhnder Inc", +[9][0x18 - 1] = "Impinj", +[9][0x19 - 1] = "DEPO Computers", +[9][0x1a - 1] = "Nespeed Sysems", +[9][0x1b - 1] = "Yangtze Memory Technologies Co Ltd", +[9][0x1c - 1] = "MemxPro Inc", +[9][0x1d - 1] = "Tammuz Co Ltd", +[9][0x1e - 1] = "Allwinner Technology", +[9][0x1f - 1] = "Shenzhen City Futian District Qing Xuan Tong Computer Trading Firm", +[9][0x20 - 1] = "XMC", +[9][0x21 - 1] = "Teclast", +[9][0x22 - 1] = "Maxsun", +[9][0x23 - 1] = "Haiguang Integrated Circuit Design", +[9][0x24 - 1] = "RamCENTER Technology", +[9][0x25 - 1] = "Phison Electronics Corporation", +[9][0x26 - 1] = "Guizhou Huaxintong Semi-Conductor", +[9][0x27 - 1] = "Network Intelligence", +[9][0x28 - 1] = "Continental Technology (Holdings)", +[9][0x29 - 1] = "Guangzhou Huayan Suning Electronic", +[9][0x2a - 1] = "Guangzhou Zhouji Electronic Co Ltd", +[9][0x2b - 1] = "Shenzhen Giant Hui Kang Tech Co Ltd", +[9][0x2c - 1] = "Shenzhen Yilong Innovative Co Ltd", +[9][0x2d - 1] = "Neo Forza", +[9][0x2e - 1] = "Lyontek Inc", +[9][0x2f - 1] = "Shanghai Kuxin Microelectronics Ltd", +[9][0x30 - 1] = "Shenzhen Larix Technology Co Ltd", +[9][0x31 - 1] = "Qbit Semiconductor Ltd", +[9][0x32 - 1] = "Insignis Technology Corporation", +[9][0x33 - 1] = "Lanson Memory Co Ltd", +[9][0x34 - 1] = "Shenzhen Superway Electronics Co Ltd", +[9][0x35 - 1] = "Canaan-Creative Co Ltd", +[9][0x36 - 1] = "Black Diamond Memory", +[9][0x37 - 1] = "Shenzhen City Parker Baking Electronics", +[9][0x38 - 1] = "Shenzhen Baihong Technology Co Ltd", +[9][0x39 - 1] = "GEO Semiconductors", +[9][0x3a - 1] = "OCPC", +[9][0x3b - 1] = "Artery Technology Co Ltd", +[9][0x3c - 1] = "Jinyu", +[9][0x3d - 1] = "ShenzhenYing Chi Technology Development", +[9][0x3e - 1] = "Shenzhen Pengcheng Xin Technology", +[9][0x3f - 1] = "Pegasus Semiconductor (Shanghai) Co", +[9][0x40 - 1] = "Mythic Inc", +[9][0x41 - 1] = "Elmos Semiconductor AG", +[9][0x42 - 1] = "Kllisre", +[9][0x43 - 1] = "Shenzhen Winconway Technology", +[9][0x44 - 1] = "Shenzhen Xingmem Technology Corp", +[9][0x45 - 1] = "Gold Key Technology Co Ltd", +[9][0x46 - 1] = "Habana Labs Ltd", +[9][0x47 - 1] = "Hoodisk Electronics Co Ltd", +[9][0x48 - 1] = "SemsoTai (SZ) Technology Co Ltd", +[9][0x49 - 1] = "OM Nanotech Pvt. Ltd", +[9][0x4a - 1] = "Shenzhen Zhifeng Weiye Technology", +[9][0x4b - 1] = "Xinshirui (Shenzhen) Electronics Co", +[9][0x4c - 1] = "Guangzhou Zhong Hao Tian Electronic", +[9][0x4d - 1] = "Shenzhen Longsys Electronics Co Ltd", +[9][0x4e - 1] = "Deciso B.V.", +[9][0x4f - 1] = "Puya Semiconductor (Shenzhen)", +[9][0x50 - 1] = "Shenzhen Veineda Technology Co Ltd", +[9][0x51 - 1] = "Antec Memory", +[9][0x52 - 1] = "Cortus SAS", +[9][0x53 - 1] = "Dust Leopard", +[9][0x54 - 1] = "MyWo AS", +[9][0x55 - 1] = "J&A Information Inc", +[9][0x56 - 1] = "Shenzhen JIEPEI Technology Co Ltd", +[9][0x57 - 1] = "Heidelberg University", +[9][0x58 - 1] = "Flexxon PTE Ltd", +[9][0x59 - 1] = "Wiliot", +[9][0x5a - 1] = "Raysun Electronics International Ltd", +[9][0x5b - 1] = "Aquarius Production Company LLC", +[9][0x5c - 1] = "MACNICA DHW LTDA", +[9][0x5d - 1] = "Intelimem", +[9][0x5e - 1] = "Zbit Semiconductor Inc", +[9][0x5f - 1] = "Shenzhen Technology Co Ltd", +[9][0x60 - 1] = "Signalchip", +[9][0x61 - 1] = "Shenzen Recadata Storage Technology", +[9][0x62 - 1] = "Hyundai Technology", +[9][0x63 - 1] = "Shanghai Fudi Investment Development", +[9][0x64 - 1] = "Aixi Technology", +[9][0x65 - 1] = "Tecon MT", +[9][0x66 - 1] = "Onda Electric Co Ltd", +[9][0x67 - 1] = "Jinshen", +[9][0x68 - 1] = "Kimtigo Semiconductor (HK) Limited", +[9][0x69 - 1] = "IIT Madras", +[9][0x6a - 1] = "Shenshan (Shenzhen) Electronic", +[9][0x6b - 1] = "Hefei Core Storage Electronic Limited", +[9][0x6c - 1] = "Colorful Technology Ltd", +[9][0x6d - 1] = "Visenta (Xiamen) Technology Co Ltd", +[9][0x6e - 1] = "Roa Logic BV", +[9][0x6f - 1] = "NSITEXE Inc", +[9][0x70 - 1] = "Hong Kong Hyunion Electronics", +[9][0x71 - 1] = "ASK Technology Group Limited", +[9][0x72 - 1] = "GIGA-BYTE Technology Co Ltd", +[9][0x73 - 1] = "Terabyte Co Ltd", +[9][0x74 - 1] = "Hyundai Inc", +[9][0x75 - 1] = "EXCELERAM", +[9][0x76 - 1] = "PsiKick", +[9][0x77 - 1] = "Netac Technology Co Ltd", +[9][0x78 - 1] = "PCCOOLER", +[9][0x79 - 1] = "Jiangsu Huacun Electronic Technology", +[9][0x7a - 1] = "Shenzhen Micro Innovation Industry", +[9][0x7b - 1] = "Beijing Tongfang Microelectronics Co", +[9][0x7c - 1] = "XZN Storage Technology", +[9][0x7d - 1] = "ChipCraft Sp. z.o.o.", +[9][0x7e - 1] = "ALLFLASH Technology Limited", +[10][0x01 - 1] = "Foerd Technology Co Ltd", +[10][0x02 - 1] = "KingSpec", +[10][0x03 - 1] = "Codasip GmbH", +[10][0x04 - 1] = "SL Link Co Ltd", +[10][0x05 - 1] = "Shenzhen Kefu Technology Co Limited", +[10][0x06 - 1] = "Shenzhen ZST Electronics Technology", +[10][0x07 - 1] = "Kyokuto Electronic Inc", +[10][0x08 - 1] = "Warrior Technology", +[10][0x09 - 1] = "TRINAMIC Motion Control GmbH & Co", +[10][0x0a - 1] = "PixelDisplay Inc", +[10][0x0b - 1] = "Shenzhen Futian District Bo Yueda Elec", +[10][0x0c - 1] = "Richtek Power", +[10][0x0d - 1] = "Shenzhen LianTeng Electronics Co Ltd", +[10][0x0e - 1] = "AITC Memory", +[10][0x0f - 1] = "UNIC Memory Technology Co Ltd", +[10][0x10 - 1] = "Shenzhen Huafeng Science Technology", +[10][0x11 - 1] = "CXMT", +[10][0x12 - 1] = "Guangzhou Xinyi Heng Computer Trading Firm", +[10][0x13 - 1] = "SambaNova Systems", +[10][0x14 - 1] = "V-GEN", +[10][0x15 - 1] = "Jump Trading", +[10][0x16 - 1] = "Ampere Computing", +[10][0x17 - 1] = "Shenzhen Zhongshi Technology Co Ltd", +[10][0x18 - 1] = "Shenzhen Zhongtian Bozhong Technology", +[10][0x19 - 1] = "Tri-Tech International", +[10][0x1a - 1] = "Silicon Intergrated Systems Corporation", +[10][0x1b - 1] = "Shenzhen HongDingChen Information", +[10][0x1c - 1] = "Plexton Holdings Limited", +[10][0x1d - 1] = "AMS (Jiangsu Advanced Memory Semi)", +[10][0x1e - 1] = "Wuhan Jing Tian Interconnected Tech Co", +[10][0x1f - 1] = "Axia Memory Technology", +[10][0x20 - 1] = "Chipset Technology Holding Limited", +[10][0x21 - 1] = "Shenzhen Xinshida Technology Co Ltd", +[10][0x22 - 1] = "Shenzhen Chuangshifeida Technology", +[10][0x23 - 1] = "Guangzhou MiaoYuanJi Technology", +[10][0x24 - 1] = "ADVAN Inc", +[10][0x25 - 1] = "Shenzhen Qianhai Weishengda Electronic Commerce Company Ltd", +[10][0x26 - 1] = "Guangzhou Guang Xie Cheng Trading", +[10][0x27 - 1] = "StarRam International Co Ltd", +[10][0x28 - 1] = "Shen Zhen XinShenHua Tech Co Ltd", +[10][0x29 - 1] = "UltraMemory Inc", +[10][0x2a - 1] = "New Coastline Global Tech Industry Co", +[10][0x2b - 1] = "Sinker", +[10][0x2c - 1] = "Diamond", +[10][0x2d - 1] = "PUSKILL", +[10][0x2e - 1] = "Guangzhou Hao Jia Ye Technology Co", +[10][0x2f - 1] = "Ming Xin Limited", +[10][0x30 - 1] = "Barefoot Networks", +[10][0x31 - 1] = "Biwin Semiconductor (HK) Co Ltd", +[10][0x32 - 1] = "UD INFO Corporation", +[10][0x33 - 1] = "Trek Technology (S) PTE Ltd", +[10][0x34 - 1] = "Xiamen Kingblaze Technology Co Ltd", +[10][0x35 - 1] = "Shenzhen Lomica Technology Co Ltd", +[10][0x36 - 1] = "Nuclei System Technology Co Ltd", +[10][0x37 - 1] = "Wuhan Xun Zhan Electronic Technology", +[10][0x38 - 1] = "Shenzhen Ingacom Semiconductor Ltd", +[10][0x39 - 1] = "Zotac Technology Ltd", +[10][0x3a - 1] = "Foxline", +[10][0x3b - 1] = "Shenzhen Farasia Science Technology", +[10][0x3c - 1] = "Efinix Inc", +[10][0x3d - 1] = "Hua Nan San Xian Technology Co Ltd", +[10][0x3e - 1] = "Goldtech Electronics Co Ltd", +[10][0x3f - 1] = "Shanghai Han Rong Microelectronics Co", +[10][0x40 - 1] = "Shenzhen Zhongguang Yunhe Trading", +[10][0x41 - 1] = "Smart Shine(QingDao) Microelectronics", +[10][0x42 - 1] = "Thermaltake Technology Co Ltd", +[10][0x43 - 1] = "Shenzhen O'Yang Maile Technology Ltd", +[10][0x44 - 1] = "UPMEM", +[10][0x45 - 1] = "Chun Well Technology Holding Limited", +[10][0x46 - 1] = "Astera Labs Inc", +[10][0x47 - 1] = "Winconway", +[10][0x48 - 1] = "Advantech Co Ltd", +[10][0x49 - 1] = "Chengdu Fengcai Electronic Technology", +[10][0x4a - 1] = "The Boeing Company", +[10][0x4b - 1] = "Blaize Inc", +[10][0x4c - 1] = "Ramonster Technology Co Ltd", +[10][0x4d - 1] = "Wuhan Naonongmai Technology Co Ltd", +[10][0x4e - 1] = "Shenzhen Hui ShingTong Technology", +[10][0x4f - 1] = "Yourlyon", +[10][0x50 - 1] = "Fabu Technology", +[10][0x51 - 1] = "Shenzhen Yikesheng Technology Co Ltd", +[10][0x52 - 1] = "NOR-MEM", +[10][0x53 - 1] = "Cervoz Co Ltd", +[10][0x54 - 1] = "Bitmain Technologies Inc.", +[10][0x55 - 1] = "Facebook Inc", +[10][0x56 - 1] = "Shenzhen Longsys Electronics Co Ltd", +[10][0x57 - 1] = "Guangzhou Siye Electronic Technology", +[10][0x58 - 1] = "Silergy", +[10][0x59 - 1] = "Adamway", +[10][0x5a - 1] = "PZG", +[10][0x5b - 1] = "Shenzhen King Power Electronics", +[10][0x5c - 1] = "Guangzhou ZiaoFu Tranding Co Ltd", +[10][0x5d - 1] = "Shenzhen SKIHOTAR Semiconductor", +[10][0x5e - 1] = "PulseRain Technology", +[10][0x5f - 1] = "Seeker Technology Limited", +[10][0x60 - 1] = "Shenzhen OSCOO Tech Co Ltd", +[10][0x61 - 1] = "Shenzhen Yze Technology Co Ltd", +[10][0x62 - 1] = "Shenzhen Jieshuo Electronic Commerce", +[10][0x63 - 1] = "Gazda", +[10][0x64 - 1] = "Hua Wei Technology Co Ltd", +[10][0x65 - 1] = "Esperanto Technologies", +[10][0x66 - 1] = "JinSheng Electronic (Shenzhen) Co Ltd", +[10][0x67 - 1] = "Shenzhen Shi Bolunshuai Technology", +[10][0x68 - 1] = "Shanghai Rei Zuan Information Tech", +[10][0x69 - 1] = "Fraunhofer IIS", +[10][0x6a - 1] = "Kandou Bus SA", +[10][0x6b - 1] = "Acer", +[10][0x6c - 1] = "Artmem Technology Co Ltd", +[10][0x6d - 1] = "Gstar Semiconductor Co Ltd", +[10][0x6e - 1] = "ShineDisk", +[10][0x6f - 1] = "Shenzhen CHN Technology Co Ltd", +[10][0x70 - 1] = "UnionChip Semiconductor Co Ltd", +[10][0x71 - 1] = "Tanbassh", +[10][0x72 - 1] = "Shenzhen Tianyu Jieyun Intl Logistics", +[10][0x73 - 1] = "MCLogic Inc", +[10][0x74 - 1] = "Eorex Corporation", +[10][0x75 - 1] = "Arm Technology (China) Co Ltd", +[10][0x76 - 1] = "Lexar Co Limited", +[10][0x77 - 1] = "QinetiQ Group plc", +[10][0x78 - 1] = "Exascend", +[10][0x79 - 1] = "Hong Kong Hyunion Electronics Co Ltd", +[10][0x7a - 1] = "Shenzhen Banghong Electronics Co Ltd", +[10][0x7b - 1] = "MBit Wireless Inc", +[10][0x7c - 1] = "Hex Five Security Inc", +[10][0x7d - 1] = "ShenZhen Juhor Precision Tech Co Ltd", +[10][0x7e - 1] = "Shenzhen Reeinno Technology Co Ltd", +[11][0x01 - 1] = "ABIT Electronics (Shenzhen) Co Ltd", +[11][0x02 - 1] = "Semidrive", +[11][0x03 - 1] = "MyTek Electronics Corp", +[11][0x04 - 1] = "Wxilicon Technology Co Ltd", +[11][0x05 - 1] = "Shenzhen Meixin Electronics Ltd", +[11][0x06 - 1] = "Ghost Wolf", +[11][0x07 - 1] = "LiSion Technologies Inc", +[11][0x08 - 1] = "Power Active Co Ltd", +[11][0x09 - 1] = "Pioneer High Fidelity Taiwan Co. Ltd", +[11][0x0a - 1] = "LuoSilk", +[11][0x0b - 1] = "Shenzhen Chuangshifeida Technology", +[11][0x0c - 1] = "Black Sesame Technologies Inc", +[11][0x0d - 1] = "Jiangsu Xinsheng Intelligent Technology", +[11][0x0e - 1] = "MLOONG", +[11][0x0f - 1] = "Quadratica LLC", +[11][0x10 - 1] = "Anpec Electronics", +[11][0x11 - 1] = "Xi'an Morebeck Semiconductor Tech Co", +[11][0x12 - 1] = "Kingbank Technology Co Ltd", +[11][0x13 - 1] = "ITRenew Inc", +[11][0x14 - 1] = "Shenzhen Eaget Innovation Tech Ltd", +[11][0x15 - 1] = "Jazer", +[11][0x16 - 1] = "Xiamen Semiconductor Investment Group", +[11][0x17 - 1] = "Guangzhou Longdao Network Tech Co", +[11][0x18 - 1] = "Shenzhen Futian SEC Electronic Market", +[11][0x19 - 1] = "Allegro Microsystems LLC", +[11][0x1a - 1] = "Hunan RunCore Innovation Technology", +[11][0x1b - 1] = "C-Corsa Technology", +[11][0x1c - 1] = "Zhuhai Chuangfeixin Technology Co Ltd", +[11][0x1d - 1] = "Beijing InnoMem Technologies Co Ltd", +[11][0x1e - 1] = "YooTin", +[11][0x1f - 1] = "Shenzhen Pengxiong Technology Co Ltd", +[11][0x20 - 1] = "Dongguan Yingbang Commercial Trading Co", +[11][0x21 - 1] = "Shenzhen Ronisys Electronics Co Ltd", +[11][0x22 - 1] = "Hongkong Xinlan Guangke Co Ltd", +[11][0x23 - 1] = "Apex Microelectronics Co Ltd", +[11][0x24 - 1] = "Beijing Hongda Jinming Technology Co Ltd", +[11][0x25 - 1] = "Ling Rui Technology (Shenzhen) Co Ltd", +[11][0x26 - 1] = "Hongkong Hyunion Electronics Co Ltd", +[11][0x27 - 1] = "Starsystems Inc", +[11][0x28 - 1] = "Shenzhen Yingjiaxun Industrial Co Ltd", +[11][0x29 - 1] = "Dongguan Crown Code Electronic Commerce", +[11][0x2a - 1] = "Monolithic Power Systems Inc", +[11][0x2b - 1] = "WuHan SenNaiBo E-Commerce Co Ltd", +[11][0x2c - 1] = "Hangzhou Hikstorage Technology Co", +[11][0x2d - 1] = "Shenzhen Goodix Technology Co Ltd", +[11][0x2e - 1] = "Aigo Electronic Technology Co Ltd", +[11][0x2f - 1] = "Hefei Konsemi Storage Technology Co Ltd", +[11][0x30 - 1] = "Cactus Technologies Limited", +[11][0x31 - 1] = "DSIN", +[11][0x32 - 1] = "Blu Wireless Technology", +[11][0x33 - 1] = "Nanjing UCUN Technology Inc", +[11][0x34 - 1] = "Acacia Communications", +[11][0x35 - 1] = "Beijinjinshengyihe Technology Co Ltd", +[11][0x36 - 1] = "Zyzyx", +[11][0x37 - 1] = "T-HEAD Semiconductor Co Ltd", +[11][0x38 - 1] = "Shenzhen Hystou Technology Co Ltd", +[11][0x39 - 1] = "Syzexion", +[11][0x3a - 1] = "Kembona", +[11][0x3b - 1] = "Qingdao Thunderobot Technology Co Ltd", +[11][0x3c - 1] = "Morse Micro", +[11][0x3d - 1] = "Shenzhen Envida Technology Co Ltd", +[11][0x3e - 1] = "UDStore Solution Limited", +[11][0x3f - 1] = "Shunlie", +[11][0x40 - 1] = "Shenzhen Xin Hong Rui Tech Ltd", +[11][0x41 - 1] = "Shenzhen Yze Technology Co Ltd", +[11][0x42 - 1] = "Shenzhen Huang Pu He Xin Technology", +[11][0x43 - 1] = "Xiamen Pengpai Microelectronics Co Ltd", +[11][0x44 - 1] = "JISHUN", +[11][0x45 - 1] = "Shenzhen WODPOSIT Technology Co", +[11][0x46 - 1] = "Unistar", +[11][0x47 - 1] = "UNICORE Electronic (Suzhou) Co Ltd", +[11][0x48 - 1] = "Axonne Inc", +[11][0x49 - 1] = "Shenzhen SOVERECA Technology Co", +[11][0x4a - 1] = "Dire Wolf", +[11][0x4b - 1] = "Whampoa Core Technology Co Ltd", +[11][0x4c - 1] = "CSI Halbleiter GmbH", +[11][0x4d - 1] = "ONE Semiconductor", +[11][0x4e - 1] = "SimpleMachines Inc", +[11][0x4f - 1] = "Shenzhen Chengyi Qingdian Electronic", +[11][0x50 - 1] = "Shenzhen Xinlianxin Network Technology", +[11][0x51 - 1] = "Vayyar Imaging Ltd", +[11][0x52 - 1] = "Paisen Network Technology Co Ltd", +[11][0x53 - 1] = "Shenzhen Fengwensi Technology Co Ltd", +[11][0x54 - 1] = "Caplink Technology Limited", +[11][0x55 - 1] = "JJT Solution Co Ltd", +[11][0x56 - 1] = "HOSIN Global Electronics Co Ltd", +[11][0x57 - 1] = "Shenzhen KingDisk Century Technology", +[11][0x58 - 1] = "SOYO", +[11][0x59 - 1] = "DIT Technology Co Ltd", +[11][0x5a - 1] = "iFound", +[11][0x5b - 1] = "Aril Computer Company", +[11][0x5c - 1] = "ASUS", +[11][0x5d - 1] = "Shenzhen Ruiyingtong Technology Co", +[11][0x5e - 1] = "HANA Micron", +[11][0x5f - 1] = "RANSOR", +[11][0x60 - 1] = "Axiado Corporation", +[11][0x61 - 1] = "Tesla Corporation", +[11][0x62 - 1] = "Pingtouge (Shanghai) Semiconductor Co", +[11][0x63 - 1] = "S3Plus Technologies SA", +[11][0x64 - 1] = "Integrated Silicon Solution Israel Ltd", +[11][0x65 - 1] = "GreenWaves Technologies", +[11][0x66 - 1] = "NUVIA Inc", +[11][0x67 - 1] = "Guangzhou Shuvrwine Technology Co", +[11][0x68 - 1] = "Shenzhen Hangshun Chip Technology", +[11][0x69 - 1] = "Chengboliwei Electronic Business", +[11][0x6a - 1] = "Kowin Technology HK Limited", +[11][0x6b - 1] = "Euronet Technology Inc", +[11][0x6c - 1] = "SCY", +[11][0x6d - 1] = "Shenzhen Xinhongyusheng Electrical", +[11][0x6e - 1] = "PICOCOM", +[11][0x6f - 1] = "Shenzhen Toooogo Memory Technology", +[11][0x70 - 1] = "VLSI Solution", +[11][0x71 - 1] = "Costar Electronics Inc", +[11][0x72 - 1] = "Shenzhen Huatop Technology Co Ltd", +[11][0x73 - 1] = "Inspur Electronic Information Industry", +[11][0x74 - 1] = "Shenzhen Boyuan Computer Technology", +[11][0x75 - 1] = "Beijing Welldisk Electronics Co Ltd", +[11][0x76 - 1] = "Suzhou EP Semicon Co Ltd", +[11][0x77 - 1] = "Zhejiang Dahua Memory Technology", +[11][0x78 - 1] = "Virtu Financial", +[11][0x79 - 1] = "Datotek International Co Ltd", +[11][0x7a - 1] = "Telecom and Microelectronics Industries", +[11][0x7b - 1] = "Echow Technology Ltd", +[11][0x7c - 1] = "APEX-INFO", +[11][0x7d - 1] = "Yingpark", +[11][0x7e - 1] = "Shenzhen Bigway Tech Co Ltd", +[12][0x01 - 1] = "Beijing Haawking Technology Co Ltd", +[12][0x02 - 1] = "Open HW Group", +[12][0x03 - 1] = "JHICC", +[12][0x04 - 1] = "ncoder AG", +[12][0x05 - 1] = "ThinkTech Information Technology Co", +[12][0x06 - 1] = "Shenzhen Chixingzhe Technology Co Ltd", +[12][0x07 - 1] = "Biao Ram Technology Co Ltd", +[12][0x08 - 1] = "Shenzhen Kaizhuoyue Electronics Co Ltd", +[12][0x09 - 1] = "Shenzhen YC Storage Technology Co Ltd", +[12][0x0a - 1] = "Shenzhen Chixingzhe Technology Co", +[12][0x0b - 1] = "Wink Semiconductor (Shenzhen) Co Ltd", +[12][0x0c - 1] = "AISTOR", +[12][0x0d - 1] = "Palma Ceia SemiDesign", +[12][0x0e - 1] = "EM Microelectronic-Marin SA", +[12][0x0f - 1] = "Shenzhen Monarch Memory Technology", +[12][0x10 - 1] = "Reliance Memory Inc", +[12][0x11 - 1] = "Jesis", +[12][0x12 - 1] = "Espressif Systems (Shanghai) Co Ltd", +[12][0x13 - 1] = "Shenzhen Sati Smart Technology Co Ltd", +[12][0x14 - 1] = "NeuMem Co Ltd", +[12][0x15 - 1] = "Lifelong", +[12][0x16 - 1] = "Beijing Oitech Technology Co Ltd", +[12][0x17 - 1] = "Groupe LDLC", +[12][0x18 - 1] = "Semidynamics Technology Services SLU", +[12][0x19 - 1] = "swordbill", +[12][0x1a - 1] = "YIREN", +[12][0x1b - 1] = "Shenzhen Yinxiang Technology Co Ltd", +[12][0x1c - 1] = "PoweV Electronic Technology Co Ltd", +[12][0x1d - 1] = "LEORICE", +[12][0x1e - 1] = "Waymo LLC", +[12][0x1f - 1] = "Ventana Micro Systems", +[12][0x20 - 1] = "Hefei Guangxin Microelectronics Co Ltd", +[12][0x21 - 1] = "Shenzhen Sooner Industrial Co Ltd", +[12][0x22 - 1] = "Horizon Robotics", +[12][0x23 - 1] = "Tangem AG", +[12][0x24 - 1] = "FuturePath Technology (Shenzhen) Co", +[12][0x25 - 1] = "RC Module", +[12][0x26 - 1] = "Timetec International Inc", +[12][0x27 - 1] = "ICMAX Technologies Co Limited", +[12][0x28 - 1] = "Lynxi Technologies Ltd Co", +[12][0x29 - 1] = "Guangzhou Taisupanke Computer Equipment", +[12][0x2a - 1] = "Ceremorphic Inc", +[12][0x2b - 1] = "Biwin Storage Technology Co Ltd", +[12][0x2c - 1] = "Beijing ESWIN Computing Technology", +[12][0x2d - 1] = "WeForce Co Ltd", +[12][0x2e - 1] = "Shenzhen Fanxiang Information Technology", +[12][0x2f - 1] = "Unisoc", +[12][0x30 - 1] = "YingChu", +[12][0x31 - 1] = "GUANCUN", +[12][0x32 - 1] = "IPASON", +[12][0x33 - 1] = "Ayar Labs", +[12][0x34 - 1] = "Amazon", +[12][0x35 - 1] = "Shenzhen Xinxinshun Technology Co", +[12][0x36 - 1] = "Galois Inc", +[12][0x37 - 1] = "Ubilite Inc", +[12][0x38 - 1] = "Shenzhen Quanxing Technology Co Ltd", +[12][0x39 - 1] = "Group RZX Technology LTDA", +[12][0x3a - 1] = "Yottac Technology (XI'AN) Cooperation", +[12][0x3b - 1] = "Shenzhen RuiRen Technology Co Ltd", +[12][0x3c - 1] = "Group Star Technology Co Ltd", +[12][0x3d - 1] = "RWA (Hong Kong) Ltd", +[12][0x3e - 1] = "Genesys Logic Inc", +[12][0x3f - 1] = "T3 Robotics Inc.", +[12][0x40 - 1] = "Biostar Microtech International Corp", +[12][0x41 - 1] = "Shenzhen SXmicro Technology Co Ltd", +[12][0x42 - 1] = "Shanghai Yili Computer Technology Co", +[12][0x43 - 1] = "Zhixin Semicoducotor Co Ltd", +[12][0x44 - 1] = "uFound", +[12][0x45 - 1] = "Aigo Data Security Technology Co. Ltd", +[12][0x46 - 1] = ".GXore Technologies", +[12][0x47 - 1] = "Shenzhen Pradeon Intelligent Technology", +[12][0x48 - 1] = "Power LSI", +[12][0x49 - 1] = "PRIME", +[12][0x4a - 1] = "Shenzhen Juyang Innovative Technology", +[12][0x4b - 1] = "CERVO", +[12][0x4c - 1] = "SiEngine Technology Co., Ltd.", +[12][0x4d - 1] = "Beijing Unigroup Tsingteng MicroSystem", +[12][0x4e - 1] = "Brainsao GmbH", +[12][0x4f - 1] = "Credo Technology Group Ltd", +[12][0x50 - 1] = "Shanghai Biren Technology Co Ltd", +[12][0x51 - 1] = "Nucleu Semiconductor", +[12][0x52 - 1] = "Shenzhen Guangshuo Electronics Co Ltd", +[12][0x53 - 1] = "ZhongsihangTechnology Co Ltd", +[12][0x54 - 1] = "Suzhou Mainshine Electronic Co Ltd.", +[12][0x55 - 1] = "Guangzhou Riss Electronic Technology", +[12][0x56 - 1] = "Shenzhen Cloud Security Storage Co", +[12][0x57 - 1] = "ROG", +[12][0x58 - 1] = "Perceive", +[12][0x59 - 1] = "e-peas", +[12][0x5a - 1] = "Fraunhofer IPMS", +[12][0x5b - 1] = "Shenzhen Daxinlang Electronic Tech Co", +[12][0x5c - 1] = "Abacus Peripherals Private Limited", +[12][0x5d - 1] = "OLOy Technology", +[12][0x5e - 1] = "Wuhan P&S Semiconductor Co Ltd", +[12][0x5f - 1] = "Sitrus Technology", +[12][0x60 - 1] = "AnHui Conner Storage Co Ltd", +[12][0x61 - 1] = "Rochester Electronics", +[12][0x62 - 1] = "Wuxi Petabyte Technologies Co Ltd", +[12][0x63 - 1] = "Star Memory", +[12][0x64 - 1] = "Agile Memory Technology Co Ltd", +[12][0x65 - 1] = "MEJEC", +[12][0x66 - 1] = "Rockchip Electronics Co Ltd", +[12][0x67 - 1] = "Dongguan Guanma e-commerce Co Ltd", +[12][0x68 - 1] = "Rayson Hi-Tech (SZ) Limited", +[12][0x69 - 1] = "MINRES Technologies GmbH", +[12][0x6a - 1] = "Himax Technologies Inc", +[12][0x6b - 1] = "Shenzhen Cwinner Technology Co Ltd", +[12][0x6c - 1] = "Tecmiyo", +[12][0x6d - 1] = "Shenzhen Suhuicun Technology Co Ltd", +[12][0x6e - 1] = "Vickter Electronics Co. Ltd.", +[12][0x6f - 1] = "lowRISC", +[12][0x70 - 1] = "EXEGate FZE", +[12][0x71 - 1] = "Shenzhen 9 Chapter Technologies Co", +[12][0x72 - 1] = "Addlink", +[12][0x73 - 1] = "Starsway", +[12][0x74 - 1] = "Pensando Systems Inc.", +[12][0x75 - 1] = "AirDisk", +[12][0x76 - 1] = "Shenzhen Speedmobile Technology Co", +[12][0x77 - 1] = "PEZY Computing", +[12][0x78 - 1] = "Extreme Engineering Solutions Inc", +[12][0x79 - 1] = "Shangxin Technology Co Ltd", +[12][0x7a - 1] = "Shanghai Zhaoxin Semiconductor Co", +[12][0x7b - 1] = "Xsight Labs Ltd", +[12][0x7c - 1] = "Hangzhou Hikstorage Technology Co", +[12][0x7d - 1] = "Dell Technologies", +[12][0x7e - 1] = "Guangdong StarFive Technology Co", +[13][0x01 - 1] = "TECOTON", +[13][0x02 - 1] = "Abko Co Ltd", +[13][0x03 - 1] = "Shenzhen Feisrike Technology Co Ltd", +[13][0x04 - 1] = "Shenzhen Sunhome Electronics Co Ltd", +[13][0x05 - 1] = "Global Mixed-mode Technology Inc", +[13][0x06 - 1] = "Shenzhen Weien Electronics Co. Ltd.", +[13][0x07 - 1] = "Shenzhen Cooyes Technology Co Ltd", +[13][0x08 - 1] = "Keymos Electronics Co., Limited", +[13][0x09 - 1] = "E-Rockic Technology Company Limited", +[13][0x0a - 1] = "Aerospace Science Memory Shenzhen", +[13][0x0b - 1] = "Shenzhen Quanji Technology Co Ltd", +[13][0x0c - 1] = "Dukosi", +[13][0x0d - 1] = "Maxell Corporation of America", +[13][0x0e - 1] = "Shenshen Xinxintao Electronics Co Ltd", +[13][0x0f - 1] = "Zhuhai Sanxia Semiconductor Co Ltd", +[13][0x10 - 1] = "Groq Inc", +[13][0x11 - 1] = "AstraTek", +[13][0x12 - 1] = "Shenzhen Xinyuze Technology Co Ltd", +[13][0x13 - 1] = "All Bit Semiconductor", +[13][0x14 - 1] = "ACFlow", +[13][0x15 - 1] = "Shenzhen Sipeed Technology Co Ltd", +[13][0x16 - 1] = "Linzhi Hong Kong Co Limited", +[13][0x17 - 1] = "Supreme Wise Limited", +[13][0x18 - 1] = "Blue Cheetah Analog Design Inc", +[13][0x19 - 1] = "Hefei Laiku Technology Co Ltd", +[13][0x1a - 1] = "Zord", +[13][0x1b - 1] = "SBO Hearing A/S", +[13][0x1c - 1] = "Regent Sharp International Limited", +[13][0x1d - 1] = "Permanent Potential Limited", +[13][0x1e - 1] = "Creative World International Limited", +[13][0x1f - 1] = "Base Creation International Limited", +[13][0x20 - 1] = "Shenzhen Zhixin Chuanglian Technology", +[13][0x21 - 1] = "Protected Logic Corporation", +[13][0x22 - 1] = "Sabrent", +[13][0x23 - 1] = "Union Memory", +[13][0x24 - 1] = "NEUCHIPS Corporation", +[13][0x25 - 1] = "Ingenic Semiconductor Co Ltd", +[13][0x26 - 1] = "SiPearl", +[13][0x27 - 1] = "Shenzhen Actseno Information Technology", +[13][0x28 - 1] = "RIVAI Technologies (Shenzhen) Co Ltd", +[13][0x29 - 1] = "Shenzhen Sunny Technology Co Ltd", +[13][0x2a - 1] = "Cott Electronics Ltd", +[13][0x2b - 1] = "Shanghai Synsense Technologies Co Ltd", +[13][0x2c - 1] = "Shenzhen Jintang Fuming Optoelectronics", +[13][0x2d - 1] = "CloudBEAR LLC", +[13][0x2e - 1] = "Emzior, LLC", +[13][0x2f - 1] = "Ehiway Microelectronic Science Tech Co", +[13][0x30 - 1] = "UNIM Innovation Technology (Wu XI)", +[13][0x31 - 1] = "GDRAMARS", +[13][0x32 - 1] = "Meminsights Technology", +[13][0x33 - 1] = "Zhuzhou Hongda Electronics Corp Ltd", +[13][0x34 - 1] = "Luminous Computing Inc", +[13][0x35 - 1] = "PROXMEM", +[13][0x36 - 1] = "Draper Labs", +[13][0x37 - 1] = "ORICO Technologies Co. Ltd.", +[13][0x38 - 1] = "Space Exploration Technologies Corp", +[13][0x39 - 1] = "AONDEVICES Inc", +[13][0x3a - 1] = "Shenzhen Netforward Micro Electronic", +[13][0x3b - 1] = "Syntacore Ltd", +[13][0x3c - 1] = "Shenzhen Secmem Microelectronics Co", +[13][0x3d - 1] = "ONiO As", +[13][0x3e - 1] = "Shenzhen Peladn Technology Co Ltd", +[13][0x3f - 1] = "O-Cubes Shanghai Microelectronics", +[13][0x40 - 1] = "ASTC", +[13][0x41 - 1] = "UMIS", +[13][0x42 - 1] = "Paradromics", +[13][0x43 - 1] = "Sinh Micro Co Ltd", +[13][0x44 - 1] = "Metorage Semiconductor Technology Co", +[13][0x45 - 1] = "Aeva Inc", +[13][0x46 - 1] = "HongKong Hyunion Electronics Co Ltd", +[13][0x47 - 1] = "China Flash Co Ltd", +[13][0x48 - 1] = "Sunplus Technology Co Ltd", +[13][0x49 - 1] = "Idaho Scientific", +[13][0x4a - 1] = "Suzhou SF Micro Electronics Co Ltd", +[13][0x4b - 1] = "IMEX Cap AG", +[13][0x4c - 1] = "Fitipower Integrated Technology Co Ltd", +[13][0x4d - 1] = "ShenzhenWooacme Technology Co Ltd", +[13][0x4e - 1] = "KeepData Original Chips", +[13][0x4f - 1] = "Rivos Inc", +[13][0x50 - 1] = "Big Innovation Company Limited", +[13][0x51 - 1] = "Wuhan YuXin Semiconductor Co Ltd", +[13][0x52 - 1] = "United Memory Technology (Jiangsu)", +[13][0x53 - 1] = "PQShield Ltd", +[13][0x54 - 1] = "ArchiTek Corporation", +[13][0x55 - 1] = "ShenZhen AZW Technology Co Ltd", +[13][0x56 - 1] = "Hengchi Zhixin (Dongguan) Technology", +[13][0x57 - 1] = "Eggtronic Engineering Spa", +[13][0x58 - 1] = "Fusontai Technology", +[13][0x59 - 1] = "PULP Platform", +[13][0x5a - 1] = "Koitek Electronic Technology (Shenzhen) Co", +[13][0x5b - 1] = "Shenzhen Jiteng Network Technology Co", +[13][0x5c - 1] = "Aviva Links Inc", +[13][0x5d - 1] = "Trilinear Technologies Inc", +[13][0x5e - 1] = "Shenzhen Developer Microelectronics Co", +[13][0x5f - 1] = "Guangdong OPPO Mobile Telecommunication", +[13][0x60 - 1] = "Akeana", +[13][0x61 - 1] = "Lyczar", +[13][0x62 - 1] = "Shenzhen Qiji Technology Co Ltd", +[13][0x63 - 1] = "Shenzhen Shangzhaoyuan Technology", +[13][0x64 - 1] = "Han Stor", +[13][0x65 - 1] = "China Micro Semicon Co., Ltd.", +[13][0x66 - 1] = "Shenzhen Zhuqin Technology Co Ltd", +[13][0x67 - 1] = "Shanghai Ningyuan Electronic Technology", +[13][0x68 - 1] = "Auradine", +[13][0x69 - 1] = "Suzhou Yishuo Electronics Co Ltd", +[13][0x6a - 1] = "Faurecia Clarion Electronics", +[13][0x6b - 1] = "SiMa Technologies", +[13][0x6c - 1] = "CFD Sales Inc", +[13][0x6d - 1] = "Suzhou Comay Information Co Ltd", +[13][0x6e - 1] = "Yentek", +[13][0x6f - 1] = "Qorvo Inc", +[13][0x70 - 1] = "Shenzhen Youzhi Computer Technology", +[13][0x71 - 1] = "Sychw Technology (Shenzhen) Co Ltd", +[13][0x72 - 1] = "MK Founder Technology Co Ltd", +[13][0x73 - 1] = "Siliconwaves Technologies Co Ltd", +[13][0x74 - 1] = "Hongkong Hyunion Electronics Co Ltd", +[13][0x75 - 1] = "Shenzhen Xinxinzhitao Electronics Business", +[13][0x76 - 1] = "Shenzhen HenQi Electronic Commerce Co", +[13][0x77 - 1] = "Shenzhen Jingyi Technology Co Ltd", +[13][0x78 - 1] = "Xiaohua Semiconductor Co. Ltd.", +[13][0x79 - 1] = "Shenzhen Dalu Semiconductor Technology", +[13][0x7a - 1] = "Shenzhen Ninespeed Electronics Co Ltd", +[13][0x7b - 1] = "ICYC Semiconductor Co Ltd", +[13][0x7c - 1] = "Shenzhen Jaguar Microsystems Co Ltd", +[13][0x7d - 1] = "Beijing EC-Founder Co Ltd", +[13][0x7e - 1] = "Shenzhen Taike Industrial Automation Co", +[14][0x01 - 1] = "Kalray SA", +[14][0x02 - 1] = "Shanghai Iluvatar CoreX Semiconductor Co", +[14][0x03 - 1] = "Fungible Inc", +[14][0x04 - 1] = "Song Industria E Comercio de Eletronicos", +[14][0x05 - 1] = "DreamBig Semiconductor Inc", +[14][0x06 - 1] = "ChampTek Electronics Corp", +[14][0x07 - 1] = "Fusontai Technology", +[14][0x08 - 1] = "Endress Hauser AG", +[14][0x09 - 1] = "altec ComputerSysteme GmbH", +[14][0x0a - 1] = "UltraRISC Technology (Shanghai) Co Ltd", +[14][0x0b - 1] = "Shenzhen Jing Da Kang Technology Co Ltd", +[14][0x0c - 1] = "Hangzhou Hongjun Microelectronics Co Ltd", +/* EOF */ diff --git a/applications/plugins/swd_probe/model/chip.ply b/applications/plugins/swd_probe/model/chip.ply new file mode 100644 index 000000000..7dc20abfa --- /dev/null +++ b/applications/plugins/swd_probe/model/chip.ply @@ -0,0 +1,216 @@ +ply +format ascii 1.0 +comment Created by Blender 3.3.1 - www.blender.org +element vertex 136 +property float x +property float y +property float z +element face 70 +property list uchar uint vertex_indices +end_header +1.000000 1.000000 0.152153 +-1.000000 1.000000 0.152153 +-1.000000 -1.000000 0.152153 +1.000000 -1.000000 0.152153 +1.000000 -1.000000 -0.185787 +-1.000000 -1.000000 -0.185787 +-1.000000 1.000000 -0.185787 +1.000000 1.000000 -0.185787 +-1.000043 -0.785071 -0.015780 +-1.155724 -0.785071 -0.015780 +-1.155724 -0.918718 -0.015780 +-1.000043 -0.918718 -0.015780 +-1.155724 -0.785071 0.127052 +-1.000043 -0.785071 0.127052 +-1.000043 -0.918718 0.127052 +-1.155724 -0.918718 0.127052 +-1.234192 -0.918846 -0.087021 +-1.234397 -0.785201 -0.086336 +-1.235319 -0.784943 -0.229143 +-1.235114 -0.918588 -0.229828 +-1.388133 -0.919573 -0.078673 +-1.389056 -0.919314 -0.221479 +-1.389261 -0.785669 -0.220795 +-1.388338 -0.785927 -0.077988 +-1.000043 -0.219627 -0.015780 +-1.155724 -0.219627 -0.015780 +-1.155724 -0.353273 -0.015780 +-1.000043 -0.353273 -0.015780 +-1.155724 -0.219627 0.127052 +-1.000043 -0.219627 0.127052 +-1.000043 -0.353273 0.127052 +-1.155724 -0.353273 0.127052 +-1.234192 -0.353402 -0.087021 +-1.234397 -0.219756 -0.086336 +-1.235319 -0.219498 -0.229143 +-1.235114 -0.353143 -0.229828 +-1.388133 -0.354128 -0.078673 +-1.389056 -0.353870 -0.221479 +-1.389261 -0.220224 -0.220795 +-1.388338 -0.220482 -0.077988 +-1.000043 0.345818 -0.015780 +-1.155724 0.345818 -0.015780 +-1.155724 0.212172 -0.015780 +-1.000043 0.212172 -0.015780 +-1.155724 0.345818 0.127052 +-1.000043 0.345818 0.127052 +-1.000043 0.212172 0.127052 +-1.155724 0.212172 0.127052 +-1.234192 0.212043 -0.087021 +-1.234397 0.345689 -0.086336 +-1.235319 0.345947 -0.229143 +-1.235114 0.212301 -0.229828 +-1.388133 0.211317 -0.078673 +-1.389056 0.211575 -0.221479 +-1.389261 0.345221 -0.220795 +-1.388338 0.344962 -0.077988 +-1.000043 0.911263 -0.015780 +-1.155724 0.911263 -0.015780 +-1.155724 0.777617 -0.015780 +-1.000043 0.777617 -0.015780 +-1.155724 0.911263 0.127052 +-1.000043 0.911263 0.127052 +-1.000043 0.777617 0.127052 +-1.155724 0.777617 0.127052 +-1.234192 0.777488 -0.087021 +-1.234397 0.911133 -0.086336 +-1.235319 0.911392 -0.229143 +-1.235114 0.777746 -0.229828 +-1.388133 0.776762 -0.078673 +-1.389056 0.777020 -0.221479 +-1.389261 0.910665 -0.220795 +-1.388338 0.910407 -0.077988 +1.000043 -0.785071 -0.015780 +1.000043 -0.918718 -0.015780 +1.155723 -0.918718 -0.015780 +1.155723 -0.785071 -0.015780 +1.155723 -0.785071 0.127052 +1.155723 -0.918718 0.127052 +1.000043 -0.918718 0.127052 +1.000043 -0.785071 0.127052 +1.234397 -0.785201 -0.086336 +1.234192 -0.918846 -0.087021 +1.235114 -0.918588 -0.229828 +1.235319 -0.784943 -0.229143 +1.388133 -0.919573 -0.078673 +1.388338 -0.785927 -0.077988 +1.389260 -0.785669 -0.220795 +1.389056 -0.919314 -0.221479 +1.000043 -0.219627 -0.015780 +1.000043 -0.353273 -0.015780 +1.155723 -0.353273 -0.015780 +1.155723 -0.219627 -0.015780 +1.155723 -0.219627 0.127052 +1.155723 -0.353273 0.127052 +1.000043 -0.353273 0.127052 +1.000043 -0.219627 0.127052 +1.234397 -0.219756 -0.086336 +1.234192 -0.353402 -0.087021 +1.235114 -0.353143 -0.229828 +1.235319 -0.219498 -0.229143 +1.388133 -0.354128 -0.078673 +1.388338 -0.220482 -0.077988 +1.389260 -0.220224 -0.220795 +1.389056 -0.353870 -0.221479 +1.000043 0.345818 -0.015780 +1.000043 0.212172 -0.015780 +1.155723 0.212172 -0.015780 +1.155723 0.345818 -0.015780 +1.155723 0.345818 0.127052 +1.155723 0.212172 0.127052 +1.000043 0.212172 0.127052 +1.000043 0.345818 0.127052 +1.234397 0.345689 -0.086336 +1.234192 0.212043 -0.087021 +1.235114 0.212301 -0.229828 +1.235319 0.345947 -0.229143 +1.388133 0.211317 -0.078673 +1.388338 0.344962 -0.077988 +1.389260 0.345221 -0.220795 +1.389056 0.211575 -0.221479 +1.000043 0.911263 -0.015780 +1.000043 0.777616 -0.015780 +1.155723 0.777616 -0.015780 +1.155723 0.911263 -0.015780 +1.155723 0.911263 0.127052 +1.155723 0.777616 0.127052 +1.000043 0.777616 0.127052 +1.000043 0.911263 0.127052 +1.234397 0.911133 -0.086336 +1.234192 0.777488 -0.087021 +1.235114 0.777746 -0.229828 +1.235319 0.911392 -0.229143 +1.388133 0.776762 -0.078673 +1.388338 0.910407 -0.077988 +1.389260 0.910665 -0.220795 +1.389056 0.777020 -0.221479 +4 0 1 2 3 +4 4 3 2 5 +4 5 2 1 6 +4 6 7 4 5 +4 7 0 3 4 +4 6 1 0 7 +4 8 9 10 11 +4 12 13 14 15 +4 13 8 11 14 +4 12 15 16 17 +4 10 9 18 19 +4 20 21 22 23 +4 17 16 20 23 +4 19 18 22 21 +4 24 25 26 27 +4 28 29 30 31 +4 29 24 27 30 +4 28 31 32 33 +4 26 25 34 35 +4 36 37 38 39 +4 33 32 36 39 +4 35 34 38 37 +4 40 41 42 43 +4 44 45 46 47 +4 45 40 43 46 +4 44 47 48 49 +4 42 41 50 51 +4 52 53 54 55 +4 49 48 52 55 +4 51 50 54 53 +4 56 57 58 59 +4 60 61 62 63 +4 61 56 59 62 +4 60 63 64 65 +4 58 57 66 67 +4 68 69 70 71 +4 65 64 68 71 +4 67 66 70 69 +4 72 73 74 75 +4 76 77 78 79 +4 79 78 73 72 +4 76 80 81 77 +4 74 82 83 75 +4 84 85 86 87 +4 80 85 84 81 +4 82 87 86 83 +4 88 89 90 91 +4 92 93 94 95 +4 95 94 89 88 +4 92 96 97 93 +4 90 98 99 91 +4 100 101 102 103 +4 96 101 100 97 +4 98 103 102 99 +4 104 105 106 107 +4 108 109 110 111 +4 111 110 105 104 +4 108 112 113 109 +4 106 114 115 107 +4 116 117 118 119 +4 112 117 116 113 +4 114 119 118 115 +4 120 121 122 123 +4 124 125 126 127 +4 127 126 121 120 +4 124 128 129 125 +4 122 130 131 123 +4 132 133 134 135 +4 128 133 132 129 +4 130 135 134 131 diff --git a/applications/plugins/swd_probe/model/convert.py b/applications/plugins/swd_probe/model/convert.py new file mode 100644 index 000000000..7c99ca215 --- /dev/null +++ b/applications/plugins/swd_probe/model/convert.py @@ -0,0 +1,39 @@ +#!/usr/bin/python + +import plyfile +import argparse + +parser = argparse.ArgumentParser(description='Convert a PLY file to C arrays.') +parser.add_argument('input_file', help='the input PLY file') +parser.add_argument('output_file', help='the output C file') +args = parser.parse_args() + +# Open the PLY file +plydata = plyfile.PlyData.read(args.input_file) + +# Extract the vertices +vertices = plydata['vertex'].data +num_vertices = len(vertices) + +with open(args.output_file, 'w') as f: + f.write('#define NUM_VERTICES %d\n' % num_vertices) + f.write('float vertexCoords[NUM_VERTICES][3] = {\n') + for i in range(num_vertices): + x, y, z = vertices[i][0], vertices[i][1], vertices[i][2] + f.write(' {%f, %f, %f},\n' % (x, y, z)) + f.write('};') + + # Extract the faces + faces = plydata['face'].data + num_faces = len(faces) + f.write('int edgeIndices[][3] = {\n') + for i in range(num_faces): + face = faces[i][0] + if len(face) == 3: + f.write(' {%d, %d, %d},\n' % (face[0], face[1], face[2])) + elif len(face) == 4: + # Convert 4-index face to 2-index edges + edges = [(face[0], face[1]), (face[1], face[2]), (face[2], face[3]), (face[3], face[0])] + for edge in edges: + f.write(' {%d, %d},\n' % (edge[0], edge[1])) + f.write('};\n') diff --git a/applications/plugins/swd_probe/model/model_chip.h b/applications/plugins/swd_probe/model/model_chip.h new file mode 100644 index 000000000..ed96105af --- /dev/null +++ b/applications/plugins/swd_probe/model/model_chip.h @@ -0,0 +1,420 @@ +#define NUM_VERTICES 136 +float vertexCoords[NUM_VERTICES][3] = { + {1.000000, 1.000000, 0.152153}, + {-1.000000, 1.000000, 0.152153}, + {-1.000000, -1.000000, 0.152153}, + {1.000000, -1.000000, 0.152153}, + {1.000000, -1.000000, -0.185787}, + {-1.000000, -1.000000, -0.185787}, + {-1.000000, 1.000000, -0.185787}, + {1.000000, 1.000000, -0.185787}, + {-1.000043, -0.785071, -0.015780}, + {-1.155724, -0.785071, -0.015780}, + {-1.155724, -0.918718, -0.015780}, + {-1.000043, -0.918718, -0.015780}, + {-1.155724, -0.785071, 0.127052}, + {-1.000043, -0.785071, 0.127052}, + {-1.000043, -0.918718, 0.127052}, + {-1.155724, -0.918718, 0.127052}, + {-1.234192, -0.918846, -0.087021}, + {-1.234397, -0.785201, -0.086336}, + {-1.235319, -0.784943, -0.229143}, + {-1.235114, -0.918588, -0.229828}, + {-1.388133, -0.919573, -0.078673}, + {-1.389056, -0.919314, -0.221479}, + {-1.389261, -0.785669, -0.220795}, + {-1.388338, -0.785927, -0.077988}, + {-1.000043, -0.219627, -0.015780}, + {-1.155724, -0.219627, -0.015780}, + {-1.155724, -0.353273, -0.015780}, + {-1.000043, -0.353273, -0.015780}, + {-1.155724, -0.219627, 0.127052}, + {-1.000043, -0.219627, 0.127052}, + {-1.000043, -0.353273, 0.127052}, + {-1.155724, -0.353273, 0.127052}, + {-1.234192, -0.353402, -0.087021}, + {-1.234397, -0.219756, -0.086336}, + {-1.235319, -0.219498, -0.229143}, + {-1.235114, -0.353143, -0.229828}, + {-1.388133, -0.354128, -0.078673}, + {-1.389056, -0.353870, -0.221479}, + {-1.389261, -0.220224, -0.220795}, + {-1.388338, -0.220482, -0.077988}, + {-1.000043, 0.345818, -0.015780}, + {-1.155724, 0.345818, -0.015780}, + {-1.155724, 0.212172, -0.015780}, + {-1.000043, 0.212172, -0.015780}, + {-1.155724, 0.345818, 0.127052}, + {-1.000043, 0.345818, 0.127052}, + {-1.000043, 0.212172, 0.127052}, + {-1.155724, 0.212172, 0.127052}, + {-1.234192, 0.212043, -0.087021}, + {-1.234397, 0.345689, -0.086336}, + {-1.235319, 0.345947, -0.229143}, + {-1.235114, 0.212301, -0.229828}, + {-1.388133, 0.211317, -0.078673}, + {-1.389056, 0.211575, -0.221479}, + {-1.389261, 0.345221, -0.220795}, + {-1.388338, 0.344962, -0.077988}, + {-1.000043, 0.911263, -0.015780}, + {-1.155724, 0.911263, -0.015780}, + {-1.155724, 0.777617, -0.015780}, + {-1.000043, 0.777617, -0.015780}, + {-1.155724, 0.911263, 0.127052}, + {-1.000043, 0.911263, 0.127052}, + {-1.000043, 0.777617, 0.127052}, + {-1.155724, 0.777617, 0.127052}, + {-1.234192, 0.777488, -0.087021}, + {-1.234397, 0.911133, -0.086336}, + {-1.235319, 0.911392, -0.229143}, + {-1.235114, 0.777746, -0.229828}, + {-1.388133, 0.776762, -0.078673}, + {-1.389056, 0.777020, -0.221479}, + {-1.389261, 0.910665, -0.220795}, + {-1.388338, 0.910407, -0.077988}, + {1.000043, -0.785071, -0.015780}, + {1.000043, -0.918718, -0.015780}, + {1.155723, -0.918718, -0.015780}, + {1.155723, -0.785071, -0.015780}, + {1.155723, -0.785071, 0.127052}, + {1.155723, -0.918718, 0.127052}, + {1.000043, -0.918718, 0.127052}, + {1.000043, -0.785071, 0.127052}, + {1.234397, -0.785201, -0.086336}, + {1.234192, -0.918846, -0.087021}, + {1.235114, -0.918588, -0.229828}, + {1.235319, -0.784943, -0.229143}, + {1.388133, -0.919573, -0.078673}, + {1.388338, -0.785927, -0.077988}, + {1.389260, -0.785669, -0.220795}, + {1.389056, -0.919314, -0.221479}, + {1.000043, -0.219627, -0.015780}, + {1.000043, -0.353273, -0.015780}, + {1.155723, -0.353273, -0.015780}, + {1.155723, -0.219627, -0.015780}, + {1.155723, -0.219627, 0.127052}, + {1.155723, -0.353273, 0.127052}, + {1.000043, -0.353273, 0.127052}, + {1.000043, -0.219627, 0.127052}, + {1.234397, -0.219756, -0.086336}, + {1.234192, -0.353402, -0.087021}, + {1.235114, -0.353143, -0.229828}, + {1.235319, -0.219498, -0.229143}, + {1.388133, -0.354128, -0.078673}, + {1.388338, -0.220482, -0.077988}, + {1.389260, -0.220224, -0.220795}, + {1.389056, -0.353870, -0.221479}, + {1.000043, 0.345818, -0.015780}, + {1.000043, 0.212172, -0.015780}, + {1.155723, 0.212172, -0.015780}, + {1.155723, 0.345818, -0.015780}, + {1.155723, 0.345818, 0.127052}, + {1.155723, 0.212172, 0.127052}, + {1.000043, 0.212172, 0.127052}, + {1.000043, 0.345818, 0.127052}, + {1.234397, 0.345689, -0.086336}, + {1.234192, 0.212043, -0.087021}, + {1.235114, 0.212301, -0.229828}, + {1.235319, 0.345947, -0.229143}, + {1.388133, 0.211317, -0.078673}, + {1.388338, 0.344962, -0.077988}, + {1.389260, 0.345221, -0.220795}, + {1.389056, 0.211575, -0.221479}, + {1.000043, 0.911263, -0.015780}, + {1.000043, 0.777616, -0.015780}, + {1.155723, 0.777616, -0.015780}, + {1.155723, 0.911263, -0.015780}, + {1.155723, 0.911263, 0.127052}, + {1.155723, 0.777616, 0.127052}, + {1.000043, 0.777616, 0.127052}, + {1.000043, 0.911263, 0.127052}, + {1.234397, 0.911133, -0.086336}, + {1.234192, 0.777488, -0.087021}, + {1.235114, 0.777746, -0.229828}, + {1.235319, 0.911392, -0.229143}, + {1.388133, 0.776762, -0.078673}, + {1.388338, 0.910407, -0.077988}, + {1.389260, 0.910665, -0.220795}, + {1.389056, 0.777020, -0.221479}, +};int edgeIndices[][3] = { + {0, 1}, + {1, 2}, + {2, 3}, + {3, 0}, + {4, 3}, + {3, 2}, + {2, 5}, + {5, 4}, + {5, 2}, + {2, 1}, + {1, 6}, + {6, 5}, + {6, 7}, + {7, 4}, + {4, 5}, + {5, 6}, + {7, 0}, + {0, 3}, + {3, 4}, + {4, 7}, + {6, 1}, + {1, 0}, + {0, 7}, + {7, 6}, + {8, 9}, + {9, 10}, + {10, 11}, + {11, 8}, + {12, 13}, + {13, 14}, + {14, 15}, + {15, 12}, + {13, 8}, + {8, 11}, + {11, 14}, + {14, 13}, + {12, 15}, + {15, 16}, + {16, 17}, + {17, 12}, + {10, 9}, + {9, 18}, + {18, 19}, + {19, 10}, + {20, 21}, + {21, 22}, + {22, 23}, + {23, 20}, + {17, 16}, + {16, 20}, + {20, 23}, + {23, 17}, + {19, 18}, + {18, 22}, + {22, 21}, + {21, 19}, + {24, 25}, + {25, 26}, + {26, 27}, + {27, 24}, + {28, 29}, + {29, 30}, + {30, 31}, + {31, 28}, + {29, 24}, + {24, 27}, + {27, 30}, + {30, 29}, + {28, 31}, + {31, 32}, + {32, 33}, + {33, 28}, + {26, 25}, + {25, 34}, + {34, 35}, + {35, 26}, + {36, 37}, + {37, 38}, + {38, 39}, + {39, 36}, + {33, 32}, + {32, 36}, + {36, 39}, + {39, 33}, + {35, 34}, + {34, 38}, + {38, 37}, + {37, 35}, + {40, 41}, + {41, 42}, + {42, 43}, + {43, 40}, + {44, 45}, + {45, 46}, + {46, 47}, + {47, 44}, + {45, 40}, + {40, 43}, + {43, 46}, + {46, 45}, + {44, 47}, + {47, 48}, + {48, 49}, + {49, 44}, + {42, 41}, + {41, 50}, + {50, 51}, + {51, 42}, + {52, 53}, + {53, 54}, + {54, 55}, + {55, 52}, + {49, 48}, + {48, 52}, + {52, 55}, + {55, 49}, + {51, 50}, + {50, 54}, + {54, 53}, + {53, 51}, + {56, 57}, + {57, 58}, + {58, 59}, + {59, 56}, + {60, 61}, + {61, 62}, + {62, 63}, + {63, 60}, + {61, 56}, + {56, 59}, + {59, 62}, + {62, 61}, + {60, 63}, + {63, 64}, + {64, 65}, + {65, 60}, + {58, 57}, + {57, 66}, + {66, 67}, + {67, 58}, + {68, 69}, + {69, 70}, + {70, 71}, + {71, 68}, + {65, 64}, + {64, 68}, + {68, 71}, + {71, 65}, + {67, 66}, + {66, 70}, + {70, 69}, + {69, 67}, + {72, 73}, + {73, 74}, + {74, 75}, + {75, 72}, + {76, 77}, + {77, 78}, + {78, 79}, + {79, 76}, + {79, 78}, + {78, 73}, + {73, 72}, + {72, 79}, + {76, 80}, + {80, 81}, + {81, 77}, + {77, 76}, + {74, 82}, + {82, 83}, + {83, 75}, + {75, 74}, + {84, 85}, + {85, 86}, + {86, 87}, + {87, 84}, + {80, 85}, + {85, 84}, + {84, 81}, + {81, 80}, + {82, 87}, + {87, 86}, + {86, 83}, + {83, 82}, + {88, 89}, + {89, 90}, + {90, 91}, + {91, 88}, + {92, 93}, + {93, 94}, + {94, 95}, + {95, 92}, + {95, 94}, + {94, 89}, + {89, 88}, + {88, 95}, + {92, 96}, + {96, 97}, + {97, 93}, + {93, 92}, + {90, 98}, + {98, 99}, + {99, 91}, + {91, 90}, + {100, 101}, + {101, 102}, + {102, 103}, + {103, 100}, + {96, 101}, + {101, 100}, + {100, 97}, + {97, 96}, + {98, 103}, + {103, 102}, + {102, 99}, + {99, 98}, + {104, 105}, + {105, 106}, + {106, 107}, + {107, 104}, + {108, 109}, + {109, 110}, + {110, 111}, + {111, 108}, + {111, 110}, + {110, 105}, + {105, 104}, + {104, 111}, + {108, 112}, + {112, 113}, + {113, 109}, + {109, 108}, + {106, 114}, + {114, 115}, + {115, 107}, + {107, 106}, + {116, 117}, + {117, 118}, + {118, 119}, + {119, 116}, + {112, 117}, + {117, 116}, + {116, 113}, + {113, 112}, + {114, 119}, + {119, 118}, + {118, 115}, + {115, 114}, + {120, 121}, + {121, 122}, + {122, 123}, + {123, 120}, + {124, 125}, + {125, 126}, + {126, 127}, + {127, 124}, + {127, 126}, + {126, 121}, + {121, 120}, + {120, 127}, + {124, 128}, + {128, 129}, + {129, 125}, + {125, 124}, + {122, 130}, + {130, 131}, + {131, 123}, + {123, 122}, + {132, 133}, + {133, 134}, + {134, 135}, + {135, 132}, + {128, 133}, + {133, 132}, + {132, 129}, + {129, 128}, + {130, 135}, + {135, 134}, + {134, 131}, + {131, 130}, +}; diff --git a/applications/plugins/swd_probe/swd_probe_app.c b/applications/plugins/swd_probe/swd_probe_app.c new file mode 100644 index 000000000..0561cbde7 --- /dev/null +++ b/applications/plugins/swd_probe/swd_probe_app.c @@ -0,0 +1,2840 @@ + + +#include "swd_probe_app.h" +#include "swd_probe_icons.h" +#include "jep106.h" +#include "adi.h" + +static void render_callback(Canvas* const canvas, void* cb_ctx); +static bool swd_message_process(AppFSM* ctx); +static uint8_t swd_transfer(AppFSM* const ctx, bool ap, bool write, uint8_t a23, uint32_t* data); +static bool swd_execute_script(AppFSM* const ctx, const char* filename); + +static const GpioPin* gpios[] = { + &gpio_ext_pc0, + &gpio_ext_pc1, + &gpio_ext_pc3, + &gpio_ext_pb2, + &gpio_ext_pb3, + &gpio_ext_pa4, + &gpio_ext_pa6, + &gpio_ext_pa7}; + +static const char* gpio_names[] = {"PC0", "PC1", "PC3", "PB2", "PB3", "PA4", "PA6", "PA7"}; + +/* bit set: clock, else data */ +static const uint8_t gpio_direction_mask[6] = + {0b10101010, 0b01010101, 0b11001100, 0b00110011, 0b11110000, 0b00001111}; + +const NotificationSequence seq_c_minor = { + &message_note_c4, + &message_delay_100, + &message_sound_off, + &message_delay_10, + + &message_note_ds4, + &message_delay_100, + &message_sound_off, + &message_delay_10, + + &message_note_g4, + &message_delay_100, + &message_sound_off, + &message_delay_10, + + &message_vibro_on, + &message_delay_50, + &message_vibro_off, + NULL, +}; + +const NotificationSequence seq_error = { + + &message_vibro_on, + &message_delay_50, + &message_vibro_off, + + &message_note_g4, + &message_delay_100, + &message_sound_off, + &message_delay_10, + + &message_note_c4, + &message_delay_500, + &message_sound_off, + &message_delay_10, + NULL, +}; + +const NotificationSequence* seq_sounds[] = {&seq_c_minor, &seq_error}; + +static bool has_multiple_bits(uint8_t x) { + return (x & (x - 1)) != 0; +} + +static uint8_t get_bit_num(uint8_t x) { + return (uint8_t)__builtin_ctz(x); +} + +static const char* gpio_name(uint8_t mask) { + if(has_multiple_bits(mask)) { + return "Pxx"; + } + uint8_t io = get_bit_num(mask); + if(io >= COUNT(gpio_names)) { + return "Pxx"; + } + + return gpio_names[io]; +} + +static void swd_configure_pins(AppFSM* const ctx, bool output) { + if(ctx->mode_page > ModePageFound && ctx->io_num_swc < 8 && ctx->io_num_swd < 8) { + furi_hal_gpio_init( + gpios[ctx->io_num_swc], GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + if(!output) { + furi_hal_gpio_init( + gpios[ctx->io_num_swd], GpioModeInput, GpioPullUp, GpioSpeedVeryHigh); + } else { + furi_hal_gpio_init( + gpios[ctx->io_num_swd], GpioModeOutputOpenDrain, GpioPullUp, GpioSpeedVeryHigh); + } + return; + } + + for(int io = 0; io < 8; io++) { + uint8_t bitmask = 1 << io; + + /* if neither candidate for SWC nor SWD then skip */ + if(!(ctx->io_swc & bitmask) && !(ctx->io_swd & bitmask)) { + furi_hal_gpio_init(gpios[io], GpioModeInput, GpioPullUp, GpioSpeedVeryHigh); + continue; + } + + if(ctx->current_mask & bitmask) { + /* set for clock */ + furi_hal_gpio_init(gpios[io], GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh); + } else { + /* set for data */ + if(!output) { + furi_hal_gpio_init(gpios[io], GpioModeInput, GpioPullUp, GpioSpeedVeryHigh); + } else { + furi_hal_gpio_init( + gpios[io], GpioModeOutputOpenDrain, GpioPullUp, GpioSpeedVeryHigh); + } + } + } +} + +static void swd_set_clock(AppFSM* const ctx, const uint8_t level) { + if(ctx->mode_page > ModePageFound && ctx->io_num_swc < 8) { + furi_hal_gpio_write(gpios[ctx->io_num_swc], level); + return; + } + + for(int io = 0; io < 8; io++) { + uint8_t bitmask = 1 << io; + + /* if no candidate for SWC then skip */ + if(!(ctx->io_swc & bitmask)) { + continue; + } + + if(ctx->current_mask & bitmask) { + furi_hal_gpio_write(gpios[io], level); + } + } +} + +static void swd_set_data(AppFSM* const ctx, const uint8_t level) { + if(ctx->mode_page > ModePageFound && ctx->io_num_swd < 8) { + furi_hal_gpio_write(gpios[ctx->io_num_swd], level); + return; + } + + for(int io = 0; io < 8; io++) { + uint8_t bitmask = 1 << io; + + /* if no candidate for SWD then skip */ + if(!(ctx->io_swd & bitmask)) { + continue; + } + + if(!(ctx->current_mask & bitmask)) { + furi_hal_gpio_write(gpios[io], level); + } + } +} + +static uint8_t swd_get_data(AppFSM* const ctx) { + if(ctx->mode_page > ModePageFound && ctx->io_num_swd < 8) { + return furi_hal_gpio_read(gpios[ctx->io_num_swd]); + } + + uint8_t bits = 0; + for(int io = 0; io < 8; io++) { + uint8_t bitmask = 1 << io; + + /* if no candidate for SWD then skip */ + if(!(ctx->io_swd & bitmask)) { + continue; + } + bits |= furi_hal_gpio_read(gpios[io]) ? bitmask : 0; + } + return bits; +} + +static void swd_clock_delay(AppFSM* const ctx) { + if(ctx->swd_clock_delay) { + furi_delay_us(ctx->swd_clock_delay); + } +} + +static void swd_write_bit(AppFSM* const ctx, bool level) { + swd_set_clock(ctx, 0); + swd_set_data(ctx, level); + swd_clock_delay(ctx); + swd_set_clock(ctx, 1); + swd_clock_delay(ctx); + swd_set_clock(ctx, 0); +} + +static uint8_t swd_read_bit(AppFSM* const ctx) { + swd_set_clock(ctx, 1); + swd_clock_delay(ctx); + swd_set_clock(ctx, 0); + uint8_t bits = swd_get_data(ctx); + swd_clock_delay(ctx); + swd_set_clock(ctx, 1); + + return bits; +} + +/* send a byte or less LSB-first */ +static void swd_write_byte(AppFSM* const ctx, const uint8_t data, size_t bits) { + for(size_t pos = 0; pos < bits; pos++) { + swd_write_bit(ctx, data & (1 << pos)); + } +} + +/* send a sequence of bytes LSB-first */ +static void swd_write(AppFSM* const ctx, const uint8_t* data, size_t bits) { + size_t byte_pos = 0; + while(bits > 0) { + size_t remain = (bits > 8) ? 8 : bits; + swd_write_byte(ctx, data[byte_pos++], remain); + bits -= remain; + } +} + +static uint8_t swd_transfer(AppFSM* const ctx, bool ap, bool write, uint8_t a23, uint32_t* data) { + //notification_message(ctx->notification, &sequence_set_blue_255); + //notification_message(ctx->notification, &sequence_reset_red); + + swd_set_data(ctx, false); + swd_configure_pins(ctx, true); + + uint32_t idle = 0; + swd_write(ctx, (uint8_t*)&idle, ctx->swd_idle_bits); + + uint8_t request[] = {0}; + + request[0] |= 0x01; /* start bit*/ + request[0] |= ap ? 0x02 : 0; /* APnDP */ + request[0] |= write ? 0 : 0x04; /* operation */ + request[0] |= (a23 & 0x01) ? 0x08 : 0; /* A[2:3] */ + request[0] |= (a23 & 0x02) ? 0x10 : 0; /* A[2:3] */ + request[0] |= 0x80; /* park bit */ + request[0] |= __builtin_parity(request[0]) ? 0x20 : 0; /* parity */ + + swd_write(ctx, request, sizeof(request) * 8); + + /* turnaround cycle */ + swd_configure_pins(ctx, false); + + uint8_t ack = 0; + + /* receive 3 ACK bits */ + for(int pos = 0; pos < 3; pos++) { + ack >>= 1; + ack |= swd_read_bit(ctx) ? 0x04 : 0; + } + + /* force ABORT/CTRL to always work */ + if(!ap && a23 == 0) { + ack = 1; + } + + if(ack != 0x01) { + //notification_message(ctx->notification, &sequence_reset_blue); + //notification_message(ctx->notification, &sequence_set_red_255); + return ack; + } + + if(write) { + swd_write_bit(ctx, 0); + swd_configure_pins(ctx, true); + + /* send 32 WDATA bits */ + for(int pos = 0; pos < 32; pos++) { + swd_write_bit(ctx, *data & (1 << pos)); + } + + /* send parity bit */ + swd_write_bit(ctx, __builtin_parity(*data)); + } else { + *data = 0; + /* receive 32 RDATA bits */ + for(int pos = 0; pos < 32; pos++) { + *data >>= 1; + *data |= swd_read_bit(ctx) ? 0x80000000 : 0; + } + + /* receive parity bit */ + bool parity = swd_read_bit(ctx); + + if(parity != __builtin_parity(*data)) { + //notification_message(ctx->notification, &sequence_reset_blue); + //notification_message(ctx->notification, &sequence_set_red_255); + return 8; + } + } + swd_set_data(ctx, false); + swd_configure_pins(ctx, true); + //notification_message(ctx->notification, &sequence_reset_blue); + + return ack; +} + +/* A line reset is achieved by holding the data signal HIGH for at least 50 clock cycles, followed by at least two idle cycles. */ +static void swd_line_reset(AppFSM* const ctx) { + //notification_message(ctx->notification, &sequence_set_red_255); + for(int bitcount = 0; bitcount < 50; bitcount += 8) { + swd_write_byte(ctx, 0xFF, 8); + } + swd_write_byte(ctx, 0, 8); + ctx->dp_regs.select_ok = false; + //notification_message(ctx->notification, &sequence_reset_red); +} + +static void swd_abort(AppFSM* const ctx) { + uint32_t dpidr; + + /* first reset the line */ + swd_line_reset(ctx); + swd_transfer(ctx, false, false, 0, &dpidr); + uint32_t abort = 0x0E; + swd_transfer(ctx, false, true, 0, &abort); +} + +static void swd_abort_simple(AppFSM* const ctx) { + uint32_t abort = 0x0E; + swd_transfer(ctx, false, true, 0, &abort); + + uint32_t dpidr; + if(swd_transfer(ctx, false, false, 0, &dpidr) != 1) { + swd_abort(ctx); + } +} + +static uint8_t swd_select(AppFSM* const ctx, uint8_t ap_sel, uint8_t ap_bank, uint8_t dp_bank) { + uint32_t bank_reg = (ap_sel << 24) | ((ap_bank & 0x0F) << 4) | (dp_bank & 0x0F); + + if(ctx->dp_regs.select_ok && bank_reg == ctx->dp_regs.select) { + return 1; + } + + uint8_t ret = swd_transfer(ctx, false, true, REG_SELECT, &bank_reg); + if(ret != 1) { + ctx->dp_regs.select_ok = false; + DBG("failed: %d", ret); + return ret; + } + + ctx->dp_regs.select = bank_reg; + ctx->dp_regs.select_ok = true; + return ret; +} + +static uint8_t + swd_read_dpbank(AppFSM* const ctx, uint8_t dp_off, uint8_t dp_bank, uint32_t* data) { + uint8_t ret = 0; + + /* select target bank */ + if(dp_bank < 0x10) { + uint8_t ret = swd_select(ctx, 0, 0, dp_bank); + if(ret != 1) { + DBGS("swd_select failed"); + return ret; + } + } + + /* read data from it */ + *data = 0; + ret = swd_transfer(ctx, false, false, dp_off, data); + if(ret != 1) { + DBG("failed: %d", ret); + return ret; + } + return ret; +} + +static uint8_t + swd_write_dpbank(AppFSM* const ctx, uint8_t dp_off, uint8_t dp_bank, uint32_t* data) { + uint8_t ret = 0; + + /* select target bank */ + if(dp_bank < 0x10) { + ret = swd_select(ctx, 0, 0, dp_bank); + if(ret != 1) { + DBGS("swd_select failed"); + return ret; + } + } + + /* write it */ + ret = swd_transfer(ctx, false, true, dp_off, data); + if(ret != 1) { + DBG("failed: %d", ret); + return ret; + } + return ret; +} + +static uint8_t swd_read_ap(AppFSM* const ctx, uint8_t ap, uint8_t ap_off, uint32_t* data) { + /* select target bank */ + uint8_t ret = swd_select(ctx, ap, (ap_off >> 4) & 0x0F, 0); + if(ret != 1) { + DBGS("swd_select failed"); + return ret; + } + ret = swd_transfer(ctx, true, false, (ap_off >> 2) & 3, data); + *data = 0; + ret = swd_transfer(ctx, true, false, (ap_off >> 2) & 3, data); + if(ret != 1) { + DBG("failed: %d", ret); + return ret; + } + return ret; +} + +static uint8_t swd_read_ap_single(AppFSM* const ctx, uint8_t ap, uint8_t ap_off, uint32_t* data) { + uint8_t ret = swd_select(ctx, ap, (ap_off >> 4) & 0x0F, 0); + if(ret != 1) { + DBGS("swd_select failed"); + return ret; + } + *data = 0; + ret = swd_transfer(ctx, true, false, (ap_off >> 2) & 3, data); + if(ret != 1) { + DBG("failed: %d", ret); + return ret; + } + return ret; +} + +static uint8_t swd_write_ap(AppFSM* const ctx, uint8_t ap, uint8_t ap_off, uint32_t data) { + uint8_t ret = swd_select(ctx, ap, (ap_off >> 4) & 0x0F, 0); + if(ret != 1) { + DBGS("swd_select failed"); + return ret; + } + ret = swd_transfer(ctx, true, true, (ap_off >> 2) & 3, &data); + if(ret != 1) { + DBG("failed: %d", ret); + return ret; + } + return ret; +} + +static uint8_t swd_write_memory(AppFSM* const ctx, uint8_t ap, uint32_t address, uint32_t data) { + uint8_t ret = 0; + uint32_t csw = 0x23000002; + + ret |= swd_write_ap(ctx, ap, MEMAP_CSW, csw); + ret |= swd_write_ap(ctx, ap, MEMAP_TAR, address); + ret |= swd_write_ap(ctx, ap, MEMAP_DRW, data); + DBG("write 0x%08lX to 0x%08lX", data, address); + + if(ret != 1) { + swd_abort(ctx); + } + return ret; +} + +uint8_t swd_read_memory(AppFSM* const ctx, uint8_t ap, uint32_t address, uint32_t* data) { + uint8_t ret = 0; + uint32_t csw = 0x23000002; + + ret |= swd_write_ap(ctx, ap, MEMAP_CSW, csw); + ret |= swd_write_ap(ctx, ap, MEMAP_TAR, address); + ret |= swd_read_ap(ctx, ap, MEMAP_DRW, data); + + if(ret != 1) { + swd_abort(ctx); + } + return ret; +} + +static uint8_t swd_read_memory_block( + AppFSM* const ctx, + uint8_t ap, + uint32_t address, + uint8_t* buf, + uint32_t len) { + uint8_t ret = 0; + uint32_t data = 0; + uint32_t csw = 0x23000012; + + ret |= swd_write_ap(ctx, ap, MEMAP_CSW, csw); + ret |= swd_write_ap(ctx, ap, MEMAP_TAR, address); + ret |= swd_read_ap_single(ctx, ap, MEMAP_DRW, &data); + + for(size_t pos = 0; pos < len; pos += 4) { + data = 0xDEADBEEF; + ret |= swd_read_ap_single(ctx, ap, MEMAP_DRW, &data); + DBG("read %lX", data); + + memcpy(&buf[pos], &data, 4); + + if(ret != 1) { + swd_abort(ctx); + return ret; + } + } + return ret; +} + +static uint32_t swd_detect(AppFSM* const ctx) { + swd_set_data(ctx, false); + swd_configure_pins(ctx, true); + + uint8_t data[] = {0xA5}; + swd_write(ctx, data, sizeof(data) * 8); + + /* turnaround cycle */ + swd_configure_pins(ctx, false); + + uint8_t ack_bits[3]; + uint8_t rdata[32]; + + /* receive 3 ACK bits */ + for(int pos = 0; pos < 3; pos++) { + ack_bits[pos] = swd_read_bit(ctx); + } + + /* receive 32 RDATA bits */ + for(int pos = 0; pos < 32; pos++) { + rdata[pos] = swd_read_bit(ctx); + } + + /* receive parity bit */ + uint8_t parity = swd_read_bit(ctx); + + for(int io = 0; io < 8; io++) { + uint8_t bitmask = 1 << io; + + /* skip if it's a clock */ + if(ctx->current_mask & bitmask) { + continue; + } + + uint8_t ack = 0; + for(int pos = 0; pos < 3; pos++) { + ack >>= 1; + ack |= (ack_bits[pos] & bitmask) ? 4 : 0; + } + + uint32_t dpidr = 0; + for(int pos = 0; pos < 32; pos++) { + dpidr >>= 1; + dpidr |= (rdata[pos] & bitmask) ? 0x80000000 : 0; + } + + if(ack == 1 && dpidr != 0 && dpidr != 0xFFFFFFFF) { + bool received_parity = (parity & bitmask); + if(__builtin_parity(dpidr) == received_parity) { + ctx->dp_regs.dpidr = dpidr; + ctx->dp_regs.dpidr_ok = true; + ctx->detected = true; + ctx->io_swd = bitmask; + ctx->io_swc &= ctx->current_mask; + LOG("swd_detect: data: %08lX, io_swd %02X, io_swc %02X", + dpidr, + ctx->io_swd, + ctx->io_swc); + + if(!has_multiple_bits(ctx->io_swc)) { + ctx->io_num_swd = get_bit_num(ctx->io_swd); + ctx->io_num_swc = get_bit_num(ctx->io_swc); + } + } + } + } + swd_set_data(ctx, false); + swd_configure_pins(ctx, true); + + return 0; +} + +static void swd_scan(AppFSM* const ctx) { + /* To switch SWJ-DP from JTAG to SWD operation: + 1. Send at least 50 SWCLKTCK cycles with SWDIOTMS HIGH. This ensures that the current interface is in its reset state. The JTAG interface only detects the 16-bit JTAG-to-SWD sequence starting from the Test-Logic-Reset state. + 2. Send the 16-bit JTAG-to-SWD select sequence 0x79e7 on SWDIOTMS. + 3. Send at least 50 SWCLKTCK cycles with SWDIOTMS HIGH. This ensures that if SWJ-DP was already in SWD operation before sending the select sequence, the SWD interface enters line reset state. + */ + swd_configure_pins(ctx, true); + + /* reset JTAG interface */ + for(int bitcount = 0; bitcount < 50; bitcount += 8) { + swd_write_byte(ctx, 0xFF, 8); + } + + /* Send the 16-bit JTAG-to-SWD select sequence */ + swd_write_byte(ctx, 0x9E, 8); + swd_write_byte(ctx, 0xE7, 8); + + /* resynchronize SWD */ + swd_line_reset(ctx); + + swd_detect(ctx); +} + +static bool swd_ensure_powerup(AppFSM* const ctx) { + bool ret = true; + + if(!(ctx->dp_regs.ctrlstat & (CSYSPWRUPREQ | CDBGPWRUPREQ))) { + DBGS("no (CSYSPWRUPREQ | CDBGPWRUPREQ)"); + + /* fetch current CTRL/STAT */ + DBGS(" - Fetch CTRL/STAT"); + ctx->dp_regs.ctrlstat_ok = + swd_read_dpbank(ctx, REG_CTRLSTAT, REG_CTRLSTAT_BANK, &ctx->dp_regs.ctrlstat) == 1; + DBG(" %08lX %s", ctx->dp_regs.ctrlstat, ctx->dp_regs.ctrlstat_ok ? "OK" : "FAIL"); + /* enable requests */ + ctx->dp_regs.ctrlstat |= (CSYSPWRUPREQ | CDBGPWRUPREQ); + + swd_write_dpbank(ctx, REG_CTRLSTAT, REG_CTRLSTAT_BANK, &ctx->dp_regs.ctrlstat); + + ret = false; + } + if(!(ctx->dp_regs.ctrlstat & CDBGPWRUPACK)) { + DBGS("no CDBGPWRUPACK"); + /* fetch current CTRL/STAT */ + swd_read_dpbank(ctx, REG_CTRLSTAT, REG_CTRLSTAT_BANK, &ctx->dp_regs.ctrlstat); + ret = false; + } + + if(!ret) { + DBGS(" - Fetch CTRL/STAT"); + ctx->dp_regs.ctrlstat_ok = + swd_read_dpbank(ctx, REG_CTRLSTAT, REG_CTRLSTAT_BANK, &ctx->dp_regs.ctrlstat) == 1; + DBG(" %08lX %s", ctx->dp_regs.ctrlstat, ctx->dp_regs.ctrlstat_ok ? "OK" : "FAIL"); + } + + return ret; +} + +static void swd_apscan_reset(AppFSM* const ctx) { + for(size_t reset_ap = 0; reset_ap < COUNT(ctx->apidr_info); reset_ap++) { + ctx->apidr_info[reset_ap].tested = false; + } +} + +static bool swd_apscan_test(AppFSM* const ctx, uint32_t ap) { + furi_assert(ctx); + furi_assert(ap < sizeof(ctx->apidr_info)); + bool ret = true; + + ctx->apidr_info[ap].tested = true; + + uint32_t data = 0; + if(swd_read_ap(ctx, ap, AP_IDR, &data) != 1) { + swd_abort(ctx); + return false; + } + if(data == 0) { + return false; + } + DBG("AP%lu detected", ap); + ctx->apidr_info[ap].ok = true; + ctx->apidr_info[ap].revision = (data >> 24) & 0x0F; + ctx->apidr_info[ap].designer = (data >> 17) & 0x3FF; + ctx->apidr_info[ap].class = (data >> 13) & 0x0F; + ctx->apidr_info[ap].variant = (data >> 4) & 0x0F; + ctx->apidr_info[ap].type = (data >> 0) & 0x0F; + + if(swd_read_ap(ctx, ap, AP_BASE, &ctx->apidr_info[ap].base) != 1) { + swd_abort(ctx); + ret = false; + } + return ret; +} + +/************************** script helpers **************************/ + +static void swd_script_log(ScriptContext* ctx, FuriLogLevel level, const char* format, ...) { + bool commandline = false; + ScriptContext* cur = ctx; + char buffer[256]; + va_list argp; + va_start(argp, format); + + do { + if(cur == ctx->app->commandline) { + commandline = true; + } + cur = cur->parent; + } while(cur); + + if(commandline) { + const char* prefix = ""; + + switch(level) { + case FuriLogLevelWarn: + prefix = "Warning: "; + break; + case FuriLogLevelError: + prefix = "ERROR: "; + break; + default: + break; + } + + strcpy(buffer, prefix); + size_t pos = strlen(buffer); + vsnprintf(&buffer[pos], sizeof(buffer) - pos - 2, format, argp); + strcat(buffer, "\n"); + usb_uart_tx_data(ctx->app->uart, (uint8_t*)buffer, strlen(buffer)); + } else { + LOG(buffer); + } + va_end(argp); +} + +/* read characters until newline was read */ +static bool swd_script_seek_newline(ScriptContext* ctx) { + while(true) { + uint8_t ch = 0; + + if(ctx->script_file) { + if(storage_file_read(ctx->script_file, &ch, 1) != 1) { + return false; + } + } else { + ch = ctx->line_data[ctx->line_pos]; + if(ch == 0) { + return false; + } + ctx->line_pos++; + } + if(ch == '\n') { + return true; + } + } +} + +/* read whitespaces until the next character is read. + returns false if EOF or newline was read */ +static bool swd_script_skip_whitespace(ScriptContext* ctx) { + while(true) { + uint8_t ch = 0; + uint64_t start_pos = 0; + + if(ctx->script_file) { + start_pos = storage_file_tell(ctx->script_file); + + if(storage_file_read(ctx->script_file, &ch, 1) != 1) { + return false; + } + } else { + start_pos = ctx->line_pos; + ch = ctx->line_data[ctx->line_pos]; + + if(ch == 0) { + return false; + } + ctx->line_pos++; + } + if(ch == '\n') { + return false; + } + if(ch != ' ') { + if(ctx->script_file) { + storage_file_seek(ctx->script_file, start_pos, true); + } else { + ctx->line_pos = start_pos; + } + return true; + } + } +} + +static bool swd_script_get_string(ScriptContext* ctx, char* str, size_t max_length) { + bool quot = false; + size_t pos = 0; + + str[pos] = '\000'; + + while(true) { + char ch = 0; + uint64_t start_pos = 0; + + if(ctx->script_file) { + start_pos = storage_file_tell(ctx->script_file); + + if(storage_file_read(ctx->script_file, &ch, 1) != 1) { + DBGS("end reached"); + return false; + } + } else { + start_pos = ctx->line_pos; + ch = ctx->line_data[ctx->line_pos]; + + if(ch == 0) { + DBGS("end reached"); + return false; + } + ctx->line_pos++; + } + + if(ch == '"') { + quot = !quot; + continue; + } + if(!quot) { + if(ch == ' ') { + break; + } + if(ch == '\r' || ch == '\n') { + if(ctx->script_file) { + storage_file_seek(ctx->script_file, start_pos, true); + } else { + ctx->line_pos = start_pos; + } + break; + } + } + if(pos + 2 > max_length) { + DBGS("too long"); + return false; + } + str[pos++] = ch; + str[pos] = '\000'; + } + DBG("got '%s'", str); + + return true; +} + +static bool swd_script_get_number(ScriptContext* ctx, uint32_t* number) { + char str[16]; + + if(!swd_script_get_string(ctx, str, sizeof(str))) { + DBGS("could not get string"); + return false; + } + DBG("got '%s'", str); + + size_t pos = 0; + *number = 0; + + /* hex number? */ + if(!strncmp(str, "0x", 2)) { + pos += 2; + while(str[pos]) { + uint8_t ch = str[pos++]; + uint8_t ch_num = ch - '0'; + uint8_t ch_hex = (ch & ~0x20) - 'A'; + + *number <<= 4; + + if(ch_num <= 10) { + *number += ch_num; + } else if(ch_hex <= 5) { + *number += 10 + ch_hex; + } else { + return false; + } + } + } else { + while(str[pos]) { + uint8_t ch = str[pos++]; + uint8_t ch_num = ch - '0'; + + *number *= 10; + + if(ch_num < 10) { + *number += ch_num; + } else { + return false; + } + } + } + + return true; +} + +static void swd_script_gui_refresh(ScriptContext* ctx) { + if(furi_message_queue_get_count(ctx->app->event_queue) > 0) { + swd_message_process(ctx->app); + } + if(!ctx->status_ignore) { + DBG("Status: %s", ctx->app->state_string); + view_port_update(ctx->app->view_port); + } +} + +/************************** script functions **************************/ + +static bool swd_scriptfunc_comment(ScriptContext* ctx) { + DBGS("comment"); + + swd_script_seek_newline(ctx); + + return true; +} + +static bool swd_scriptfunc_label(ScriptContext* ctx) { + char label[256]; + DBGS("label"); + + swd_script_skip_whitespace(ctx); + if(!swd_script_get_string(ctx, label, sizeof(label))) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse label"); + return false; + } + + if(!strcmp(label, ctx->goto_label)) { + ctx->goto_active = false; + DBG("matches '%s'", ctx->goto_label); + } + + swd_script_seek_newline(ctx); + + return true; +} + +static bool swd_scriptfunc_goto(ScriptContext* ctx) { + DBGS("goto"); + + swd_script_skip_whitespace(ctx); + + if(!swd_script_get_string(ctx, ctx->goto_label, sizeof(ctx->goto_label))) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse target label"); + return false; + } + + /* start from beginning and rerun starting from label */ + ctx->goto_active = true; + ctx->restart = true; + + swd_script_seek_newline(ctx); + + return true; +} + +static bool swd_scriptfunc_call(ScriptContext* ctx) { + DBGS("call"); + + swd_script_skip_whitespace(ctx); + + /* fetch previous file directory */ + char filename[MAX_FILE_LENGTH]; + strncpy(filename, ctx->filename, sizeof(filename)); + char* path = strrchr(filename, '/'); + path[1] = '\000'; + + /* append filename */ + if(!swd_script_get_string(ctx, &path[1], sizeof(filename) - strlen(path))) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse filename"); + return false; + } + + swd_script_seek_newline(ctx); + + /* append extension */ + if(strlen(filename) + 5 >= sizeof(filename)) { + swd_script_log(ctx, FuriLogLevelError, "name too long"); + return false; + } + + strcat(filename, ".swd"); + + bool ret = swd_execute_script(ctx->app, filename); + + if(!ret) { + swd_script_log(ctx, FuriLogLevelError, "failed to exec '%s'", filename); + return false; + } + + return true; +} + +static bool swd_scriptfunc_status(ScriptContext* ctx) { + uint32_t status = 1; + DBGS("status"); + + swd_script_skip_whitespace(ctx); + swd_script_get_number(ctx, &status); + + ctx->status_ignore = (status == 0); + + swd_script_seek_newline(ctx); + + return true; +} + +static bool swd_scriptfunc_errors(ScriptContext* ctx) { + char type[32]; + DBGS("errors"); + + swd_script_skip_whitespace(ctx); + + if(!swd_script_get_string(ctx, type, sizeof(type))) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse"); + return false; + } + + if(!strcmp(type, "ignore")) { + ctx->errors_ignore = true; + } + if(!strcmp(type, "fail")) { + ctx->errors_ignore = false; + } + swd_script_seek_newline(ctx); + + return true; +} + +static bool swd_scriptfunc_beep(ScriptContext* ctx) { + uint32_t sound = 0; + DBGS("beep"); + + swd_script_skip_whitespace(ctx); + swd_script_get_number(ctx, &sound); + + notification_message_block(ctx->app->notification, seq_sounds[sound]); + + swd_script_seek_newline(ctx); + + return true; +} + +static bool swd_scriptfunc_message(ScriptContext* ctx) { + uint32_t wait_time = 0; + char message[256]; + char type[256]; + bool success = true; + bool show_dialog = false; + + if(!swd_script_skip_whitespace(ctx)) { + swd_script_log(ctx, FuriLogLevelError, "missing whitespace"); + return false; + } + + if(!swd_script_get_number(ctx, &wait_time)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse wait_time"); + return false; + } + + if(!swd_script_get_string(ctx, message, sizeof(message))) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse message"); + return false; + } + + if(swd_script_get_string(ctx, type, sizeof(type))) { + if(!strcmp(type, "dialog")) { + show_dialog = true; + } + } + + if(wait_time <= 60 * 1000) { + strncpy(ctx->app->state_string, message, sizeof(ctx->app->state_string)); + swd_script_gui_refresh(ctx); + furi_delay_ms(wait_time); + if(show_dialog) { + DialogMessage* message = dialog_message_alloc(); + dialog_message_set_header(message, "SWD Probe", 16, 2, AlignLeft, AlignTop); + dialog_message_set_icon(message, &I_app, 3, 2); + dialog_message_set_text(message, ctx->app->state_string, 3, 16, AlignLeft, AlignTop); + dialog_message_set_buttons(message, "Abort", "Ok", NULL); + success = dialog_message_show(ctx->app->dialogs, message) == DialogMessageButtonCenter; + dialog_message_free(message); + } + } + + swd_script_seek_newline(ctx); + + return success; +} + +static bool swd_scriptfunc_swd_idle_bits(ScriptContext* ctx) { + uint32_t swd_idle_bits = 0; + + if(!swd_script_skip_whitespace(ctx)) { + swd_script_log(ctx, FuriLogLevelError, "missing whitespace"); + return false; + } + + if(!swd_script_get_number(ctx, &swd_idle_bits)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse"); + return false; + } + + if(swd_idle_bits <= 32) { + ctx->app->swd_idle_bits = swd_idle_bits; + } else { + swd_script_log(ctx, FuriLogLevelError, "value must be between 1 and 32"); + } + + swd_script_seek_newline(ctx); + + return true; +} + +static bool swd_scriptfunc_swd_clock_delay(ScriptContext* ctx) { + uint32_t swd_clock_delay = 0; + + if(!swd_script_skip_whitespace(ctx)) { + swd_script_log(ctx, FuriLogLevelError, "missing whitespace"); + return false; + } + + if(!swd_script_get_number(ctx, &swd_clock_delay)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse"); + return false; + } + + if(swd_clock_delay <= 1000000) { + ctx->app->swd_clock_delay = swd_clock_delay; + } else { + swd_script_log(ctx, FuriLogLevelError, "value must be between 1 and 1000000"); + } + + swd_script_seek_newline(ctx); + + return true; +} + +static bool swd_scriptfunc_maxtries(ScriptContext* ctx) { + uint32_t max_tries = 0; + + if(!swd_script_skip_whitespace(ctx)) { + swd_script_log(ctx, FuriLogLevelError, "missing whitespace"); + return false; + } + + if(!swd_script_get_number(ctx, &max_tries)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse"); + return false; + } + + if(max_tries >= 1 && max_tries <= 1024) { + ctx->max_tries = max_tries; + } else { + DBGS("value must be between 1 and 1024"); + } + + swd_script_seek_newline(ctx); + + return true; +} + +static bool swd_scriptfunc_blocksize(ScriptContext* ctx) { + uint32_t block_size = 0; + + if(!swd_script_skip_whitespace(ctx)) { + swd_script_log(ctx, FuriLogLevelError, "missing whitespace"); + return false; + } + + if(!swd_script_get_number(ctx, &block_size)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse"); + return false; + } + + if(block_size >= 4 && block_size <= 0x1000) { + ctx->block_size = block_size; + } else { + swd_script_log(ctx, FuriLogLevelError, "value must be between 4 and 4096"); + } + + swd_script_seek_newline(ctx); + + return true; +} + +static bool swd_scriptfunc_apselect(ScriptContext* ctx) { + uint32_t ap = 0; + + if(!swd_script_skip_whitespace(ctx)) { + swd_script_log(ctx, FuriLogLevelError, "missing whitespace"); + return false; + } + + if(!swd_script_get_number(ctx, &ap)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse AP"); + return false; + } + + if(!swd_apscan_test(ctx->app, ap)) { + swd_script_log(ctx, FuriLogLevelError, "no selected AP"); + return false; + } + + ctx->selected_ap = ap; + + swd_script_seek_newline(ctx); + + return true; +} + +static bool swd_scriptfunc_apscan(ScriptContext* ctx) { + DBGS("Scanning APs"); + for(uint32_t ap = 0; ap < 255; ap++) { + snprintf(ctx->app->state_string, sizeof(ctx->app->state_string), "Scan AP %lu", ap); + swd_script_gui_refresh(ctx); + if(swd_apscan_test(ctx->app, ap)) { + DBG(" AP%lu detected", ap); + } + } + swd_script_seek_newline(ctx); + + return true; +} + +static bool swd_scriptfunc_abort(ScriptContext* ctx) { + DBGS("Aborting"); + swd_abort(ctx->app); + swd_script_seek_newline(ctx); + + return true; +} + +static bool swd_scriptfunc_mem_dump(ScriptContext* ctx) { + char filename[MAX_FILE_LENGTH]; + uint32_t address = 0; + uint32_t length = 0; + uint32_t flags = 0; + bool success = true; + + /* get file */ + if(!swd_script_skip_whitespace(ctx)) { + swd_script_log(ctx, FuriLogLevelError, "missing whitespace"); + return false; + } + + if(!swd_script_get_string(ctx, filename, sizeof(filename))) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse filename"); + return false; + } + /* get address */ + if(!swd_script_get_number(ctx, &address)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse address"); + return false; + } + + /* get length */ + if(!swd_script_get_number(ctx, &length)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse length"); + return false; + } + + /* get flags */ + if(swd_script_get_number(ctx, &flags)) { + DBGS("found extra flags"); + } + + LOG("would dump %08lX, len %08lX into %s", address, length, filename); + + File* dump = storage_file_alloc(ctx->app->storage); + + if(!storage_file_open(dump, filename, FSAM_WRITE, FSOM_CREATE_ALWAYS)) { + storage_file_free(dump); + snprintf(ctx->app->state_string, sizeof(ctx->app->state_string), "Failed to create file"); + swd_script_gui_refresh(ctx); + notification_message_block(ctx->app->notification, &seq_error); + return false; + } + + if(ctx->block_size == 0) { + ctx->block_size = 0x100; + } + if(ctx->block_size > 0x1000) { + ctx->block_size = 0x1000; + } + + uint8_t* buffer = malloc(ctx->block_size); + + furi_mutex_acquire(ctx->app->swd_mutex, FuriWaitForever); + + for(uint32_t pos = 0; pos < length; pos += ctx->block_size) { + if((pos & 0xFF) == 0) { + int pct = pos * 100 / length; + snprintf( + ctx->app->state_string, + sizeof(ctx->app->state_string), + "Dump %08lX (%d%%)", + pos, + pct); + swd_script_gui_refresh(ctx); + } + + bool read_ok = false; + + for(uint32_t tries = 0; tries < ctx->max_tries; tries++) { + if(ctx->abort) { + DBGS("aborting read"); + break; + } + uint32_t ret = 0; + + if(ctx->block_size > 4) { + ret = swd_read_memory_block( + ctx->app, ctx->selected_ap, address + pos, buffer, ctx->block_size); + } else { + ret = + swd_read_memory(ctx->app, ctx->selected_ap, address + pos, (uint32_t*)buffer); + } + read_ok = (ret == 1); + + if(!read_ok) { + snprintf( + ctx->app->state_string, + sizeof(ctx->app->state_string), + "Failed at 0x%08lX", + address + pos); + swd_script_gui_refresh(ctx); + furi_delay_ms(100); + } else { + break; + } + } + if(ctx->abort) { + DBGS("aborting"); + break; + } + + if(!read_ok) { + /* flags == 1: "continue reading even if it fails" */ + /* flags == 2: "its okay if cannot dump fully" */ + if(flags & 1) { + /* set all content to a known value as indication */ + for(size_t fill_pos = 0; fill_pos < ctx->block_size; fill_pos += 4) { + *((uint32_t*)&buffer[fill_pos]) = 0xDEADFACE; + } + } else if(flags & 2) { + success = (pos > 0); + break; + } else { + notification_message_block(ctx->app->notification, &seq_error); + success = false; + break; + } + } + storage_file_write(dump, buffer, ctx->block_size); + } + + furi_mutex_release(ctx->app->swd_mutex); + + storage_file_close(dump); + swd_script_seek_newline(ctx); + free(buffer); + + return success; +} + +static bool swd_scriptfunc_mem_write(ScriptContext* ctx) { + uint32_t address = 0; + uint32_t data = 0; + bool success = true; + + /* get file */ + if(!swd_script_skip_whitespace(ctx)) { + swd_script_log(ctx, FuriLogLevelError, "missing whitespace"); + return false; + } + + /* get address */ + if(!swd_script_get_number(ctx, &address)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse address"); + return false; + } + + /* get data */ + if(!swd_script_get_number(ctx, &data)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse data"); + return false; + } + + DBG("write %08lX to %08lX", data, address); + + bool access_ok = false; + for(uint32_t tries = 0; tries < ctx->max_tries; tries++) { + if(ctx->abort) { + DBGS("aborting"); + break; + } + + furi_mutex_acquire(ctx->app->swd_mutex, FuriWaitForever); + access_ok = swd_write_memory(ctx->app, ctx->selected_ap, address, data) == 1; + furi_mutex_release(ctx->app->swd_mutex); + access_ok |= ctx->errors_ignore; + swd_read_memory(ctx->app, ctx->selected_ap, address, &data); + DBG("read %08lX from %08lX", data, address); + + if(!access_ok) { + snprintf( + ctx->app->state_string, + sizeof(ctx->app->state_string), + "Failed write 0x%08lX", + address); + swd_script_gui_refresh(ctx); + } else { + break; + } + } + + if(!access_ok) { + notification_message_block(ctx->app->notification, &seq_error); + success = false; + } + + swd_script_seek_newline(ctx); + + return success; +} + +static bool swd_scriptfunc_mem_ldmst(ScriptContext* ctx) { + uint32_t address = 0; + uint32_t data = 0; + uint32_t mask = 0; + bool success = true; + + if(!swd_script_skip_whitespace(ctx)) { + swd_script_log(ctx, FuriLogLevelError, "missing whitespace"); + return false; + } + + /* get address */ + if(!swd_script_get_number(ctx, &address)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse address"); + return false; + } + + /* get data */ + if(!swd_script_get_number(ctx, &data)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse data"); + return false; + } + + /* get mask */ + if(!swd_script_get_number(ctx, &mask)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse mask"); + return false; + } + + LOG("write %08lX to %08lX, mask %08lX", data, address, mask); + + bool access_ok = false; + uint32_t modified = 0; + for(uint32_t tries = 0; tries < ctx->max_tries; tries++) { + if(ctx->abort) { + DBGS("aborting"); + break; + } + furi_mutex_acquire(ctx->app->swd_mutex, FuriWaitForever); + + access_ok = swd_read_memory(ctx->app, ctx->selected_ap, address, &modified) == 1; + modified = (modified & mask) | data; + access_ok &= swd_write_memory(ctx->app, ctx->selected_ap, address, modified) == 1; + + furi_mutex_release(ctx->app->swd_mutex); + access_ok |= ctx->errors_ignore; + + if(!access_ok) { + snprintf( + ctx->app->state_string, + sizeof(ctx->app->state_string), + "Failed access 0x%08lX", + address); + swd_script_gui_refresh(ctx); + } else { + break; + } + } + + if(!access_ok) { + notification_message_block(ctx->app->notification, &seq_error); + success = false; + } + + swd_script_seek_newline(ctx); + + return success; +} + +static bool swd_scriptfunc_dp_write(ScriptContext* ctx) { + uint32_t dp_bank = 0; + uint32_t dp_off = 0; + uint32_t data = 0; + bool success = true; + + if(!swd_script_skip_whitespace(ctx)) { + swd_script_log(ctx, FuriLogLevelError, "missing whitespace"); + return false; + } + + /* get data */ + if(!swd_script_get_number(ctx, &data)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse data"); + return false; + } + + /* get dp_off */ + if(!swd_script_get_number(ctx, &dp_off)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse DP offset"); + return false; + } + + /* get dp_bank */ + if(!swd_script_get_number(ctx, &dp_bank)) { + dp_bank = 0xFF; + } + + swd_script_log( + ctx, FuriLogLevelDefault, "write %08lX to reg %08lX / bank %08lX", data, dp_off, dp_bank); + + furi_mutex_acquire(ctx->app->swd_mutex, FuriWaitForever); + + uint8_t ret = swd_write_dpbank(ctx->app, dp_off, dp_bank, &data); + if(ret != 1) { + swd_script_log(ctx, FuriLogLevelError, "swd_write_dpbank failed"); + success = false; + } + + furi_mutex_release(ctx->app->swd_mutex); + + swd_script_seek_newline(ctx); + + return success; +} + +static bool swd_scriptfunc_dp_read(ScriptContext* ctx) { + uint32_t dp_bank = 0; + uint32_t dp_off = 0; + uint32_t data = 0; + bool success = true; + + if(!swd_script_skip_whitespace(ctx)) { + swd_script_log(ctx, FuriLogLevelError, "missing whitespace"); + return false; + } + + /* get dp_off */ + if(!swd_script_get_number(ctx, &dp_off)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse DP offset"); + return false; + } + + /* get dp_bank */ + if(!swd_script_get_number(ctx, &dp_bank)) { + dp_bank = 0xFF; + } + + swd_script_log(ctx, FuriLogLevelDefault, "read reg %02lX / bank %02lX", dp_off, dp_bank); + + furi_mutex_acquire(ctx->app->swd_mutex, FuriWaitForever); + + uint8_t ret = swd_read_dpbank(ctx->app, dp_off, dp_bank, &data); + if(ret != 1) { + swd_script_log(ctx, FuriLogLevelError, "swd_read_dpbank failed"); + success = false; + } else { + swd_script_log(ctx, FuriLogLevelDefault, "result: 0x%08lX", data); + } + furi_mutex_release(ctx->app->swd_mutex); + + swd_script_seek_newline(ctx); + + return success; +} + +static bool swd_scriptfunc_ap_write(ScriptContext* ctx) { + uint32_t ap_reg = 0; + uint32_t data = 0; + bool success = true; + + if(!swd_script_skip_whitespace(ctx)) { + swd_script_log(ctx, FuriLogLevelError, "missing whitespace"); + return false; + } + + /* get data */ + if(!swd_script_get_number(ctx, &data)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse data"); + return false; + } + + /* get ap_reg */ + if(!swd_script_get_number(ctx, &ap_reg)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse AP register"); + return false; + } + + swd_script_log( + ctx, FuriLogLevelDefault, "AP%d %08lX -> %02lX", ctx->selected_ap, data, ap_reg); + + furi_mutex_acquire(ctx->app->swd_mutex, FuriWaitForever); + + uint8_t ret = swd_write_ap(ctx->app, ctx->selected_ap, ap_reg, data); + if(ret != 1) { + swd_script_log(ctx, FuriLogLevelError, "swd_write_ap failed"); + success = false; + } + furi_mutex_release(ctx->app->swd_mutex); + + swd_script_seek_newline(ctx); + + return success; +} + +static bool swd_scriptfunc_ap_read(ScriptContext* ctx) { + uint32_t ap_reg = 0; + uint32_t data = 0; + bool success = true; + + if(!swd_script_skip_whitespace(ctx)) { + swd_script_log(ctx, FuriLogLevelError, "missing whitespace"); + return false; + } + + /* get ap_reg */ + if(!swd_script_get_number(ctx, &ap_reg)) { + swd_script_log(ctx, FuriLogLevelError, "failed to parse AP register"); + return false; + } + + furi_mutex_acquire(ctx->app->swd_mutex, FuriWaitForever); + + uint8_t ret = swd_read_ap(ctx->app, ctx->selected_ap, ap_reg, &data); + if(ret != 1) { + swd_script_log(ctx, FuriLogLevelError, "swd_read_ap failed"); + success = false; + } else { + swd_script_log( + ctx, FuriLogLevelDefault, "AP%d %02lX: %08lX", ctx->selected_ap, ap_reg, data); + } + furi_mutex_release(ctx->app->swd_mutex); + + swd_script_seek_newline(ctx); + + return success; +} + +static const ScriptFunctionInfo script_funcs[] = { + {"#", &swd_scriptfunc_comment}, + {".label", &swd_scriptfunc_label}, + {"goto", &swd_scriptfunc_goto}, + {"call", &swd_scriptfunc_call}, + {"status", &swd_scriptfunc_status}, + {"errors", &swd_scriptfunc_errors}, + {"message", &swd_scriptfunc_message}, + {"beep", &swd_scriptfunc_beep}, + {"max_tries", &swd_scriptfunc_maxtries}, + {"swd_clock_delay", &swd_scriptfunc_swd_clock_delay}, + {"swd_idle_bits", &swd_scriptfunc_swd_idle_bits}, + {"block_size", &swd_scriptfunc_blocksize}, + {"abort", &swd_scriptfunc_abort}, + {"mem_dump", &swd_scriptfunc_mem_dump}, + {"mem_ldmst", &swd_scriptfunc_mem_ldmst}, + {"mem_write", &swd_scriptfunc_mem_write}, + {"dp_write", &swd_scriptfunc_dp_write}, + {"dp_read", &swd_scriptfunc_dp_read}, + {"ap_scan", &swd_scriptfunc_apscan}, + {"ap_select", &swd_scriptfunc_apselect}, + {"ap_read", &swd_scriptfunc_ap_read}, + {"ap_write", &swd_scriptfunc_ap_write}}; + +/************************** script main code **************************/ + +static bool swd_execute_script_line(ScriptContext* const ctx) { + char buffer[64]; + uint64_t start_pos = 0; + + if(ctx->script_file) { + start_pos = storage_file_tell(ctx->script_file); + uint16_t ret = storage_file_read(ctx->script_file, buffer, 2); + storage_file_seek(ctx->script_file, start_pos, true); + + if(ret < 2) { + return true; + } + } else { + start_pos = ctx->line_pos; + strncpy(buffer, ctx->line_data, 2); + + if(buffer[0] == 0 || buffer[1] == 0) { + return true; + } + } + + if(buffer[0] == '\n' || (buffer[0] == '\r' && buffer[1] == '\n')) { + swd_script_seek_newline(ctx); + return true; + } + + for(size_t entry = 0; entry < COUNT(script_funcs); entry++) { + if(ctx->abort) { + DBGS("aborting"); + break; + } + size_t expected = strlen(script_funcs[entry].prefix); + + if(ctx->script_file) { + storage_file_seek(ctx->script_file, start_pos, true); + + if(storage_file_read(ctx->script_file, buffer, expected) != expected) { + continue; + } + } else { + ctx->line_pos = start_pos; + + if(strlen(ctx->line_data) < expected) { + continue; + } + strncpy(buffer, ctx->line_data, expected); + ctx->line_pos += expected; + } + + buffer[expected] = '\000'; + if(strncmp(buffer, script_funcs[entry].prefix, expected)) { + continue; + } + bool success = true; + + if(ctx->goto_active) { + DBG("ignore: '%s'", script_funcs[entry].prefix); + + /* only execute label handlers */ + if(buffer[0] == '.') { + success = script_funcs[entry].func(ctx); + } else { + swd_script_seek_newline(ctx); + } + } else { + DBG("command: '%s'", script_funcs[entry].prefix); + + if(!ctx->status_ignore) { + snprintf( + ctx->app->state_string, + sizeof(ctx->app->state_string), + "CMD: %s", + script_funcs[entry].prefix); + } + swd_script_gui_refresh(ctx); + + /* function, execute */ + success = script_funcs[entry].func(ctx); + + if(!success && !ctx->errors_ignore) { + swd_script_log( + ctx, FuriLogLevelError, "Command failed: %s", script_funcs[entry].prefix); + snprintf( + ctx->app->state_string, + sizeof(ctx->app->state_string), + "Command failed: %s", + script_funcs[entry].prefix); + return false; + } + } + + return true; + } + swd_script_log(ctx, FuriLogLevelError, "unknown command '%s'", buffer); + + return false; +} + +static bool swd_execute_script(AppFSM* const ctx, const char* filename) { + bool success = true; + + /* fetch current script and set as parent */ + ScriptContext* parent = ctx->script; + + ctx->script = malloc(sizeof(ScriptContext)); + ctx->script->app = ctx; + ctx->script->max_tries = 1; + ctx->script->parent = parent; + strcpy(ctx->script->filename, filename); + + if(!storage_file_exists(ctx->storage, filename)) { + DBG("Does not exist '%s'", filename); + parent = ctx->script->parent; + free(ctx->script); + ctx->script = parent; + return false; + } + + /* first allocate a file object */ + ctx->script->script_file = storage_file_alloc(ctx->storage); + + /* then get our script opened */ + if(!storage_file_open(ctx->script->script_file, filename, FSAM_READ, FSOM_OPEN_EXISTING)) { + FURI_LOG_E(TAG, "open, %s", storage_file_get_error_desc(ctx->script->script_file)); + DBG("Failed to open '%s'", filename); + storage_file_free(ctx->script->script_file); + parent = ctx->script->parent; + free(ctx->script); + ctx->script = parent; + return false; + } + + do { + success = true; + ctx->script->restart = false; + + storage_file_seek(ctx->script->script_file, 0, true); + + uint32_t line = 1; + while(line < SCRIPT_MAX_LINES) { + if(ctx->script->abort) { + DBGS("Abort requested"); + break; + } + if(storage_file_eof(ctx->script->script_file)) { + break; + } + DBG("line %lu", line); + if(!swd_execute_script_line(ctx->script)) { + success = false; + break; + } + if(ctx->script->restart) { + break; + } + line++; + } + + if(ctx->script->restart) { + DBGS("Restarting"); + } else { + DBGS("Finished"); + } + + if(line >= SCRIPT_MAX_LINES) { + success = true; + char text_buf[128]; + + snprintf(text_buf, sizeof(text_buf), "aborting after %d lines", SCRIPT_MAX_LINES); + DialogMessage* message = dialog_message_alloc(); + dialog_message_set_header(message, "SWD Probe", 16, 2, AlignLeft, AlignTop); + dialog_message_set_icon(message, &I_app, 3, 2); + dialog_message_set_text(message, text_buf, 3, 16, AlignLeft, AlignTop); + dialog_message_set_buttons(message, "Back", NULL, NULL); + dialog_message_free(message); + + ctx->script->restart = false; + } + + if(!success) { + char text_buf[128]; + + snprintf(text_buf, sizeof(text_buf), "Line %lu failed:\n%s", line, ctx->state_string); + DialogMessage* message = dialog_message_alloc(); + dialog_message_set_header(message, "SWD Probe", 16, 2, AlignLeft, AlignTop); + dialog_message_set_icon(message, &I_app, 3, 2); + dialog_message_set_text(message, text_buf, 3, 16, AlignLeft, AlignTop); + dialog_message_set_buttons(message, "Back", "Retry", NULL); + if(dialog_message_show(ctx->dialogs, message) == DialogMessageButtonCenter) { + ctx->script->restart = true; + } + dialog_message_free(message); + } + } while(ctx->script->restart); + + storage_file_close(ctx->script->script_file); + storage_file_free(ctx->script->script_file); + + parent = ctx->script->parent; + free(ctx->script); + ctx->script = parent; + + return success; +} + +/************************** UI functions **************************/ + +#define CANVAS_WIDTH 128 +#define CANVAS_HEIGHT 64 + +#define COERCE(d, min, max) \ + do { \ + if(d < (min)) { \ + d = (min); \ + } \ + if(d > (max)) { \ + d = (max); \ + } \ + } while(0) + +#define COERCE_COORDS(x1, y1, x2, y2) \ + do { \ + COERCE(x1, 0, CANVAS_WIDTH); \ + COERCE(x2, 0, CANVAS_WIDTH); \ + COERCE(y1, 0, CANVAS_HEIGHT); \ + COERCE(y1, 0, CANVAS_HEIGHT); \ + } while(0) + +#include "model/model_chip.h" + +static int rotatedVertexCoords[NUM_VERTICES][3]; + +static void draw_model(Canvas* const canvas) { + static float xAngle = 0; + static float yAngle = 0; + static float zAngle = 0; + static float zoom = 0; + static float speed = 0.6f; + + float cosXAngle = cosf(xAngle); + float sinXAngle = sinf(xAngle); + float cosYAngle = cosf(yAngle); + float sinYAngle = sinf(yAngle); + float cosZAngle = cosf(zAngle); + float sinZAngle = sinf(zAngle); + float sinZoom = 1.2f + sinf(zoom) * 0.25f; + + int centerX = CANVAS_WIDTH / 2; + int centerY = CANVAS_HEIGHT / 2 + 5; + + for(int i = 0; i < NUM_VERTICES; i++) { + int x = vertexCoords[i][0] * sinZoom * 16; + int y = vertexCoords[i][1] * sinZoom * 16; + int z = vertexCoords[i][2] * sinZoom * 16; + + int y1 = y * cosXAngle - z * sinXAngle; + int z1 = y * sinXAngle + z * cosXAngle; + + int x2 = x * cosYAngle + z1 * sinYAngle; + int z2 = -x * sinYAngle + z1 * cosYAngle; + + int x3 = x2 * cosZAngle - y1 * sinZAngle; + int y3 = x2 * sinZAngle + y1 * cosZAngle; + + rotatedVertexCoords[i][0] = x3 + centerX; + rotatedVertexCoords[i][1] = y3 + centerY; + rotatedVertexCoords[i][2] = z2; + } + + for(size_t i = 0; i < COUNT(edgeIndices); i++) { + int v1Index = edgeIndices[i][0]; + int v2Index = edgeIndices[i][1]; + int x1 = rotatedVertexCoords[v1Index][0]; + int y1 = rotatedVertexCoords[v1Index][1]; + int x2 = rotatedVertexCoords[v2Index][0]; + int y2 = rotatedVertexCoords[v2Index][1]; + + COERCE_COORDS(x1, y1, x2, y2); + canvas_draw_line(canvas, x1, y1, x2, y2); + } + + xAngle += speed * 0.02 / sinZoom; + yAngle += speed * 0.023 / sinZoom; + zAngle += speed * 0.029 * sinZoom; + zoom += speed * 0.005; +} + +static void render_callback(Canvas* const canvas, void* ctx_in) { + furi_assert(canvas); + furi_assert(ctx_in); + + AppFSM* ctx = ctx_in; + furi_mutex_acquire(ctx->gui_mutex, FuriWaitForever); + + char buffer[64]; + int y = 10; + + canvas_draw_frame(canvas, 0, 0, 128, 64); + canvas_set_font(canvas, FontPrimary); + + if(!ctx->detected_device) { + ctx->mode_page = ModePageScan; + } else if(ctx->mode_page == ModePageScan) { + ctx->mode_page = ModePageFound; + } + + /* if seen less than a quarter second ago */ + switch(ctx->mode_page) { + case ModePageScan: { + draw_model(canvas); + + canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, "Searching"); + y += 14; + + canvas_set_font(canvas, FontSecondary); + + bool info_page = (ctx->loop_count % 500) >= 250; + if(info_page) { + canvas_draw_str(canvas, 2, y, "Connect GND with target GND"); + y += 10; + canvas_draw_str(canvas, 2, y, "and any two GPIOs with pads"); + y += 10; + canvas_draw_str(canvas, 2, y, "you want to check for SWD"); + + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 111, 62, "2/2"); + } else { + const char* filename = ""; + if(strlen(ctx->script_detected) > 0) { + const char* slash = strrchr(ctx->script_detected, '/'); + if(slash) { + filename = &slash[1]; + } else { + filename = ctx->script_detected; + } + } + + canvas_set_font(canvas, FontSecondary); + canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, "Autoexec Script"); + y += 10; + canvas_set_font(canvas, FontKeyboard); + canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, filename); + y += 16; + + canvas_set_font(canvas, FontSecondary); + canvas_draw_icon(canvas, 14, y - 5, &I_ButtonUp_7x4); + canvas_draw_icon(canvas, 78, y - 5, &I_ButtonDown_7x4); + canvas_draw_str(canvas, 23, y, "Clear"); + canvas_draw_str(canvas, 87, y, "Choose"); + + canvas_set_font(canvas, FontPrimary); + canvas_draw_str(canvas, 111, 62, "1/2"); + } + canvas_set_font(canvas, FontSecondary); + elements_button_left(canvas, "Script"); + break; + } + case ModePageFound: { + if((ctx->detected_timeout + TIMER_HZ / 4) >= TIMER_HZ * TIMEOUT) { + snprintf(buffer, sizeof(buffer), "FOUND!"); + } else { + /* if it was seen more than a quarter second ago, show countdown */ + snprintf( + buffer, sizeof(buffer), "FOUND! (%lus)", (ctx->detected_timeout / TIMER_HZ) + 1); + } + canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, buffer); + y += 10; + canvas_set_font(canvas, FontKeyboard); + + snprintf( + buffer, + sizeof(buffer), + "SWC/SWD: %s/%s", + gpio_name(ctx->io_swc), + gpio_name(ctx->io_swd)); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + y += 10; + snprintf(buffer, sizeof(buffer), "DPIDR 0x%08lX", ctx->dp_regs.dpidr); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + y += 10; + + snprintf( + buffer, + sizeof(buffer), + "Part %02X Rev %X DAPv%d", + ctx->dpidr_info.partno, + ctx->dpidr_info.revision, + ctx->dpidr_info.version); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + y += 10; + + canvas_set_font(canvas, FontSecondary); + snprintf(buffer, sizeof(buffer), "%s", jep106_manufacturer(ctx->dpidr_info.designer)); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + y += 10; + + canvas_set_font(canvas, FontSecondary); + elements_button_left(canvas, "Script"); + elements_button_right(canvas, "DP Regs"); + + break; + } + case ModePageDPRegs: { + canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, "DP Registers"); + y += 10; + canvas_set_font(canvas, FontKeyboard); + if(ctx->dp_regs.dpidr_ok) { + snprintf(buffer, sizeof(buffer), "DPIDR %08lX", ctx->dp_regs.dpidr); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + } + y += 10; + + if(ctx->dp_regs.ctrlstat_ok) { + snprintf(buffer, sizeof(buffer), "CTRL %08lX", ctx->dp_regs.ctrlstat); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + } + y += 10; + + if(ctx->dp_regs.targetid_ok) { + snprintf(buffer, sizeof(buffer), "TGTID %08lX", ctx->dp_regs.targetid); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + } + y += 10; + + if(ctx->dp_regs.eventstat_ok) { + snprintf(buffer, sizeof(buffer), "EVTST %08lX", ctx->dp_regs.eventstat); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + } + y += 10; + canvas_set_font(canvas, FontSecondary); + elements_button_left(canvas, "Scan"); + elements_button_right(canvas, "DPID"); + + break; + } + + case ModePageDPID: { + canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, "DP ID Register"); + y += 10; + canvas_set_font(canvas, FontKeyboard); + if(ctx->dpidr_info.version != 2) { + snprintf(buffer, sizeof(buffer), "TARGETID not supported"); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + y += 10; + } else { + if(ctx->dp_regs.targetid_ok) { + snprintf(buffer, sizeof(buffer), "TGTID %08lX", ctx->dp_regs.targetid); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + y += 10; + + snprintf(buffer, sizeof(buffer), "Part No. %04X", ctx->targetid_info.partno); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + y += 10; + snprintf( + buffer, sizeof(buffer), "%s", jep106_manufacturer(ctx->targetid_info.designer)); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + y += 10; + } + } + canvas_set_font(canvas, FontSecondary); + elements_button_left(canvas, "DP Regs"); + elements_button_right(canvas, "APs"); + break; + } + + case ModePageAPID: { + canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, "AP Menu"); + y += 10; + canvas_set_font(canvas, FontKeyboard); + + char state = ' '; + if(ctx->ap_pos >= ctx->ap_scanned && ctx->ap_pos <= ctx->ap_scanned + 10) { + state = '*'; + } + + if(!ctx->apidr_info[ctx->ap_pos].ok) { + snprintf(buffer, sizeof(buffer), "[%d]%c", ctx->ap_pos, state); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + y += 10; + + if(ctx->ap_pos == 0) { + for(size_t pos = 0; pos < COUNT(ctx->apidr_info); pos++) { + if(ctx->apidr_info[pos].ok) { + ctx->ap_pos = pos; + } + } + } + } else { + const char* class = ""; + + switch(ctx->apidr_info[ctx->ap_pos].class) { + case 0: + class = "und"; + break; + case 1: + class = "COM"; + break; + case 8: + class = "MEM"; + break; + default: + class = "unk"; + break; + } + + const char* types[] = { + "COM-AP", + "AHB3", + "APB2 or APB3", + "Type unknown", + "AXI3 or AXI4", + "AHB5", + "APB4 and APB5", + "AXI5", + "AHB5 enh.", + }; + const char* type = "Type unk"; + + if(ctx->apidr_info[ctx->ap_pos].type < COUNT(types)) { + type = types[ctx->apidr_info[ctx->ap_pos].type]; + } + + snprintf(buffer, sizeof(buffer), "[%d]%c%s, %s", ctx->ap_pos, state, class, type); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + y += 10; + + snprintf(buffer, sizeof(buffer), "Base 0x%08lX", ctx->apidr_info[ctx->ap_pos].base); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + y += 10; + + snprintf( + buffer, + sizeof(buffer), + "Rev %d Var %d", + ctx->apidr_info[ctx->ap_pos].revision, + ctx->apidr_info[ctx->ap_pos].variant); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + y += 10; + + snprintf( + buffer, + sizeof(buffer), + "%s", + jep106_manufacturer(ctx->apidr_info[ctx->ap_pos].designer)); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + y += 10; + + elements_button_center(canvas, "Show"); + } + canvas_set_font(canvas, FontSecondary); + elements_button_left(canvas, "DPID"); + elements_button_right(canvas, "CoreS."); + elements_scrollbar_pos(canvas, 4, 10, 40, ctx->ap_pos / 32, COUNT(ctx->apidr_info) / 32); + break; + } + + /* hex dump view */ + case ModePageHexDump: { + canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, "Hex dump"); + y += 10; + canvas_set_font(canvas, FontKeyboard); + + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, "Addr:"); + + snprintf(buffer, sizeof(buffer), "%08lX", ctx->hex_addr); + canvas_draw_str_aligned(canvas, 38, y, AlignLeft, AlignBottom, buffer); + uint32_t font_width = canvas_glyph_width(canvas, '0'); + uint32_t x = 37 + (7 - ctx->hex_select) * font_width; + + /* draw selection */ + canvas_draw_line(canvas, x, y + 1, x + font_width, y + 1); + y += 10; + + uint32_t byte_num = 0; + for(int line = 0; line < 4; line++) { + uint32_t x_pos = 5; + + for(int byte_pos = 0; byte_pos < 8; byte_pos++) { + if(ctx->hex_buffer_valid[byte_num / 4]) { + snprintf(buffer, sizeof(buffer), "%02X", ctx->hex_buffer[byte_num]); + } else { + snprintf(buffer, sizeof(buffer), "--"); + } + byte_num++; + canvas_draw_str_aligned(canvas, x_pos, y, AlignLeft, AlignBottom, buffer); + x_pos += font_width * 2 + font_width / 2; + } + y += 10; + } + break; + } + + case ModePageCoresight: { + canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, "Coresight"); + y += 10; + canvas_set_font(canvas, FontSecondary); + + uint32_t base = ctx->coresight_bases[ctx->coresight_level]; + uint32_t base_next = adi_romtable_get(ctx, base, ctx->coresight_pos[ctx->coresight_level]); + + snprintf(buffer, sizeof(buffer), "Base: %08lX", base); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + y += 10; + snprintf(buffer, sizeof(buffer), "Type: %s", adi_romtable_type(ctx, base)); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + y += 10; + snprintf(buffer, sizeof(buffer), "Full: %s", adi_romtable_full(ctx, base)); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + y += 10; + + if(adi_is_romtable(ctx, base)) { + snprintf( + buffer, + sizeof(buffer), + "[%lu/%lu] -> %08lX", + ctx->coresight_pos[ctx->coresight_level] + 1, + ctx->coresight_count[ctx->coresight_level], + base_next); + canvas_draw_str_aligned(canvas, 5, y, AlignLeft, AlignBottom, buffer); + canvas_set_font(canvas, FontSecondary); + elements_button_center(canvas, "Enter"); + } + y += 10; + + canvas_set_font(canvas, FontSecondary); + + if(ctx->coresight_level) { + elements_button_left(canvas, "Prev"); + } else { + elements_button_left(canvas, "APs"); + } + elements_scrollbar_pos( + canvas, + 4, + 10, + 40, + ctx->coresight_pos[ctx->coresight_level], + ctx->coresight_count[ctx->coresight_level]); + + break; + } + + /* hex dump view */ + case ModePageScript: { + canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, "Script"); + y += 10; + y += 10; + canvas_draw_str_aligned(canvas, 10, y, AlignLeft, AlignBottom, "Status:"); + y += 10; + canvas_set_font(canvas, FontKeyboard); + canvas_draw_str_aligned(canvas, 64, y, AlignCenter, AlignBottom, ctx->state_string); + y += 10; + break; + } + } + + furi_mutex_release(ctx->gui_mutex); +} + +static void input_callback(InputEvent* input_event, void* ctx_in) { + furi_assert(input_event); + furi_assert(ctx_in); + AppFSM* ctx = ctx_in; + + int entries = furi_message_queue_get_count(ctx->event_queue); + + /* better skip than sorry */ + if(entries < QUEUE_SIZE) { + AppEvent event = {.type = EventKeyPress, .input = *input_event}; + furi_message_queue_put(ctx->event_queue, &event, 0); + } +} + +static void app_init(AppFSM* const app) { + furi_assert(app); + + app->loop_count = 0; + app->current_mask_id = 0; + app->current_mask = gpio_direction_mask[app->current_mask_id]; + app->io_swd = 0xFF; + app->io_swc = 0xFF; + app->hex_addr = 0x40002800; + app->hex_addr = 0xE000EDF0; + app->swd_clock_delay = CLOCK_DELAY; + app->swd_idle_bits = IDLE_BITS; + + strcpy(app->state_string, "none"); + strcpy(app->script_detected, ""); +} + +static void app_deinit(AppFSM* const app) { + furi_assert(app); + + strcpy(app->state_string, "exiting"); +} + +static void swd_main_loop(AppFSM* ctx) { + furi_assert(ctx); + + ctx->loop_count++; + + switch(ctx->mode_page) { + case ModePageScan: + case ModePageFound: { + /* reset after timeout */ + if(ctx->detected_timeout > 0) { + ctx->detected_timeout--; + } else { + DBGS("Reset detected flag"); + ctx->detected_device = false; + ctx->io_swd = 0xFF; + ctx->io_swc = 0xFF; + ctx->io_num_swd = 0xFF; + ctx->io_num_swc = 0xFF; + ctx->ap_scanned = 0; + memset(&ctx->dp_regs, 0x00, sizeof(ctx->dp_regs)); + memset(&ctx->targetid_info, 0x00, sizeof(ctx->targetid_info)); + memset(&ctx->apidr_info, 0x00, sizeof(ctx->apidr_info)); + ctx->script_detected_executed = false; + } + + ctx->detected = false; + ctx->current_mask = gpio_direction_mask[ctx->current_mask_id]; + + /* when SWD was already detected, set it to data pin regardless of the mask */ + if(ctx->detected_device) { + ctx->current_mask &= ~ctx->io_swd; + } + + /* do the scan */ + furi_mutex_acquire(ctx->swd_mutex, FuriWaitForever); + swd_scan(ctx); + furi_mutex_release(ctx->swd_mutex); + + /* now when detected a device, set the timeout */ + if(ctx->detected) { + DBGS("Set detected flag"); + ctx->detected_device = true; + ctx->detected_timeout = TIMER_HZ * TIMEOUT; + + /* update DPIDR fields */ + ctx->dpidr_info.revision = (ctx->dp_regs.dpidr >> 28) & 0x0F; + ctx->dpidr_info.partno = (ctx->dp_regs.dpidr >> 20) & 0xFF; + ctx->dpidr_info.version = (ctx->dp_regs.dpidr >> 12) & 0x0F; + ctx->dpidr_info.designer = (ctx->dp_regs.dpidr >> 1) & 0x3FF; + + if(!has_multiple_bits(ctx->io_swc)) { + DBGS(" - Detected pins"); + DBGS(" - Resetting error"); + + furi_mutex_acquire(ctx->swd_mutex, FuriWaitForever); + /* reset error */ + /* first make sure we have the correct bank by invalidating the current select cache */ + ctx->dp_regs.select_ok = false; + uint8_t ack = + swd_read_dpbank(ctx, REG_CTRLSTAT, REG_CTRLSTAT_BANK, &ctx->dp_regs.ctrlstat); + + if(ack != 1 || (ctx->dp_regs.ctrlstat & STAT_ERROR_FLAGS)) { + DBGS(" - send ABORT"); + swd_abort(ctx); + } + DBGS(" - Fetch CTRL/STAT"); + ctx->dp_regs.ctrlstat_ok = + swd_read_dpbank( + ctx, REG_CTRLSTAT, REG_CTRLSTAT_BANK, &ctx->dp_regs.ctrlstat) == 1; + DBG(" %08lX %s", + ctx->dp_regs.ctrlstat, + ctx->dp_regs.ctrlstat_ok ? "OK" : "FAIL"); + + if(ctx->dpidr_info.version >= 1) { + DBGS(" - DAPv1, read DLCR"); + ctx->dp_regs.dlcr_ok = + swd_read_dpbank(ctx, REG_DLCR, REG_DLCR_BANK, &ctx->dp_regs.dlcr) == 1; + DBG(" %08lX %s", ctx->dp_regs.dlcr, ctx->dp_regs.dlcr_ok ? "OK" : "FAIL"); + } + + if(ctx->dpidr_info.version >= 2) { + DBGS(" - DAPv2, read TARGETID"); + ctx->dp_regs.targetid_ok = + swd_read_dpbank( + ctx, REG_TARGETID, REG_TARGETID_BANK, &ctx->dp_regs.targetid) == 1; + DBG(" %08lX %s", + ctx->dp_regs.targetid, + ctx->dp_regs.targetid_ok ? "OK" : "FAIL"); + DBGS(" - DAPv2, read EVENTSTAT"); + ctx->dp_regs.eventstat_ok = + swd_read_dpbank( + ctx, REG_EVENTSTAT, REG_EVENTSTAT_BANK, &ctx->dp_regs.eventstat) == 1; + DBG(" %08lX %s", + ctx->dp_regs.eventstat, + ctx->dp_regs.eventstat_ok ? "OK" : "FAIL"); + DBGS(" - DAPv2, read DLPIDR"); + ctx->dp_regs.dlpidr_ok = + swd_read_dpbank(ctx, REG_DLPIDR, REG_DLPIDR_BANK, &ctx->dp_regs.dlpidr) == + 1; + DBG(" %08lX %s", + ctx->dp_regs.dlpidr, + ctx->dp_regs.dlpidr_ok ? "OK" : "FAIL"); + } + + if(ctx->dp_regs.targetid_ok) { + ctx->targetid_info.revision = (ctx->dp_regs.targetid >> 28) & 0x0F; + ctx->targetid_info.partno = (ctx->dp_regs.targetid >> 12) & 0xFFFF; + ctx->targetid_info.designer = (ctx->dp_regs.targetid >> 1) & 0x3FF; + } + + if(!ctx->script_detected_executed && strlen(ctx->script_detected) > 0) { + DBG(" - Run script '%s'", ctx->script_detected); + + ctx->script_detected_executed = true; + + ctx->mode_page = ModePageScript; + swd_execute_script(ctx, ctx->script_detected); + ctx->mode_page = ModePageFound; + } + furi_mutex_release(ctx->swd_mutex); + } + } else { + if(!has_multiple_bits(ctx->io_swc)) { + DBGS(" - Lost device"); + } + } + + ctx->current_mask_id = (ctx->current_mask_id + 1) % COUNT(gpio_direction_mask); + break; + } + + case ModePageDPRegs: + case ModePageDPID: + case ModePageAPID: { + furi_mutex_acquire(ctx->swd_mutex, FuriWaitForever); + /* set debug enable request */ + if(!swd_ensure_powerup(ctx)) { + furi_mutex_release(ctx->swd_mutex); + break; + } + + /* only scan a few APs at once to stay responsive */ + for(int pos = 0; pos < 8; pos++) { + if(ctx->ap_scanned == 0) { + swd_apscan_reset(ctx); + } + + uint8_t ap = ctx->ap_scanned++; + + if(ctx->apidr_info[ap].tested) { + continue; + } + if(swd_apscan_test(ctx, ap)) { + break; + } + } + furi_mutex_release(ctx->swd_mutex); + break; + } + + case ModePageHexDump: { + furi_mutex_acquire(ctx->swd_mutex, FuriWaitForever); + + for(size_t byte_pos = 0; byte_pos < sizeof(ctx->hex_buffer); byte_pos += 4) { + uint32_t* data = (uint32_t*)&ctx->hex_buffer[byte_pos]; + bool ret = swd_read_memory(ctx, ctx->ap_pos, ctx->hex_addr + byte_pos, data) == 1; + + ctx->hex_buffer_valid[byte_pos / 4] = ret; + + if(!ret) { + swd_abort_simple(ctx); + } + } + furi_mutex_release(ctx->swd_mutex); + break; + } + + case ModePageCoresight: + furi_delay_ms(50); + break; + } +} + +static bool swd_message_process(AppFSM* ctx) { + bool processing = true; + AppEvent event; + + /* wait to make sure the OS can do its stuff */ + FuriStatus event_status = furi_message_queue_get(ctx->event_queue, &event, 1000 / TIMER_HZ); + + if(event_status != FuriStatusOk) { + return processing; + } + + if(event.type == EventKeyPress) { + if(event.input.type == InputTypePress) { + switch(event.input.key) { + case InputKeyUp: + switch(ctx->mode_page) { + default: + break; + + case ModePageScan: + case ModePageFound: { + strcpy(ctx->script_detected, ""); + break; + } + + case ModePageAPID: + if(ctx->ap_pos > 0) { + ctx->ap_pos--; + } + break; + + case ModePageHexDump: { + ctx->hex_addr += ((ctx->hex_select) ? 1 : 8) * (1 << (4 * ctx->hex_select)); + break; + } + + case ModePageCoresight: { + if(ctx->coresight_pos[ctx->coresight_level] > 0) { + ctx->coresight_pos[ctx->coresight_level]--; + } + break; + } + } + break; + + case InputKeyDown: { + switch(ctx->mode_page) { + default: + break; + + case ModePageScan: { + FuriString* result_path = furi_string_alloc_printf(ANY_PATH("swd_scripts")); + FuriString* preselected = furi_string_alloc_printf( + (strlen(ctx->script_detected) > 0) ? ctx->script_detected : + ANY_PATH("swd_scripts")); + DialogsFileBrowserOptions options; + + dialog_file_browser_set_basic_options(&options, "swd", &I_swd); + + if(dialog_file_browser_show(ctx->dialogs, result_path, preselected, &options)) { + const char* path = furi_string_get_cstr(result_path); + strcpy(ctx->script_detected, path); + } + + furi_string_free(result_path); + furi_string_free(preselected); + break; + } + + case ModePageAPID: + if(ctx->ap_pos + 1U < COUNT(ctx->apidr_info)) { + ctx->ap_pos++; + } + break; + + case ModePageHexDump: { + ctx->hex_addr -= ((ctx->hex_select) ? 1 : 8) * (1 << (4 * ctx->hex_select)); + break; + } + + case ModePageCoresight: { + if(ctx->coresight_pos[ctx->coresight_level] + 1 < + ctx->coresight_count[ctx->coresight_level]) { + ctx->coresight_pos[ctx->coresight_level]++; + } + break; + } + } + break; + } + + case InputKeyRight: + if(ctx->mode_page == ModePageHexDump) { + if(ctx->hex_select > 0) { + ctx->hex_select--; + } + } else if(ctx->mode_page == ModePageAPID && ctx->apidr_info[ctx->ap_pos].ok) { + ctx->mode_page = ModePageCoresight; + uint32_t base = ctx->apidr_info[ctx->ap_pos].base & 0xFFFFF000; + ctx->coresight_level = 0; + ctx->coresight_bases[ctx->coresight_level] = base; + ctx->coresight_pos[ctx->coresight_level] = 0; + ctx->coresight_count[ctx->coresight_level] = + adi_romtable_entry_count(ctx, base); + } else if(ctx->detected) { + if(ctx->mode_page + 1 < ModePageCount) { + ctx->mode_page++; + } + } + break; + + case InputKeyLeft: + if(ctx->mode_page == ModePageHexDump) { + if(ctx->hex_select < 7) { + ctx->hex_select++; + } + } else if(ctx->mode_page == ModePageCoresight) { + if(ctx->coresight_level > 0) { + ctx->coresight_level--; + } else { + ctx->mode_page = ModePageAPID; + } + } else if((ctx->mode_page == ModePageScan) || (ctx->mode_page == ModePageFound)) { + uint32_t mode_page = ctx->mode_page; + FuriString* result_path = furi_string_alloc_printf(ANY_PATH("swd_scripts")); + FuriString* preselected = furi_string_alloc_printf( + (strlen(ctx->script_detected) > 0) ? ctx->script_detected : + ANY_PATH("swd_scripts")); + DialogsFileBrowserOptions options; + + dialog_file_browser_set_basic_options(&options, "swd", &I_swd); + + if(dialog_file_browser_show(ctx->dialogs, result_path, preselected, &options)) { + const char* path = furi_string_get_cstr(result_path); + ctx->mode_page = ModePageScript; + swd_execute_script(ctx, path); + ctx->mode_page = mode_page; + } + + furi_string_free(result_path); + furi_string_free(preselected); + break; + } else { + if(ctx->mode_page > 0) { + ctx->mode_page--; + } + } + break; + + case InputKeyOk: + if(ctx->mode_page == ModePageAPID && ctx->apidr_info[ctx->ap_pos].ok) { + ctx->mode_page = ModePageHexDump; + } else if(ctx->mode_page == ModePageCoresight) { + uint32_t base = ctx->coresight_bases[ctx->coresight_level]; + + if(!adi_is_romtable(ctx, base)) { + break; + } + + uint32_t cur_pos = ctx->coresight_pos[ctx->coresight_level]; + uint32_t base_next = adi_romtable_get(ctx, base, cur_pos); + uint32_t new_count = adi_romtable_entry_count(ctx, base_next); + + ctx->coresight_level++; + ctx->coresight_pos[ctx->coresight_level] = 0; + ctx->coresight_count[ctx->coresight_level] = new_count; + ctx->coresight_bases[ctx->coresight_level] = base_next; + } + break; + + case InputKeyBack: + if(ctx->mode_page == ModePageHexDump) { + ctx->mode_page = ModePageAPID; + } else if(ctx->mode_page == ModePageScript) { + ctx->script->abort = true; + } else if(ctx->mode_page > ModePageFound) { + ctx->mode_page = ModePageScan; + } else if(ctx->mode_page == ModePageScan) { + processing = false; + } else if(ctx->mode_page == ModePageFound) { + processing = false; + } + break; + + default: + break; + } + } + } + return processing; +} + +size_t data_received(void* ctx, uint8_t* data, size_t length) { + AppFSM* app = (AppFSM*)ctx; + + strncpy(app->commandline->line_data, (const char*)data, length); + app->commandline->line_pos = 0; + + for(size_t pos = 0; pos < length; pos++) { + uint8_t ch = app->commandline->line_data[pos]; + + if((ch == '\r') || (ch == '\n')) { + app->commandline->line_data[pos++] = '\n'; + app->commandline->line_data[pos] = 0; + LOG("direct command '%s'", app->commandline->line_data); + swd_execute_script_line(app->commandline); + return pos; + } + } + + return 0; +} + +int32_t swd_probe_app_main(void* p) { + UNUSED(p); + + AppFSM* app = malloc(sizeof(AppFSM)); + + DBGS("App init"); + app_init(app); + + DBGS("furi_record_open"); + app->notification = furi_record_open(RECORD_NOTIFICATION); + app->gui = furi_record_open(RECORD_GUI); + app->dialogs = furi_record_open(RECORD_DIALOGS); + app->storage = furi_record_open(RECORD_STORAGE); + + DBGS("furi_mutex_alloc"); + app->swd_mutex = furi_mutex_alloc(FuriMutexTypeNormal); + app->gui_mutex = furi_mutex_alloc(FuriMutexTypeNormal); + app->event_queue = furi_message_queue_alloc(QUEUE_SIZE, sizeof(AppEvent)); + + DBGS("usb_uart_enable"); + UsbUartConfig uart_config; + uart_config.vcp_ch = 1; + uart_config.rx_data = &data_received; + uart_config.rx_data_ctx = app; + app->uart = usb_uart_enable(&uart_config); + + app->commandline = malloc(sizeof(ScriptContext)); + app->commandline->max_tries = 1; + app->commandline->app = app; + + DBGS("view_port_alloc"); + app->view_port = view_port_alloc(); + view_port_draw_callback_set(app->view_port, render_callback, app); + view_port_input_callback_set(app->view_port, input_callback, app); + gui_add_view_port(app->gui, app->view_port, GuiLayerFullscreen); + + DBGS("notification_message_block"); + notification_message(app->notification, &sequence_display_backlight_enforce_on); + + DBGS("swd_execute_script"); + swd_execute_script(app, ANY_PATH("swd_scripts/startup.swd")); + + DOLPHIN_DEED(DolphinDeedPluginGameStart); + + DBGS("processing"); + for(bool processing = true; processing;) { + swd_main_loop(app); + view_port_update(app->view_port); + + processing = swd_message_process(app); + + bool beep = false; + + if(app->detected_device && !app->detected_notified) { + app->detected_notified = true; + beep = true; + } + if(!app->detected_device && app->detected_notified) { + app->detected_notified = false; + } + if(beep) { + notification_message_block(app->notification, &seq_c_minor); + } + } + + view_port_enabled_set(app->view_port, false); + gui_remove_view_port(app->gui, app->view_port); + view_port_free(app->view_port); + + app_deinit(app); + + notification_message(app->notification, &sequence_display_backlight_enforce_auto); + + usb_uart_disable(app->uart); + + furi_message_queue_free(app->event_queue); + furi_mutex_free(app->gui_mutex); + furi_mutex_free(app->swd_mutex); + free(app); + + furi_record_close(RECORD_GUI); + furi_record_close(RECORD_NOTIFICATION); + furi_record_close(RECORD_DIALOGS); + furi_record_close(RECORD_STORAGE); + + return 0; +} diff --git a/applications/plugins/swd_probe/swd_probe_app.h b/applications/plugins/swd_probe/swd_probe_app.h new file mode 100644 index 000000000..152088925 --- /dev/null +++ b/applications/plugins/swd_probe/swd_probe_app.h @@ -0,0 +1,233 @@ +#ifndef __ARHA_FLIPPERAPP_DEMO +#define __ARHA_FLIPPERAPP_DEMO + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "usb_uart.h" + +#define TAG "SWD" + +/* short debug message */ +#define DBGS(format) furi_log_print_format(FuriLogLevelDebug, TAG, "%s: " format, __FUNCTION__) +/* formatted debug message */ +#define DBG(format, ...) \ + furi_log_print_format(FuriLogLevelDebug, TAG, "%s: " format, __FUNCTION__, __VA_ARGS__) +/* log message*/ +#define LOG(...) furi_log_print_format(FuriLogLevelDefault, TAG, __VA_ARGS__) + +#define COUNT(x) ((size_t)(sizeof(x) / sizeof((x)[0]))) +#define ARRAY_SIZE(x) COUNT(x) + +#define SWD_DELAY_US 0 +#define TIMER_HZ 25 +#define TIMEOUT 3 +#define QUEUE_SIZE 8 +#define IDLE_BITS 8 +#define CLOCK_DELAY 0 + +#define MAX_FILE_LENGTH 128 +#define SCRIPT_MAX_LINES 1000 + +typedef enum { + ModePageScan = 0, + ModePageFound = 1, + ModePageDPRegs = 2, + ModePageDPID = 3, + ModePageAPID = 4, + ModePageCount = 5, + ModePageHexDump = 0x100, + ModePageScript = 0x101, + ModePageCoresight = 0x102, +} ModePages; + +#define CDBGPWRUPREQ (1 << 28) +#define CDBGPWRUPACK (1 << 29) +#define CSYSPWRUPREQ (1 << 30) +#define CSYSPWRUPACK (1 << 31) +#define WDATAERR (1 << 7) +#define STICKYERR (1 << 5) +#define STAT_ERROR_FLAGS (WDATAERR | STICKYERR) + +#define REG_IDCODE 0x00 +#define REG_CTRLSTAT 0x01 +#define REG_CTRLSTAT_BANK 0x00 +#define REG_DLCR 0x01 +#define REG_DLCR_BANK 0x01 +#define REG_TARGETID 0x01 +#define REG_TARGETID_BANK 0x02 +#define REG_DLPIDR 0x01 +#define REG_DLPIDR_BANK 0x03 +#define REG_EVENTSTAT 0x01 +#define REG_EVENTSTAT_BANK 0x04 + +#define REG_SELECT 0x02 + +#define MEMAP_CSW 0x00 +#define MEMAP_TAR 0x04 +#define MEMAP_DRW 0x0C +#define AP_IDR 0xFC +#define AP_BASE 0xF8 + +typedef enum { KeyNone, KeyUp, KeyRight, KeyDown, KeyLeft, KeyOK } KeyCode; + +typedef enum { + EventTimerTick, + EventKeyPress, +} EventType; + +typedef struct { + EventType type; + InputEvent input; +} AppEvent; + +typedef struct { + uint32_t ctrlstat; + bool ctrlstat_ok; + uint32_t dlcr; + bool dlcr_ok; + uint32_t dlpidr; + bool dlpidr_ok; + uint32_t dpidr; + bool dpidr_ok; + uint32_t eventstat; + bool eventstat_ok; + uint32_t select; + bool select_ok; + uint32_t targetid; + bool targetid_ok; +} swd_dpreg_t; + +typedef struct { + bool ok; + bool tested; + uint8_t revision; + uint16_t designer; + uint8_t class; + uint8_t variant; + uint8_t type; + uint32_t base; +} swd_apidr_info_t; + +typedef struct { + uint8_t revision; + uint8_t partno; + uint8_t version; + uint16_t designer; +} swd_dpidr_info_t; + +typedef struct { + uint8_t revision; + uint16_t partno; + uint16_t designer; +} swd_targetid_info_t; + +typedef struct sScriptContext ScriptContext; + +typedef struct { + Storage* storage; + Gui* gui; + DialogsApp* dialogs; + NotificationApp* notification; + + FuriTimer* timer; + UsbUart* uart; + ViewPort* view_port; + + FuriMessageQueue* event_queue; + FuriMutex* swd_mutex; + FuriMutex* gui_mutex; + + swd_targetid_info_t targetid_info; + swd_dpidr_info_t dpidr_info; + swd_dpreg_t dp_regs; + swd_apidr_info_t apidr_info[256]; + + ScriptContext* script; + ScriptContext* commandline; + + uint8_t timeout_overdue; + uint32_t loop_count; + uint8_t current_mask_id; + uint32_t current_mask; + uint8_t io_swc; + uint8_t io_swd; + uint8_t io_num_swc; + uint8_t io_num_swd; + int32_t detected_timeout; + uint32_t swd_clock_delay; + uint32_t swd_idle_bits; + bool detected; + bool detected_device; + bool detected_notified; + uint32_t mode_page; + uint8_t ap_pos; + uint8_t ap_scanned; + + uint32_t coresight_pos[16]; + uint32_t coresight_count[16]; + uint8_t coresight_level; + uint32_t coresight_bases[16]; + + uint32_t hex_addr; + uint8_t hex_select; + uint8_t hex_buffer[32]; + uint8_t hex_buffer_valid[8]; + + char state_string[64]; + char script_detected[MAX_FILE_LENGTH]; + bool script_detected_executed; +} AppFSM; + +struct sScriptContext { + AppFSM* app; + ScriptContext* parent; + char filename[MAX_FILE_LENGTH]; + + /* when used with string input */ + char line_data[128]; + uint64_t line_pos; + + /* when used with file input */ + File* script_file; + + uint64_t position; + uint32_t selected_ap; + uint32_t max_tries; + uint32_t block_size; + + bool abort; + bool restart; + bool errors_ignore; + bool status_ignore; + bool goto_active; + char goto_label[64]; +}; + +typedef struct { + const char* prefix; + bool (*func)(ScriptContext* ctx); +} ScriptFunctionInfo; + +uint8_t swd_read_memory(AppFSM* const ctx, uint8_t ap, uint32_t address, uint32_t* data); + +#endif \ No newline at end of file diff --git a/applications/plugins/swd_probe/usb_uart.c b/applications/plugins/swd_probe/usb_uart.c new file mode 100644 index 000000000..76841cf11 --- /dev/null +++ b/applications/plugins/swd_probe/usb_uart.c @@ -0,0 +1,223 @@ + +#include + +#include "usb_uart.h" +#include "furi_hal.h" +#include +#include "usb_cdc.h" +#include "cli/cli_vcp.h" +#include +#include "cli/cli.h" + +#define USB_CDC_PKT_LEN CDC_DATA_SZ +#define USB_UART_RX_BUF_SIZE (USB_CDC_PKT_LEN * 5) + +#define USB_CDC_BIT_DTR (1 << 0) +#define USB_CDC_BIT_RTS (1 << 1) + +typedef enum { + WorkerEvtStop = (1 << 0), + WorkerEvtCdcRx = (1 << 1), + WorkerEvtCfgChange = (1 << 2) + +} WorkerEvtFlags; + +#define WORKER_ALL_EVENTS (WorkerEvtStop | WorkerEvtCfgChange | WorkerEvtCdcRx) + +struct UsbUart { + UsbUartConfig cfg; + UsbUartConfig cfg_new; + + FuriThread* thread; + FuriMutex* usb_mutex; + FuriSemaphore* tx_sem; + UsbUartState st; + FuriApiLock cfg_lock; + + uint8_t rx_buf[USB_CDC_PKT_LEN]; +}; + +static void vcp_on_cdc_tx_complete(void* context); +static void vcp_on_cdc_rx(void* context); +static void vcp_state_callback(void* context, uint8_t state); +static void vcp_on_cdc_control_line(void* context, uint8_t state); +static void vcp_on_line_config(void* context, struct usb_cdc_line_coding* config); + +static const CdcCallbacks cdc_cb = { + .tx_ep_callback = &vcp_on_cdc_tx_complete, + .rx_ep_callback = &vcp_on_cdc_rx, + .state_callback = &vcp_state_callback, + .ctrl_line_callback = &vcp_on_cdc_control_line, + .config_callback = &vcp_on_line_config}; + +static void usb_uart_vcp_init(UsbUart* usb_uart, uint8_t vcp_ch) { + furi_hal_usb_unlock(); + + Cli* cli = furi_record_open(RECORD_CLI); + cli_session_close(cli); + + if(vcp_ch == 0) { + furi_check(furi_hal_usb_set_config(&usb_cdc_single, NULL) == true); + } else { + furi_check(furi_hal_usb_set_config(&usb_cdc_dual, NULL) == true); + cli_session_open(cli, &cli_vcp); + } + furi_record_close(RECORD_CLI); + furi_hal_cdc_set_callbacks(vcp_ch, (CdcCallbacks*)&cdc_cb, usb_uart); +} + +static void usb_uart_vcp_deinit(UsbUart* usb_uart, uint8_t vcp_ch) { + UNUSED(usb_uart); + furi_hal_cdc_set_callbacks(vcp_ch, NULL, NULL); + if(vcp_ch != 0) { + Cli* cli = furi_record_open(RECORD_CLI); + cli_session_close(cli); + furi_record_close(RECORD_CLI); + } +} + +void usb_uart_tx_data(UsbUart* usb_uart, uint8_t* data, size_t length) { + uint32_t pos = 0; + while(pos < length) { + size_t pkt_size = length - pos; + + if(pkt_size > USB_CDC_PKT_LEN) { + pkt_size = USB_CDC_PKT_LEN; + } + + if(furi_semaphore_acquire(usb_uart->tx_sem, 100) == FuriStatusOk) { + furi_check(furi_mutex_acquire(usb_uart->usb_mutex, FuriWaitForever) == FuriStatusOk); + furi_hal_cdc_send(usb_uart->cfg.vcp_ch, &data[pos], pkt_size); + furi_check(furi_mutex_release(usb_uart->usb_mutex) == FuriStatusOk); + usb_uart->st.tx_cnt += pkt_size; + pos += pkt_size; + } + } +} + +static int32_t usb_uart_worker(void* context) { + UsbUart* usb_uart = (UsbUart*)context; + + memcpy(&usb_uart->cfg, &usb_uart->cfg_new, sizeof(UsbUartConfig)); + + usb_uart->tx_sem = furi_semaphore_alloc(1, 1); + usb_uart->usb_mutex = furi_mutex_alloc(FuriMutexTypeNormal); + + usb_uart_vcp_init(usb_uart, usb_uart->cfg.vcp_ch); + + uint8_t data[2 * USB_CDC_PKT_LEN]; + size_t remain = 0; + + while(1) { + uint32_t events = + furi_thread_flags_wait(WORKER_ALL_EVENTS, FuriFlagWaitAny, FuriWaitForever); + furi_check(!(events & FuriFlagError)); + + if(events & WorkerEvtStop) { + break; + } + + if(events & WorkerEvtCdcRx) { + furi_check(furi_mutex_acquire(usb_uart->usb_mutex, FuriWaitForever) == FuriStatusOk); + size_t len = + furi_hal_cdc_receive(usb_uart->cfg.vcp_ch, &data[remain], USB_CDC_PKT_LEN); + furi_check(furi_mutex_release(usb_uart->usb_mutex) == FuriStatusOk); + + if(len > 0) { + usb_uart->st.rx_cnt += len; + remain += len; + + size_t handled = usb_uart->cfg.rx_data(usb_uart->cfg.rx_data_ctx, data, remain); + + memcpy(data, &data[handled], remain - handled); + remain -= handled; + } + } + + if(events & WorkerEvtCfgChange) { + if(usb_uart->cfg.vcp_ch != usb_uart->cfg_new.vcp_ch) { + usb_uart_vcp_deinit(usb_uart, usb_uart->cfg.vcp_ch); + usb_uart_vcp_init(usb_uart, usb_uart->cfg_new.vcp_ch); + + usb_uart->cfg.vcp_ch = usb_uart->cfg_new.vcp_ch; + } + api_lock_unlock(usb_uart->cfg_lock); + } + } + usb_uart_vcp_deinit(usb_uart, usb_uart->cfg.vcp_ch); + + furi_mutex_free(usb_uart->usb_mutex); + furi_semaphore_free(usb_uart->tx_sem); + + furi_hal_usb_unlock(); + furi_check(furi_hal_usb_set_config(&usb_cdc_single, NULL) == true); + Cli* cli = furi_record_open(RECORD_CLI); + cli_session_open(cli, &cli_vcp); + furi_record_close(RECORD_CLI); + + return 0; +} + +/* VCP callbacks */ +static void vcp_on_cdc_tx_complete(void* context) { + UsbUart* usb_uart = (UsbUart*)context; + furi_semaphore_release(usb_uart->tx_sem); +} + +static void vcp_on_cdc_rx(void* context) { + UsbUart* usb_uart = (UsbUart*)context; + furi_thread_flags_set(furi_thread_get_id(usb_uart->thread), WorkerEvtCdcRx); +} + +static void vcp_state_callback(void* context, uint8_t state) { + UNUSED(context); + UNUSED(state); +} + +static void vcp_on_cdc_control_line(void* context, uint8_t state) { + UNUSED(context); + UNUSED(state); +} + +static void vcp_on_line_config(void* context, struct usb_cdc_line_coding* config) { + UNUSED(context); + UNUSED(config); +} + +UsbUart* usb_uart_enable(UsbUartConfig* cfg) { + UsbUart* usb_uart = malloc(sizeof(UsbUart)); + memcpy(&(usb_uart->cfg_new), cfg, sizeof(UsbUartConfig)); + + usb_uart->thread = furi_thread_alloc_ex("UsbUartWorker", 1024, usb_uart_worker, usb_uart); + furi_thread_start(usb_uart->thread); + return usb_uart; +} + +void usb_uart_disable(UsbUart* usb_uart) { + furi_assert(usb_uart); + furi_thread_flags_set(furi_thread_get_id(usb_uart->thread), WorkerEvtStop); + furi_thread_join(usb_uart->thread); + furi_thread_free(usb_uart->thread); + free(usb_uart); +} + +void usb_uart_set_config(UsbUart* usb_uart, UsbUartConfig* cfg) { + furi_assert(usb_uart); + furi_assert(cfg); + usb_uart->cfg_lock = api_lock_alloc_locked(); + memcpy(&(usb_uart->cfg_new), cfg, sizeof(UsbUartConfig)); + furi_thread_flags_set(furi_thread_get_id(usb_uart->thread), WorkerEvtCfgChange); + api_lock_wait_unlock_and_free(usb_uart->cfg_lock); +} + +void usb_uart_get_config(UsbUart* usb_uart, UsbUartConfig* cfg) { + furi_assert(usb_uart); + furi_assert(cfg); + memcpy(cfg, &(usb_uart->cfg_new), sizeof(UsbUartConfig)); +} + +void usb_uart_get_state(UsbUart* usb_uart, UsbUartState* st) { + furi_assert(usb_uart); + furi_assert(st); + memcpy(st, &(usb_uart->st), sizeof(UsbUartState)); +} diff --git a/applications/plugins/swd_probe/usb_uart.h b/applications/plugins/swd_probe/usb_uart.h new file mode 100644 index 000000000..a82f36a05 --- /dev/null +++ b/applications/plugins/swd_probe/usb_uart.h @@ -0,0 +1,29 @@ +#pragma once + +#include +#include + +typedef struct UsbUart UsbUart; + +typedef struct { + uint8_t vcp_ch; + size_t (*rx_data)(void* ctx, uint8_t* data, size_t length); + void* rx_data_ctx; +} UsbUartConfig; + +typedef struct { + uint32_t rx_cnt; + uint32_t tx_cnt; +} UsbUartState; + +UsbUart* usb_uart_enable(UsbUartConfig* cfg); + +void usb_uart_disable(UsbUart* usb_uart); + +void usb_uart_set_config(UsbUart* usb_uart, UsbUartConfig* cfg); + +void usb_uart_get_config(UsbUart* usb_uart, UsbUartConfig* cfg); + +void usb_uart_get_state(UsbUart* usb_uart, UsbUartState* st); + +void usb_uart_tx_data(UsbUart* usb_uart, uint8_t* data, size_t length); diff --git a/applications/plugins/tetris_game/tetris_game.c b/applications/plugins/tetris_game/tetris_game.c index 1e8e85afa..a54c0ae57 100644 --- a/applications/plugins/tetris_game/tetris_game.c +++ b/applications/plugins/tetris_game/tetris_game.c @@ -326,9 +326,10 @@ static void uint16_t oldNumLines = tetris_state->numLines; tetris_state->numLines += numLines; if((oldNumLines / 10) % 10 != (tetris_state->numLines / 10) % 10) { - nextFallSpeed = tetris_state->fallSpeed - (100 / (tetris_state->numLines / 10)); - if (nextFallSpeed >= MIN_FALL_SPEED){ - tetris_state->fallSpeed = nextFallSpeed; + nextFallSpeed = + tetris_state->fallSpeed - (100 / (tetris_state->numLines / 10)); + if(nextFallSpeed >= MIN_FALL_SPEED) { + tetris_state->fallSpeed = nextFallSpeed; } } } diff --git a/applications/plugins/weather_station/scenes/weather_station_receiver.c b/applications/plugins/weather_station/scenes/weather_station_receiver.c index 3b62a1512..e76810430 100644 --- a/applications/plugins/weather_station/scenes/weather_station_receiver.c +++ b/applications/plugins/weather_station/scenes/weather_station_receiver.c @@ -197,7 +197,7 @@ bool weather_station_scene_receiver_on_event(void* context, SceneManagerEvent ev } // Get current RSSI float rssi = furi_hal_subghz_get_rssi(); - ws_receiver_rssi(app->ws_receiver, rssi); + ws_view_receiver_set_rssi(app->ws_receiver, rssi); if(app->txrx->txrx_state == WSTxRxStateRx) { notification_message(app->notifications, &sequence_blink_cyan_10); diff --git a/applications/plugins/weather_station/views/weather_station_receiver.c b/applications/plugins/weather_station/views/weather_station_receiver.c index c98b46de5..ecfeba09c 100644 --- a/applications/plugins/weather_station/views/weather_station_receiver.c +++ b/applications/plugins/weather_station/views/weather_station_receiver.c @@ -63,7 +63,7 @@ typedef struct { uint8_t u_rssi; } WSReceiverModel; -void ws_receiver_rssi(WSReceiver* instance, float rssi) { +void ws_view_receiver_set_rssi(WSReceiver* instance, float rssi) { furi_assert(instance); with_view_model( instance->view, @@ -197,7 +197,6 @@ void ws_view_receiver_draw(Canvas* canvas, WSReceiverModel* model) { canvas_set_font(canvas, FontSecondary); elements_button_left(canvas, "Config"); - //canvas_draw_line(canvas, 46, 51, 125, 51); bool scrollbar = model->history_item > 4; FuriString* str_buff; @@ -230,7 +229,6 @@ void ws_view_receiver_draw(Canvas* canvas, WSReceiverModel* model) { canvas_draw_icon(canvas, 0, 0, &I_Scanning_123x52); canvas_set_font(canvas, FontPrimary); canvas_draw_str(canvas, 63, 46, "Scanning..."); - //canvas_draw_line(canvas, 46, 51, 125, 51); canvas_set_font(canvas, FontSecondary); } diff --git a/applications/plugins/weather_station/views/weather_station_receiver.h b/applications/plugins/weather_station/views/weather_station_receiver.h index abe2c6255..f81aa1f5e 100644 --- a/applications/plugins/weather_station/views/weather_station_receiver.h +++ b/applications/plugins/weather_station/views/weather_station_receiver.h @@ -8,7 +8,7 @@ typedef struct WSReceiver WSReceiver; typedef void (*WSReceiverCallback)(WSCustomEvent event, void* context); -void ws_receiver_rssi(WSReceiver* instance, float rssi); +void ws_view_receiver_set_rssi(WSReceiver* instance, float rssi); void ws_view_receiver_set_lock(WSReceiver* ws_receiver, WSLock keyboard); diff --git a/applications/services/cli/cli_commands.c b/applications/services/cli/cli_commands.c index bb1f3ab7f..f37349b03 100644 --- a/applications/services/cli/cli_commands.c +++ b/applications/services/cli/cli_commands.c @@ -137,7 +137,7 @@ void cli_command_date(Cli* cli, FuriString* args, void* context) { } void cli_command_src(Cli* cli, FuriString* args, void* context) { - // Quality of life feaature for people exploring CLI on lab.flipper.net/cli + // Quality of life feature for people exploring CLI on lab.flipper.net/cli // By Yousef AK UNUSED(cli); UNUSED(args); diff --git a/applications/services/crypto/crypto_cli.c b/applications/services/crypto/crypto_cli.c index a286f4457..511a9d2a8 100644 --- a/applications/services/crypto/crypto_cli.c +++ b/applications/services/crypto/crypto_cli.c @@ -14,7 +14,7 @@ void crypto_cli_print_usage() { "\tdecrypt \t - Using key from secure enclave and IV decrypt hex encoded encrypted with AES256CBC data to plain text\r\n"); printf("\thas_key \t - Check if secure enclave has key in slot\r\n"); printf( - "\tstore_key \t - Store key in secure enclave. !!! NON-REVERSABLE OPERATION - READ MANUAL FIRST !!!\r\n"); + "\tstore_key \t - Store key in secure enclave. !!! NON-REVERSIBLE OPERATION - READ MANUAL FIRST !!!\r\n"); }; void crypto_cli_encrypt(Cli* cli, FuriString* args) { diff --git a/applications/services/desktop/animations/animation_manager.h b/applications/services/desktop/animations/animation_manager.h index e1340a0b5..a3305ec19 100644 --- a/applications/services/desktop/animations/animation_manager.h +++ b/applications/services/desktop/animations/animation_manager.h @@ -152,7 +152,7 @@ bool animation_manager_is_animation_loaded(AnimationManager* animation_manager); void animation_manager_unload_and_stall_animation(AnimationManager* animation_manager); /** - * Load and Contunue execution of animation manager. + * Load and Continue execution of animation manager. * * @animation_manager instance */ diff --git a/applications/services/desktop/views/desktop_view_main.c b/applications/services/desktop/views/desktop_view_main.c index 9149fd562..f1f4b637a 100644 --- a/applications/services/desktop/views/desktop_view_main.c +++ b/applications/services/desktop/views/desktop_view_main.c @@ -16,7 +16,7 @@ struct DesktopMainView { TimerHandle_t poweroff_timer; }; -#define DESKTOP_MAIN_VIEW_POWEROFF_TIMEOUT 2000 +#define DESKTOP_MAIN_VIEW_POWEROFF_TIMEOUT 1300 static void desktop_main_poweroff_timer_callback(TimerHandle_t timer) { DesktopMainView* main_view = pvTimerGetTimerID(timer); diff --git a/applications/services/gui/canvas.h b/applications/services/gui/canvas.h index 9fb554be2..a372b0ccc 100644 --- a/applications/services/gui/canvas.h +++ b/applications/services/gui/canvas.h @@ -363,7 +363,7 @@ void canvas_draw_rframe( uint8_t height, uint8_t radius); -/** Draw rounded-corner box of width, height at x,y, with round value raduis +/** Draw rounded-corner box of width, height at x,y, with round value radius * * @param canvas Canvas instance * @param x x coordinate diff --git a/applications/services/gui/elements.c b/applications/services/gui/elements.c index 54c36af76..3cdc36bd5 100644 --- a/applications/services/gui/elements.c +++ b/applications/services/gui/elements.c @@ -635,8 +635,8 @@ void elements_text_box( ElementTextBoxLine line[ELEMENTS_MAX_LINES_NUM]; bool bold = false; bool mono = false; - bool inversed = false; - bool inversed_present = false; + bool inverse = false; + bool inverse_present = false; Font current_font = FontSecondary; Font prev_font = FontSecondary; CanvasFontParameters* font_params = canvas_get_font_params(canvas, current_font); @@ -692,8 +692,8 @@ void elements_text_box( canvas_set_font(canvas, FontKeyboard); mono = !mono; } - if(text[i] == ELEMENTS_INVERSED_MARKER) { - inversed_present = true; + if(text[i] == ELEMENTS_INVERSE_MARKER) { + inverse_present = true; } continue; } @@ -709,10 +709,10 @@ void elements_text_box( if(text[i] == '\0') { full_text_processed = true; } - if(inversed_present) { + if(inverse_present) { line_leading_min += 1; line_leading_default += 1; - inversed_present = false; + inverse_present = false; } line[line_num].leading_min = line_leading_min; line[line_num].leading_default = line_leading_default; @@ -775,7 +775,7 @@ void elements_text_box( canvas_set_font(canvas, FontSecondary); bold = false; mono = false; - inversed = false; + inverse = false; for(uint8_t i = 0; i < line_num; i++) { for(uint8_t j = 0; j < line[i].len; j++) { // Process format symbols @@ -799,11 +799,11 @@ void elements_text_box( mono = !mono; continue; } - if(line[i].text[j] == ELEMENTS_INVERSED_MARKER) { - inversed = !inversed; + if(line[i].text[j] == ELEMENTS_INVERSE_MARKER) { + inverse = !inverse; continue; } - if(inversed) { + if(inverse) { canvas_draw_box( canvas, line[i].x - 1, diff --git a/applications/services/gui/elements.h b/applications/services/gui/elements.h index 485335131..04ca357b8 100644 --- a/applications/services/gui/elements.h +++ b/applications/services/gui/elements.h @@ -19,7 +19,7 @@ extern "C" { #define ELEMENTS_MAX_LINES_NUM (7) #define ELEMENTS_BOLD_MARKER '#' #define ELEMENTS_MONO_MARKER '*' -#define ELEMENTS_INVERSED_MARKER '!' +#define ELEMENTS_INVERSE_MARKER '!' /** Draw progress bar. * @@ -240,7 +240,7 @@ void elements_scrollable_text_line( * @param[in] text Formatted text. The following formats are available: * "\e#Bold text\e#" - bold font is used * "\e*Monospaced text\e*" - monospaced font is used - * "\e!Inversed text\e!" - white text on black background + * "\e!Inverted text\e!" - white text on black background * @param strip_to_dots Strip text to ... if does not fit to width */ void elements_text_box( diff --git a/applications/services/gui/modules/button_panel.h b/applications/services/gui/modules/button_panel.h index e74f7bc3b..4733b4695 100644 --- a/applications/services/gui/modules/button_panel.h +++ b/applications/services/gui/modules/button_panel.h @@ -61,7 +61,7 @@ void button_panel_reserve(ButtonPanel* button_panel, size_t reserve_x, size_t re * @param matrix_place_x coordinates by x-axis on virtual grid, it * is only used for navigation * @param matrix_place_y coordinates by y-axis on virtual grid, it - * is only used for naviagation + * is only used for navigation * @param x x-coordinate to draw icon on * @param y y-coordinate to draw icon on * @param icon_name name of the icon to draw diff --git a/applications/services/gui/modules/widget.h b/applications/services/gui/modules/widget.h index 9076ce7f2..a78c4ce06 100644 --- a/applications/services/gui/modules/widget.h +++ b/applications/services/gui/modules/widget.h @@ -91,7 +91,7 @@ void widget_add_string_element( * @param[in] text Formatted text. The following formats are available: * "\e#Bold text\e#" - bold font is used * "\e*Monospaced text\e*" - monospaced font is used - * "\e!Inversed text\e!" - white text on black background + * "\e!Inverted text\e!" - white text on black background * @param strip_to_dots Strip text to ... if does not fit to width */ void widget_add_text_box_element( diff --git a/applications/services/gui/scene_manager.c b/applications/services/gui/scene_manager.c index 590145e1e..484d1dbde 100644 --- a/applications/services/gui/scene_manager.c +++ b/applications/services/gui/scene_manager.c @@ -10,7 +10,7 @@ SceneManager* scene_manager_alloc(const SceneManagerHandlers* app_scene_handlers scene_manager->scene_handlers = app_scene_handlers; // Allocate all scenes scene_manager->scene = malloc(sizeof(AppScene) * app_scene_handlers->scene_num); - // Initialize ScaneManager array for navigation + // Initialize SceneManager array for navigation SceneManagerIdStack_init(scene_manager->scene_id_stack); return scene_manager; @@ -19,7 +19,7 @@ SceneManager* scene_manager_alloc(const SceneManagerHandlers* app_scene_handlers void scene_manager_free(SceneManager* scene_manager) { furi_assert(scene_manager); - // Clear ScaneManager array + // Clear SceneManager array SceneManagerIdStack_clear(scene_manager->scene_id_stack); // Clear allocated scenes free(scene_manager->scene); diff --git a/applications/services/gui/view_stack.h b/applications/services/gui/view_stack.h index cd62b4f6a..f16f5febc 100644 --- a/applications/services/gui/view_stack.h +++ b/applications/services/gui/view_stack.h @@ -3,7 +3,7 @@ * GUI: ViewStack API * * ViewStack accumulates several Views in one stack. - * Draw callbacks are called sequenctially starting from + * Draw callbacks are called sequentially starting from * first added. Input callbacks are called in reverse order. * Consumed input is not passed on underlying layers. */ diff --git a/applications/services/power/power_service/power.c b/applications/services/power/power_service/power.c index d2ced27de..62bb3c85a 100644 --- a/applications/services/power/power_service/power.c +++ b/applications/services/power/power_service/power.c @@ -77,7 +77,7 @@ void power_draw_battery_callback(Canvas* canvas, void* context) { 4.2)) { // not looking nice with low voltage indicator canvas_set_font(canvas, FontBatteryPercent); - // align charge dispaly value with digits to draw + // align charge display value with digits to draw uint8_t bar_charge = power->info.charge; if(bar_charge > 23 && bar_charge < 38) { bar_charge = 23; @@ -169,7 +169,7 @@ void power_draw_battery_callback(Canvas* canvas, void* context) { canvas_set_color(canvas, ColorWhite); canvas_draw_box(canvas, 1, 1, 22, 6); - // align charge dispaly value with digits to draw + // align charge display value with digits to draw uint8_t bar_charge = power->info.charge; if(bar_charge > 48 && bar_charge < 63) { diff --git a/applications/services/rpc/rpc.c b/applications/services/rpc/rpc.c index 63a71ad06..ecb4b7639 100644 --- a/applications/services/rpc/rpc.c +++ b/applications/services/rpc/rpc.c @@ -145,8 +145,8 @@ void rpc_session_set_terminated_callback( /* Doesn't forbid using rpc_feed_bytes() after session close - it's safe. * Because any bytes received in buffer will be flushed before next session. - * If bytes get into stream buffer before it's get epmtified and this - * command is gets processed - it's safe either. But case of it is quite + * If bytes get into stream buffer before it's get emptied and this + * command is gets processed - it's safe either way. But case of it is quite * odd: client sends close request and sends command after. */ size_t diff --git a/applications/services/storage/storage.h b/applications/services/storage/storage.h index e093cbe0f..df85a40b8 100644 --- a/applications/services/storage/storage.h +++ b/applications/services/storage/storage.h @@ -305,14 +305,14 @@ typedef void (*Storage_name_converter)(FuriString*); /** Backs up internal storage to a tar archive * @param api pointer to the api - * @param dstmane destination archive path + * @param dstname destination archive path * @return FS_Error operation result */ FS_Error storage_int_backup(Storage* api, const char* dstname); /** Restores internal storage from a tar archive * @param api pointer to the api - * @param dstmane archive path + * @param dstname archive path * @param converter pointer to filename conversion function, may be NULL * @return FS_Error operation result */ diff --git a/applications/settings/power_settings_app/power_settings_app.c b/applications/settings/power_settings_app/power_settings_app.c index 016439c0d..8843a31ed 100644 --- a/applications/settings/power_settings_app/power_settings_app.c +++ b/applications/settings/power_settings_app/power_settings_app.c @@ -42,11 +42,11 @@ PowerSettingsApp* power_settings_app_alloc(uint32_t first_scene) { view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); // Views - app->batery_info = battery_info_alloc(); + app->battery_info = battery_info_alloc(); view_dispatcher_add_view( app->view_dispatcher, PowerSettingsAppViewBatteryInfo, - battery_info_get_view(app->batery_info)); + battery_info_get_view(app->battery_info)); app->submenu = submenu_alloc(); app->variable_item_list = variable_item_list_alloc(); view_dispatcher_add_view( @@ -68,7 +68,7 @@ void power_settings_app_free(PowerSettingsApp* app) { furi_assert(app); // Views view_dispatcher_remove_view(app->view_dispatcher, PowerSettingsAppViewBatteryInfo); - battery_info_free(app->batery_info); + battery_info_free(app->battery_info); view_dispatcher_remove_view(app->view_dispatcher, PowerSettingsAppViewSubmenu); submenu_free(app->submenu); diff --git a/applications/settings/power_settings_app/power_settings_app.h b/applications/settings/power_settings_app/power_settings_app.h index d30cbaf43..65f7f7ab1 100644 --- a/applications/settings/power_settings_app/power_settings_app.h +++ b/applications/settings/power_settings_app/power_settings_app.h @@ -21,7 +21,7 @@ typedef struct { Gui* gui; SceneManager* scene_manager; ViewDispatcher* view_dispatcher; - BatteryInfo* batery_info; + BatteryInfo* battery_info; Submenu* submenu; DialogEx* dialog; PowerInfo info; diff --git a/applications/settings/power_settings_app/scenes/power_settings_scene_battery_info.c b/applications/settings/power_settings_app/scenes/power_settings_scene_battery_info.c index 5fa38df72..2b70662c8 100644 --- a/applications/settings/power_settings_app/scenes/power_settings_scene_battery_info.c +++ b/applications/settings/power_settings_app/scenes/power_settings_scene_battery_info.c @@ -11,7 +11,7 @@ static void power_settings_scene_battery_info_update_model(PowerSettingsApp* app .charge = app->info.charge, .health = app->info.health, }; - battery_info_set_data(app->batery_info, &battery_info_data); + battery_info_set_data(app->battery_info, &battery_info_data); } void power_settings_scene_battery_info_on_enter(void* context) { diff --git a/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark.c b/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark.c index 71a3df78b..8359c00be 100644 --- a/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark.c +++ b/applications/settings/storage_settings/scenes/storage_settings_scene_benchmark.c @@ -103,6 +103,9 @@ static void storage_settings_scene_benchmark(StorageSettings* app) { break; furi_string_cat_printf(app->text_string, "R %luK", bench_r_speed[i]); + + storage_common_remove(app->fs_api, BENCH_FILE); + dialog_ex_set_text( dialog_ex, furi_string_get_cstr(app->text_string), 0, 32, AlignLeft, AlignCenter); } diff --git a/applications/settings/system/system_settings.c b/applications/settings/system/system_settings.c index 5eade2115..f9abdb693 100644 --- a/applications/settings/system/system_settings.c +++ b/applications/settings/system/system_settings.c @@ -71,21 +71,21 @@ static void heap_trace_mode_changed(VariableItem* item) { furi_hal_rtc_set_heap_track_mode(heap_trace_mode_value[index]); } -const char* const mesurement_units_text[] = { +const char* const measurement_units_text[] = { "Metric", "Imperial", }; -const uint32_t mesurement_units_value[] = { +const uint32_t measurement_units_value[] = { LocaleMeasurementUnitsMetric, LocaleMeasurementUnitsImperial, }; -static void mesurement_units_changed(VariableItem* item) { +static void measurement_units_changed(VariableItem* item) { // SystemSettings* app = variable_item_get_context(item); uint8_t index = variable_item_get_current_value_index(item); - variable_item_set_current_value_text(item, mesurement_units_text[index]); - locale_set_measurement_unit(mesurement_units_value[index]); + variable_item_set_current_value_text(item, measurement_units_text[index]); + locale_set_measurement_unit(measurement_units_value[index]); } const char* const time_format_text[] = { @@ -148,13 +148,13 @@ SystemSettings* system_settings_alloc() { item = variable_item_list_add( app->var_item_list, "Units", - COUNT_OF(mesurement_units_text), - mesurement_units_changed, + COUNT_OF(measurement_units_text), + measurement_units_changed, app); value_index = value_index_uint32( - locale_get_measurement_unit(), mesurement_units_value, COUNT_OF(mesurement_units_value)); + locale_get_measurement_unit(), measurement_units_value, COUNT_OF(measurement_units_value)); variable_item_set_current_value_index(item, value_index); - variable_item_set_current_value_text(item, mesurement_units_text[value_index]); + variable_item_set_current_value_text(item, measurement_units_text[value_index]); item = variable_item_list_add( app->var_item_list, "Time Format", COUNT_OF(time_format_text), time_format_changed, app); diff --git a/assets/resources/infrared/assets/ac.ir b/assets/resources/infrared/assets/ac.ir index e55c27f30..3b25a5c86 100644 --- a/assets/resources/infrared/assets/ac.ir +++ b/assets/resources/infrared/assets/ac.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 15th Feb, 2023 -# Last Checked 15th Feb, 2023 +# Last Updated 21st Feb, 2023 +# Last Checked 21st Feb, 2023 # name: POWER type: raw @@ -1560,3 +1560,15 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 8838 3941 624 1427 514 500 515 497 541 473 540 1487 540 474 539 474 538 476 512 1538 514 1516 544 466 514 497 514 501 514 499 514 500 513 499 513 501 487 525 514 499 512 502 487 526 512 1517 542 470 487 1539 513 499 512 503 513 499 512 1513 512 +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8364 4223 621 1958 1115 1478 593 1986 1082 1566 1072 1497 576 2003 1069 1513 1069 1541 1070 1505 1069 1505 1069 1497 1070 1550 1069 1530 1045 1522 551 2028 1045 1582 1044 1530 1044 1522 1045 1530 1044 1566 1045 1530 1045 1530 550 2021 550 2064 1044 1530 1044 1523 1043 1531 1044 1566 1045 1531 1043 1531 1044 1523 1044 1575 1043 1531 1044 1523 1044 1531 1044 1567 1044 1531 1043 1531 1044 1524 1043 1575 1043 1532 1043 1524 1043 1532 1043 1568 1042 1532 1043 1532 1043 1524 1043 1576 1042 1532 1043 1524 1043 1532 1042 1569 1042 1533 1016 1558 1042 1525 1042 1577 1016 1558 523 2048 1042 1525 547 2071 1041 1533 523 2049 522 2049 522 +# +name: MODE +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8362 4223 595 1983 1116 1480 592 1987 1081 1567 1070 1524 550 2029 1043 1540 1042 1568 1043 1532 549 2030 1042 1540 1042 1568 1042 1532 1042 1532 549 2022 549 2065 1043 1528 1043 1532 1043 1524 1042 1576 1042 1532 1042 1525 548 2030 549 2082 1042 1524 1042 1533 1042 1525 1042 1576 1042 1533 1042 1525 1041 1533 1042 1569 1042 1533 1042 1533 1042 1525 1041 1577 1041 1533 1042 1525 1041 1534 1041 1569 1042 1533 1041 1534 1040 1526 1041 1578 1041 1534 1041 1526 1040 1534 1041 1570 1041 1534 1015 1560 1015 1552 1015 1604 1040 1535 1040 1527 1039 1535 1014 1597 1013 1561 1014 1561 1013 1554 519 2129 987 1554 544 2036 518 2093 987 diff --git a/assets/resources/infrared/assets/audio.ir b/assets/resources/infrared/assets/audio.ir index 1bb3c11e0..b3b56e211 100644 --- a/assets/resources/infrared/assets/audio.ir +++ b/assets/resources/infrared/assets/audio.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 15th Feb, 2023 -# Last Checked 15th Feb, 2023 +# Last Updated 21st Feb, 2023 +# Last Checked 21st Feb, 2023 # name: POWER type: parsed @@ -1913,7 +1913,7 @@ protocol: SIRC address: 0F 00 00 00 command: 15 00 00 00 # -name: Power +name: POWER type: parsed protocol: Samsung32 address: 10 00 00 00 @@ -2068,3 +2068,27 @@ type: raw frequency: 38000 duty_cycle: 0.330000 data: 325 50440 173 137541 4551 4465 530 475 529 475 529 474 530 474 530 1479 530 1479 529 476 528 477 527 1480 554 1457 551 1480 528 1481 527 477 527 478 526 478 526 478 526 4497 525 478 526 478 526 478 526 478 526 479 525 479 525 479 525 1484 525 1483 526 1484 525 1483 526 479 525 1483 526 1483 526 1483 526 479 525 479 525 479 525 479 525 1484 525 +# +name: POWER +type: parsed +protocol: NECext +address: 30 FC 00 00 +command: 10 EF 00 00 +# +name: MUTE +type: parsed +protocol: NECext +address: 30 FC 00 00 +command: 0C F3 00 00 +# +name: VOL+ +type: parsed +protocol: NECext +address: 30 FC 00 00 +command: 0D F2 00 00 +# +name: VOL- +type: parsed +protocol: NECext +address: 30 FC 00 00 +command: 17 E8 00 00 diff --git a/assets/resources/infrared/assets/fans.ir b/assets/resources/infrared/assets/fans.ir index c30f58e5e..535f96274 100644 --- a/assets/resources/infrared/assets/fans.ir +++ b/assets/resources/infrared/assets/fans.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 # Last Updated 15th Feb, 2023 -# Last Checked 15th Feb, 2023 +# Last Checked 21st Feb, 2023 # name: POWER type: raw diff --git a/assets/resources/infrared/assets/projectors.ir b/assets/resources/infrared/assets/projectors.ir index 6378f2d12..d073dccfa 100644 --- a/assets/resources/infrared/assets/projectors.ir +++ b/assets/resources/infrared/assets/projectors.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 -# Last Updated 8th Feb, 2023 -# Last Checked 15th Feb, 2023 +# Last Updated 21st Feb, 2023 +# Last Checked 21st Feb, 2023 # # ON name: POWER @@ -838,3 +838,9 @@ type: parsed protocol: NECext address: 87 45 00 00 command: 52 AD 00 00 +# +name: POWER +type: raw +frequency: 38000 +duty_cycle: 0.330000 +data: 8811 4222 530 1580 531 1579 531 507 531 507 531 507 531 508 531 508 530 1582 528 1583 527 535 503 1608 502 536 501 1609 501 537 501 1610 500 538 500 1611 499 538 500 539 500 538 500 1611 500 539 499 538 500 1611 499 539 499 1611 499 1611 500 1611 499 539 499 1611 500 1611 500 539 499 35437 8784 4252 500 1611 500 1612 500 539 500 539 500 539 500 539 500 539 500 1611 500 1612 499 539 500 1612 500 539 500 1612 499 539 500 1612 500 539 500 1612 499 539 500 539 500 539 499 1612 499 540 499 539 500 1612 499 539 500 1612 499 1613 499 1612 499 539 500 1612 500 1612 500 539 500 diff --git a/assets/resources/infrared/assets/tv.ir b/assets/resources/infrared/assets/tv.ir index e3d41b9a7..7b203b15e 100755 --- a/assets/resources/infrared/assets/tv.ir +++ b/assets/resources/infrared/assets/tv.ir @@ -1,7 +1,7 @@ Filetype: IR library file Version: 1 # Last Updated 15th Feb, 2023 -# Last Checked 15th Feb, 2023 +# Last Checked 21st Feb, 2023 # name: POWER type: parsed diff --git a/assets/resources/swd_scripts/100us.swd b/assets/resources/swd_scripts/100us.swd new file mode 100644 index 000000000..3ad89a0ab --- /dev/null +++ b/assets/resources/swd_scripts/100us.swd @@ -0,0 +1 @@ +swd_clock_delay 100 diff --git a/assets/resources/swd_scripts/call_test_1.swd b/assets/resources/swd_scripts/call_test_1.swd new file mode 100644 index 000000000..03f5575f4 --- /dev/null +++ b/assets/resources/swd_scripts/call_test_1.swd @@ -0,0 +1,6 @@ + +message 0 "gonna call call_test_2" dialog + +call call_test_2 + +message 0 "back now" dialog diff --git a/assets/resources/swd_scripts/call_test_2.swd b/assets/resources/swd_scripts/call_test_2.swd new file mode 100644 index 000000000..f358b6ece --- /dev/null +++ b/assets/resources/swd_scripts/call_test_2.swd @@ -0,0 +1,7 @@ + +# first do a beeeeeep +beep 1 + +message 0 "Seems to work" dialog + +beep 0 diff --git a/assets/resources/swd_scripts/dump_0x00000000_1k.swd b/assets/resources/swd_scripts/dump_0x00000000_1k.swd new file mode 100644 index 000000000..a8870fe30 --- /dev/null +++ b/assets/resources/swd_scripts/dump_0x00000000_1k.swd @@ -0,0 +1,6 @@ +ap_select 0 +max_tries 50 +block_size 4 +mem_dump /ext/swd_scripts/flash.bin 0x00000000 0x100000 2 +beep 1 +message 5 "Reading sucessful" diff --git a/assets/resources/swd_scripts/dump_0x00000000_4b.swd b/assets/resources/swd_scripts/dump_0x00000000_4b.swd new file mode 100644 index 000000000..a8870fe30 --- /dev/null +++ b/assets/resources/swd_scripts/dump_0x00000000_4b.swd @@ -0,0 +1,6 @@ +ap_select 0 +max_tries 50 +block_size 4 +mem_dump /ext/swd_scripts/flash.bin 0x00000000 0x100000 2 +beep 1 +message 5 "Reading sucessful" diff --git a/assets/resources/swd_scripts/dump_STM32.swd b/assets/resources/swd_scripts/dump_STM32.swd new file mode 100644 index 000000000..e675537c9 --- /dev/null +++ b/assets/resources/swd_scripts/dump_STM32.swd @@ -0,0 +1,6 @@ +ap_select 0 +max_tries 50 +block_size 1024 +mem_dump /ext/swd_scripts/flash.bin 0x08000000 0x100000 2 +beep 1 +message 0 "Reading finished" dialog diff --git a/assets/resources/swd_scripts/goto_test.swd b/assets/resources/swd_scripts/goto_test.swd new file mode 100644 index 000000000..680285653 --- /dev/null +++ b/assets/resources/swd_scripts/goto_test.swd @@ -0,0 +1,7 @@ +beep 1 +goto l2 +.label l1 +beep 0 +.label l2 +beep 1 +goto l1 diff --git a/assets/resources/swd_scripts/halt.swd b/assets/resources/swd_scripts/halt.swd new file mode 100644 index 000000000..6aad4c194 --- /dev/null +++ b/assets/resources/swd_scripts/halt.swd @@ -0,0 +1,11 @@ + +# make sure errors do not cause a script abort +errors ignore + +message 0 "HAMMER TIME! Trying to halt CPU" +ap_select 0 + +# loop writing the halt bits +.label l1 +mem_write 0xE000EDF0 0xA05F0003 +goto l1 diff --git a/assets/resources/swd_scripts/reset.swd b/assets/resources/swd_scripts/reset.swd new file mode 100644 index 000000000..1872757fb --- /dev/null +++ b/assets/resources/swd_scripts/reset.swd @@ -0,0 +1,8 @@ +errors ignore +status 0 +message 0 "HAMMER TIME! Try to halt the CPU" +.label l1 +ap_select 0 +mem_write 0xE000EDF0 0xA05F0001 +mem_write 0xE000ED0C 0x05FA0004 +goto l1 diff --git a/assets/resources/swd_scripts/test_write.swd b/assets/resources/swd_scripts/test_write.swd new file mode 100644 index 000000000..df69461fd --- /dev/null +++ b/assets/resources/swd_scripts/test_write.swd @@ -0,0 +1,3 @@ +mem_write 0x20002000 0xdeadbeef +mem_write 0xE000EDF0 0xA05F0001 +mem_write 0xE000EDF0 0xA05F0007 diff --git a/fbt_options.py b/fbt_options.py index d3670b01a..780e6fe92 100644 --- a/fbt_options.py +++ b/fbt_options.py @@ -32,7 +32,7 @@ COPRO_STACK_TYPE = "ble_light" # Leave 0 to let scripts automatically calculate it COPRO_STACK_ADDR = "0x0" -# If you override COPRO_CUBE_DIR on commandline, override this as well +# If you override COPRO_CUBE_DIR on command-line, override this as well COPRO_STACK_BIN_DIR = posixpath.join( COPRO_CUBE_DIR, "Projects", diff --git a/firmware/targets/f7/api_symbols.csv b/firmware/targets/f7/api_symbols.csv index eca5f1cf3..2db05fc50 100644 --- a/firmware/targets/f7/api_symbols.csv +++ b/firmware/targets/f7/api_symbols.csv @@ -1,5 +1,5 @@ entry,status,name,type,params -Version,+,14.0,, +Version,+,14.1,, Header,+,applications/services/bt/bt_service/bt.h,, Header,+,applications/services/cli/cli.h,, Header,+,applications/services/cli/cli_vcp.h,, @@ -1221,6 +1221,7 @@ Function,+,furi_hal_mpu_protect_disable,void,FuriHalMpuRegion Function,+,furi_hal_mpu_protect_no_access,void,"FuriHalMpuRegion, uint32_t, FuriHalMPURegionSize" Function,+,furi_hal_mpu_protect_read_only,void,"FuriHalMpuRegion, uint32_t, FuriHalMPURegionSize" Function,+,furi_hal_nfc_activate_nfca,_Bool,"uint32_t, uint32_t*" +Function,-,furi_hal_nfc_deinit,void, Function,+,furi_hal_nfc_detect,_Bool,"FuriHalNfcDevData*, uint32_t" Function,+,furi_hal_nfc_emulate_nfca,_Bool,"uint8_t*, uint8_t, uint8_t*, uint8_t, FuriHalNfcEmulateCallback, void*, uint32_t" Function,+,furi_hal_nfc_exit_sleep,void, diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.c b/firmware/targets/f7/furi_hal/furi_hal_nfc.c index ce81fd058..8910d887b 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc.c +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc.c @@ -24,13 +24,29 @@ FuriEventFlag* event = NULL; #define FURI_HAL_NFC_UID_INCOMPLETE (0x04) void furi_hal_nfc_init() { + furi_assert(!event); + event = furi_event_flag_alloc(); + ReturnCode ret = rfalNfcInitialize(); if(ret == ERR_NONE) { furi_hal_nfc_start_sleep(); - event = furi_event_flag_alloc(); FURI_LOG_I(TAG, "Init OK"); } else { - FURI_LOG_W(TAG, "Initialization failed, RFAL returned: %d", ret); + FURI_LOG_W(TAG, "Init Failed, RFAL returned: %d", ret); + } +} + +void furi_hal_nfc_deinit() { + ReturnCode ret = rfalDeinitialize(); + if(ret == ERR_NONE) { + FURI_LOG_I(TAG, "Deinit OK"); + } else { + FURI_LOG_W(TAG, "Deinit Failed, RFAL returned: %d", ret); + } + + if(event) { + furi_event_flag_free(event); + event = NULL; } } diff --git a/firmware/targets/f7/furi_hal/furi_hal_nfc.h b/firmware/targets/f7/furi_hal/furi_hal_nfc.h index d3f6de602..dc3f873f3 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_nfc.h +++ b/firmware/targets/f7/furi_hal/furi_hal_nfc.h @@ -101,6 +101,10 @@ typedef struct { */ void furi_hal_nfc_init(); +/** Deinit nfc + */ +void furi_hal_nfc_deinit(); + /** Check if nfc worker is busy * * @return true if busy diff --git a/firmware/targets/f7/furi_hal/furi_hal_uart.h b/firmware/targets/f7/furi_hal/furi_hal_uart.h index 07211db8b..3ba4dc483 100644 --- a/firmware/targets/f7/furi_hal/furi_hal_uart.h +++ b/firmware/targets/f7/furi_hal/furi_hal_uart.h @@ -31,7 +31,7 @@ typedef enum { /** * Init UART - * Configures GPIO to UART function, сonfigures UART hardware, enables UART hardware + * Configures GPIO to UART function, configures UART hardware, enables UART hardware * @param channel UART channel * @param baud baudrate */ diff --git a/lib/nfc/nfc_worker.c b/lib/nfc/nfc_worker.c index 4138bf033..dc2d5f9a4 100644 --- a/lib/nfc/nfc_worker.c +++ b/lib/nfc/nfc_worker.c @@ -61,6 +61,8 @@ void nfc_worker_start( while(furi_hal_nfc_is_busy()) { furi_delay_ms(10); } + furi_hal_nfc_deinit(); + furi_hal_nfc_init(); nfc_worker->callback = callback; nfc_worker->context = context; diff --git a/lib/subghz/subghz_file_encoder_worker.c b/lib/subghz/subghz_file_encoder_worker.c index a8c6519ef..8bc6e8446 100644 --- a/lib/subghz/subghz_file_encoder_worker.c +++ b/lib/subghz/subghz_file_encoder_worker.c @@ -16,7 +16,7 @@ struct SubGhzFileEncoderWorker { FlipperFormat* flipper_format; volatile bool worker_running; - volatile bool worker_stoping; + volatile bool worker_stopping; bool level; bool is_storage_slow; FuriString* str_data; @@ -105,7 +105,7 @@ LevelDuration subghz_file_encoder_worker_get_level_duration(void* context) { } else if(duration == 0) { //-V547 level_duration = level_duration_reset(); FURI_LOG_I(TAG, "Stop transmission"); - instance->worker_stoping = true; + instance->worker_stopping = true; } return level_duration; } else { @@ -142,7 +142,7 @@ static int32_t subghz_file_encoder_worker_thread(void* context) { //skip the end of the previous line "\n" stream_seek(stream, 1, StreamOffsetFromCurrent); res = true; - instance->worker_stoping = false; + instance->worker_stopping = false; FURI_LOG_I(TAG, "Start transmission"); } while(0); @@ -174,7 +174,7 @@ static int32_t subghz_file_encoder_worker_thread(void* context) { } FURI_LOG_I(TAG, "End transmission"); while(instance->worker_running) { - if(instance->worker_stoping) { + if(instance->worker_stopping) { if(instance->callback_end) instance->callback_end(instance->context_end); } furi_delay_ms(50); @@ -198,7 +198,7 @@ SubGhzFileEncoderWorker* subghz_file_encoder_worker_alloc() { instance->str_data = furi_string_alloc(); instance->file_path = furi_string_alloc(); instance->level = false; - instance->worker_stoping = true; + instance->worker_stopping = true; return instance; } diff --git a/lib/subghz/subghz_tx_rx_worker.c b/lib/subghz/subghz_tx_rx_worker.c index e380fc967..21568dab1 100644 --- a/lib/subghz/subghz_tx_rx_worker.c +++ b/lib/subghz/subghz_tx_rx_worker.c @@ -16,7 +16,7 @@ struct SubGhzTxRxWorker { FuriStreamBuffer* stream_rx; volatile bool worker_running; - volatile bool worker_stoping; + volatile bool worker_stopping; SubGhzTxRxWorkerStatus status; @@ -166,7 +166,7 @@ static int32_t subghz_tx_rx_worker_thread(void* context) { subghz_tx_rx_worker_tx(instance, data, size_tx); } } else { - //recive + //receive if(subghz_tx_rx_worker_rx(instance, data, size_rx)) { if(furi_stream_buffer_spaces_available(instance->stream_rx) >= size_rx[0]) { if(instance->callback_have_read && @@ -211,7 +211,7 @@ SubGhzTxRxWorker* subghz_tx_rx_worker_alloc() { furi_stream_buffer_alloc(sizeof(uint8_t) * SUBGHZ_TXRX_WORKER_BUF_SIZE, sizeof(uint8_t)); instance->status = SubGhzTxRxWorkerStatusIDLE; - instance->worker_stoping = true; + instance->worker_stopping = true; return instance; } diff --git a/scripts/fbt_tools/fbt_dist.py b/scripts/fbt_tools/fbt_dist.py index f0b443486..c0eca0d2a 100644 --- a/scripts/fbt_tools/fbt_dist.py +++ b/scripts/fbt_tools/fbt_dist.py @@ -4,7 +4,7 @@ from SCons.Script import Mkdir from SCons.Defaults import Touch -def GetProjetDirName(env, project=None): +def GetProjectDirName(env, project=None): parts = [f"f{env['TARGET_HW']}"] if project: parts.append(project) @@ -21,7 +21,7 @@ def GetProjetDirName(env, project=None): def create_fw_build_targets(env, configuration_name): - flavor = GetProjetDirName(env, configuration_name) + flavor = GetProjectDirName(env, configuration_name) build_dir = env.Dir("build").Dir(flavor) return env.SConscript( "firmware.scons", @@ -49,7 +49,7 @@ def AddFwProject(env, base_env, fw_type, fw_env_key): ], ) - env.Replace(DIST_DIR=env.GetProjetDirName()) + env.Replace(DIST_DIR=env.GetProjectDirName()) return project_env @@ -115,7 +115,7 @@ def generate(env): env.AddMethod(AddFwProject) env.AddMethod(DistCommand) env.AddMethod(AddOpenOCDFlashTarget) - env.AddMethod(GetProjetDirName) + env.AddMethod(GetProjectDirName) env.AddMethod(AddJFlashTarget) env.AddMethod(AddUsbFlashTarget) diff --git a/scripts/fbt_tools/fbt_help.py b/scripts/fbt_tools/fbt_help.py index afdb36665..1b2903058 100644 --- a/scripts/fbt_tools/fbt_help.py +++ b/scripts/fbt_tools/fbt_help.py @@ -26,7 +26,7 @@ Other: cli: Open a Flipper CLI session over USB firmware_cdb, updater_cdb: - Generate сompilation_database.json + Generate compilation_database.json lint, lint_py: run linters format, format_py: diff --git a/scripts/fbt_tools/fbt_hwtarget.py b/scripts/fbt_tools/fbt_hwtarget.py index b4e1e58ac..7deb3e87f 100644 --- a/scripts/fbt_tools/fbt_hwtarget.py +++ b/scripts/fbt_tools/fbt_hwtarget.py @@ -93,7 +93,7 @@ class HardwareTargetLoader: sdk_headers = [] seen_sdk_headers = set(self.excluded_headers) for sdk_path in self.sdk_header_paths: - # dirty, but fast - exclude headers from overlayed targets by name + # dirty, but fast - exclude headers from overlaid targets by name # proper way would be to use relative paths, but names will do for now for header in self.env.GlobRecursive("*.h", sdk_path, "*_i.h"): if header.name not in seen_sdk_headers: diff --git a/scripts/toolchain/fbtenv.cmd b/scripts/toolchain/fbtenv.cmd index dce5f37c4..8587f6d0e 100644 --- a/scripts/toolchain/fbtenv.cmd +++ b/scripts/toolchain/fbtenv.cmd @@ -13,7 +13,7 @@ if not ["%FBT_NOENV%"] == [""] ( exit /b 0 ) -set "FLIPPER_TOOLCHAIN_VERSION=19" +set "FLIPPER_TOOLCHAIN_VERSION=21" if ["%FBT_TOOLCHAIN_ROOT%"] == [""] ( set "FBT_TOOLCHAIN_ROOT=%FBT_ROOT%\toolchain\x86_64-windows" diff --git a/scripts/toolchain/fbtenv.sh b/scripts/toolchain/fbtenv.sh index c65d68ea4..cefa55d7e 100755 --- a/scripts/toolchain/fbtenv.sh +++ b/scripts/toolchain/fbtenv.sh @@ -5,7 +5,7 @@ # public variables DEFAULT_SCRIPT_PATH="$(pwd -P)"; SCRIPT_PATH="${SCRIPT_PATH:-$DEFAULT_SCRIPT_PATH}"; -FBT_TOOLCHAIN_VERSION="${FBT_TOOLCHAIN_VERSION:-"19"}"; +FBT_TOOLCHAIN_VERSION="${FBT_TOOLCHAIN_VERSION:-"21"}"; FBT_TOOLCHAIN_PATH="${FBT_TOOLCHAIN_PATH:-$SCRIPT_PATH}"; FBT_VERBOSE="${FBT_VERBOSE:-""}"; @@ -43,10 +43,19 @@ fbtenv_restore_env() PROMPT="$(echo "$PROMPT" | sed 's/\[fbt\]//g')"; fi + if [ -n "$SAVED_SSL_CERT_FILE" ]; then + export SSL_CERT_FILE="$SAVED_SSL_CERT_FILE"; + export REQUESTS_CA_BUNDLE="$SAVED_REQUESTS_CA_BUNDLE"; + else + unset SSL_CERT_FILE; + unset REQUESTS_CA_BUNDLE; + fi export PYTHONNOUSERSITE="$SAVED_PYTHONNOUSERSITE"; export PYTHONPATH="$SAVED_PYTHONPATH"; export PYTHONHOME="$SAVED_PYTHONHOME"; + unset SAVED_SSL_CERT_FILE; + unset SAVED_REQUESTS_CA_BUNDLE; unset SAVED_PYTHONNOUSERSITE; unset SAVED_PYTHONPATH; unset SAVED_PYTHONHOME; @@ -309,10 +318,14 @@ fbtenv_main() PATH="$TOOLCHAIN_ARCH_DIR/openssl/bin:$PATH"; export PATH; + export SAVED_SSL_CERT_FILE="${SSL_CERT_FILE:-""}"; + export SAVED_REQUESTS_CA_BUNDLE="${REQUESTS_CA_BUNDLE:-""}"; export SAVED_PYTHONNOUSERSITE="${PYTHONNOUSERSITE:-""}"; export SAVED_PYTHONPATH="${PYTHONPATH:-""}"; export SAVED_PYTHONHOME="${PYTHONHOME:-""}"; + export SSL_CERT_FILE="$TOOLCHAIN_ARCH_DIR/python/lib/python3.11/site-packages/certifi/cacert.pem"; + export REQUESTS_CA_BUNDLE="$SSL_CERT_FILE"; export PYTHONNOUSERSITE=1; export PYTHONPATH=; export PYTHONHOME=;