Skip to content

Commit 5884a74

Browse files
committed
views/trade: Cease my abuse of View model
After converting select_pokemon, it only makes sense to clean up trade as well. There were a number of globals vars passed in the main PokemonFap struct that are only used by trade and have been moved to the View model data. There are also currently still some globals vars in the trade code that could either be relocated to specific functions or moved in to the trade View model. This also adds a periodic timer to the trade view. The functions that get called through the lifetime of the trade process are mostly in an interrupt context. This means we cannot request a View update via with_view_model(). In order to handle regular drawing, a timer is used to call a function out of an interrupt context that does a null with_view_model() to simply trigger a redraw.
1 parent 5ce0ed1 commit 5884a74

File tree

2 files changed

+102
-49
lines changed

2 files changed

+102
-49
lines changed

pokemon_app.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,14 +88,6 @@ struct pokemon_fap {
8888
/* The currently selected pokemon */
8989
int curr_pokemon;
9090

91-
/* Some state tracking */
92-
/* This, combined with some globals in trade.cpp, can probably be better
93-
* consolidated at some point.
94-
*/
95-
bool trading;
96-
bool connected;
97-
render_gameboy_state_t gameboy_status;
98-
9991
/* TODO: Other variables will end up here, like selected level, EV/IV,
10092
* moveset, etc. Likely will want to be another sub struct similar to
10193
* the actual pokemon data structure.

views/trade.c

Lines changed: 102 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
#include <furi_hal_light.h>
2+
#include <furi.h>
3+
24
#include <gui/view.h>
35
#include <pokemon_icons.h>
46

@@ -31,6 +33,15 @@
3133

3234
#define TRADE_CENTRE_WAIT 0xFD
3335

36+
struct trade_model {
37+
bool trading;
38+
bool connected;
39+
render_gameboy_state_t gameboy_status;
40+
uint8_t curr_pokemon;
41+
const PokemonTable* pokemon_table;
42+
FuriTimer* draw_timer;
43+
};
44+
3445
typedef unsigned char byte;
3546
typedef enum { NOT_CONNECTED, CONNECTED, TRADE_CENTRE, COLOSSEUM } connection_state_t;
3647
typedef enum {
@@ -49,15 +60,17 @@ typedef enum {
4960
} trade_centre_state_t;
5061

5162
/* TODO: Convert all of these to be maintained in a struct in the Trade context */
52-
uint8_t out_data = 0;
53-
uint8_t in_data = 0;
54-
uint8_t shift = 0;
55-
uint32_t time = 0;
56-
volatile int counter = 0;
57-
volatile bool procesing = true;
58-
volatile connection_state_t connection_state = NOT_CONNECTED;
59-
volatile trade_centre_state_t trade_centre_state = INIT;
60-
unsigned char INPUT_BLOCK[405];
63+
uint8_t out_data = 0; // Should be able to be made as part of view model or static in used function
64+
uint8_t in_data = 0; //Should be able to be made as part of view model, is used in multiple funcs
65+
uint8_t shift = 0; //Should be able to be made as part of view model, is used in multiple funcs
66+
uint32_t time = 0; //Should be able to be made static in used function
67+
volatile int counter = 0; // Should be able to be made static in used function
68+
volatile bool procesing = true; // Review this vars use, it could potentially be removed
69+
volatile connection_state_t connection_state =
70+
NOT_CONNECTED; // Should be made in to view model struct
71+
volatile trade_centre_state_t trade_centre_state =
72+
INIT; // Should be able to be made part of view model
73+
unsigned char INPUT_BLOCK[405]; // Put this in pokemon_fap? Not sure yet
6174

6275
void screen_gameboy_connect(Canvas* const canvas) {
6376
canvas_draw_frame(canvas, 0, 0, 128, 64);
@@ -80,11 +93,12 @@ int time_in_seconds = 0;
8093

8194
static void trade_draw_callback(Canvas* canvas, void* model) {
8295
const char* gameboy_status_text = NULL;
83-
PokemonFap* pokemon_fap = *(PokemonFap**)model;
96+
struct trade_model* view_model = model;
97+
uint8_t curr_pokemon = view_model->curr_pokemon;
8498

8599
canvas_clear(canvas);
86-
if(!pokemon_fap->trading) {
87-
if(!pokemon_fap->connected) {
100+
if(!view_model->trading) {
101+
if(!view_model->connected) {
88102
furi_hal_light_set(LightGreen, 0x00);
89103
furi_hal_light_set(LightBlue, 0x00);
90104
furi_hal_light_set(LightRed, 0xff);
@@ -96,7 +110,7 @@ static void trade_draw_callback(Canvas* canvas, void* model) {
96110
screen_gameboy_connected(canvas);
97111
}
98112
} else {
99-
switch(pokemon_fap->gameboy_status) {
113+
switch(view_model->gameboy_status) {
100114
case GAMEBOY_TRADING:
101115
furi_hal_light_set(LightGreen, 0x00);
102116
furi_hal_light_set(LightRed, 0x00);
@@ -111,8 +125,7 @@ static void trade_draw_callback(Canvas* canvas, void* model) {
111125
case GAMEBOY_READY:
112126
case GAMEBOY_WAITING:
113127
case GAMEBOY_SEND:
114-
canvas_draw_icon(
115-
canvas, 38, 11, pokemon_fap->pokemon_table[pokemon_fap->curr_pokemon].icon);
128+
canvas_draw_icon(canvas, 38, 11, view_model->pokemon_table[curr_pokemon].icon);
116129
break;
117130
default:
118131
// Default state added to eliminated enum warning
@@ -123,7 +136,7 @@ static void trade_draw_callback(Canvas* canvas, void* model) {
123136
canvas_draw_frame(canvas, 0, 0, 128, 64);
124137
canvas_draw_icon(canvas, 24, 0, &I_Space_80x18);
125138

126-
switch(pokemon_fap->gameboy_status) {
139+
switch(view_model->gameboy_status) {
127140
case GAMEBOY_READY:
128141
gameboy_status_text = "READY";
129142
break;
@@ -217,10 +230,17 @@ byte getMenuResponse(byte in) {
217230
byte getTradeCentreResponse(byte in, void* context) {
218231
PokemonFap* pokemon_fap = (PokemonFap*)context;
219232
uint8_t* trade_block_flat = (uint8_t*)pokemon_fap->trade_block;
233+
render_gameboy_state_t gameboy_status;
220234
byte send = in;
221235

222236
furi_assert(context);
223237

238+
with_view_model(
239+
pokemon_fap->trade_view,
240+
struct trade_model * model,
241+
{ gameboy_status = model->gameboy_status; },
242+
false);
243+
224244
switch(trade_centre_state) {
225245
case INIT:
226246
// TODO: What does this value of in mean?
@@ -229,7 +249,7 @@ byte getTradeCentreResponse(byte in, void* context) {
229249
if(counter == 5) {
230250
trade_centre_state = READY_TO_GO;
231251
// CLICK EN LA MESA
232-
pokemon_fap->gameboy_status = GAMEBOY_READY;
252+
gameboy_status = GAMEBOY_READY;
233253
}
234254
counter++;
235255
}
@@ -250,7 +270,7 @@ byte getTradeCentreResponse(byte in, void* context) {
250270
if((in & 0xF0) == 0xF0) {
251271
if(counter == 5) {
252272
trade_centre_state = WAITING_TO_SEND_DATA;
253-
pokemon_fap->gameboy_status = GAMEBOY_WAITING;
273+
gameboy_status = GAMEBOY_WAITING;
254274
}
255275
counter++;
256276
}
@@ -290,10 +310,10 @@ byte getTradeCentreResponse(byte in, void* context) {
290310
if(in == 0x6F) {
291311
trade_centre_state = READY_TO_GO;
292312
send = 0x6F;
293-
pokemon_fap->gameboy_status = GAMEBOY_TRADE_READY;
313+
gameboy_status = GAMEBOY_TRADE_READY;
294314
} else if((in & 0x60) == 0x60) {
295315
send = 0x60; // first pokemon
296-
pokemon_fap->gameboy_status = GAMEBOY_SEND;
316+
gameboy_status = GAMEBOY_SEND;
297317
} else if(in == 0x00) {
298318
send = 0;
299319
trade_centre_state = TRADE_CONFIRMATION;
@@ -303,7 +323,7 @@ byte getTradeCentreResponse(byte in, void* context) {
303323
case TRADE_CONFIRMATION:
304324
if(in == 0x61) {
305325
trade_centre_state = TRADE_PENDING;
306-
pokemon_fap->gameboy_status = GAMEBOY_PENDING;
326+
gameboy_status = GAMEBOY_PENDING;
307327
} else if((in & 0x60) == 0x60) {
308328
trade_centre_state = DONE;
309329
}
@@ -313,7 +333,7 @@ byte getTradeCentreResponse(byte in, void* context) {
313333
if(in == 0x00) {
314334
send = 0;
315335
trade_centre_state = INIT;
316-
pokemon_fap->gameboy_status = GAMEBOY_TRADING;
336+
gameboy_status = GAMEBOY_TRADING;
317337
}
318338
break;
319339

@@ -322,24 +342,41 @@ byte getTradeCentreResponse(byte in, void* context) {
322342
break;
323343
}
324344

345+
with_view_model(
346+
pokemon_fap->trade_view,
347+
struct trade_model * model,
348+
{ model->gameboy_status = gameboy_status; },
349+
false);
350+
325351
return send;
326352
}
327353

328354
void transferBit(void* context) {
329355
PokemonFap* pokemon_fap = (PokemonFap*)context;
330356
furi_assert(context);
357+
bool connected;
358+
bool trading;
359+
360+
with_view_model(
361+
pokemon_fap->trade_view,
362+
struct trade_model * model,
363+
{
364+
connected = model->connected;
365+
trading = model->trading;
366+
},
367+
false);
331368

332369
byte raw_data = furi_hal_gpio_read(&GAME_BOY_SI);
333370
in_data |= raw_data << (7 - shift);
334371
if(++shift > 7) {
335372
shift = 0;
336373
switch(connection_state) {
337374
case NOT_CONNECTED:
338-
pokemon_fap->connected = false;
375+
connected = false;
339376
out_data = getConnectResponse(in_data);
340377
break;
341378
case CONNECTED:
342-
pokemon_fap->connected = true;
379+
connected = true;
343380
out_data = getMenuResponse(in_data);
344381
break;
345382
case TRADE_CENTRE:
@@ -361,9 +398,18 @@ void transferBit(void* context) {
361398
DELAY_MICROSECONDS); // Wait 20-60us ... 120us max (in slave mode is not necessary)
362399
// TODO: The above comment doesn't make sense as DELAY_MICROSECONDS is defined as 15
363400

364-
if(trade_centre_state == READY_TO_GO) pokemon_fap->trading = true;
401+
if(trade_centre_state == READY_TO_GO) trading = true;
365402

366403
out_data = out_data << 1;
404+
405+
with_view_model(
406+
pokemon_fap->trade_view,
407+
struct trade_model * model,
408+
{
409+
model->connected = connected;
410+
model->trading = trading;
411+
},
412+
false);
367413
}
368414

369415
void input_clk_gameboy(void* context) {
@@ -382,13 +428,32 @@ void input_clk_gameboy(void* context) {
382428
time = micros();
383429
}
384430

431+
void trade_draw_timer_callback(void* context) {
432+
PokemonFap* pokemon_fap = (PokemonFap*)context;
433+
434+
with_view_model(
435+
pokemon_fap->trade_view, struct trade_model * model, { UNUSED(model); }, true);
436+
}
437+
385438
void trade_enter_callback(void* context) {
386439
PokemonFap* pokemon_fap = (PokemonFap*)context;
387440
furi_assert(context);
388441

389-
pokemon_fap->trading = false;
390-
pokemon_fap->connected = false;
391-
pokemon_fap->gameboy_status = GAMEBOY_INITIAL;
442+
with_view_model(
443+
pokemon_fap->trade_view,
444+
struct trade_model * model,
445+
{
446+
model->trading = false;
447+
model->connected = false;
448+
model->gameboy_status = GAMEBOY_INITIAL;
449+
model->pokemon_table = pokemon_fap->pokemon_table;
450+
model->curr_pokemon = (uint8_t)pokemon_fap->curr_pokemon;
451+
model->draw_timer =
452+
furi_timer_alloc(trade_draw_timer_callback, FuriTimerTypePeriodic, pokemon_fap);
453+
/* Every 100 ms, trigger a draw update */
454+
furi_timer_start(model->draw_timer, 100);
455+
},
456+
true);
392457

393458
// B3 (Pin6) / SO (2)
394459
furi_hal_gpio_write(&GAME_BOY_SO, false);
@@ -397,18 +462,9 @@ void trade_enter_callback(void* context) {
397462
furi_hal_gpio_write(&GAME_BOY_SI, false);
398463
furi_hal_gpio_init(&GAME_BOY_SI, GpioModeInput, GpioPullNo, GpioSpeedVeryHigh);
399464
// // C3 (Pin7) / CLK (5)
400-
furi_hal_gpio_init(
401-
&GAME_BOY_CLK,
402-
GpioModeInterruptRise,
403-
GpioPullNo,
404-
GpioSpeedVeryHigh); // <-- This line causes the "OK" to stop functioning when exiting the application, so a reboot of the Flipper Zero is required.
465+
furi_hal_gpio_init(&GAME_BOY_CLK, GpioModeInterruptRise, GpioPullNo, GpioSpeedVeryHigh);
405466
furi_hal_gpio_remove_int_callback(&GAME_BOY_CLK);
406467
furi_hal_gpio_add_int_callback(&GAME_BOY_CLK, input_clk_gameboy, pokemon_fap);
407-
408-
// furi_hal_gpio_disable_int_callback(&GAME_BOY_CLK);
409-
// furi_hal_gpio_remove_int_callback(&GAME_BOY_CLK);
410-
// Reset GPIO pins to default state
411-
// furi_hal_gpio_init(&GAME_BOY_CLK, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
412468
}
413469

414470
void disconnect_pin(const GpioPin* pin) {
@@ -417,11 +473,18 @@ void disconnect_pin(const GpioPin* pin) {
417473
}
418474

419475
void trade_exit_callback(void* context) {
476+
PokemonFap* pokemon_fap = (PokemonFap*)context;
420477
furi_assert(context);
421478
procesing = false;
422479
furi_hal_light_set(LightGreen, 0x00);
423480
furi_hal_light_set(LightBlue, 0x00);
424481
furi_hal_light_set(LightRed, 0x00);
482+
/* Stop the timer, and deallocate it as the enter callback allocates it on entry */
483+
with_view_model(
484+
pokemon_fap->trade_view,
485+
struct trade_model * model,
486+
{ furi_timer_free(model->draw_timer); },
487+
false);
425488
}
426489

427490
View* trade_alloc(PokemonFap* pokemon_fap) {
@@ -431,9 +494,7 @@ View* trade_alloc(PokemonFap* pokemon_fap) {
431494
procesing = true;
432495

433496
view_set_context(view, pokemon_fap);
434-
view_allocate_model(view, ViewModelTypeLockFree, sizeof(PokemonFap**));
435-
with_view_model(
436-
view, PokemonFap** model_fap, { *model_fap = pokemon_fap; }, false);
497+
view_allocate_model(view, ViewModelTypeLockFree, sizeof(struct trade_model));
437498

438499
view_set_draw_callback(view, trade_draw_callback);
439500
view_set_enter_callback(view, trade_enter_callback);

0 commit comments

Comments
 (0)