1
1
#include <furi_hal_light.h>
2
+ #include <furi.h>
3
+
2
4
#include <gui/view.h>
3
5
#include <pokemon_icons.h>
4
6
31
33
32
34
#define TRADE_CENTRE_WAIT 0xFD
33
35
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
+
34
45
typedef unsigned char byte ;
35
46
typedef enum { NOT_CONNECTED , CONNECTED , TRADE_CENTRE , COLOSSEUM } connection_state_t ;
36
47
typedef enum {
@@ -49,15 +60,17 @@ typedef enum {
49
60
} trade_centre_state_t ;
50
61
51
62
/* 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
61
74
62
75
void screen_gameboy_connect (Canvas * const canvas ) {
63
76
canvas_draw_frame (canvas , 0 , 0 , 128 , 64 );
@@ -80,11 +93,12 @@ int time_in_seconds = 0;
80
93
81
94
static void trade_draw_callback (Canvas * canvas , void * model ) {
82
95
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 ;
84
98
85
99
canvas_clear (canvas );
86
- if (!pokemon_fap -> trading ) {
87
- if (!pokemon_fap -> connected ) {
100
+ if (!view_model -> trading ) {
101
+ if (!view_model -> connected ) {
88
102
furi_hal_light_set (LightGreen , 0x00 );
89
103
furi_hal_light_set (LightBlue , 0x00 );
90
104
furi_hal_light_set (LightRed , 0xff );
@@ -96,7 +110,7 @@ static void trade_draw_callback(Canvas* canvas, void* model) {
96
110
screen_gameboy_connected (canvas );
97
111
}
98
112
} else {
99
- switch (pokemon_fap -> gameboy_status ) {
113
+ switch (view_model -> gameboy_status ) {
100
114
case GAMEBOY_TRADING :
101
115
furi_hal_light_set (LightGreen , 0x00 );
102
116
furi_hal_light_set (LightRed , 0x00 );
@@ -111,8 +125,7 @@ static void trade_draw_callback(Canvas* canvas, void* model) {
111
125
case GAMEBOY_READY :
112
126
case GAMEBOY_WAITING :
113
127
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 );
116
129
break ;
117
130
default :
118
131
// Default state added to eliminated enum warning
@@ -123,7 +136,7 @@ static void trade_draw_callback(Canvas* canvas, void* model) {
123
136
canvas_draw_frame (canvas , 0 , 0 , 128 , 64 );
124
137
canvas_draw_icon (canvas , 24 , 0 , & I_Space_80x18 );
125
138
126
- switch (pokemon_fap -> gameboy_status ) {
139
+ switch (view_model -> gameboy_status ) {
127
140
case GAMEBOY_READY :
128
141
gameboy_status_text = "READY" ;
129
142
break ;
@@ -217,10 +230,17 @@ byte getMenuResponse(byte in) {
217
230
byte getTradeCentreResponse (byte in , void * context ) {
218
231
PokemonFap * pokemon_fap = (PokemonFap * )context ;
219
232
uint8_t * trade_block_flat = (uint8_t * )pokemon_fap -> trade_block ;
233
+ render_gameboy_state_t gameboy_status ;
220
234
byte send = in ;
221
235
222
236
furi_assert (context );
223
237
238
+ with_view_model (
239
+ pokemon_fap -> trade_view ,
240
+ struct trade_model * model ,
241
+ { gameboy_status = model -> gameboy_status ; },
242
+ false);
243
+
224
244
switch (trade_centre_state ) {
225
245
case INIT :
226
246
// TODO: What does this value of in mean?
@@ -229,7 +249,7 @@ byte getTradeCentreResponse(byte in, void* context) {
229
249
if (counter == 5 ) {
230
250
trade_centre_state = READY_TO_GO ;
231
251
// CLICK EN LA MESA
232
- pokemon_fap -> gameboy_status = GAMEBOY_READY ;
252
+ gameboy_status = GAMEBOY_READY ;
233
253
}
234
254
counter ++ ;
235
255
}
@@ -250,7 +270,7 @@ byte getTradeCentreResponse(byte in, void* context) {
250
270
if ((in & 0xF0 ) == 0xF0 ) {
251
271
if (counter == 5 ) {
252
272
trade_centre_state = WAITING_TO_SEND_DATA ;
253
- pokemon_fap -> gameboy_status = GAMEBOY_WAITING ;
273
+ gameboy_status = GAMEBOY_WAITING ;
254
274
}
255
275
counter ++ ;
256
276
}
@@ -290,10 +310,10 @@ byte getTradeCentreResponse(byte in, void* context) {
290
310
if (in == 0x6F ) {
291
311
trade_centre_state = READY_TO_GO ;
292
312
send = 0x6F ;
293
- pokemon_fap -> gameboy_status = GAMEBOY_TRADE_READY ;
313
+ gameboy_status = GAMEBOY_TRADE_READY ;
294
314
} else if ((in & 0x60 ) == 0x60 ) {
295
315
send = 0x60 ; // first pokemon
296
- pokemon_fap -> gameboy_status = GAMEBOY_SEND ;
316
+ gameboy_status = GAMEBOY_SEND ;
297
317
} else if (in == 0x00 ) {
298
318
send = 0 ;
299
319
trade_centre_state = TRADE_CONFIRMATION ;
@@ -303,7 +323,7 @@ byte getTradeCentreResponse(byte in, void* context) {
303
323
case TRADE_CONFIRMATION :
304
324
if (in == 0x61 ) {
305
325
trade_centre_state = TRADE_PENDING ;
306
- pokemon_fap -> gameboy_status = GAMEBOY_PENDING ;
326
+ gameboy_status = GAMEBOY_PENDING ;
307
327
} else if ((in & 0x60 ) == 0x60 ) {
308
328
trade_centre_state = DONE ;
309
329
}
@@ -313,7 +333,7 @@ byte getTradeCentreResponse(byte in, void* context) {
313
333
if (in == 0x00 ) {
314
334
send = 0 ;
315
335
trade_centre_state = INIT ;
316
- pokemon_fap -> gameboy_status = GAMEBOY_TRADING ;
336
+ gameboy_status = GAMEBOY_TRADING ;
317
337
}
318
338
break ;
319
339
@@ -322,24 +342,41 @@ byte getTradeCentreResponse(byte in, void* context) {
322
342
break ;
323
343
}
324
344
345
+ with_view_model (
346
+ pokemon_fap -> trade_view ,
347
+ struct trade_model * model ,
348
+ { model -> gameboy_status = gameboy_status ; },
349
+ false);
350
+
325
351
return send ;
326
352
}
327
353
328
354
void transferBit (void * context ) {
329
355
PokemonFap * pokemon_fap = (PokemonFap * )context ;
330
356
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);
331
368
332
369
byte raw_data = furi_hal_gpio_read (& GAME_BOY_SI );
333
370
in_data |= raw_data << (7 - shift );
334
371
if (++ shift > 7 ) {
335
372
shift = 0 ;
336
373
switch (connection_state ) {
337
374
case NOT_CONNECTED :
338
- pokemon_fap -> connected = false;
375
+ connected = false;
339
376
out_data = getConnectResponse (in_data );
340
377
break ;
341
378
case CONNECTED :
342
- pokemon_fap -> connected = true;
379
+ connected = true;
343
380
out_data = getMenuResponse (in_data );
344
381
break ;
345
382
case TRADE_CENTRE :
@@ -361,9 +398,18 @@ void transferBit(void* context) {
361
398
DELAY_MICROSECONDS ); // Wait 20-60us ... 120us max (in slave mode is not necessary)
362
399
// TODO: The above comment doesn't make sense as DELAY_MICROSECONDS is defined as 15
363
400
364
- if (trade_centre_state == READY_TO_GO ) pokemon_fap -> trading = true;
401
+ if (trade_centre_state == READY_TO_GO ) trading = true;
365
402
366
403
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);
367
413
}
368
414
369
415
void input_clk_gameboy (void * context ) {
@@ -382,13 +428,32 @@ void input_clk_gameboy(void* context) {
382
428
time = micros ();
383
429
}
384
430
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
+
385
438
void trade_enter_callback (void * context ) {
386
439
PokemonFap * pokemon_fap = (PokemonFap * )context ;
387
440
furi_assert (context );
388
441
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);
392
457
393
458
// B3 (Pin6) / SO (2)
394
459
furi_hal_gpio_write (& GAME_BOY_SO , false);
@@ -397,18 +462,9 @@ void trade_enter_callback(void* context) {
397
462
furi_hal_gpio_write (& GAME_BOY_SI , false);
398
463
furi_hal_gpio_init (& GAME_BOY_SI , GpioModeInput , GpioPullNo , GpioSpeedVeryHigh );
399
464
// // 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 );
405
466
furi_hal_gpio_remove_int_callback (& GAME_BOY_CLK );
406
467
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);
412
468
}
413
469
414
470
void disconnect_pin (const GpioPin * pin ) {
@@ -417,11 +473,18 @@ void disconnect_pin(const GpioPin* pin) {
417
473
}
418
474
419
475
void trade_exit_callback (void * context ) {
476
+ PokemonFap * pokemon_fap = (PokemonFap * )context ;
420
477
furi_assert (context );
421
478
procesing = false;
422
479
furi_hal_light_set (LightGreen , 0x00 );
423
480
furi_hal_light_set (LightBlue , 0x00 );
424
481
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);
425
488
}
426
489
427
490
View * trade_alloc (PokemonFap * pokemon_fap ) {
@@ -431,9 +494,7 @@ View* trade_alloc(PokemonFap* pokemon_fap) {
431
494
procesing = true;
432
495
433
496
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 ));
437
498
438
499
view_set_draw_callback (view , trade_draw_callback );
439
500
view_set_enter_callback (view , trade_enter_callback );
0 commit comments