Explorar o código

upd pokemon trading

MX %!s(int64=2) %!d(string=hai) anos
pai
achega
4421edb13d
Modificáronse 6 ficheiros con 135 adicións e 70 borrados
  1. 1 1
      application.fam
  2. 0 8
      pokemon_app.h
  3. 1 1
      pokemon_char_encode.c
  4. 1 5
      scenes/pokemon_menu.c
  5. 30 14
      views/select_pokemon.c
  6. 102 41
      views/trade.c

+ 1 - 1
application.fam

@@ -5,7 +5,7 @@ App(
     entry_point="pokemon_app",
     requires=["gui"],
     stack_size=2 * 1024,
-    fap_version=[1,2],
+    fap_version=[1,3],
     fap_category="GPIO",
     fap_icon="pokemon_10px.png",
     fap_icon_assets="assets",

+ 0 - 8
pokemon_app.h

@@ -88,14 +88,6 @@ struct pokemon_fap {
     /* The currently selected pokemon */
     int curr_pokemon;
 
-    /* Some state tracking */
-    /* This, combined with some globals in trade.cpp, can probably be better
-     * consolidated at some point.
-     */
-    bool trading;
-    bool connected;
-    render_gameboy_state_t gameboy_status;
-
     /* TODO: Other variables will end up here, like selected level, EV/IV,
      * moveset, etc. Likely will want to be another sub struct similar to
      * the actual pokemon data structure.

+ 1 - 1
pokemon_char_encode.c

@@ -131,7 +131,7 @@ char pokemon_char_to_encoded(int byte) {
     case '9':
         return _9_;
 
-    /* This was previously implemented with unicode escape codes, however, that
+        /* This was previously implemented with unicode escape codes, however, that
      * seemed to cause compilation issues. Which is strange because others reported
      * compilation issues with the actual unicode characters. I'm not sure a good
      * universal way to resolve this.

+ 1 - 5
scenes/pokemon_menu.c

@@ -54,11 +54,7 @@ void main_menu_scene_on_enter(void* context) {
         pokemon_fap->submenu, buf, SelectNicknameScene, scene_change_from_main_cb, pokemon_fap);
     snprintf(buf, sizeof(buf), "Level:           %d", pokemon_fap->trade_block->party[0].level);
     submenu_add_item(
-        pokemon_fap->submenu,
-        buf,
-        SelectLevelScene,
-        scene_change_from_main_cb,
-        pokemon_fap);
+        pokemon_fap->submenu, buf, SelectLevelScene, scene_change_from_main_cb, pokemon_fap);
     submenu_add_item(
         pokemon_fap->submenu,
         "Select Moves",

+ 30 - 14
views/select_pokemon.c

@@ -4,21 +4,24 @@
 #include "../scenes/pokemon_menu.h"
 #include "../pokemon_app.h"
 
-int selected_pokemon;
+struct select_model {
+    uint8_t curr_pokemon;
+    const PokemonTable* pokemon_table;
+};
 
 static void select_pokemon_render_callback(Canvas* canvas, void* model) {
-    PokemonFap* pokemon_fap = *(PokemonFap**)model;
-    const uint8_t current_index = selected_pokemon;
+    struct select_model* view_model = model;
+    uint8_t curr_pokemon = view_model->curr_pokemon;
     char pokedex_num[5];
 
-    snprintf(pokedex_num, sizeof(pokedex_num), "#%03d", current_index + 1);
+    snprintf(pokedex_num, sizeof(pokedex_num), "#%03d", curr_pokemon + 1);
     canvas_set_font(canvas, FontPrimary);
     canvas_draw_str_aligned(
-        canvas, 55, 54 / 2, AlignLeft, AlignTop, pokemon_fap->pokemon_table[current_index].name);
+        canvas, 55, 54 / 2, AlignLeft, AlignTop, view_model->pokemon_table[curr_pokemon].name);
 
     canvas_set_font(canvas, FontSecondary);
     canvas_draw_str_aligned(canvas, 55, 38, AlignLeft, AlignTop, pokedex_num);
-    canvas_draw_icon(canvas, 0, 0, pokemon_fap->pokemon_table[current_index].icon);
+    canvas_draw_icon(canvas, 0, 0, view_model->pokemon_table[curr_pokemon].icon);
     canvas_draw_icon(canvas, 128 - 80, 0, &I_Space_80x18);
     canvas_draw_str_aligned(canvas, (128 - 40), 5, AlignCenter, AlignTop, "Select Pokemon");
 
@@ -29,12 +32,19 @@ static void select_pokemon_render_callback(Canvas* canvas, void* model) {
 static bool select_pokemon_input_callback(InputEvent* event, void* context) {
     PokemonFap* pokemon_fap = (PokemonFap*)context;
     bool consumed = false;
+    uint8_t selected_pokemon;
 
     furi_assert(context);
 
     /* We only handle InputTypePress at the moment */
     if(event->type != InputTypePress) return consumed;
 
+    with_view_model(
+        pokemon_fap->select_view,
+        struct select_model * model,
+        { selected_pokemon = model->curr_pokemon; },
+        false);
+
     switch(event->key) {
     /* Advance to next view with the selected pokemon */
     case InputKeyOk:
@@ -87,19 +97,27 @@ static bool select_pokemon_input_callback(InputEvent* event, void* context) {
         // Do Nothing
         break;
     }
+
     with_view_model(
         pokemon_fap->select_view,
-        PokemonFap* model,
-        {
-            model->curr_pokemon = selected_pokemon;
-        },
+        struct select_model * model,
+        { model->curr_pokemon = selected_pokemon; },
         true);
+
     return consumed;
 }
 
 void select_pokemon_enter_callback(void* context) {
     PokemonFap* pokemon_fap = (PokemonFap*)context;
-    selected_pokemon = pokemon_fap->curr_pokemon;
+
+    with_view_model(
+        pokemon_fap->select_view,
+        struct select_model * model,
+        {
+            model->curr_pokemon = (uint8_t)pokemon_fap->curr_pokemon;
+            model->pokemon_table = pokemon_fap->pokemon_table;
+        },
+        true);
 }
 
 View* select_pokemon_alloc(PokemonFap* pokemon_fap) {
@@ -108,9 +126,7 @@ View* select_pokemon_alloc(PokemonFap* pokemon_fap) {
     view = view_alloc();
 
     view_set_context(view, pokemon_fap);
-    view_allocate_model(view, ViewModelTypeLockFree, sizeof(PokemonFap**));
-    with_view_model(
-        view, PokemonFap** model_fap, { *model_fap = pokemon_fap; }, false);
+    view_allocate_model(view, ViewModelTypeLockFree, sizeof(struct select_model));
 
     view_set_draw_callback(view, select_pokemon_render_callback);
     view_set_input_callback(view, select_pokemon_input_callback);

+ 102 - 41
views/trade.c

@@ -1,4 +1,6 @@
 #include <furi_hal_light.h>
+#include <furi.h>
+
 #include <gui/view.h>
 #include <pokemon_icons.h>
 
@@ -31,6 +33,15 @@
 
 #define TRADE_CENTRE_WAIT 0xFD
 
+struct trade_model {
+    bool trading;
+    bool connected;
+    render_gameboy_state_t gameboy_status;
+    uint8_t curr_pokemon;
+    const PokemonTable* pokemon_table;
+    FuriTimer* draw_timer;
+};
+
 typedef unsigned char byte;
 typedef enum { NOT_CONNECTED, CONNECTED, TRADE_CENTRE, COLOSSEUM } connection_state_t;
 typedef enum {
@@ -49,15 +60,17 @@ typedef enum {
 } trade_centre_state_t;
 
 /* TODO: Convert all of these to be maintained in a struct in the Trade context */
-uint8_t out_data = 0;
-uint8_t in_data = 0;
-uint8_t shift = 0;
-uint32_t time = 0;
-volatile int counter = 0;
-volatile bool procesing = true;
-volatile connection_state_t connection_state = NOT_CONNECTED;
-volatile trade_centre_state_t trade_centre_state = INIT;
-unsigned char INPUT_BLOCK[405];
+uint8_t out_data = 0; // Should be able to be made as part of view model or static in used function
+uint8_t in_data = 0; //Should be able to be made as part of view model, is used in multiple funcs
+uint8_t shift = 0; //Should be able to be made as part of view model, is used in multiple funcs
+uint32_t time = 0; //Should be able to be made static in used function
+volatile int counter = 0; // Should be able to be made static in used function
+volatile bool procesing = true; // Review this vars use, it could potentially be removed
+volatile connection_state_t connection_state =
+    NOT_CONNECTED; // Should be made in to view model struct
+volatile trade_centre_state_t trade_centre_state =
+    INIT; // Should be able to be made part of view model
+unsigned char INPUT_BLOCK[405]; // Put this in pokemon_fap? Not sure yet
 
 void screen_gameboy_connect(Canvas* const canvas) {
     canvas_draw_frame(canvas, 0, 0, 128, 64);
@@ -80,11 +93,12 @@ int time_in_seconds = 0;
 
 static void trade_draw_callback(Canvas* canvas, void* model) {
     const char* gameboy_status_text = NULL;
-    PokemonFap* pokemon_fap = *(PokemonFap**)model;
+    struct trade_model* view_model = model;
+    uint8_t curr_pokemon = view_model->curr_pokemon;
 
     canvas_clear(canvas);
-    if(!pokemon_fap->trading) {
-        if(!pokemon_fap->connected) {
+    if(!view_model->trading) {
+        if(!view_model->connected) {
             furi_hal_light_set(LightGreen, 0x00);
             furi_hal_light_set(LightBlue, 0x00);
             furi_hal_light_set(LightRed, 0xff);
@@ -96,7 +110,7 @@ static void trade_draw_callback(Canvas* canvas, void* model) {
             screen_gameboy_connected(canvas);
         }
     } else {
-        switch(pokemon_fap->gameboy_status) {
+        switch(view_model->gameboy_status) {
         case GAMEBOY_TRADING:
             furi_hal_light_set(LightGreen, 0x00);
             furi_hal_light_set(LightRed, 0x00);
@@ -111,8 +125,7 @@ static void trade_draw_callback(Canvas* canvas, void* model) {
         case GAMEBOY_READY:
         case GAMEBOY_WAITING:
         case GAMEBOY_SEND:
-            canvas_draw_icon(
-                canvas, 38, 11, pokemon_fap->pokemon_table[pokemon_fap->curr_pokemon].icon);
+            canvas_draw_icon(canvas, 38, 11, view_model->pokemon_table[curr_pokemon].icon);
             break;
         default:
             // Default state added to eliminated enum warning
@@ -123,7 +136,7 @@ static void trade_draw_callback(Canvas* canvas, void* model) {
         canvas_draw_frame(canvas, 0, 0, 128, 64);
         canvas_draw_icon(canvas, 24, 0, &I_Space_80x18);
 
-        switch(pokemon_fap->gameboy_status) {
+        switch(view_model->gameboy_status) {
         case GAMEBOY_READY:
             gameboy_status_text = "READY";
             break;
@@ -217,10 +230,17 @@ byte getMenuResponse(byte in) {
 byte getTradeCentreResponse(byte in, void* context) {
     PokemonFap* pokemon_fap = (PokemonFap*)context;
     uint8_t* trade_block_flat = (uint8_t*)pokemon_fap->trade_block;
+    render_gameboy_state_t gameboy_status;
     byte send = in;
 
     furi_assert(context);
 
+    with_view_model(
+        pokemon_fap->trade_view,
+        struct trade_model * model,
+        { gameboy_status = model->gameboy_status; },
+        false);
+
     switch(trade_centre_state) {
     case INIT:
         // TODO: What does this value of in mean?
@@ -229,7 +249,7 @@ byte getTradeCentreResponse(byte in, void* context) {
             if(counter == 5) {
                 trade_centre_state = READY_TO_GO;
                 //  CLICK EN LA MESA
-                pokemon_fap->gameboy_status = GAMEBOY_READY;
+                gameboy_status = GAMEBOY_READY;
             }
             counter++;
         }
@@ -250,7 +270,7 @@ byte getTradeCentreResponse(byte in, void* context) {
         if((in & 0xF0) == 0xF0) {
             if(counter == 5) {
                 trade_centre_state = WAITING_TO_SEND_DATA;
-                pokemon_fap->gameboy_status = GAMEBOY_WAITING;
+                gameboy_status = GAMEBOY_WAITING;
             }
             counter++;
         }
@@ -290,10 +310,10 @@ byte getTradeCentreResponse(byte in, void* context) {
         if(in == 0x6F) {
             trade_centre_state = READY_TO_GO;
             send = 0x6F;
-            pokemon_fap->gameboy_status = GAMEBOY_TRADE_READY;
+            gameboy_status = GAMEBOY_TRADE_READY;
         } else if((in & 0x60) == 0x60) {
             send = 0x60; // first pokemon
-            pokemon_fap->gameboy_status = GAMEBOY_SEND;
+            gameboy_status = GAMEBOY_SEND;
         } else if(in == 0x00) {
             send = 0;
             trade_centre_state = TRADE_CONFIRMATION;
@@ -303,7 +323,7 @@ byte getTradeCentreResponse(byte in, void* context) {
     case TRADE_CONFIRMATION:
         if(in == 0x61) {
             trade_centre_state = TRADE_PENDING;
-            pokemon_fap->gameboy_status = GAMEBOY_PENDING;
+            gameboy_status = GAMEBOY_PENDING;
         } else if((in & 0x60) == 0x60) {
             trade_centre_state = DONE;
         }
@@ -313,7 +333,7 @@ byte getTradeCentreResponse(byte in, void* context) {
         if(in == 0x00) {
             send = 0;
             trade_centre_state = INIT;
-            pokemon_fap->gameboy_status = GAMEBOY_TRADING;
+            gameboy_status = GAMEBOY_TRADING;
         }
         break;
 
@@ -322,12 +342,29 @@ byte getTradeCentreResponse(byte in, void* context) {
         break;
     }
 
+    with_view_model(
+        pokemon_fap->trade_view,
+        struct trade_model * model,
+        { model->gameboy_status = gameboy_status; },
+        false);
+
     return send;
 }
 
 void transferBit(void* context) {
     PokemonFap* pokemon_fap = (PokemonFap*)context;
     furi_assert(context);
+    bool connected;
+    bool trading;
+
+    with_view_model(
+        pokemon_fap->trade_view,
+        struct trade_model * model,
+        {
+            connected = model->connected;
+            trading = model->trading;
+        },
+        false);
 
     byte raw_data = furi_hal_gpio_read(&GAME_BOY_SI);
     in_data |= raw_data << (7 - shift);
@@ -335,11 +372,11 @@ void transferBit(void* context) {
         shift = 0;
         switch(connection_state) {
         case NOT_CONNECTED:
-            pokemon_fap->connected = false;
+            connected = false;
             out_data = getConnectResponse(in_data);
             break;
         case CONNECTED:
-            pokemon_fap->connected = true;
+            connected = true;
             out_data = getMenuResponse(in_data);
             break;
         case TRADE_CENTRE:
@@ -361,9 +398,18 @@ void transferBit(void* context) {
         DELAY_MICROSECONDS); // Wait 20-60us ... 120us max (in slave mode is not necessary)
     // TODO: The above comment doesn't make sense as DELAY_MICROSECONDS is defined as 15
 
-    if(trade_centre_state == READY_TO_GO) pokemon_fap->trading = true;
+    if(trade_centre_state == READY_TO_GO) trading = true;
 
     out_data = out_data << 1;
+
+    with_view_model(
+        pokemon_fap->trade_view,
+        struct trade_model * model,
+        {
+            model->connected = connected;
+            model->trading = trading;
+        },
+        false);
 }
 
 void input_clk_gameboy(void* context) {
@@ -382,13 +428,32 @@ void input_clk_gameboy(void* context) {
     time = micros();
 }
 
+void trade_draw_timer_callback(void* context) {
+    PokemonFap* pokemon_fap = (PokemonFap*)context;
+
+    with_view_model(
+        pokemon_fap->trade_view, struct trade_model * model, { UNUSED(model); }, true);
+}
+
 void trade_enter_callback(void* context) {
     PokemonFap* pokemon_fap = (PokemonFap*)context;
     furi_assert(context);
 
-    pokemon_fap->trading = false;
-    pokemon_fap->connected = false;
-    pokemon_fap->gameboy_status = GAMEBOY_INITIAL;
+    with_view_model(
+        pokemon_fap->trade_view,
+        struct trade_model * model,
+        {
+            model->trading = false;
+            model->connected = false;
+            model->gameboy_status = GAMEBOY_INITIAL;
+            model->pokemon_table = pokemon_fap->pokemon_table;
+            model->curr_pokemon = (uint8_t)pokemon_fap->curr_pokemon;
+            model->draw_timer =
+                furi_timer_alloc(trade_draw_timer_callback, FuriTimerTypePeriodic, pokemon_fap);
+            /* Every 100 ms, trigger a draw update */
+            furi_timer_start(model->draw_timer, 100);
+        },
+        true);
 
     // B3 (Pin6) / SO (2)
     furi_hal_gpio_write(&GAME_BOY_SO, false);
@@ -397,18 +462,9 @@ void trade_enter_callback(void* context) {
     furi_hal_gpio_write(&GAME_BOY_SI, false);
     furi_hal_gpio_init(&GAME_BOY_SI, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
     // // C3 (Pin7) / CLK (5)
-    furi_hal_gpio_init(
-        &GAME_BOY_CLK,
-        GpioModeInterruptRise,
-        GpioPullNo,
-        GpioSpeedVeryHigh); // <-- This line causes the "OK" to stop functioning when exiting the application, so a reboot of the Flipper Zero is required.
+    furi_hal_gpio_init(&GAME_BOY_CLK, GpioModeInterruptRise, GpioPullNo, GpioSpeedVeryHigh);
     furi_hal_gpio_remove_int_callback(&GAME_BOY_CLK);
     furi_hal_gpio_add_int_callback(&GAME_BOY_CLK, input_clk_gameboy, pokemon_fap);
-
-    // furi_hal_gpio_disable_int_callback(&GAME_BOY_CLK);
-    // furi_hal_gpio_remove_int_callback(&GAME_BOY_CLK);
-    // Reset GPIO pins to default state
-    // furi_hal_gpio_init(&GAME_BOY_CLK, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
 }
 
 void disconnect_pin(const GpioPin* pin) {
@@ -417,11 +473,18 @@ void disconnect_pin(const GpioPin* pin) {
 }
 
 void trade_exit_callback(void* context) {
+    PokemonFap* pokemon_fap = (PokemonFap*)context;
     furi_assert(context);
     procesing = false;
     furi_hal_light_set(LightGreen, 0x00);
     furi_hal_light_set(LightBlue, 0x00);
     furi_hal_light_set(LightRed, 0x00);
+    /* Stop the timer, and deallocate it as the enter callback allocates it on entry */
+    with_view_model(
+        pokemon_fap->trade_view,
+        struct trade_model * model,
+        { furi_timer_free(model->draw_timer); },
+        false);
 }
 
 View* trade_alloc(PokemonFap* pokemon_fap) {
@@ -431,9 +494,7 @@ View* trade_alloc(PokemonFap* pokemon_fap) {
     procesing = true;
 
     view_set_context(view, pokemon_fap);
-    view_allocate_model(view, ViewModelTypeLockFree, sizeof(PokemonFap**));
-    with_view_model(
-        view, PokemonFap** model_fap, { *model_fap = pokemon_fap; }, false);
+    view_allocate_model(view, ViewModelTypeLockFree, sizeof(struct trade_model));
 
     view_set_draw_callback(view, trade_draw_callback);
     view_set_enter_callback(view, trade_enter_callback);