| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626 |
- commit ecce5b6363adb067cef424eab09fead2f038baf5
- Author: Kris Bahnsen <Kris@KBEmbedded.com>
- Date: Fri Nov 8 19:20:53 2024 -0800
- gblink_pinconf: add save/load configurations and helper funcs
-
- The pin get/set functions have _by_gpiopin and _by_pinnum variants
- with macros linking the original functions to _by_gpiopin
-
- Signed-off-by: Kris Bahnsen <Kris@KBEmbedded.com>
- diff --git a/gblink/gblink_pinconf.c b/gblink/gblink_pinconf.c
- index 83e7ef206..abb5766cd 100644
- --- a/gblink/gblink_pinconf.c
- +++ b/gblink/gblink_pinconf.c
- @@ -2,13 +2,26 @@
- // Copyright (c) 2023 KBEmbedded
-
- #include <furi.h>
- -#include <furi_hal.h>
- +#include <storage/storage.h>
- +#include <lib/toolbox/stream/stream.h>
- +#include <lib/flipper_format/flipper_format.h>
-
- #include <stdint.h>
-
- #include <gblink/include/gblink.h>
- #include "gblink_i.h"
-
- +#define PINCONF_FILE_TYPE "Flipper GB Link Pinconf"
- +#define PINCONF_FILE_VER 1
- +
- +#define PINCONF_ORIG "Original"
- +#define PINCONF_MLVK "MLVK2.5"
- +#define PINCONF_CUST "Custom"
- +
- +#define PINCONF_SI "SI"
- +#define PINCONF_SO "SO"
- +#define PINCONF_CLK "CLK"
- +
- struct gblink_pins {
- const GpioPin *serin;
- const GpioPin *serout;
- @@ -33,13 +46,14 @@ const struct gblink_pins common_pinouts[PINOUT_COUNT] = {
- },
- };
-
- -int gblink_pin_set(void *handle, gblink_bus_pins pin, const GpioPin *gpio)
- +
- +int gblink_pin_set_by_gpiopin(void *handle, gblink_bus_pins pin, const GpioPin *gpio)
- {
- furi_assert(handle);
- struct gblink *gblink = handle;
-
- if (furi_mutex_acquire(gblink->start_mutex, 0) != FuriStatusOk)
- - return 1;
- + return -1;
-
- switch (pin) {
- case PIN_SERIN:
- @@ -64,7 +78,7 @@ int gblink_pin_set(void *handle, gblink_bus_pins pin, const GpioPin *gpio)
- return 0;
- }
-
- -const GpioPin *gblink_pin_get(void *handle, gblink_bus_pins pin)
- +const GpioPin *gblink_pin_get_by_gpiopin(void *handle, gblink_bus_pins pin)
- {
- furi_assert(handle);
- struct gblink *gblink = handle;
- @@ -91,8 +105,11 @@ int gblink_pin_set_default(void *handle, gblink_pinouts pinout)
- furi_assert(handle);
- struct gblink *gblink = handle;
-
- + if (pinout == PINOUT_CUSTOM || pinout >= PINOUT_COUNT)
- + return -1;
- +
- if (furi_mutex_acquire(gblink->start_mutex, 0) != FuriStatusOk)
- - return 1;
- + return -1;
-
- gblink->serin = common_pinouts[pinout].serin;
- gblink->serout = common_pinouts[pinout].serout;
- @@ -127,3 +144,281 @@ int gblink_pin_get_default(void *handle)
-
- return i;
- }
- +
- +int gblink_pin_set(void *handle, gblink_bus_pins pin, unsigned int pinnum)
- +{
- + furi_assert(handle);
- + furi_assert(pinnum < gpio_pins_count);
- +
- + struct gblink *gblink = handle;
- +
- + if (furi_mutex_acquire(gblink->start_mutex, 0) != FuriStatusOk)
- + return -1;
- +
- + switch (pin) {
- + case PIN_SERIN:
- + gblink->serin = gpio_pins[pinnum].pin;
- + break;
- + case PIN_SEROUT:
- + gblink->serout = gpio_pins[pinnum].pin;
- + break;
- + case PIN_CLK:
- + gblink->clk = gpio_pins[pinnum].pin;
- + break;
- + case PIN_SD:
- + gblink->sd = gpio_pins[pinnum].pin;
- + break;
- + default:
- + furi_crash();
- + break;
- + }
- +
- + furi_mutex_release(gblink->start_mutex);
- +
- + return 0;
- +}
- +
- +int gblink_pin_get(void *handle, gblink_bus_pins pin)
- +{
- + furi_assert(handle);
- + struct gblink *gblink = handle;
- + unsigned int i;
- +
- + for (i = 0; i < gpio_pins_count; i++) {
- + switch (pin) {
- + case PIN_SERIN:
- + if (gpio_pins[i].pin == gblink->serin)
- + return i;
- + break;
- + case PIN_SEROUT:
- + if (gpio_pins[i].pin == gblink->serout)
- + return i;
- + break;
- + case PIN_CLK:
- + if (gpio_pins[i].pin == gblink->clk)
- + return i;
- + break;
- + case PIN_SD:
- + if (gpio_pins[i].pin == gblink->sd)
- + return i;
- + break;
- + default:
- + furi_crash();
- + break;
- + }
- + }
- +
- + return -1;
- +}
- +
- +int gblink_pin_count_max(void)
- +{
- + unsigned int i;
- + int count = 0;
- +
- + for (i = 0; i < gpio_pins_count; i++)
- + if (!gpio_pins[i].debug)
- + count = i;
- +
- + return count;
- +}
- +
- +int gblink_pin_get_next(unsigned int pinnum)
- +{
- + unsigned int i;
- +
- + /* The check could be eliminated and just rely on the return -1 at the
- + * end of the function, but this is a shortcut so we don't have to walk
- + * through the whole table just to find out its an out-of-bounds pin.
- + */
- + if (pinnum >= gpio_pins_count)
- + return -1;
- +
- + for (i = pinnum; i < gpio_pins_count; i++)
- + if (!gpio_pins[i].debug)
- + return i;
- +
- + return -1;
- +}
- +
- +int gblink_pin_get_prev(unsigned int pinnum)
- +{
- + int i;
- +
- + /* The check could be eliminated and just rely on the return -1 at the
- + * end of the function, but this is a shortcut so we don't have to walk
- + * through the whole table just to find out its an out-of-bounds pin.
- + */
- + if (pinnum >= gpio_pins_count)
- + return -1;
- +
- + for (i = pinnum; i >= 0; i--)
- + if (!gpio_pins[i].debug)
- + return i;
- +
- + return -1;
- +}
- +
- +bool gblink_pinconf_load(void *gblink)
- +{
- +
- + Storage *storage = NULL;;
- + FlipperFormat *data_file = NULL;
- + FuriString *string = NULL;
- + uint32_t val;
- + bool ret = false;
- +
- + storage = furi_record_open(RECORD_STORAGE);
- +
- + string = furi_string_alloc_set(APP_DATA_PATH(""));
- + storage_common_resolve_path_and_ensure_app_directory(storage, string);
- + furi_string_cat_str(string, ".gblink_pinconf");
- +
- + data_file = flipper_format_file_alloc(storage);
- +
- + if (!flipper_format_file_open_existing(data_file, furi_string_get_cstr(string))) {
- + FURI_LOG_E("pinconf", "Error opening file %s", furi_string_get_cstr(string));
- + goto out;
- + }
- +
- + if (!flipper_format_read_header(data_file, string, &val)) {
- + FURI_LOG_E("pinconf", "Missing or incorrect header");
- + goto out;
- + }
- +
- + if (strncmp(furi_string_get_cstr(string), PINCONF_FILE_TYPE, strlen(PINCONF_FILE_TYPE)) ||
- + val != PINCONF_FILE_VER) {
- + FURI_LOG_E("pinconf", "Type or version mismatch");
- + goto out;
- + }
- +
- + if (!flipper_format_read_string(data_file, "Mode", string)) {
- + FURI_LOG_E("pinconf", "Missing Mode");
- + goto out;
- + }
- +
- + if (!strncmp(furi_string_get_cstr(string), PINCONF_ORIG, strlen(PINCONF_ORIG))) {
- + FURI_LOG_I("pinconf", "Setting Original pinout");
- + gblink_pin_set_default(gblink, PINOUT_ORIGINAL);
- + goto out;
- + }
- +
- + if (!strncmp(furi_string_get_cstr(string), PINCONF_MLVK, strlen(PINCONF_MLVK))) {
- + FURI_LOG_I("pinconf", "Setting MALVEKE 2.5 pinout");
- + gblink_pin_set_default(gblink, PINOUT_MALVEKE_EXT1);
- + goto out;
- + }
- +
- + if (!strncmp(furi_string_get_cstr(string), PINCONF_CUST, strlen(PINCONF_CUST))) {
- + FURI_LOG_I("pinconf", "Setting Custom pinout");
- + }
- +
- + if (!flipper_format_read_uint32(data_file, PINCONF_SI, &val, 1)) {
- + FURI_LOG_E("pinconf", "Missing SI");
- + goto out;
- + } else {
- + gblink_pin_set(gblink, PIN_SERIN, val);
- + }
- +
- + if (!flipper_format_read_uint32(data_file, PINCONF_SO, &val, 1)) {
- + FURI_LOG_E("pinconf", "Missing SO");
- + goto out;
- + } else {
- + gblink_pin_set(gblink, PIN_SEROUT, val);
- + }
- +
- + if (!flipper_format_read_uint32(data_file, PINCONF_CLK, &val, 1)) {
- + FURI_LOG_E("pinconf", "Missing CLK");
- + goto out;
- + } else {
- + gblink_pin_set(gblink, PIN_CLK, val);
- + }
- +
- + ret = true;
- +
- +out:
- + flipper_format_file_close(data_file);
- + furi_string_free(string);
- + furi_record_close(RECORD_STORAGE);
- + return ret;
- +}
- +
- +/* XXX: TODO: I think there is a way to build this ahead of time and
- + * write it in one go to be a bit more time efficient.
- + */
- +bool gblink_pinconf_save(void *gblink)
- +{
- +
- + Storage *storage = NULL;;
- + FlipperFormat *data_file = NULL;
- + FuriString *string = NULL;
- + int rc;
- + uint32_t pin;
- + bool ret = false;
- +
- + storage = furi_record_open(RECORD_STORAGE);
- +
- + string = furi_string_alloc_set(APP_DATA_PATH(""));
- + storage_common_resolve_path_and_ensure_app_directory(storage, string);
- + furi_string_cat_str(string, ".gblink_pinconf");
- +
- + data_file = flipper_format_file_alloc(storage);
- +
- + if (!flipper_format_file_open_always(data_file, furi_string_get_cstr(string))) {
- + FURI_LOG_E("pinconf", "Error opening file %s", furi_string_get_cstr(string));
- + goto out;
- + }
- +
- + if (!flipper_format_write_header_cstr(data_file, PINCONF_FILE_TYPE, PINCONF_FILE_VER)) {
- + FURI_LOG_E("pinconf", "Error writing header to file");
- + goto out;
- + }
- +
- + rc = gblink_pin_get_default(gblink);
- + switch (rc) {
- + case 0:
- + if (!flipper_format_write_string_cstr(data_file, "Mode", PINCONF_ORIG))
- + FURI_LOG_E("pinconf", "Error writing mode to file");
- + goto out;
- + break;
- + case 1:
- + if (!flipper_format_write_string_cstr(data_file, "Mode", PINCONF_MLVK))
- + FURI_LOG_E("pinconf", "Error writing mode to file");
- + goto out;
- + break;
- + case -1:
- + if (!flipper_format_write_string_cstr(data_file, "Mode", PINCONF_CUST))
- + FURI_LOG_E("pinconf", "Error writing mode to file");
- + break;
- + default:
- + FURI_LOG_E("pinconf", "Unknown mode");
- + goto out;
- + break;
- + }
- +
- + pin = gblink_pin_get(gblink, PIN_SERIN);
- + if (!flipper_format_write_uint32(data_file, "SI", &pin, 1)) {
- + FURI_LOG_E("pinconf", "Error writing SI to file");
- + goto out;
- + }
- +
- + pin = gblink_pin_get(gblink, PIN_SEROUT);
- + if (!flipper_format_write_uint32(data_file, "SO", &pin, 1)) {
- + FURI_LOG_E("pinconf", "Error writing SO to file");
- + goto out;
- + }
- +
- + pin = gblink_pin_get(gblink, PIN_CLK);
- + if (!flipper_format_write_uint32(data_file, "CLK", &pin, 1)) {
- + FURI_LOG_E("pinconf", "Error writing CLK to file");
- + }
- +
- + ret = true;
- +
- +out:
- + flipper_format_file_close(data_file);
- + furi_string_free(string);
- + furi_record_close(RECORD_STORAGE);
- + return ret;
- +}
- +
- diff --git a/gblink/include/gblink.h b/gblink/include/gblink.h
- index d60fa49fb..eb714872c 100644
- --- a/gblink/include/gblink.h
- +++ b/gblink/include/gblink.h
- @@ -49,7 +49,8 @@ typedef enum {
- } gblink_speed;
-
- typedef enum {
- - PINOUT_ORIGINAL,
- + PINOUT_CUSTOM = -1,
- + PINOUT_ORIGINAL = 0,
- PINOUT_MALVEKE_EXT1,
- PINOUT_COUNT,
- } gblink_pinouts;
- diff --git a/gblink/include/gblink_pinconf.h b/gblink/include/gblink_pinconf.h
- index eb264abbf..3be45571d 100644
- --- a/gblink/include/gblink_pinconf.h
- +++ b/gblink/include/gblink_pinconf.h
- @@ -21,7 +21,7 @@ extern "C" {
- *
- * @note The gblink instance must not be gblink_start()'ed!
- *
- - * @returns 0 on success, 1 if gblink instance is not gblink_stop()'ed.
- + * @returns 0 on success, -1 if gblink instance is not gblink_stop()'ed.
- */
- int gblink_pin_set_default(void *handle, gblink_pinouts pinout);
-
- @@ -35,27 +35,115 @@ int gblink_pin_set_default(void *handle, gblink_pinouts pinout);
- int gblink_pin_get_default(void *handle);
-
- /**
- - * Set a gpio pin to a specific pin mode
- + * Set a GPIO pin to a specific pin mode for the EXT interface
- + *
- + * @param handle Pointer to gblink handle
- + * @param pin Pin mode to assign to the gpio pin
- + * @param pinnum GPIO pin number to assign pin mode to
- + *
- + * @note The gblink instance must not be gblink_start()'ed!
- + *
- + * @returns 0 on success, -1 if gblink instance is not gblink_stop()ed
- + */
- +int gblink_pin_set(void *handle, gblink_bus_pins pin, unsigned int pinum);
- +
- +/**
- + * Get the pin number associated with the requested pin mode
- + *
- + *
- + * @param handle Pointer to gblink handle
- + * @param pin Pin mode to inquire about
- + *
- + * @returns Pin number of the requested pin or -1 on error
- + */
- +int gblink_pin_get(void *handle, gblink_bus_pins pin);
- +
- +/**
- + * Set a gpio pin to a specific pin mode via GpioPin
- *
- * @param handle Pointer to gblink handle
- * @param pin Pin mode to assign to the gpio pin
- * @param gpio Which gpio pin to assign the pin mode
- *
- * @note The gblink instance must not be gblink_start()'ed!
- + * @note There is no sane way to do bounds checking with this function, so be
- + * careful when passing pointers to ensure they are actually Flipper GpioPin
- + * references.
- *
- - * @returns 0 on success, 1 if gblink instance is not gblink_stop()'ed.
- + * @returns 0 on success, -1 if gblink instance is not gblink_stop()'ed.
- */
- -int gblink_pin_set(void *handle, gblink_bus_pins pin, const GpioPin *gpio);
- +int gblink_pin_set_by_gpiopin(void *handle, gblink_bus_pins pin, const GpioPin *gpio);
-
- /**
- - * Get the gpio pin associated with the requested pin mode
- + * Get the GpioPin associated with the requested pin mode
- *
- * @param handle Pointer to gblink handle
- * @param pin Pin mode to inquire about
- *
- * @returns GpioPin pointer
- */
- -const GpioPin *gblink_pin_get(void *handle, gblink_bus_pins pin);
- +const GpioPin *gblink_pin_get_by_gpiopin(void *handle, gblink_bus_pins pin);
- +
- +/**
- + * Returns the pinnum of the highest usable, non-debug pin.
- + *
- + * @returns count of highest usable, non-debug pin or -1 on error
- + */
- +int gblink_pin_count_max(void);
- +
- +/**
- + * Get the next usable, non-debug GPIO pin by number.
- + *
- + * The return value is the next usable, non-debug pin starting from pinnum and
- + * will include pinnum if it is a valid pin.
- + *
- + * @param pinnum GPIO pin number to check if it is a valid pin.
- + *
- + * @returns -1 on error or no more valid pins. Any other value is the next usable
- + * pin which can include pinnum if it is usable. If pinnum is not usable, the next
- + * numbered pin which is will be returned or -1 if there are no further pins.
- + */
- +int gblink_pin_get_next(unsigned int pinnum);
- +
- +/**
- + * Get the previous usable, non-debug GPIO pin by number.
- + *
- + * The return value is the previous usable, non-debug pin starting from pinnum and
- + * will include pinnum if it is a valid pin.
- + *
- + * @param pinnum GPIO pin number to check if it is a valid pin.
- + *
- + * @returns -1 on error or no more valid pins. Any other value is the previous usable
- + * pin which can include pinnum if it is usable. If pinnum is not usable, the previous
- + * numbered pin which is will be returned or -1 if there are no further pins.
- + */
- +int gblink_pin_get_prev(unsigned int pinnum);
- +
- +/**
- + * Load pin configuration from file automatically
- + * Loads from .gblink_pinconf in app data folder
- + *
- + * @param gblink Pointer to gblink instance to set pins configurations
- + *
- + * @returns true on success, false on error
- + *
- + * @note This function should be called from the context of the application and
- + * not any other threads as it uses the app data folder to load data from
- + */
- +bool gblink_pinconf_load(void *gblink);
- +
- +/**
- + * Save current pin configuration to file automatically
- + * Saves to .gblink_pinconf in app data folder
- + *
- + * @param gblink Pointer to gblink instance to save pins configurations
- + *
- + * @returns true on success, false on error
- + *
- + * @note This function should be called from the context of the application and
- + * not any other threads as it uses the app data folder to save data to.
- + */
- +bool gblink_pinconf_save(void *gblink);
-
- #ifdef __cplusplus
- }
- diff --git a/protocols/printer/include/printer_proto.h b/protocols/printer/include/printer_proto.h
- index 9124b2fcb..094c7295f 100644
- --- a/protocols/printer/include/printer_proto.h
- +++ b/protocols/printer/include/printer_proto.h
- @@ -91,50 +91,27 @@ void printer_callback_context_set(void *printer_handle, void *context);
- */
- void printer_callback_set(void *printer_handle, void (*callback)(void *context, struct gb_image *image, enum cb_reason reason));
-
- -/* Can only be run after alloc, before start */
- /**
- - * Set one of the pre-configured pinouts
- - *
- - * @param printer_handle Printer instance handle
- - * @param pinout Which pinout to use
- - *
- - * @note The printer instance must not be actively sending or receiving
- - *
- - * @returns 0 on success, 1 if gblink instance is not gblink_stop()'ed.
- - */
- -int printer_pin_set_default(void *printer_handle, gblink_pinouts pinout);
- -
- -/**
- - * Set a gpio pin to a specific pin mode
- - *
- - * @param printer_handle Printer instance handle
- - * @param pin Pin mode to assign to the gpio pin
- - * @param gpio Which gpio pin to assign the pin mode
- - *
- - * @note The printer instance must not be actively sending or receiving
- + * Stop a printer instance
- *
- - * @returns 0 on success, 1 if gblink instance is not gblink_stop()'ed.
- - */
- -int printer_pin_set(void *printer_handle, gblink_bus_pins pin, const GpioPin *gpio);
- -
- -/**
- - * Get the gpio pin associated with the requested pin mode
- + * Disables interrupts, stops any pending timers, and enters back to an idle
- + * state. Once called, re-allows changes to be made.
- *
- * @param printer_handle Printer instance handle
- - * @param pin Pin mode to inquire about
- - *
- - * @returns GpioPin pointer
- */
- -const GpioPin *printer_pin_get(void *printer_handle, gblink_bus_pins pin);
- +void printer_stop(void *printer_handle);
-
- /**
- - * Stop a printer instance
- + * Get the gblink handle associated with the printer instance.
- *
- - * Disables interrupts, stops any pending timers, and enters back to an idle
- - * state. Once called, re-allows changes to be made.
- + * @warning It is not recommended to use this to change any gblink variables other
- + * than pin settings! Changing any other settings such as mode, speed, timeout,
- + * callback, etc., can break printer communication.
- *
- * @param printer_handle Printer instance handle
- + *
- + * @returns Pointer that can be used with gblink calls directly
- */
- -void printer_stop(void *printer_handle);
- +void *printer_gblink_handle_get(void *printer_handle);
-
- #endif // PRINTER_PROTO_H
- diff --git a/protocols/printer/printer_proto.c b/protocols/printer/printer_proto.c
- index 9430c6d3a..374ae601b 100644
- --- a/protocols/printer/printer_proto.c
- +++ b/protocols/printer/printer_proto.c
- @@ -4,6 +4,7 @@
- #include <furi.h>
-
- #include <gblink/include/gblink.h>
- +#include <gblink/include/gblink_pinconf.h>
- #include <protocols/printer/include/printer_proto.h>
- #include "printer_i.h"
-
- @@ -54,6 +55,7 @@ void *printer_alloc(void)
- printer->image = malloc(sizeof(struct gb_image));
-
- printer->gblink_handle = gblink_alloc();
- + gblink_pinconf_load(printer->gblink_handle);
-
- /* Set up some settings for the print protocol. The final send/receive() calls
- * may clobber some of these, but that is intentional and they don't need to
- @@ -96,25 +98,13 @@ void printer_callback_set(void *printer_handle, void (*callback)(void *context,
- printer->callback = callback;
- }
-
- -int printer_pin_set_default(void *printer_handle, gblink_pinouts pinout)
- +void *printer_gblink_handle_get(void *printer_handle)
- {
- struct printer_proto *printer = printer_handle;
- - return gblink_pin_set_default(printer->gblink_handle, pinout);
- -}
- -
- -int printer_pin_set(void *printer_handle, gblink_bus_pins pin, const GpioPin *gpio)
- -{
- - struct printer_proto *printer = printer_handle;
- - return gblink_pin_set(printer->gblink_handle, pin, gpio);
- -}
-
- -const GpioPin *printer_pin_get(void *printer_handle, gblink_bus_pins pin)
- -{
- - struct printer_proto *printer = printer_handle;
- - return gblink_pin_get(printer->gblink_handle, pin);
- + return printer->gblink_handle;
- }
-
- -
- void printer_stop(void *printer_handle)
- {
- struct printer_proto *printer = printer_handle;
|