Skip to content

Commit

Permalink
Merge pull request #4 from SegerEnd/dev
Browse files Browse the repository at this point in the history
Dev
  • Loading branch information
SegerEnd authored Jan 14, 2025
2 parents bbbb1c5 + fad0999 commit 5c8dd2b
Show file tree
Hide file tree
Showing 16 changed files with 624 additions and 348 deletions.
27 changes: 15 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,28 @@
This project aims to create a USB emulation app for the Flipper Zero to emulate the functionality of a Lego Dimensions ToyPad.

## Project Status
The project is currently in development, but I'm encountering some issues that I need help with. If you're passionate about reverse engineering, USB emulation, or have experience with the Flipper Zero app programming, your help and expertise would be greatly appreciated and is needed to continue this project.
The project is currently in development. **Character placement is working** 🎉, but there are issues with vehicle emulation and the placement indexes for characters.

## Planned Features
Emulate Lego Dimensions ToyPad via USB using Flipper Zero.
## Features
Placing characters on the ToyPad,
When the ToyPad is connected to the game, you can use the **arrow keys** to select a spot on the ToyPad

USB packet emulation for Lego Dimensions ToyPad interaction.
![Schermafbeelding 2025-01-14 163051](https://github.com/user-attachments/assets/e62fb2bd-8ee1-4b7e-9271-cc68068758d9)

Interface on the Flipper Zero to select minifigures and add to a slot on the toypad
And press **OK** to select a character from the list:

![Schermafbeelding 2025-01-14 163150](https://github.com/user-attachments/assets/9f47cb9d-1990-476e-adb0-3872d39496f8)

## Current Issues
I'm currently facing the following challenges:
I'm currently facing the following issues:

#### Issue 1 USB Connection:
The Flipper Zero is not being detected as a toypad by the PlayStation maybe I need to send and recieve some start packets?
#### Issue 2 Packet generation logic (checksum):
Implement the necessary packet generation logic to replicate the communication between the ToyPad and the videogame
#### Vehicles:
Currenly vehicles are not working there is, I think a issue in the CMD_MODEL or CMD_READ or with the packet generation that is causing it not to work
#### Issue character removing
When removing a character from the ToyPad, the figure is removed, but the indexes are not reset/shifted correctly. Causing unexpected behavior afterwards.

## Code Reference
I have found a similar project that might be useful for insight and code snippets for the emulation. [Node LD](https://github.com/AlinaNova21/node-ld) & [LD-ToyPad-Emulator](https://github.com/Berny23/LD-ToyPad-Emulator) repository, which could help us understand specific aspects of the ToyPad emulation process.
I have found a similar project that helped this project for insight and code snippets for the emulation. [Node LD](https://github.com/AlinaNova21/node-ld) & [LD-ToyPad-Emulator](https://github.com/Berny23/LD-ToyPad-Emulator) repository.

#
If you have any insights, solutions, you can help me by making a pull request and reach out to me or fork this project.
If you'd like to help complete this project, feel free to make a pull request or reach out to me!
Binary file added images/box_longer.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/car.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/car_bigger.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/car_bigger_selected.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/minifig_selected.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
117 changes: 91 additions & 26 deletions ldtoypad.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,21 +59,43 @@ static void ldtoypad_submenu_callback(void* context, uint32_t index) {
}
}

static bool setting_bool_values[] = {false, true};
static char* setting_no_yes[] = {"No", "Yes"};

/**
* First setting is the show debug text setting. This setting has 2 options: yes or no. Default is no.
*/
static const char* setting_show_debug_text_config_label = "Show Debug text";
static uint8_t setting_show_debug_text_values[] = {false, true};
static char* setting_show_debug_text_names[] = {"No", "Yes"};
static const char* setting_show_debug_text_config_label = "Show Debug texts";
static void ldtoypad_setting_setting_show_debug_text_index_change(VariableItem* item) {
LDToyPadApp* app = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, setting_show_debug_text_names[index]);
variable_item_set_current_value_text(item, setting_no_yes[index]);
LDToyPadSceneEmulateModel* model =
view_get_model(ldtoypad_scene_emulate_get_view(app->view_scene_emulate));
model->show_debug_text_index = index;
}

static const char* setting_show_icons_names_config_label = "Show letter or icon";
static char* setting_show_icons_names_names[] = {"Letter", "Icon"};

static void ldtoypad_setting_setting_show_icons_names_index_change(VariableItem* item) {
LDToyPadApp* app = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, setting_show_icons_names_names[index]);
LDToyPadSceneEmulateModel* model =
view_get_model(ldtoypad_scene_emulate_get_view(app->view_scene_emulate));
model->show_icons_index = index;
}

static void ldtoypad_setting_minifig_only_mode_change(VariableItem* item) {
LDToyPadApp* app = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
variable_item_set_current_value_text(item, setting_no_yes[index]);
LDToyPadSceneEmulateModel* model =
view_get_model(ldtoypad_scene_emulate_get_view(app->view_scene_emulate));
model->minifig_only_mode = index;
}

static uint32_t minifigures_submenu_previous_callback(void* context) {
UNUSED(context);
return ViewEmulate;
Expand All @@ -84,6 +106,7 @@ ViewDispatcher* view_dispatcher;
ViewDispatcher* get_view_dispatcher() {
return view_dispatcher;
}

/**
* @brief Allocate the ldtoypad application. Set up the views and resources.
* @details This function allocates the ldtoypad application resources.
Expand All @@ -109,25 +132,47 @@ static LDToyPadApp* ldtoypad_app_alloc() {
view_dispatcher_add_view(app->view_dispatcher, ViewSubmenu, submenu_get_view(app->submenu));
view_dispatcher_switch_to_view(app->view_dispatcher, ViewSubmenu);

app->text_input = text_input_alloc();
view_dispatcher_add_view(
app->view_dispatcher, ViewTextInput, text_input_get_view(app->text_input));
app->temp_buffer_size = 32;
app->temp_buffer = (char*)malloc(app->temp_buffer_size);
// app->text_input = text_input_alloc();
// view_dispatcher_add_view(
// app->view_dispatcher, ViewTextInput, text_input_get_view(app->text_input));
// app->temp_buffer_size = 32;
// app->temp_buffer = (char*)malloc(app->temp_buffer_size);

app->variable_item_list_config = variable_item_list_alloc();
variable_item_list_reset(app->variable_item_list_config);
VariableItem* item = variable_item_list_add(
app->variable_item_list_config,
setting_show_debug_text_config_label,
COUNT_OF(setting_show_debug_text_values),
COUNT_OF(setting_bool_values),
ldtoypad_setting_setting_show_debug_text_index_change,
app);

bool setting_show_debug_text_index = 0;
bool setting_show_debug_text_index = false;
variable_item_set_current_value_index(item, setting_show_debug_text_index);
variable_item_set_current_value_text(item, setting_no_yes[setting_show_debug_text_index]);

// setting 2 show icons or first letter of minifig name
item = variable_item_list_add(
app->variable_item_list_config,
setting_show_icons_names_config_label,
COUNT_OF(setting_bool_values),
ldtoypad_setting_setting_show_icons_names_index_change,
app);
bool setting_show_icons_names_index = false;
variable_item_set_current_value_index(item, setting_show_icons_names_index);
variable_item_set_current_value_text(
item, setting_show_debug_text_names[setting_show_debug_text_index]);
item, setting_show_icons_names_names[setting_show_icons_names_index]);

// setting 3 skip vehicle selection
item = variable_item_list_add(
app->variable_item_list_config,
"Skip vehicle selection / Only minifig mode",
COUNT_OF(setting_bool_values),
ldtoypad_setting_minifig_only_mode_change,
app);
bool setting_minifig_only_mode =
true; // currently true because, vehicles aren't implemented yet. Little bit annoying to go through the double selection currently.
variable_item_set_current_value_index(item, setting_minifig_only_mode);
variable_item_set_current_value_text(item, setting_no_yes[setting_minifig_only_mode]);

view_set_previous_callback(
variable_item_list_get_view(app->variable_item_list_config),
Expand All @@ -139,19 +184,13 @@ static LDToyPadApp* ldtoypad_app_alloc() {

app->view_scene_emulate = ldtoypad_scene_emulate_alloc(app);

// This is allready happening in ldtoypad_scene_emulate_alloc

// view_set_draw_callback(app->view_scene_emulate->view, ldtoypad_view_game_draw_callback);
// view_set_input_callback(app->view_scene_emulate->view, ldtoypad_view_game_input_callback);
// view_set_previous_callback(app->view_scene_emulate->view, ldtoypad_navigation_submenu_callback);
// view_set_context(app->view_scene_emulate->view, app);
// view_set_custom_callback(app->view_game, ldtoypad_view_game_custom_event_callback);
// view_allocate_model(app->view_game, ViewModelTypeLockFree, sizeof(AppGameModel));

LDToyPadSceneEmulateModel* model =
view_get_model(ldtoypad_scene_emulate_get_view(app->view_scene_emulate));

model->show_debug_text_index = setting_show_debug_text_index;
model->show_icons_index = setting_show_icons_names_index;
model->minifig_only_mode = setting_minifig_only_mode;

// view_dispatcher_add_view(app->view_dispatcher, ViewEmulate, app->view_game);
view_dispatcher_add_view(
app->view_dispatcher,
Expand All @@ -174,7 +213,7 @@ static LDToyPadApp* ldtoypad_app_alloc() {
// create a minifigure selection screen
app->submenu_minifigure_selection = submenu_alloc();
// get the minifigures from minifigures.h
for(int i = 0; minifigures[i].name != NULL; i++) {
for(int i = 0; i < minifigures_count; i++) {
submenu_add_item(
app->submenu_minifigure_selection,
minifigures[i].name,
Expand All @@ -193,6 +232,27 @@ static LDToyPadApp* ldtoypad_app_alloc() {

submenu_set_header(app->submenu_minifigure_selection, "Select minifigure");

// create a vehicle selection screen
app->submenu_vehicle_selection = submenu_alloc();
// get the vehicles from minifigures.h
for(int i = 0; i < vehicles_count; i++) {
submenu_add_item(
app->submenu_vehicle_selection,
vehicles[i].name,
vehicles[i].id,
vehicles_submenu_callback,
app);
}
view_set_previous_callback(
submenu_get_view(app->submenu_vehicle_selection), minifigures_submenu_previous_callback);

view_dispatcher_add_view(
app->view_dispatcher,
ViewVehicleSelection,
submenu_get_view(app->submenu_vehicle_selection));

submenu_set_header(app->submenu_vehicle_selection, "Select vehicle");

return app;
}

Expand All @@ -202,9 +262,9 @@ static LDToyPadApp* ldtoypad_app_alloc() {
* @param app The ldtoypad application object.
*/
static void ldtoypad_app_free(LDToyPadApp* app) {
view_dispatcher_remove_view(app->view_dispatcher, ViewTextInput);
text_input_free(app->text_input);
free(app->temp_buffer);
// view_dispatcher_remove_view(app->view_dispatcher, ViewTextInput);
// text_input_free(app->text_input); // we doesnt have a text input view anymore
// free(app->temp_buffer); // same as this

view_dispatcher_remove_view(app->view_dispatcher, ViewAbout);
widget_free(app->widget_about);
Expand All @@ -221,9 +281,14 @@ static void ldtoypad_app_free(LDToyPadApp* app) {
view_dispatcher_remove_view(app->view_dispatcher, ViewSubmenu);
submenu_free(app->submenu);

submenu_reset(app->submenu_minifigure_selection);
view_dispatcher_remove_view(app->view_dispatcher, ViewMinifigureSelection);
submenu_free(app->submenu_minifigure_selection);

submenu_reset(app->submenu_vehicle_selection);
view_dispatcher_remove_view(app->view_dispatcher, ViewVehicleSelection);
submenu_free(app->submenu_vehicle_selection);

// view_dispatcher_free(app->view_dispatcher); // this is causing a crash
furi_record_close(RECORD_GUI);

Expand Down
9 changes: 5 additions & 4 deletions ldtoypad.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,21 +40,22 @@ typedef struct {

Widget* widget_about; // The about screen

char* temp_buffer; // Temporary buffer for text input
uint32_t temp_buffer_size; // Size of temporary buffer
// char* temp_buffer; // Temporary buffer for text input
// uint32_t temp_buffer_size; // Size of temporary buffer

Submenu* submenu_minifigure_selection; // The minifigure selection screen

Submenu* submenu_vehicle_selection; // The vehicle selection screen
} LDToyPadApp;

// Each view is a screen we show the user.
typedef enum {
ViewSubmenu, // The menu when the app starts
ViewTextInput, // Input for configuring text settings
// ViewTextInput, // Input for configuring text settings
ViewConfigure, // The configuration screen
ViewEmulate, // The main screen
ViewAbout, // The about screen with directions, link to social channel, etc.
ViewMinifigureSelection, // The minifigure selection screen
ViewVehicleSelection, // The vehicle selection screen
} Views;

ViewDispatcher* get_view_dispatcher();
Expand Down
38 changes: 37 additions & 1 deletion minifigures.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#include "minifigures.h"

Minifigure minifigures[] = {
#include "furi.h"

Minifigure minifigures[75] = {
{1, "Batman"},
{2, "Gandalf"},
{3, "Wyldstyle"},
Expand Down Expand Up @@ -79,3 +81,37 @@ Minifigure minifigures[] = {
{76, "Buttercup"},
{77, "Starfire"},
};
int minifigures_count = sizeof(minifigures) / sizeof(Minifigure);

Vehicle vehicles[1] = {
{1000, "Police Car"},
};

int vehicles_count = sizeof(vehicles) / sizeof(Vehicle);

const char* get_minifigure_name(int id) {
for(int i = 0; minifigures[i].name != NULL; i++) {
if(minifigures[i].id == id) {
return minifigures[i].name;
}
}
return "?";
}

// int get_minifigure_id(const char* name) {
// for(int i = 0; minifigures[i].name != NULL; i++) {
// if(strcmp(minifigures[i].name, name) == 0) {
// return minifigures[i].id;
// }
// }
// return -1;
// }

const char* get_vehicle_name(int id) {
for(int i = 0; vehicles[i].name != NULL; i++) {
if(vehicles[i].id == id) {
return vehicles[i].name;
}
}
return "?";
}
37 changes: 37 additions & 0 deletions minifigures.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,43 @@ typedef struct {

extern Minifigure minifigures[];

typedef struct {
int id;
const char* name;

// upgrades, not yet implemented
} Vehicle;

extern Vehicle vehicles[];

// count of minifigures
extern int minifigures_count;

// count of vehicles

extern int vehicles_count;

/**
* @brief Get the character name by its id
* @param id The id of the character
* @return The character name
*/
const char* get_minifigure_name(int id);

/**
* @brief Get the character id by its name
* @param name The name of the character
* @return The character id
*/
// int get_minifigure_id(const char* name);

/**
* @brief Get the vehicle name by its id
* @param id The id of the vehicle
* @return The vehicle name
*/
const char* get_vehicle_name(int id);

#ifdef __cplusplus
}
#endif
Loading

0 comments on commit 5c8dd2b

Please sign in to comment.