diff --git a/Canbus_app/app_user.h b/Canbus_app/app_user.h index 357620d..afe84b3 100644 --- a/Canbus_app/app_user.h +++ b/Canbus_app/app_user.h @@ -80,6 +80,7 @@ typedef enum { SenderOption, ObdiiOption, ReadLOGOption, + PlayLOGOption, SettingsOption, AboutUsOption, } MainMenuOptions; @@ -91,6 +92,7 @@ typedef enum { SettingsOptionEvent, ObdiiOptionEvent, ReadLOGOptionEvent, + PlayLOGOptionEvent, AboutUsEvent, } MainMenuEvents; diff --git a/Canbus_app/scenes/mainMenu.c b/Canbus_app/scenes/mainMenu.c index 15ffc31..88c55cb 100644 --- a/Canbus_app/scenes/mainMenu.c +++ b/Canbus_app/scenes/mainMenu.c @@ -71,8 +71,8 @@ void basic_scenes_menu_callback(void* context, uint32_t index) { scene_manager_handle_custom_event(app->scene_manager, SenderOptionEvent); break; - case PlayerOption: - scene_manager_handle_custom_event(app->scene_manager, PlayerOptionEvent); + case PlayLOGOption: + scene_manager_handle_custom_event(app->scene_manager, app_scene_play_logs); break; case SettingsOption: @@ -109,7 +109,7 @@ void app_scene_menu_on_enter(void* context) { submenu_add_item(app->submenu, "Sender", SenderOption, basic_scenes_menu_callback, app); - submenu_add_item(app->submenu, "Player", PlayerOption, basic_scenes_menu_callback, app); + submenu_add_item(app->submenu, "Player", PlayLOGOption, basic_scenes_menu_callback, app); submenu_add_item(app->submenu, "Scanner OBD2", ObdiiOption, basic_scenes_menu_callback, app); @@ -143,8 +143,8 @@ bool app_scene_menu_on_event(void* context, SceneManagerEvent event) { scene_manager_next_scene(app->scene_manager, app_scene_sender_option); break; - case PlayerOptionEvent: - scene_manager_next_scene(app->scene_manager, app_scene_player_option); + case PlayLOGOptionEvent: + scene_manager_next_scene(app->scene_manager, app_scene_play_logs); break; case SettingsOptionEvent: diff --git a/Canbus_app/scenes/playLogs.c b/Canbus_app/scenes/playLogs.c new file mode 100644 index 0000000..393908b --- /dev/null +++ b/Canbus_app/scenes/playLogs.c @@ -0,0 +1,129 @@ +#include "../app_user.h" + +uint32_t hex_to_int(const char* hex_str) { + uint32_t result = 0; + sscanf(hex_str, "%x", &result); + return result; +} + +void send_data_frame(void* context) { + + App* app = context; + + app->mcp_can->mode = MCP_NORMAL; + ERROR_CAN debug = ERROR_OK; + ERROR_CAN error = ERROR_OK; + debug = mcp2515_init(app->mcp_can); + + //#define PATHAPP "apps_data/canbus" + //DialogsApp* dialogs_tx; model or app? + //Storage* storage_tx; + //File* file_tx; + + FuriString* predefined_filepath = furi_string_alloc_set_str(PATHAPP); + FuriString* selected_filepath = furi_string_alloc(); + DialogsFileBrowserOptions browser_options; + dialog_file_browser_set_basic_options(&browser_options, LORA_LOG_FILE_EXTENSION, NULL); + browser_options.base_path = PATHAPP; + + dialog_file_browser_show(model->dialogs_tx, selected_filepath, predefined_filepath, &browser_options); + + if(storage_file_open( + model->file_tx, furi_string_get_cstr(selected_filepath), FSAM_READ, FSOM_OPEN_EXISTING)) { + + model->flag_tx_file = true; + model->test = 1; + + char buffer[256]; + size_t buffer_index = 0; + size_t bytes_read; + char c; + + while ((bytes_read = storage_file_read(model->file_tx, &c, 1)) > 0 && model->flag_signal) { + if (c == '\n' || buffer_index >= 256 - 1) { + buffer[buffer_index] = '\0'; + + FURI_LOG_E(TAG,"%s\n", buffer); + + buffer[sizeof(buffer) - 1] = '\0'; // Ensure the string is null-terminated + + CANFRAME frame_to_send = {0}; // Initialize all fields to 0 + char *saveptr; + char *token; + + // Skip the timestamp + token = strtok_r(buffer, " ", &saveptr); + if (!token) return; + + // CAN bus ID + token = strtok_r(NULL, " ", &saveptr); + if (!token) return; + frame_to_send.canId = hex_to_int(token); + + // Data length + token = strtok_r(NULL, " ", &saveptr); + if (!token) return; + frame_to_send.data_length = (uint8_t)atoi(token); + + // Fill the data buffer + for (int i = 0; i < frame_to_send.data_length && i < MAX_LEN; i++) { + token = strtok_r(NULL, " ", &saveptr); + if (!token) break; + frame_to_send.buffer[i] = (uint8_t)hex_to_int(token); + } + + if (debug == ERROR_OK) { + error = send_can_frame(app->mcp_can, app->frame_to_send); + furi_delay_ms(500); + + if (error != ERROR_OK) + scene_manager_handle_custom_event(app->scene_manager, SEND_ERROR); + else + scene_manager_handle_custom_event(app->scene_manager, SEND_OK); + } else { + scene_manager_handle_custom_event(app->scene_manager, DEVICE_NO_CONNECTED); + } + + buffer_index = 0; + } else { + buffer[buffer_index++] = c; + } + } + + } else { + dialog_message_show_storage_error(model->dialogs_tx, "Cannot open File"); + } + storage_file_close(model->file_tx); + model->test = 0; + furi_string_free(selected_filepath); + furi_string_free(predefined_filepath); + + furi_hal_gpio_write(pin_led, true); + furi_delay_ms(50); + furi_hal_gpio_write(pin_led, false); + + model->flag_tx_file = false; + +} + +void app_scene_play_logs_on_enter(void* context) { + App* app = context; + text_box_set_font(app->textBox, TextBoxFontText); + text_box_reset(app->textBox); + view_dispatcher_switch_to_view(app->view_dispatcher, TextBoxView); + text_box_set_text(app->textBox, furi_string_get_cstr(app->text)); +} + +bool app_scene_play_logs_on_event(void* context, SceneManagerEvent event) { + App* app = context; + bool consumed = false; + UNUSED(app); + UNUSED(event); + return consumed; +} + +void app_scene_play_logs_on_exit(void* context) { + App* app = context; + furi_string_reset(app->text); + text_box_reset(app->textBox); +} diff --git a/Canbus_app/scenes/playerOption.txt b/Canbus_app/scenes/playerOption.txt new file mode 100644 index 0000000..c2ea8be --- /dev/null +++ b/Canbus_app/scenes/playerOption.txt @@ -0,0 +1,512 @@ +#include "../app_user.h" + +typedef enum { + PLAY_OK, + PLAY_ERROR, +} player_status; + +// Threads To work +// ------------------------------------------------------------------------------------ + +static int32_t player_on_work(void* context) { + App* app = context; + app->mcp_can->mode = MCP_NORMAL; + ERROR_CAN debug = ERROR_OK; + ERROR_CAN error = ERROR_OK; + debug = mcp2515_init(app->mcp_can); + + furi_delay_ms(10); + + if (debug == ERROR_OK) { + error = send_can_frame(app->mcp_can, app->frame_to_send); + furi_delay_ms(500); + + if (error != ERROR_OK) + scene_manager_handle_custom_event(app->scene_manager, PLAY_ERROR); + else + scene_manager_handle_custom_event(app->scene_manager, PLAY_OK); + } else { + scene_manager_handle_custom_event(app->scene_manager, DEVICE_NO_CONNECTED); + } + + free_mcp2515(app->mcp_can); + return 0; +} + +// Scenes +// --------------------------------------------------------------------------------------------- + +// Option callback using button OK +void callback_input_player_options(void* context, uint32_t index) { + App* app = context; + app->player_selected_item = index; + switch (index) { + case PLAY_MESSAGES: + scene_manager_next_scene(app->scene_manager, app_scene_play_messages); + break; + case CHOOSE_ID: + if (app->num_of_devices > 0) { + scene_manager_next_scene(app->scene_manager, app_scene_id_list_option); + } else { + scene_manager_next_scene(app->scene_manager, + app_scene_warning_log_player); + } + break; + case SET_ID: + scene_manager_set_scene_state(app->scene_manager, + app_scene_input_text_option, SET_ID); + scene_manager_next_scene(app->scene_manager, app_scene_input_text_option); + break; + + case SET_DATA: + scene_manager_set_scene_state(app->scene_manager, + app_scene_input_text_option, SET_DATA); + scene_manager_next_scene(app->scene_manager, app_scene_input_text_option); + break; + + case SET_FIRST_DATA: + scene_manager_set_scene_state( + app->scene_manager, app_scene_input_text_option, SET_FIRST_DATA); + scene_manager_next_scene(app->scene_manager, app_scene_input_text_option); + break; + + case SET_SECOND_DATA: + scene_manager_set_scene_state( + app->scene_manager, app_scene_input_text_option, SET_SECOND_DATA); + scene_manager_next_scene(app->scene_manager, app_scene_input_text_option); + break; + + case SET_THIRD_DATA: + scene_manager_set_scene_state( + app->scene_manager, app_scene_input_text_option, SET_THIRD_DATA); + scene_manager_next_scene(app->scene_manager, app_scene_input_text_option); + break; + + case SET_FOURTH_DATA: + scene_manager_set_scene_state( + app->scene_manager, app_scene_input_text_option, SET_FOURTH_DATA); + scene_manager_next_scene(app->scene_manager, app_scene_input_text_option); + break; + + case SET_FIFTH_DATA: + scene_manager_set_scene_state( + app->scene_manager, app_scene_input_text_option, SET_FIFTH_DATA); + scene_manager_next_scene(app->scene_manager, app_scene_input_text_option); + break; + + case SET_SIXTH_DATA: + scene_manager_set_scene_state( + app->scene_manager, app_scene_input_text_option, SET_SIXTH_DATA); + scene_manager_next_scene(app->scene_manager, app_scene_input_text_option); + break; + + case SET_SEVENTH_DATA: + scene_manager_set_scene_state( + app->scene_manager, app_scene_input_text_option, SET_SEVENTH_DATA); + scene_manager_next_scene(app->scene_manager, app_scene_input_text_option); + break; + + case SET_EIGHTH_DATA: + scene_manager_set_scene_state( + app->scene_manager, app_scene_input_text_option, SET_EIGHTH_DATA); + scene_manager_next_scene(app->scene_manager, app_scene_input_text_option); + break; + + default: + break; + } +} + +// Options Callback +void callback_player_options(VariableItem* item) { + App* app = variable_item_get_context(item); + uint8_t selected_index = + variable_item_list_get_selected_item_index(app->varList); + uint8_t index_item = variable_item_get_current_value_index(item); + + switch (selected_index) { + case SET_DATA_LENGHT: + furi_string_reset(app->text); + furi_string_cat_printf(app->text, "%u", index_item); + variable_item_set_current_value_text(item, + furi_string_get_cstr(app->text)); + app->frame_to_send->data_lenght = index_item; + break; + case SET_REQ: + furi_string_reset(app->text); + furi_string_cat_printf(app->text, "%u", index_item); + variable_item_set_current_value_text(item, + furi_string_get_cstr(app->text)); + app->frame_to_send->req = index_item; + break; + default: + break; + } +} + +// Player Scene On enter +void app_scene_player_on_enter(void* context) { + App* app = context; + VariableItem* item; + + uint8_t data_lenght = app->frame_to_send->data_lenght; + uint32_t can_id = app->frame_to_send->canId; + uint8_t request = app->frame_to_send->req; + + app->player_id_compose[3] = can_id; + app->player_id_compose[2] = can_id >> 8; + app->player_id_compose[1] = can_id >> 16; + app->player_id_compose[0] = can_id >> 24; + + variable_item_list_reset(app->varList); + + // 0 + item = variable_item_list_add(app->varList, "PLAY MESSAGES", 0, + callback_player_options, app); + variable_item_set_current_value_index(item, 0); + + // 1 + item = variable_item_list_add(app->varList, "Choose Id", 0, + callback_player_options, app); + variable_item_set_current_value_index(item, 0); + variable_item_set_current_value_text(item, "SEARCH"); + + // 2 + item = variable_item_list_add(app->varList, "Id", 0, callback_player_options, + app); + variable_item_set_current_value_index(item, 0); + + furi_string_reset(app->text); + furi_string_cat_printf(app->text, "0x%lx", can_id); + variable_item_set_current_value_text(item, furi_string_get_cstr(app->text)); + + // 3 + item = variable_item_list_add(app->varList, "DLC", 9, callback_player_options, + app); + variable_item_set_current_value_index(item, data_lenght); + + furi_string_reset(app->text); + furi_string_cat_printf(app->text, "%u", data_lenght); + variable_item_set_current_value_text(item, furi_string_get_cstr(app->text)); + + // 4 + item = variable_item_list_add(app->varList, "Request", 2, + callback_player_options, app); + variable_item_set_current_value_index(item, request); + + furi_string_reset(app->text); + furi_string_cat_printf(app->text, "%u", request); + variable_item_set_current_value_text(item, furi_string_get_cstr(app->text)); + + // 5 + item = variable_item_list_add(app->varList, "CLIC TO SET DATA", 0, + callback_player_options, app); + variable_item_set_current_value_index(item, 0); + + // 6 + item = variable_item_list_add(app->varList, "BYTE [0]", 0, + callback_player_options, app); + variable_item_set_current_value_index(item, 0); + + furi_string_reset(app->text); + furi_string_cat_printf(app->text, "0x%x", app->frame_to_send->buffer[0]); + variable_item_set_current_value_text(item, furi_string_get_cstr(app->text)); + + // 7 + item = variable_item_list_add(app->varList, "BYTE [1]", 0, + callback_player_options, app); + variable_item_set_current_value_index(item, 0); + + furi_string_reset(app->text); + furi_string_cat_printf(app->text, "0x%x", app->frame_to_send->buffer[1]); + variable_item_set_current_value_text(item, furi_string_get_cstr(app->text)); + + // 8 + item = variable_item_list_add(app->varList, "BYTE [2]", 0, + callback_player_options, app); + variable_item_set_current_value_index(item, 0); + + furi_string_reset(app->text); + furi_string_cat_printf(app->text, "0x%x", app->frame_to_send->buffer[2]); + variable_item_set_current_value_text(item, furi_string_get_cstr(app->text)); + + // 9 + item = variable_item_list_add(app->varList, "BYTE [3]", 0, + callback_player_options, app); + variable_item_set_current_value_index(item, 0); + + furi_string_reset(app->text); + furi_string_cat_printf(app->text, "0x%x", app->frame_to_send->buffer[3]); + variable_item_set_current_value_text(item, furi_string_get_cstr(app->text)); + + // 10 + item = variable_item_list_add(app->varList, "BYTE [4]", 0, + callback_player_options, app); + variable_item_set_current_value_index(item, 0); + + furi_string_reset(app->text); + furi_string_cat_printf(app->text, "0x%x", app->frame_to_send->buffer[4]); + variable_item_set_current_value_text(item, furi_string_get_cstr(app->text)); + + // 11 + item = variable_item_list_add(app->varList, "BYTE [5]", 0, + callback_player_options, app); + variable_item_set_current_value_index(item, 0); + + furi_string_reset(app->text); + furi_string_cat_printf(app->text, "0x%x", app->frame_to_send->buffer[5]); + variable_item_set_current_value_text(item, furi_string_get_cstr(app->text)); + + // 12 + item = variable_item_list_add(app->varList, "BYTE [6]", 0, + callback_player_options, app); + variable_item_set_current_value_index(item, 0); + + furi_string_reset(app->text); + furi_string_cat_printf(app->text, "0x%x", app->frame_to_send->buffer[6]); + variable_item_set_current_value_text(item, furi_string_get_cstr(app->text)); + + // 13 + item = variable_item_list_add(app->varList, "BYTE [7]", 0, + callback_player_options, app); + variable_item_set_current_value_index(item, 0); + + furi_string_reset(app->text); + furi_string_cat_printf(app->text, "0x%x", app->frame_to_send->buffer[7]); + variable_item_set_current_value_text(item, furi_string_get_cstr(app->text)); + + variable_item_list_set_enter_callback(app->varList, + callback_input_player_options, app); + variable_item_list_set_selected_item(app->varList, app->player_selected_item); + view_dispatcher_switch_to_view(app->view_dispatcher, VarListView); +} + +bool app_scene_player_on_event(void* context, SceneManagerEvent event) { + App* app = context; + bool consumed = false; + if (event.type == SceneManagerEventTypeCustom) { + switch (event.event) { + case SET_ID: + scene_manager_next_scene(app->scene_manager, + app_scene_input_text_option); + consumed = true; + break; + + default: + break; + } + } + return consumed; +} + +void app_scene_player_on_exit(void* context) { + App* app = context; + variable_item_list_reset(app->varList); +} + +// ----------------------------- SCENE TO PLAY THE FRAMES --------------------- + +void app_scene_play_messages_on_enter(void* context) { + App* app = context; + + widget_reset(app->widget); + widget_add_string_element(app->widget, 65, 20, AlignCenter, AlignCenter, + FontPrimary, "Wait to Play it Messages..."); + + view_dispatcher_switch_to_view(app->view_dispatcher, ViewWidget); + + app->thread = + furi_thread_alloc_ex("player_on_work", 1024, player_on_work, app); + furi_thread_start(app->thread); +} + +bool app_scene_play_messages_on_event(void* context, SceneManagerEvent event) { + App* app = context; + bool consumed = false; + + if (event.type == SceneManagerEventTypeCustom) { + switch (event.event) { + case PLAY_OK: + widget_reset(app->widget); + widget_add_string_element(app->widget, 65, 20, AlignCenter, AlignCenter, + FontPrimary, "FILE PLAY OK"); + break; + + case PLAY_ERROR: + widget_reset(app->widget); + widget_add_string_element(app->widget, 65, 20, AlignCenter, AlignCenter, + FontPrimary, "FILE PLAY ERROR"); + break; + + case DEVICE_NO_CONNECTED: + widget_reset(app->widget); + + widget_add_string_element(app->widget, 65, 20, AlignCenter, AlignBottom, + FontPrimary, "DEVICE NO"); + + widget_add_string_element(app->widget, 65, 35, AlignCenter, AlignBottom, + FontPrimary, "CONNECTED"); + break; + + default: + break; + } + } + + return consumed; +} + +void app_scene_play_messages_on_exit(void* context) { + App* app = context; + furi_thread_join(app->thread); + furi_thread_free(app->thread); + + widget_reset(app->widget); +} + +// ---------------------------- WARNING TO GET THE ID'S ------------------------ + +void app_scene_warning_log_on_enter(void* context) { + App* app = context; + widget_reset(app->widget); + + widget_add_string_element(app->widget, 65, 20, AlignCenter, AlignBottom, + FontPrimary, "W A R N I N G"); + + widget_add_string_element(app->widget, 65, 40, AlignCenter, AlignBottom, + FontSecondary, "First go to the Sniffing option"); + widget_add_string_element(app->widget, 65, 50, AlignCenter, AlignBottom, + FontSecondary, "in the menu and get the Id's"); + + view_dispatcher_switch_to_view(app->view_dispatcher, ViewWidget); +} + +bool app_scene_warning_log_on_event(void* context, SceneManagerEvent event) { + UNUSED(context); + UNUSED(event); + bool consumed = false; + + return consumed; +} + +void app_scene_warning_log_on_exit(void* context) { + App* app = context; + widget_reset(app->widget); +} + +// ---------------------------- MENU OF THE CAN ID's --------------------------- + +void menu_ids_callback(void* context, uint32_t index) { + App* app = context; + app->frame_to_send->canId = app->frameArray[index].canId; + app->frame_to_send->data_lenght = app->frameArray[index].data_lenght; + app->frame_to_send->ext = app->frameArray[index].ext; + app->frame_to_send->req = app->frameArray[index].req; + + for (uint8_t i = 0; i < (app->frame_to_send->data_lenght); i++) { + app->frame_to_send->buffer[i] = app->frameArray[index].buffer[i]; + } + + scene_manager_handle_custom_event(app->scene_manager, ReturnEvent); +} + +void app_scene_id_list_on_enter(void* context) { + App* app = context; + submenu_reset(app->submenu); + submenu_set_header(app->submenu, "CAN ADDRESS TO PLAY"); + + for (uint8_t i = 0; i < app->num_of_devices; i++) { + furi_string_reset(app->text); + furi_string_cat_printf(app->text, "0x%lx", app->frameArray[i].canId); + submenu_add_item(app->submenu, furi_string_get_cstr(app->text), i, + menu_ids_callback, app); + } + + view_dispatcher_switch_to_view(app->view_dispatcher, SubmenuView); +} + +bool app_scene_id_list_on_event(void* context, SceneManagerEvent event) { + App* app = context; + bool consumed = false; + + if (event.type == SceneManagerEventTypeCustom) { + scene_manager_previous_scene(app->scene_manager); + consumed = true; + } + return consumed; +} + +void app_scene_id_list_on_exit(void* context) { + App* app = context; + submenu_reset(app->submenu); +} + +// ---------------------------- TO SET THE VALUE OF THE FRAME ------------------ + +void input_byte_payer_callback(void* context) { + App* app = context; + app->frame_to_send->canId = + app->player_id_compose[3] | (app->player_id_compose[2] << 8) | + (app->player_id_compose[1] << 16) | (app->player_id_compose[0] << 24); + scene_manager_handle_custom_event(app->scene_manager, ReturnEvent); +} + +void app_scene_input_text_on_enter(void* context) { + App* app = context; + ByteInput* scene = app->input_byte_value; + + uint32_t state = scene_manager_get_scene_state(app->scene_manager, + app_scene_input_text_option); + + app->player_selected_item = state; + + switch (state) { + case SET_ID: + byte_input_set_result_callback(scene, input_byte_player_callback, NULL, + app, app->player_id_compose, 4); + byte_input_set_header_text(app->input_byte_value, "SET ADDRESS"); + break; + + case SET_DATA: + byte_input_set_result_callback(scene, input_byte_player_callback, NULL, + app, app->frame_to_send->buffer, 8); + byte_input_set_header_text(app->input_byte_value, "SET ALL DATA"); + break; + + default: + if (state > 5) { + byte_input_set_result_callback( + scene, input_byte_player_callback, NULL, app, + &(app->frame_to_send->buffer[state - 6]), 1); + + furi_string_reset(app->text); + furi_string_cat_printf(app->text, "SET BYTE [%lu]", state - 6); + byte_input_set_header_text(app->input_byte_value, + furi_string_get_cstr(app->text)); + } + break; + } + + view_dispatcher_switch_to_view(app->view_dispatcher, InputByteView); +} + +bool app_scene_input_text_on_event(void* context, SceneManagerEvent event) { + App* app = context; + bool consumed = false; + + if (event.type == SceneManagerEventTypeCustom) { + switch (event.event) { + case ReturnEvent: + scene_manager_previous_scene(app->scene_manager); + break; + + default: + break; + } + } + return consumed; +} + +void app_scene_input_text_on_exit(void* context) { + UNUSED(context); +} diff --git a/Canbus_app/scenes_config/app_scene_config.h b/Canbus_app/scenes_config/app_scene_config.h index ca2af2e..734e4ba 100644 --- a/Canbus_app/scenes_config/app_scene_config.h +++ b/Canbus_app/scenes_config/app_scene_config.h @@ -27,3 +27,4 @@ ADD_SCENE(app, about_us, about_us) ADD_SCENE(app, obdii_menu, obdii_option) ADD_SCENE(app, obdii_typical_codes, obdii_typical_codes_option) ADD_SCENE(app, draw_obdii, draw_obii_option) +ADD_SCENE(app, play_logs, play_logs)