|
|
@@ -22,9 +22,21 @@ typedef struct
|
|
|
InputEvent input;
|
|
|
} PluginEvent;
|
|
|
|
|
|
+typedef enum
|
|
|
+{
|
|
|
+ WorkerEvtStop = (1 << 0),
|
|
|
+ WorkerEvtModeChange = (1 << 1),
|
|
|
+ WorkerEvtUpChange = (1 << 2),
|
|
|
+ WorkerEvtDownChange = (1 << 3),
|
|
|
+ WorkerEvtRightChange = (1 << 4),
|
|
|
+ WorkerEvtLeftChange = (1 << 5),
|
|
|
+ WorkerEvtCodeChange = (1 << 6),
|
|
|
+} WorkerEvtFlags;
|
|
|
+
|
|
|
typedef struct
|
|
|
{
|
|
|
- bool mode;
|
|
|
+ FuriThread* thread;
|
|
|
+ volatile bool mode;
|
|
|
|
|
|
bool button_up;
|
|
|
bool button_down;
|
|
|
@@ -37,37 +49,92 @@ typedef struct
|
|
|
bool dpad;
|
|
|
} Coleco;
|
|
|
|
|
|
-static void output_update(Coleco* coleco)
|
|
|
+static void mode_isr(void* context)
|
|
|
{
|
|
|
- // TODO: check mode, possibly flipped
|
|
|
- if (coleco->mode)
|
|
|
- {
|
|
|
- furi_hal_gpio_write(pin_up, !coleco->button_up);
|
|
|
- furi_hal_gpio_write(pin_down, !coleco->button_down);
|
|
|
- furi_hal_gpio_write(pin_right, !coleco->button_right);
|
|
|
- furi_hal_gpio_write(pin_left, !coleco->button_left);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- // TODO: check ordering of bits
|
|
|
- furi_hal_gpio_write(pin_left, (coleco->button_code & 1));
|
|
|
- furi_hal_gpio_write(pin_down, (coleco->button_code & 2));
|
|
|
- furi_hal_gpio_write(pin_right, (coleco->button_code & 4));
|
|
|
- furi_hal_gpio_write(pin_up, (coleco->button_code & 8));
|
|
|
- }
|
|
|
- furi_hal_gpio_write(pin_fire, !coleco->button_fire);
|
|
|
+ Coleco* coleco = (Coleco*)context;
|
|
|
+ coleco->mode = furi_hal_gpio_read(&gpio_ext_pc1);
|
|
|
+ furi_thread_flags_set(furi_thread_get_id(coleco->thread), WorkerEvtModeChange);
|
|
|
}
|
|
|
|
|
|
-static void mode_isr(void* context)
|
|
|
+static int32_t coleco_output_worker(void* context)
|
|
|
{
|
|
|
- Coleco* coleco = acquire_mutex((ValueMutex*)context, 25);
|
|
|
- if (coleco == NULL)
|
|
|
+ Coleco* coleco = (Coleco*)context;
|
|
|
+
|
|
|
+ furi_hal_gpio_add_int_callback(pin_mode, mode_isr, coleco);
|
|
|
+
|
|
|
+ while(1)
|
|
|
{
|
|
|
- return;
|
|
|
+ uint32_t events = furi_thread_flags_wait(0x7F, FuriFlagWaitAny, FuriWaitForever);
|
|
|
+ furi_check((events & FuriFlagError) == 0);
|
|
|
+
|
|
|
+ if (events & WorkerEvtStop)
|
|
|
+ {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (events & WorkerEvtModeChange)
|
|
|
+ {
|
|
|
+ if (coleco->mode)
|
|
|
+ {
|
|
|
+ furi_hal_gpio_write(pin_up, !coleco->button_up);
|
|
|
+ furi_hal_gpio_write(pin_down, !coleco->button_down);
|
|
|
+ furi_hal_gpio_write(pin_right, !coleco->button_right);
|
|
|
+ furi_hal_gpio_write(pin_left, !coleco->button_left);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ furi_hal_gpio_write(pin_left, (coleco->button_code & 1));
|
|
|
+ furi_hal_gpio_write(pin_down, (coleco->button_code & 2));
|
|
|
+ furi_hal_gpio_write(pin_right, (coleco->button_code & 4));
|
|
|
+ furi_hal_gpio_write(pin_up, (coleco->button_code & 8));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (events & WorkerEvtUpChange)
|
|
|
+ {
|
|
|
+ if (coleco->mode)
|
|
|
+ {
|
|
|
+ furi_hal_gpio_write(pin_up, !coleco->button_up);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (events & WorkerEvtDownChange)
|
|
|
+ {
|
|
|
+ if (coleco->mode)
|
|
|
+ {
|
|
|
+ furi_hal_gpio_write(pin_down, !coleco->button_down);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (events & WorkerEvtRightChange)
|
|
|
+ {
|
|
|
+ if (coleco->mode)
|
|
|
+ {
|
|
|
+ furi_hal_gpio_write(pin_right, !coleco->button_right);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (events & WorkerEvtLeftChange)
|
|
|
+ {
|
|
|
+ if (coleco->mode)
|
|
|
+ {
|
|
|
+ furi_hal_gpio_write(pin_left, !coleco->button_left);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (events & WorkerEvtCodeChange)
|
|
|
+ {
|
|
|
+ if (!coleco->mode)
|
|
|
+ {
|
|
|
+ furi_hal_gpio_write(pin_left, !(coleco->button_code & 1));
|
|
|
+ furi_hal_gpio_write(pin_down, !(coleco->button_code & 2));
|
|
|
+ furi_hal_gpio_write(pin_right, !(coleco->button_code & 4));
|
|
|
+ furi_hal_gpio_write(pin_up, !(coleco->button_code & 8));
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- coleco->mode = furi_hal_gpio_read(&gpio_ext_pc1);
|
|
|
- output_update(coleco);
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
static void render_callback(Canvas* const canvas, void* context)
|
|
|
@@ -80,10 +147,16 @@ static void render_callback(Canvas* const canvas, void* context)
|
|
|
|
|
|
canvas_set_font(canvas, FontPrimary);
|
|
|
canvas_draw_str_aligned(canvas, 64, 8, AlignCenter, AlignBottom, "ColecoVision");
|
|
|
+
|
|
|
+ canvas_set_font(canvas, FontSecondary);
|
|
|
+
|
|
|
if (coleco->dpad)
|
|
|
{
|
|
|
- canvas_set_font(canvas, FontSecondary);
|
|
|
- canvas_draw_str_aligned(canvas, 64, 18, AlignCenter, AlignBottom, "D-pad");
|
|
|
+ canvas_draw_str_aligned(canvas, 64, 18, AlignCenter, AlignBottom, "d-pad");
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ canvas_draw_str_aligned(canvas, 64, 18, AlignCenter, AlignBottom, "numbers");
|
|
|
}
|
|
|
|
|
|
release_mutex((ValueMutex*)context, coleco);
|
|
|
@@ -119,11 +192,23 @@ static Coleco* coleco_alloc()
|
|
|
furi_hal_gpio_init(pin_left, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
|
|
|
furi_hal_gpio_init(pin_fire, GpioModeOutputPushPull, GpioPullNo, GpioSpeedVeryHigh);
|
|
|
|
|
|
- output_update(coleco);
|
|
|
+ furi_hal_gpio_write(pin_up, true);
|
|
|
+ furi_hal_gpio_write(pin_down, true);
|
|
|
+ furi_hal_gpio_write(pin_right, true);
|
|
|
+ furi_hal_gpio_write(pin_left, true);
|
|
|
+ furi_hal_gpio_write(pin_fire, true);
|
|
|
|
|
|
// configure mode pin
|
|
|
furi_hal_gpio_init(pin_mode, GpioModeInterruptRiseFall, GpioPullNo, GpioSpeedVeryHigh);
|
|
|
|
|
|
+ // set up output worker thread
|
|
|
+ coleco->thread = furi_thread_alloc();
|
|
|
+ furi_thread_set_name(coleco->thread, "ColecoOutputWorker");
|
|
|
+ furi_thread_set_stack_size(coleco->thread, 1024);
|
|
|
+ furi_thread_set_context(coleco->thread, coleco);
|
|
|
+ furi_thread_set_callback(coleco->thread, coleco_output_worker);
|
|
|
+ furi_thread_start(coleco->thread);
|
|
|
+
|
|
|
return coleco;
|
|
|
}
|
|
|
|
|
|
@@ -131,6 +216,10 @@ static void coleco_free(Coleco* coleco)
|
|
|
{
|
|
|
furi_assert(coleco);
|
|
|
|
|
|
+ furi_thread_flags_set(furi_thread_get_id(coleco->thread), WorkerEvtStop);
|
|
|
+ furi_thread_join(coleco->thread);
|
|
|
+ furi_thread_free(coleco->thread);
|
|
|
+
|
|
|
button_panel_free(coleco->button_panel);
|
|
|
|
|
|
free(coleco);
|
|
|
@@ -161,9 +250,6 @@ int32_t coleco_app(void* p)
|
|
|
Gui* gui = furi_record_open("gui");
|
|
|
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
|
|
|
|
|
- // enable mode ISR
|
|
|
- furi_hal_gpio_add_int_callback(pin_mode, mode_isr, &coleco_mutex);
|
|
|
-
|
|
|
PluginEvent event;
|
|
|
for (bool processing = true; processing;)
|
|
|
{
|
|
|
@@ -184,10 +270,12 @@ int32_t coleco_app(void* p)
|
|
|
if (event.input.type == InputTypePress)
|
|
|
{
|
|
|
coleco->button_up = true;
|
|
|
+ furi_thread_flags_set(furi_thread_get_id(coleco->thread), WorkerEvtUpChange);
|
|
|
}
|
|
|
else if (event.input.type == InputTypeRelease)
|
|
|
{
|
|
|
coleco->button_up = false;
|
|
|
+ furi_thread_flags_set(furi_thread_get_id(coleco->thread), WorkerEvtUpChange);
|
|
|
}
|
|
|
}
|
|
|
else // FIXME: hack to allow the 1 to be pressed
|
|
|
@@ -195,10 +283,12 @@ int32_t coleco_app(void* p)
|
|
|
if (event.input.type == InputTypePress)
|
|
|
{
|
|
|
coleco->button_code = 0x0D;
|
|
|
+ furi_thread_flags_set(furi_thread_get_id(coleco->thread), WorkerEvtCodeChange);
|
|
|
}
|
|
|
else if (event.input.type == InputTypeRelease)
|
|
|
{
|
|
|
coleco->button_code = 0x0F;
|
|
|
+ furi_thread_flags_set(furi_thread_get_id(coleco->thread), WorkerEvtCodeChange);
|
|
|
}
|
|
|
}
|
|
|
break;
|
|
|
@@ -208,10 +298,12 @@ int32_t coleco_app(void* p)
|
|
|
if (event.input.type == InputTypePress)
|
|
|
{
|
|
|
coleco->button_down = true;
|
|
|
+ furi_thread_flags_set(furi_thread_get_id(coleco->thread), WorkerEvtDownChange);
|
|
|
}
|
|
|
else if (event.input.type == InputTypeRelease)
|
|
|
{
|
|
|
coleco->button_down = false;
|
|
|
+ furi_thread_flags_set(furi_thread_get_id(coleco->thread), WorkerEvtDownChange);
|
|
|
}
|
|
|
}
|
|
|
break;
|
|
|
@@ -221,10 +313,12 @@ int32_t coleco_app(void* p)
|
|
|
if (event.input.type == InputTypePress)
|
|
|
{
|
|
|
coleco->button_right = true;
|
|
|
+ furi_thread_flags_set(furi_thread_get_id(coleco->thread), WorkerEvtRightChange);
|
|
|
}
|
|
|
else if (event.input.type == InputTypeRelease)
|
|
|
{
|
|
|
coleco->button_right = false;
|
|
|
+ furi_thread_flags_set(furi_thread_get_id(coleco->thread), WorkerEvtRightChange);
|
|
|
}
|
|
|
}
|
|
|
break;
|
|
|
@@ -234,10 +328,12 @@ int32_t coleco_app(void* p)
|
|
|
if (event.input.type == InputTypePress)
|
|
|
{
|
|
|
coleco->button_left = true;
|
|
|
+ furi_thread_flags_set(furi_thread_get_id(coleco->thread), WorkerEvtLeftChange);
|
|
|
}
|
|
|
else if (event.input.type == InputTypeRelease)
|
|
|
{
|
|
|
coleco->button_left = false;
|
|
|
+ furi_thread_flags_set(furi_thread_get_id(coleco->thread), WorkerEvtLeftChange);
|
|
|
}
|
|
|
}
|
|
|
break;
|
|
|
@@ -247,10 +343,12 @@ int32_t coleco_app(void* p)
|
|
|
if (event.input.type == InputTypePress)
|
|
|
{
|
|
|
coleco->button_fire = true;
|
|
|
+ furi_hal_gpio_write(pin_fire, !coleco->button_fire);
|
|
|
}
|
|
|
else if (event.input.type == InputTypeRelease)
|
|
|
{
|
|
|
coleco->button_fire = false;
|
|
|
+ furi_hal_gpio_write(pin_fire, !coleco->button_fire);
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
@@ -274,6 +372,8 @@ int32_t coleco_app(void* p)
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
|
+
|
|
|
+ view_port_update(view_port);
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
@@ -281,8 +381,6 @@ int32_t coleco_app(void* p)
|
|
|
FURI_LOG_D("Coleco", "FuriMessageQueue: event timeout");
|
|
|
}
|
|
|
|
|
|
- output_update(coleco);
|
|
|
- view_port_update(view_port);
|
|
|
release_mutex(&coleco_mutex, coleco);
|
|
|
}
|
|
|
|