From 9b320e9261b6edc76b6c7fc079549b6a871deb9f Mon Sep 17 00:00:00 2001 From: ardera <2488440+ardera@users.noreply.github.com> Date: Sun, 26 Jan 2020 18:16:32 +0100 Subject: [PATCH 1/8] began work on GPIO --- include/flutter-pi.h | 2 - include/platformchannel.h | 19 ++ include/pluginregistry.h | 4 +- src/pluginregistry.c | 9 +- src/plugins/gpio-plugin.c | 434 ++++++++++++++++++++++++++++++++++++++ src/plugins/gpio-plugin.h | 32 +++ 6 files changed, 495 insertions(+), 5 deletions(-) create mode 100644 src/plugins/gpio-plugin.c create mode 100644 src/plugins/gpio-plugin.h diff --git a/include/flutter-pi.h b/include/flutter-pi.h index f23f3866..233a3d7b 100644 --- a/include/flutter-pi.h +++ b/include/flutter-pi.h @@ -102,8 +102,6 @@ struct mousepointer_mtslot { #define ISSET(uint32bitmap, bit) (uint32bitmap[(bit)/32] & (1 << ((bit) & 0x1F))) -#define STREQ(a, b) (strcmp(a, b) == 0) - struct input_device { char path[PATH_MAX]; char name[256]; diff --git a/include/platformchannel.h b/include/platformchannel.h index f454dd59..ee158faa 100644 --- a/include/platformchannel.h +++ b/include/platformchannel.h @@ -96,6 +96,25 @@ struct StdMsgCodecValue { }; }; +#define STDVALUE_IS_NULL(value) ((value).type == kNull) +#define STDVALUE_IS_BOOL(value) (((value).type == kTrue) || ((value).type == kFalse)) +#define STDVALUE_AS_BOOL(value) ((value).type == kTrue) + +#define STDVALUE_IS_INT(value) (((value).type == kInt32) || ((value).type == kInt64)) +#define STDVALUE_AS_INT(value) ((value).type == kInt32 ? (int64_t) (value).int32_value : (value).int64_value) +#define STDVALUE_IS_FLOAT(value) ((value).type == kFloat64) +#define STDVALUE_AS_FLOAT(value) ((value).float64_value) +#define STDVALUE_IS_NUM(value) (STDVALUE_IS_INT(value) || STDVALUE_IS_FLOAT(value)) +#define STDVALUE_AS_NUM(value) (STDVALUE_IS_INT(value) ? STDVALUE_AS_INT(value) : STDVALUE_AS_FLOAT(value)) + +#define STDVALUE_IS_LIST(value) ((value).type == kList) +#define STDVALUE_IS_SIZE(value, _size) ((value).size == (_size)) +#define STDVALUE_IS_SIZED_LIST(value, _size) (STDVALUE_IS_LIST(value) && STDVALUE_IS_SIZE(value, _size)) + +#define STDVALUE_IS_INT_ARRAY(value) (((value).type == kInt32Array) || ((value).type == kInt64Array) || ((value).type == kUInt8Array)) +#define STDVALUE_IS_FLOAT_ARRAY(value) ((value).type == kFloat64Array) +#define STDVALUE_IS_NUM_ARRAY(value) (STDVALUE_IS_INT_ARRAY(value) || STDVALUE_IS_FLOAT_ARRAY(value)) + /// codec of an abstract channel object /// These tell this API how it should encode ChannelObjects -> platform messages /// and how to decode platform messages -> ChannelObjects. diff --git a/include/pluginregistry.h b/include/pluginregistry.h index 67c32132..51a66435 100644 --- a/include/pluginregistry.h +++ b/include/pluginregistry.h @@ -5,7 +5,9 @@ #include #include -#include "platformchannel.h" +#include + +#define STREQ(a, b) (strcmp(a, b) == 0) /// Callback for Initialization or Deinitialization. /// Return value is 0 for success, or anything else for an error diff --git a/src/pluginregistry.c b/src/pluginregistry.c index f1178117..57c2d888 100644 --- a/src/pluginregistry.c +++ b/src/pluginregistry.c @@ -8,6 +8,7 @@ #include "plugins/services-plugin.h" #include "plugins/testplugin.h" #include "plugins/elm327plugin.h" +#include "plugins/gpio-plugin.h" struct ChannelObjectReceiverData { @@ -27,11 +28,15 @@ struct FlutterPiPlugin hardcoded_plugins[] = { {.name = "services", .init = Services_init, .deinit = Services_deinit}, #ifdef BUILD_TESTPLUGIN - {.name = "testplugin", .init = TestPlugin_init, .deinit = TestPlugin_deinit} + {.name = "testplugin", .init = TestPlugin_init, .deinit = TestPlugin_deinit}, #endif #ifdef BUILD_ELM327PLUGIN - {.name = "elm327plugin", .init = ELM327Plugin_init, .deinit = ELM327Plugin_deinit} + {.name = "elm327plugin", .init = ELM327Plugin_init, .deinit = ELM327Plugin_deinit}, +#endif + +#ifdef BUILD_GPIO_PLUGIN + {.name = "gpio-plugin", .init = GpioPlugin_init, .deinit = GpioPlugin_deinit}, #endif }; //size_t hardcoded_plugins_count; diff --git a/src/plugins/gpio-plugin.c b/src/plugins/gpio-plugin.c new file mode 100644 index 00000000..33676e84 --- /dev/null +++ b/src/plugins/gpio-plugin.c @@ -0,0 +1,434 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include +#include "gpio-plugin.h" + + + +struct { + bool initialized; + + struct gpiod_chip *chips[GPIO_PLUGIN_MAX_CHIPS]; + size_t n_chips; + + // complete list of GPIO lines + struct gpiod_line **lines; + size_t n_lines; + + // GPIO lines that flutter is currently listening to + pthread_mutex_t listening_lines_mutex; + pthread_cond_t listening_line_added; + struct gpiod_line_bulk *listening_lines; +} gpio_plugin; + +struct { + void *handle; + + // GPIO chips + void (*chip_close)(struct gpiod_chip *chip); + const char *(*chip_name)(struct gpiod_chip *chip); + const char *(*chip_label)(struct gpiod_chip *chip); + unsigned int (*chip_num_lines)(struct gpiod_chip *chip); + + // GPIO lines + unsigned int (*line_offset)(struct gpiod_line *line); + const char *(*line_name)(struct gpiod_line *line); + const char *(*line_consumer)(struct gpiod_line *line); + int (*line_direction)(struct gpiod_line *line); + int (*line_active_state)(struct gpiod_line *line); + int (*line_bias)(struct gpiod_line *line); + bool (*line_is_used)(struct gpiod_line *line); + bool (*line_is_open_drain)(struct gpiod_line *line); + bool (*line_is_open_source)(struct gpiod_line *line); + int (*line_update)(struct gpiod_line *line); + int (*line_request)(struct gpiod_line *line, const struct gpiod_line_request_config *config, int default_val); + bool (*line_is_requested)(struct gpiod_line *line); + bool (*line_is_free)(struct gpiod_line *line); + int (*line_get_value)(struct gpiod_line *line); + int (*line_set_value)(struct gpiod_line *line, int value); + int (*line_set_config)(struct gpiod_line *line, int direction, int flags, int value); + int (*line_event_wait_bulk)(struct gpiod_line_bulk *bulk, const struct timespec *timeout, struct gpiod_line_bulk *event_bulk); + int (*line_event_read_multiple)(struct gpiod_line *line, struct gpiod_line_event *events, unsigned int num_events); + + // chip iteration + struct gpiod_chip_iter *(*chip_iter_new)(void); + void (*chip_iter_free_noclose)(struct gpiod_chip_iter *iter); + struct gpiod_chip *(*chip_iter_next_noclose)(struct gpiod_chip_iter *iter); + + // line iteration + struct gpiod_line_iter *(*line_iter_new)(struct gpiod_chip *chip); + void (*line_iter_free)(struct gpiod_line_iter *iter); + struct gpiod_line *(*line_iter_next)(struct gpiod_line_iter *iter); +} libgpiod; + +//#define gpiod_chip_iter_next_noclose libgpiod.chip_iter_next_noclose +//#define gpiod_line_iter_next libgpiod.line_iter_next + +int GpioPlugin_ensureGpiodInitialized() { + struct gpiod_chip_iter *chipiter; + struct gpiod_line_iter *lineiter; + struct gpiod_chip *chip; + struct gpiod_line *line; + int ok, i, j; + + if (gpio_plugin.initialized) return 0; + + libgpiod.handle = dlopen("libgpiod.so", RTLD_LOCAL | RTLD_LAZY); + if (!libgpiod.handle) { + perror("could not load libgpiod.so"); + return errno; + } + + LOAD_GPIOD_PROC(chip_close); + LOAD_GPIOD_PROC(chip_name); + LOAD_GPIOD_PROC(chip_label); + LOAD_GPIOD_PROC(chip_num_lines); + + LOAD_GPIOD_PROC(line_name); + LOAD_GPIOD_PROC(line_consumer); + LOAD_GPIOD_PROC(line_direction); + LOAD_GPIOD_PROC(line_active_state); + LOAD_GPIOD_PROC(line_bias); + LOAD_GPIOD_PROC(line_is_used); + LOAD_GPIOD_PROC(line_is_open_drain); + LOAD_GPIOD_PROC(line_is_open_source); + LOAD_GPIOD_PROC(line_update); + LOAD_GPIOD_PROC(line_request); + LOAD_GPIOD_PROC(line_is_requested); + LOAD_GPIOD_PROC(line_is_free); + LOAD_GPIOD_PROC(line_get_value); + LOAD_GPIOD_PROC(line_set_value); + LOAD_GPIOD_PROC(line_set_config); + + LOAD_GPIOD_PROC(chip_iter_new); + LOAD_GPIOD_PROC(chip_iter_free_noclose); + LOAD_GPIOD_PROC(chip_iter_next_noclose); + + LOAD_GPIOD_PROC(line_iter_new); + LOAD_GPIOD_PROC(line_iter_free); + LOAD_GPIOD_PROC(line_iter_next); + + + // iterate through the GPIO chips + chipiter = libgpiod.chip_iter_new(); + if (!chipiter) { + perror("could not create GPIO chip iterator"); + return errno; + } + + for (gpio_plugin.n_chips = 0, gpio_plugin.n_lines = 0, chip = libgpiod.chip_iter_next_noclose(chipiter); + chip; + gpio_plugin.n_chips++, chip = libgpiod.chip_iter_next_noclose(chipiter)) + { + gpio_plugin.chips[gpio_plugin.n_chips] = chip; + gpio_plugin.n_lines += libgpiod.chip_num_lines(chip); + } + libgpiod.chip_iter_free_noclose(chipiter); + + + // prepare the GPIO line list + gpio_plugin.lines = calloc(gpio_plugin.n_lines, sizeof(struct gpiod_line*)); + if (!gpio_plugin.lines) { + perror("could not allocate memory for GPIO line list"); + return errno; + } + + // iterate through the chips and put all lines into the list + for (i = 0, j = 0; i < gpio_plugin.n_chips; i++) { + lineiter = libgpiod.line_iter_new(gpio_plugin.chips[i]); + if (!lineiter) { + perror("could not create new GPIO line iterator"); + return errno; + } + + for (line = libgpiod.line_iter_next(lineiter); line; line = libgpiod.line_iter_next(lineiter), j++) + gpio_plugin.lines[j] = line; + + libgpiod.line_iter_free(lineiter); + } + + gpio_plugin.initialized = true; + return 0; +} + +int GpioPlugin_onGpiodMethodCall(char *channel, struct ChannelObject *object, FlutterPlatformMessageResponseHandle *responsehandle) { + unsigned int chip_index, line_index; + int ok; + + if STREQ("getNumChips", object->method) { + // check arg + if (!STDVALUE_IS_NULL(object->stdarg)) { + return PlatformChannel_respondError( + responsehandle, + kStandardMethodCallResponse, + "illegalargument", + "expected null as the argument", + NULL + ); + } + + // init GPIO + ok = GpioPlugin_ensureGpiodInitialized(); + if (ok != 0) { + return PlatformChannel_respondError( + responsehandle, + kStandardMethodCallResponse, + "couldnotinit", + "gpio-plugin failed to initialize. see flutter-pi log for details.", + NULL + ); + } + + // return num chips + return PlatformChannel_respond( + responsehandle, + &(struct ChannelObject) { + .codec = kStandardMethodCallResponse, + .success = true, + .stdresult = { + .type = kInt32, + .int32_value = gpio_plugin.n_chips + } + } + ); + + } else if STREQ("getChipDetails", object->method) { + // check arg + if (!STDVALUE_IS_INT(object->stdarg)) { + return PlatformChannel_respondError( + responsehandle, + kStandardMethodCallResponse, + "illegalargument", + "expected chip index as an integer argument.", + NULL + ); + } + + // init GPIO + ok = GpioPlugin_ensureGpiodInitialized(); + if (ok != 0) { + return PlatformChannel_respondError( + responsehandle, + kStandardMethodCallResponse, + "couldnotinit", + "gpio-plugin failed to initialize. see flutter-pi log for details.", + NULL + ); + } + + chip_index = (unsigned int) STDVALUE_AS_INT(object->stdarg); + if (chip_index >= gpio_plugin.n_chips) { + return PlatformChannel_respondError( + responsehandle, + kStandardMethodCallResponse, + "illegalargument", + "chip index out of range", + NULL + ); + } + + // return chip details + return PlatformChannel_respond( + responsehandle, + &(struct ChannelObject) { + .codec = kStandardMethodCallResponse, + .success = true, + .stdresult = { + .type = kMap, + .size = 3, + .keys = (struct StdMsgCodecValue[3]) { + {.type = kString, .string_value = "name"}, + {.type = kString, .string_value = "label"}, + {.type = kString, .string_value = "numLines"}, + }, + .values = (struct StdMsgCodecValue[3]) { + {.type = kString, .string_value = libgpiod.chip_name(gpio_plugin.chips[chip_index])}, + {.type = kString, .string_value = libgpiod.chip_label(gpio_plugin.chips[chip_index])}, + {.type = kString, .string_value = libgpiod.chip_num_lines(gpio_plugin.chips[chip_index])}, + } + } + } + ); + } else if STREQ("getLineHandle", object->method) { + // check arg + if (!(STDVALUE_IS_SIZED_LIST(object->stdarg, 2) && STDVALUE_IS_INT(object->stdarg.list[0]) + && STDVALUE_IS_INT(object->stdarg.list[0]))) { + return PlatformChannel_respondError( + responsehandle, + kStandardMethodCallResponse, + "illegalargument", + "expected list containing two integers as the argument", + NULL + ); + } + + // init GPIO + ok = GpioPlugin_ensureGpiodInitialized(); + if (ok != 0) { + return PlatformChannel_respondError( + responsehandle, + kStandardMethodCallResponse, + "couldnotinit", + "gpio-plugin failed to initialize. see flutter-pi log for details.", + NULL + ); + } + + chip_index = STDVALUE_AS_INT(object->stdarg.list[0]); + line_index = STDVALUE_AS_INT(object->stdarg.list[1]); + + if (chip_index >= gpio_plugin.n_chips) { + return PlatformChannel_respondError( + responsehandle, + kStandardMethodCallResponse, + "illegalargument", + "chip index out of range", + NULL + ); + } + + if (line_index >= libgpiod.chip_num_lines(gpio_plugin.chips[chip_index])) { + return PlatformChannel_respondError( + responsehandle, + kStandardMethodCallResponse, + "illegalargument", + "line index out of range", + NULL + ); + } + + for (int i = 0; i < chip_index; i++) + line_index += libgpiod.chip_num_lines(gpio_plugin.chips[i]); + + return PlatformChannel_respond( + responsehandle, + &(struct ChannelObject) { + .codec = kStandardMethodCallResponse, + .success = true, + .stdresult = { + .type = kInt32, + .int32_value = line_index + } + } + ); + } else if STREQ("getLineDetails", object->method) { + // check arg + if (!STDVALUE_IS_INT(object->stdarg)) { + return PlatformChannel_respondError( + responsehandle, + kStandardMethodCallResponse, + "illegalargument", + "expected line handle (integer) as the argument", + NULL + ); + } + + // init GPIO + ok = GpioPlugin_ensureGpiodInitialized(); + if (ok != 0) { + return PlatformChannel_respondError( + responsehandle, + kStandardMethodCallResponse, + "couldnotinit", + "gpio-plugin failed to initialize. see flutter-pi log for details.", + NULL + ); + } + + line_index = STDVALUE_AS_INT(object->stdarg); + if (line_index >= gpio_plugin.n_lines) { + return PlatformChannel_respondError( + responsehandle, + kStandardMethodCallResponse, + "illegalargument", + "invalid line handle", + NULL + ); + } + + struct gpiod_line *line = gpio_plugin.lines[line_index]; + + // if we don't own the line, update it + if (!libgpiod.line_is_requested(line)) + libgpiod.line_update(line); + + char *direction = libgpiod.line_direction(line) == GPIOD_LINE_DIRECTION_INPUT ? + "GpioLineDirection.input" : "GpioLineDirection.output"; + char *activeState = libgpiod.line_active_state(line) == GPIOD_LINE_ACTIVE_STATE_HIGH ? + "GpioLineActiveState.high" : "GpioLineActiveState.low"; + + char *biasStr = "GpioLineBias.asIs"; + if (libgpiod.line_bias) { + int bias = libgpiod.line_bias(line); + biasStr = bias == GPIOD_LINE_BIAS_DISABLE ? "GpioLineBias.disable" : + bias == GPIOD_LINE_BIAS_PULL_UP ? "GpioLineBias.pullUp" : + "GpioLineBias.pullDown"; + } + + // return chip details + return PlatformChannel_respond( + responsehandle, + &(struct ChannelObject) { + .codec = kStandardMethodCallResponse, + .success = true, + .stdresult = { + .type = kMap, + .size = 10, + .keys = (struct StdMsgCodecValue[10]) { + {.type = kString, .string_value = "name"}, + {.type = kString, .string_value = "consumer"}, + {.type = kString, .string_value = "direction"}, + {.type = kString, .string_value = "activeState"}, + {.type = kString, .string_value = "bias"}, + {.type = kString, .string_value = "isUsed"}, + {.type = kString, .string_value = "openDrain"}, + {.type = kString, .string_value = "openSource"}, + {.type = kString, .string_value = "isRequested"}, + {.type = kString, .string_value = "isFree"} + }, + .values = (struct StdMsgCodecValue[10]) { + {.type = kString, .string_value = libgpiod.line_name(line)}, + {.type = kString, .string_value = libgpiod.line_consumer(line)}, + {.type = kString, .string_value = direction}, + {.type = kString, .string_value = activeState}, + {.type = kString, .string_value = biasStr}, + {.type = libgpiod.line_is_used(line) ? kTrue : kFalse}, + {.type = libgpiod.line_is_open_drain(line) ? kTrue : kFalse}, + {.type = libgpiod.line_is_open_source(line) ? kTrue : kFalse}, + {.type = libgpiod.line_is_requested(line) ? kTrue : kFalse}, + {.type = libgpiod.line_is_free(line) ? kTrue : kFalse} + } + } + } + ); + } else if STREQ("requestLine", object->method) { + + } else if STREQ("releaseLine", object->method) { + + } else if STREQ("reconfigureLine", object->method) { + + } else if STREQ("getLineValue", object->method) { + + } else if STREQ("setLineValue", object->method) { + + } +} + +int GpioPlugin_init(void) { + printf("[gpio-plugin] init.\n"); + + gpio_plugin.initialized = false; + + PluginRegistry_setReceiver(GPIO_PLUGIN_GPIOD_METHOD_CHANNEL, kStandardMethodCall, GpioPlugin_onGpiodMethodCall); +} + +int GpioPlugin_deinit(void) { + printf("[gpio-plugin] deinit.\n"); +} \ No newline at end of file diff --git a/src/plugins/gpio-plugin.h b/src/plugins/gpio-plugin.h new file mode 100644 index 00000000..d3f013ab --- /dev/null +++ b/src/plugins/gpio-plugin.h @@ -0,0 +1,32 @@ +#ifndef _GPIO_PLUGIN_H +#define _GPIO_PLUGIN_H + +#include + +#define GPIO_PLUGIN_GPIOD_METHOD_CHANNEL "flutter-pi/gpio/gpiod" +#define GPIO_PLUGIN_GPIOD_EVENT_CHANNEL "flutter-pi/gpio/gpiod_events" + +#define GPIO_PLUGIN_MAX_CHIPS 8 + +// a basic macro that loads a symbol from libgpiod, puts it into the libgpiod struct +// and returns the errno if an error ocurred + +#define LOAD_GPIOD_PROC(name) \ + do { \ + libgpiod.name = dlsym(libgpiod.handle, "gpiod_" #name); \ + if (!libgpiod.name) {\ + perror("could not resolve libgpiod procedure gpiod_" #name); \ + return errno; \ + } \ + } while (false) + +// because libgpiod doesn't provide it, but it's useful +static inline void gpiod_line_bulk_remove(struct gpiod_line_bulk *bulk, unsigned int index) { + memmove(&bulk->lines[index], &bulk->lines[index+1], sizeof(struct gpiod_line*) * (bulk->num_lines - index - 1)); + bulk->num_lines--; +} + +extern int GpioPlugin_init(void); +extern int GpioPlugin_deinit(void); + +#endif \ No newline at end of file From 13e2c7e69b04da13e3b1700706a79e72eedcb365 Mon Sep 17 00:00:00 2001 From: ardera <2488440+ardera@users.noreply.github.com> Date: Mon, 27 Jan 2020 15:42:18 +0100 Subject: [PATCH 2/8] started work on SPI --- src/plugins/spi-plugin.c | 124 +++++++++++++++++++++++++++++++++++++++ src/plugins/spi-plugin.h | 14 +++++ 2 files changed, 138 insertions(+) create mode 100644 src/plugins/spi-plugin.c create mode 100644 src/plugins/spi-plugin.h diff --git a/src/plugins/spi-plugin.c b/src/plugins/spi-plugin.c new file mode 100644 index 00000000..bbbbf2b4 --- /dev/null +++ b/src/plugins/spi-plugin.c @@ -0,0 +1,124 @@ +#include +#include +#include +#include +#include +#include + +#include "spi-plugin.h" + +enum spi_task_type { + kSpiTaskClose, + kSpiTaskRdMode, + kSpiTaskWrMode, + kSpiTaskWrBitsPerWord, + kSpiTaskRdBitsPerWord, + kSpiTaskWrMaxSpeedHz, + kSpiTaskRdMaxSpeedHz, + kSpiTaskTransmit +}; + +struct spi_task { + enum spi_task_type type; + union { + uint8_t mode; + uint8_t bits; + uint32_t speed; + struct spi_ioc_transfer transfer; + }; +}; + +struct spi_task_queue { + struct spi_task *tasks; + size_t size_tasks; + size_t length_tasks; + pthread_mutex_t queue_mutex; + pthread_cond_t task_added; +}; +#define SPI_TASK_QUEUE_INITIALIZER \ + ((struct spi_task_queue) {.tasks = NULL, .size_tasks = 0, .length_tasks = 0, \ + .queue_mutex = PTHREAD_MUTEX_INITIALIZER, .task_added = PTHREAD_COND_INITIALIZER}) + +struct { + fd_set spi_fds; + struct spi_task_queue queues[FD_SETSIZE]; +} spi_plugin = { + .queues = {SPI_TASK_QUEUE_INITIALIZER} +}; + +void SPIPlugin_add_task + +void *SPIPlugin_spi_loop(void *fd_void) { + int fd = (int) fd_void; + + while (FD_ISSET(fd, &spi_plugin.spi_fds)) { + + } +} + +int SPIPlugin_getFdStrict(struct StdMsgCodecValue *value, int *fd, FlutterPlatformMessageResponseHandle *responsehandle) { + *fd = -1; + + if (value->type != kInt32) { + return PlatformChannel_respondError( + responsehandle, + kStandardMethodCallResponse, + "invalidfd", + "The file-descriptor given to the SPI plugin is not an integer. (int32)", + NULL + ); + } + + if ((value->int32_value < 0) || (value->int32_value >= FD_SETSIZE)) { + return PlatformChannel_respondError( + responsehandle, + kStandardMethodCallResponse, + "invalidfd", + "The file-descriptor given to the SPI plugin is out of range. Should be 0 <= fd <= " (FD_SETSIZE-1) ".", + NULL + ); + } + + if (!FD_ISSET(value->int32_value, &spi_plugin.spi_fds)) { + return PlatformChannel_respondError( + responsehandle, + kStandardMethodCallResponse, + "invalidfd", + "The file-descriptor given to the SPI plugin was not opened by the SPI plugin.", + NULL + ); + } + + *fd = value->int32_value; + return 0; +} + +int SPIPlugin_onReceive(char *channel, struct ChannelObject *object, FlutterPlatformMessageResponseHandle *responsehandle) { + if STREQ("open", object->method) { + + } else if STREQ("setMode", object->method) { + + } else if STREQ("setMaxSpeed", object->method) { + + } else if STREQ("setWordSize", object->method) { + + } else if STREQ("spiFullDuplex", object->method) { + // we don't yet support full duplex. + return PlatformChannel_respondNotImplemented(responsehandle); + } else if STREQ("spiHalfDuplex", object->method) { + + } else if STREQ("close", object->method) { + + } + + return PlatformChannel_respondNotImplemented(responsehandle); +} + +int SPIPlugin_init(void) { + printf("[spi-plugin] init.\n"); + PluginRegistry_setReceiver(SPI_PLUGIN_METHOD_CHANNEL, kStandardMethodCall, SPIPlugin_onReceive); +} + +int SPIPlugin_deinit(void) { + printf("[spi-plugin] deinit.\n"); +} \ No newline at end of file diff --git a/src/plugins/spi-plugin.h b/src/plugins/spi-plugin.h new file mode 100644 index 00000000..97cae0b0 --- /dev/null +++ b/src/plugins/spi-plugin.h @@ -0,0 +1,14 @@ +#ifndef _SPI_PLUGIN_H +#define _SPI_PLUGIN_H + +#include +#include + +#define SPI_PLUGIN_METHOD_CHANNEL "flutter-pi/spi" + +int SPIPlugin_onReceive(char *channel, struct ChannelObject *object, FlutterPlatformMessageResponseHandle *responsehandle); + +int SPIPlugin_init(void); +int SPIPlugin_deinit(void); + +#endif \ No newline at end of file From f8f3f284c46a0bce841ea6e7d02b18ec2efe26ee Mon Sep 17 00:00:00 2001 From: ardera <2488440+ardera@users.noreply.github.com> Date: Sat, 1 Feb 2020 18:36:51 +0100 Subject: [PATCH 3/8] add SPI plugin --- Makefile | 4 +- include/platformchannel.h | 2 + src/platformchannel.c | 3 + src/pluginregistry.c | 7 +- src/plugins/spi-plugin.c | 124 ----- src/plugins/spi_plugin.c | 544 +++++++++++++++++++++ src/plugins/{spi-plugin.h => spi_plugin.h} | 2 - 7 files changed, 556 insertions(+), 130 deletions(-) delete mode 100644 src/plugins/spi-plugin.c create mode 100644 src/plugins/spi_plugin.c rename src/plugins/{spi-plugin.h => spi_plugin.h} (63%) diff --git a/Makefile b/Makefile index d9ce7357..dd02c8f0 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,9 @@ CC = cc LD = cc -REAL_CFLAGS = -I./include $(shell pkg-config --cflags dri gbm libdrm glesv2 egl) -DBUILD_ELM327PLUGIN $(CFLAGS) +REAL_CFLAGS = -I./include $(shell pkg-config --cflags dri gbm libdrm glesv2 egl) -DBUILD_ELM327PLUGIN -DBUILD_SPI_PLUGIN $(CFLAGS) REAL_LDFLAGS = $(shell pkg-config --libs dri gbm libdrm glesv2 egl) -lrt -lflutter_engine -lpthread -ldl $(LDFLAGS) -SOURCES = src/flutter-pi.c src/platformchannel.c src/pluginregistry.c src/plugins/elm327plugin.c src/plugins/services-plugin.c src/plugins/testplugin.c +SOURCES = src/flutter-pi.c src/platformchannel.c src/pluginregistry.c src/plugins/elm327plugin.c src/plugins/services-plugin.c src/plugins/testplugin.c src/plugins/spi_plugin.c OBJECTS = $(patsubst src/%.c,out/obj/%.o,$(SOURCES)) all: out/flutter-pi diff --git a/include/platformchannel.h b/include/platformchannel.h index f454dd59..9151be70 100644 --- a/include/platformchannel.h +++ b/include/platformchannel.h @@ -266,6 +266,8 @@ bool stdvalue_equals(struct StdMsgCodecValue *a, struct StdMsgCodecValue *b); /// any arbitrary StdMsgCodecValue (and must not be a string as for jsobject_get) struct StdMsgCodecValue *stdmap_get(struct StdMsgCodecValue *map, struct StdMsgCodecValue *key); +struct StdMsgCodecValue *stdmap_get_str(struct StdMsgCodecValue *map, char *key); + /// Andrew: Definitions static inline int __alignmentDiff(uint32_t value, int alignment) { alignment--; diff --git a/src/platformchannel.c b/src/platformchannel.c index dc899c79..084254f4 100644 --- a/src/platformchannel.c +++ b/src/platformchannel.c @@ -1176,3 +1176,6 @@ struct StdMsgCodecValue *stdmap_get(struct StdMsgCodecValue *map, struct StdMsgC return NULL; } +struct StdMsgCodecValue *stdmap_get_str(struct StdMsgCodecValue *map, char *key) { + return stdmap_get(map, &(struct StdMsgCodecValue) {.type = kString, .string_value = key}); +} \ No newline at end of file diff --git a/src/pluginregistry.c b/src/pluginregistry.c index f1178117..2cce7901 100644 --- a/src/pluginregistry.c +++ b/src/pluginregistry.c @@ -4,11 +4,10 @@ #include #include -// hardcoded plugin headers #include "plugins/services-plugin.h" #include "plugins/testplugin.h" #include "plugins/elm327plugin.h" - +#include "plugins/spi_plugin.h" struct ChannelObjectReceiverData { char *channel; @@ -33,6 +32,10 @@ struct FlutterPiPlugin hardcoded_plugins[] = { #ifdef BUILD_ELM327PLUGIN {.name = "elm327plugin", .init = ELM327Plugin_init, .deinit = ELM327Plugin_deinit} #endif + +#ifdef BUILD_SPI_PLUGIN + {.name = "spi_plugin", .init = SPIPlugin_init, .deinit = SPIPlugin_deinit} +#endif }; //size_t hardcoded_plugins_count; diff --git a/src/plugins/spi-plugin.c b/src/plugins/spi-plugin.c deleted file mode 100644 index bbbbf2b4..00000000 --- a/src/plugins/spi-plugin.c +++ /dev/null @@ -1,124 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "spi-plugin.h" - -enum spi_task_type { - kSpiTaskClose, - kSpiTaskRdMode, - kSpiTaskWrMode, - kSpiTaskWrBitsPerWord, - kSpiTaskRdBitsPerWord, - kSpiTaskWrMaxSpeedHz, - kSpiTaskRdMaxSpeedHz, - kSpiTaskTransmit -}; - -struct spi_task { - enum spi_task_type type; - union { - uint8_t mode; - uint8_t bits; - uint32_t speed; - struct spi_ioc_transfer transfer; - }; -}; - -struct spi_task_queue { - struct spi_task *tasks; - size_t size_tasks; - size_t length_tasks; - pthread_mutex_t queue_mutex; - pthread_cond_t task_added; -}; -#define SPI_TASK_QUEUE_INITIALIZER \ - ((struct spi_task_queue) {.tasks = NULL, .size_tasks = 0, .length_tasks = 0, \ - .queue_mutex = PTHREAD_MUTEX_INITIALIZER, .task_added = PTHREAD_COND_INITIALIZER}) - -struct { - fd_set spi_fds; - struct spi_task_queue queues[FD_SETSIZE]; -} spi_plugin = { - .queues = {SPI_TASK_QUEUE_INITIALIZER} -}; - -void SPIPlugin_add_task - -void *SPIPlugin_spi_loop(void *fd_void) { - int fd = (int) fd_void; - - while (FD_ISSET(fd, &spi_plugin.spi_fds)) { - - } -} - -int SPIPlugin_getFdStrict(struct StdMsgCodecValue *value, int *fd, FlutterPlatformMessageResponseHandle *responsehandle) { - *fd = -1; - - if (value->type != kInt32) { - return PlatformChannel_respondError( - responsehandle, - kStandardMethodCallResponse, - "invalidfd", - "The file-descriptor given to the SPI plugin is not an integer. (int32)", - NULL - ); - } - - if ((value->int32_value < 0) || (value->int32_value >= FD_SETSIZE)) { - return PlatformChannel_respondError( - responsehandle, - kStandardMethodCallResponse, - "invalidfd", - "The file-descriptor given to the SPI plugin is out of range. Should be 0 <= fd <= " (FD_SETSIZE-1) ".", - NULL - ); - } - - if (!FD_ISSET(value->int32_value, &spi_plugin.spi_fds)) { - return PlatformChannel_respondError( - responsehandle, - kStandardMethodCallResponse, - "invalidfd", - "The file-descriptor given to the SPI plugin was not opened by the SPI plugin.", - NULL - ); - } - - *fd = value->int32_value; - return 0; -} - -int SPIPlugin_onReceive(char *channel, struct ChannelObject *object, FlutterPlatformMessageResponseHandle *responsehandle) { - if STREQ("open", object->method) { - - } else if STREQ("setMode", object->method) { - - } else if STREQ("setMaxSpeed", object->method) { - - } else if STREQ("setWordSize", object->method) { - - } else if STREQ("spiFullDuplex", object->method) { - // we don't yet support full duplex. - return PlatformChannel_respondNotImplemented(responsehandle); - } else if STREQ("spiHalfDuplex", object->method) { - - } else if STREQ("close", object->method) { - - } - - return PlatformChannel_respondNotImplemented(responsehandle); -} - -int SPIPlugin_init(void) { - printf("[spi-plugin] init.\n"); - PluginRegistry_setReceiver(SPI_PLUGIN_METHOD_CHANNEL, kStandardMethodCall, SPIPlugin_onReceive); -} - -int SPIPlugin_deinit(void) { - printf("[spi-plugin] deinit.\n"); -} \ No newline at end of file diff --git a/src/plugins/spi_plugin.c b/src/plugins/spi_plugin.c new file mode 100644 index 00000000..42440993 --- /dev/null +++ b/src/plugins/spi_plugin.c @@ -0,0 +1,544 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "spi_plugin.h" + +enum spi_task_type { + kSpiTaskClose, + kSpiTaskRdMode, + kSpiTaskWrMode, + kSpiTaskWrBitsPerWord, + kSpiTaskRdBitsPerWord, + kSpiTaskWrMaxSpeedHz, + kSpiTaskRdMaxSpeedHz, + kSpiTaskTransmit +}; + +struct spi_task { + enum spi_task_type type; + union { + uint8_t mode; + uint8_t bits; + uint64_t speed; + struct spi_ioc_transfer transfer; + }; + FlutterPlatformMessageResponseHandle *responsehandle; +}; + +struct spi_thread { + int fd; + bool has_task; + struct spi_task task; + pthread_mutex_t mutex; + pthread_cond_t task_added; +}; + +#define SPI_THREAD_INITIALIZER \ + ((struct spi_thread) { \ + .fd = -1, .has_task = false, \ + .mutex = PTHREAD_MUTEX_INITIALIZER, .task_added = PTHREAD_COND_INITIALIZER \ + }) + +struct { + struct spi_thread *threads; + pthread_mutex_t threadlist_mutex; + size_t size_threads; + size_t num_threads; +} spi_plugin = { + .threads = NULL, + .threadlist_mutex = PTHREAD_MUTEX_INITIALIZER, + .size_threads = 0, + .num_threads = 0 +}; + +void *SPIPlugin_run_spi_thread(struct spi_thread *thread) { + bool running = true; + int fd = thread->fd; + int err = 0; + int ok; + + while (running) { + pthread_mutex_lock(&thread->mutex); + while (!thread->has_task) + pthread_cond_wait(&thread->task_added, &thread->mutex); + + switch (thread->task.type) { + case kSpiTaskClose: + ok = close(fd); + if (ok == -1) { + err = errno; + pthread_mutex_unlock(&thread->mutex); + break; + } + + running = false; + thread->fd = -1; + + pthread_mutex_unlock(&thread->mutex); + PlatformChannel_respond( + thread->task.responsehandle, + &(struct ChannelObject) {.codec = kStandardMethodCallResponse, .success = true, .stdresult = {.type = kNull}} + ); + break; + + case kSpiTaskRdMode: + ok = ioctl(fd, SPI_IOC_RD_MODE, &thread->task.mode); + if (ok == -1) { + err = errno; + pthread_mutex_unlock(&thread->mutex); + break; + } + + int32_t result = thread->task.mode; + + pthread_mutex_unlock(&thread->mutex); + PlatformChannel_respond( + thread->task.responsehandle, + &(struct ChannelObject) { + .codec = kStandardMethodCallResponse, .success = true, + .stdresult = {.type = kInt32, .int32_value = result} + } + ); + break; + + case kSpiTaskWrMode: + ok = ioctl(fd, SPI_IOC_WR_MODE, &thread->task.mode); + if (ok == -1) { + err = errno; + pthread_mutex_unlock(&thread->mutex); + break; + } + + pthread_mutex_unlock(&thread->mutex); + PlatformChannel_respond( + thread->task.responsehandle, + &(struct ChannelObject) {.codec = kStandardMethodCallResponse, .success = true, .stdresult = {.type = kNull}} + ); + break; + + case kSpiTaskWrBitsPerWord: + ok = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &thread->task.bits); + if (ok == -1) { + err = errno; + pthread_mutex_unlock(&thread->mutex); + break; + } + + pthread_mutex_unlock(&thread->mutex); + PlatformChannel_respond( + thread->task.responsehandle, + &(struct ChannelObject) {.codec = kStandardMethodCallResponse, .success = true, .stdresult = {.type = kNull}} + ); + break; + + case kSpiTaskRdBitsPerWord: + ok = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &thread->task.bits); + if (ok == -1) { + err = errno; + pthread_mutex_unlock(&thread->mutex); + break; + } + + int32_t result = thread->task.bits; + + pthread_mutex_unlock(&thread->mutex); + PlatformChannel_respond( + thread->task.responsehandle, + &(struct ChannelObject) { + .codec = kStandardMethodCallResponse, .success = true, + .stdresult = {.type = kInt32, .int32_value = result} + } + ); + break; + + case kSpiTaskWrMaxSpeedHz: + ok = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &thread->task.speed); + if (ok == -1) { + err = errno; + pthread_mutex_unlock(&thread->mutex); + break; + } + + pthread_mutex_unlock(&thread->mutex); + PlatformChannel_respond( + thread->task.responsehandle, + &(struct ChannelObject) {.codec = kStandardMethodCallResponse, .success = true, .stdresult = {.type = kNull}} + ); + break; + + case kSpiTaskRdMaxSpeedHz: + ok = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &thread->task.speed); + if (ok == -1) { + err = errno; + pthread_mutex_unlock(&thread->mutex); + break; + } + + int32_t result = thread->task.speed; + + pthread_mutex_unlock(&thread->mutex); + PlatformChannel_respond( + thread->task.responsehandle, + &(struct ChannelObject) { + .codec = kStandardMethodCallResponse, .success = true, + .stdresult = {.type = kInt64, .int64_value = result} + } + ); + break; + + case kSpiTaskTransmit: + ok = ioctl(fd, SPI_IOC_MESSAGE(1), thread->task.transfer); + if (ok == -1) { + err = errno; + free(thread->task.transfer.tx_buf); + pthread_mutex_unlock(&thread->mutex); + break; + } + + size_t len = thread->task.transfer.len; + uint8_t *buf = thread->task.transfer.rx_buf; + + pthread_mutex_unlock(&thread->mutex); + PlatformChannel_respond( + thread->task.responsehandle, + &(struct ChannelObject) { + .codec = kStandardMethodCallResponse, .success = true, + .stdresult = { + .type = kUInt8Array, + .size = len, + .uint8array = buf + } + } + ); + + free(buf); + + break; + + default: + break; + } + + thread->has_task = false; + if (err != 0) { + PlatformChannel_respondError( + thread->task.responsehandle, + kStandardMethodCallResponse, + "nativeerror", + strerror(err), + NULL + ); + err = 0; + } + } +} + +struct spi_thread *SPIPlugin_get_thread(const int fd) { + pthread_mutex_lock(&spi_plugin.threadlist_mutex); + + for (int i = 0; i < spi_plugin.num_threads; i++) { + if (spi_plugin.threads[i].fd == fd) + return &spi_plugin.threads[i]; + } + + pthread_mutex_unlock(&spi_plugin.threadlist_mutex); + return NULL; +} + +struct spi_thread *SPIPlugin_new_thread(const int fd) { + struct spi_thread *thread; + int ok; + + pthread_mutex_lock(&spi_plugin.threadlist_mutex); + + thread = &spi_plugin.threads[spi_plugin.num_threads++]; + thread->fd = fd; + + pthread_mutex_unlock(&spi_plugin.threadlist_mutex); + + ok = pthread_create(NULL, NULL, SPIPlugin_run_spi_thread, thread); + if (ok == -1) return errno; + + return 0; +} + +int SPIPlugin_assign_task(const int fd, const struct spi_task *const task) { + struct spi_thread *thread; + int ok; + + thread = SPIPlugin_get_thread(fd); + if (!thread) { + return EBADF; + } + + ok = pthread_mutex_trylock(&thread->mutex); + if (ok == -1) { + return errno; + } else if (ok == 0) { + thread->task = *task; + thread->has_task = true; + pthread_mutex_unlock(&thread->mutex); + pthread_cond_signal(&thread->task_added); + return 0; + } +} +[] +int SPIPlugin_onReceive(char *channel, struct ChannelObject *object, FlutterPlatformMessageResponseHandle *responsehandle) { + struct StdMsgCodecValue *temp; + struct spi_thread *thread; + struct spi_task task; + bool has_task = false; + int ok, fd; + + if STREQ("open", object->method) { + if (object->stdarg.type != kString) { + errormsg = "expected string as argument"; + goto respond_error; + } + + char *path = object->stdarg.string_value; + + fd = open(path, O_RDWR); + if (fd == -1) { + errorcode = "nativerror"; + errormsg = strerror(errno); + goto respond_error; + } + + ok = SPIPlugin_new_thread(fd); + if (ok != 0) { + errorcode = "nativerror"; + errormsg = strerror(ok); + goto respond_error; + } + + } else if STREQ("setMode", object->method) { + if ((object->stdarg.type == kList) && (object->stdarg.size == 2) && + (object->stdarg.list[0].type == kInt32) && (object->stdarg.list[1].type == kInt32)) { + fd = object->stdarg.list[0].int32_value; + task.mode = object->stdarg.int32_value; + } else if ((object->stdarg.type == kInt32Array) && (object->stdarg.size == 2)) { + fd = object->stdarg.int32array[0]; + task.mode = object->stdarg.int32array[1]; + } else { + return PlatformChannel_respondError( + responsehandle, + kStandardMethodCallResponse, + "invalidargument", + "expected list containing two int32's or an int32 array with size 2 as argument", + NULL + ); + } + + task.type = kSpiTaskWrMode; + has_task = true; + } else if STREQ("getMode", object->method) { + if (object->stdarg.type == kInt32) { + fd = object->stdarg.int32_value; + } else { + return PlatformChannel_respondError( + responsehandle, + kStandardMethodCallResponse, + "invalidargument", + "expected int32 as argument", + NULL + ); + } + + task.type = kSpiTaskRdMode; + has_task = true; + } else if STREQ("setMaxSpeed", object->method) { + if ((object->stdarg.type == kList) && (object->stdarg.size == 2) && + (object->stdarg.list[0].type == kInt32) && (object->stdarg.list[1].type == kInt32)) { + fd = object->stdarg.list[0].int32_value; + task.speed = object->stdarg.int32_value; + } else if ((object->stdarg.type == kInt32Array) && (object->stdarg.size == 2)) { + fd = object->stdarg.int32array[0]; + task.speed = object->stdarg.int32array[1]; + } else { + return PlatformChannel_respondError( + responsehandle, + kStandardMethodCallResponse, + "invalidargument", + "expected list containing two int32's or an int32 array with size 2 as argument", + NULL + ); + } + + task.type = kSpiTaskWrMaxSpeedHz; + has_task = true; + } else if STREQ("getMaxSpeed", object->method) { + if (object->stdarg.type == kInt32) { + fd = object->stdarg.int32_value; + } else { + return PlatformChannel_respondError( + responsehandle, + kStandardMethodCallResponse, + "invalidargument", + "expected int32 as argument", + NULL + ); + } + + task.type = kSpiTaskRdMaxSpeedHz; + has_task = true; + } else if STREQ("setWordSize", object->method) { + if ((object->stdarg.type == kList) && (object->stdarg.size == 2) && + (object->stdarg.list[0].type == kInt32) && (object->stdarg.list[1].type == kInt32)) { + fd = object->stdarg.list[0].int32_value; + task.bits = object->stdarg.int32_value; + } else if ((object->stdarg.type == kInt32Array) && (object->stdarg.size == 2)) { + fd = object->stdarg.int32array[0]; + task.bits = object->stdarg.int32array[1]; + } else { + return PlatformChannel_respondError( + responsehandle, + kStandardMethodCallResponse, + "invalidargument", + "expected list containing two int32's or an int32 array with size 2 as argument", + NULL + ); + } + + task.type = kSpiTaskWrBitsPerWord; + has_task = true; + } else if STREQ("getWordSize", object->method) { + if (object->stdarg.type == kInt32) { + fd = object->stdarg.int32_value; + } else { + return PlatformChannel_respondError( + responsehandle, + kStandardMethodCallResponse, + "invalidargument", + "expected int32 as argument", + NULL + ); + } + + task.type = kSpiTaskRdBitsPerWord; + has_task = true; + } else if STREQ("transmit", object->method) { + bool is_valid = false; + + if (object->stdarg.type == kMap) { + is_valid = true; + + temp = stdmap_get_str(&object->stdarg, "fd"); + if (temp && (temp->type == kInt32)) { + fd = temp->int32_value; + } else { + is_valid = false; + } + + temp = stdmap_get_str(&object->stdarg, "speed"); + if ((!temp) || (temp && temp->type == kInt32)) { + task.transfer.speed_hz = temp ? temp->int32_value : 0; + } else { + is_valid = false; + } + + temp = stdmap_get_str(&object->stdarg, "delay"); + if ((!temp) || (temp && temp->type == kInt32)) { + task.transfer.delay_usecs = temp ? temp->int32_value : 0; + } else { + is_valid = false; + } + + temp = stdmap_get_str(&object->stdarg, "wordSize"); + if ((!temp) || (temp && temp->type == kInt32)) { + task.transfer.bits_per_word = temp ? temp->int32_value : 0; + } else { + is_valid = false; + } + + temp = stdmap_get_str(&object->stdarg, "csChange"); + if (!temp || (temp && (temp->type == kTrue || temp->type == kFalse))) { + task.transfer.cs_change = temp && temp->type == kTrue; + } else { + is_valid = false; + } + + if (is_valid) { + temp = stdmap_get_str(&object->stdarg, "buffer"); + if (temp && temp->type == kUInt8Array) { + task.transfer.len = temp->size; + task.transfer.tx_buf = malloc(temp->size); + task.transfer.rx_buf = task.transfer.tx_buf; + + memcpy(task.transfer.tx_buf, temp->uint8array, temp->size); + } else { + is_valid = false; + } + } + } + + if (!is_valid) { + return PlatformChannel_respondError( + responsehandle, + kStandardMethodCallResponse, + "invalidargument", + "", + NULL + ); + } + + task.type = kSpiTaskTransmit; + has_task = true; + } else if STREQ("close", object->method) { + task.type = kSpiTaskClose; + has_task = true; + } + + if (has_task) { + ok = SPIPlugin_assign_task(fd, &task); + if (ok == 0) { + return; + } else if (ok == EBUSY) { + return PlatformChannel_respondError( + responsehandle, + kStandardMethodCallResponse, + "busy", + "a different task is running on the fd already", + NULL + ); + } else { + return PlatformChannel_respondError( + responsehandle, + kStandardMethodCallResponse, + "nativeerror", + strerror(ok), + NULL + ); + } + } + + return PlatformChannel_respondNotImplemented(responsehandle); +} + +int SPIPlugin_init(void) { + printf("[spi-plugin] init.\n"); + + spi_plugin.size_threads = 1; + spi_plugin.threads = calloc(spi_plugin.size_threads, sizeof(struct spi_thread)); + + for (int i = 0; i < spi_plugin.size_threads; i++) + spi_plugin.threads[i] = SPI_THREAD_INITIALIZER; + + PluginRegistry_setReceiver(SPI_PLUGIN_METHOD_CHANNEL, kStandardMethodCall, SPIPlugin_onReceive); + return 0; +} + +int SPIPlugin_deinit(void) { + printf("[spi-plugin] deinit.\n"); + return 0; +} \ No newline at end of file diff --git a/src/plugins/spi-plugin.h b/src/plugins/spi_plugin.h similarity index 63% rename from src/plugins/spi-plugin.h rename to src/plugins/spi_plugin.h index 97cae0b0..7cca599d 100644 --- a/src/plugins/spi-plugin.h +++ b/src/plugins/spi_plugin.h @@ -6,8 +6,6 @@ #define SPI_PLUGIN_METHOD_CHANNEL "flutter-pi/spi" -int SPIPlugin_onReceive(char *channel, struct ChannelObject *object, FlutterPlatformMessageResponseHandle *responsehandle); - int SPIPlugin_init(void); int SPIPlugin_deinit(void); From 0834f63c7b55ea4f78ae4947cff814af19b91ef4 Mon Sep 17 00:00:00 2001 From: Hannes Winkler Date: Mon, 17 Feb 2020 18:23:46 +0100 Subject: [PATCH 4/8] gpiod plugin, spidev plugin, huge refactor --- Makefile | 10 +- include/platformchannel.h | 250 ++-- include/pluginregistry.h | 32 +- {src => include}/plugins/elm327plugin.h | 0 include/plugins/gpiod.h | 43 + include/plugins/raw_keyboard.h | 11 + .../plugins/services.h | 4 +- include/plugins/spidev.h | 12 + {src => include}/plugins/testplugin.h | 4 +- {src => include}/plugins/text_input.h | 30 +- src/flutter-pi.c | 20 +- src/platformchannel.c | 660 ++++++---- src/pluginregistry.c | 121 +- src/plugins/elm327plugin.c | 68 +- src/plugins/gpio-plugin.c | 434 ------- src/plugins/gpio-plugin.h | 32 - src/plugins/gpiod.c | 1139 +++++++++++++++++ src/plugins/raw_keyboard.c | 40 +- src/plugins/raw_keyboard.h | 11 - src/plugins/{services-plugin.c => services.c} | 92 +- src/plugins/spi_plugin.c | 544 -------- src/plugins/spi_plugin.h | 12 - src/plugins/spidev.c | 483 +++++++ src/plugins/testplugin.c | 203 +-- src/plugins/text_input.c | 278 ++-- 25 files changed, 2690 insertions(+), 1843 deletions(-) rename {src => include}/plugins/elm327plugin.h (100%) create mode 100644 include/plugins/gpiod.h create mode 100644 include/plugins/raw_keyboard.h rename src/plugins/services-plugin.h => include/plugins/services.h (89%) create mode 100644 include/plugins/spidev.h rename {src => include}/plugins/testplugin.h (78%) rename {src => include}/plugins/text_input.h (67%) delete mode 100644 src/plugins/gpio-plugin.c delete mode 100644 src/plugins/gpio-plugin.h create mode 100644 src/plugins/gpiod.c delete mode 100644 src/plugins/raw_keyboard.h rename src/plugins/{services-plugin.c => services.c} (67%) delete mode 100644 src/plugins/spi_plugin.c delete mode 100644 src/plugins/spi_plugin.h create mode 100644 src/plugins/spidev.c diff --git a/Makefile b/Makefile index 6e10bba0..d0a2da8e 100644 --- a/Makefile +++ b/Makefile @@ -1,16 +1,16 @@ CC = cc LD = cc -REAL_CFLAGS = -I./include $(shell pkg-config --cflags dri gbm libdrm glesv2 egl) -DBUILD_ELM327_PLUGIN -DBUILD_GPIO_PLUGIN -DBUILD_SPI_PLUGIN -DBUILD_TEST_PLUGIN -ggdb $(CFLAGS) -REAL_LDFLAGS = $(shell pkg-config --libs dri gbm libdrm glesv2 egl) -lrt -lflutter_engine -lpthread -ldl $(LDFLAGS) +REAL_CFLAGS = -I./include $(shell pkg-config --cflags gbm libdrm glesv2 egl) -DBUILD_ELM327_PLUGIN -DBUILD_GPIO_PLUGIN -DBUILD_SPI_PLUGIN -DBUILD_TEST_PLUGIN -ggdb $(CFLAGS) +REAL_LDFLAGS = $(shell pkg-config --libs gbm libdrm glesv2 egl) -lrt -lflutter_engine -lpthread -ldl $(LDFLAGS) SOURCES = src/flutter-pi.c src/platformchannel.c src/pluginregistry.c src/console_keyboard.c \ - src/plugins/elm327plugin.c src/plugins/services-plugin.c src/plugins/testplugin.c src/plugins/text_input.c \ - src/plugins/raw_keyboard.c src/plugins/spi_plugin.c + src/plugins/elm327plugin.c src/plugins/services.c src/plugins/testplugin.c src/plugins/text_input.c \ + src/plugins/raw_keyboard.c src/plugins/gpiod.c src/plugins/spidev.c OBJECTS = $(patsubst src/%.c,out/obj/%.o,$(SOURCES)) all: out/flutter-pi -out/obj/%.o: src/%.c +out/obj/%.o: src/%.c @mkdir -p $(@D) $(CC) -c $(REAL_CFLAGS) $(REAL_LDFLAGS) $< -o $@ diff --git a/include/platformchannel.h b/include/platformchannel.h index 1520ebc3..a73c097f 100644 --- a/include/platformchannel.h +++ b/include/platformchannel.h @@ -34,45 +34,51 @@ * need to be rewritten every time they do. The handlers not needing to be rewritten would probably be the only advantage * of using a unified message value type. */ -enum JSONMsgCodecValueType { - kJSNull, kJSTrue, kJSFalse, kJSNumber, kJSString, kJSArray, kJSObject +enum json_value_type { + kJsonNull, + kJsonTrue, + kJsonFalse, + kJsonNumber, + kJsonString, + kJsonArray, + kJsonObject }; -struct JSONMsgCodecValue { - enum JSONMsgCodecValueType type; +struct json_value { + enum json_value_type type; union { double number_value; char *string_value; struct { size_t size; union { - struct JSONMsgCodecValue *array; + struct json_value *array; struct { char **keys; - struct JSONMsgCodecValue *values; + struct json_value *values; }; }; }; }; }; -enum StdMsgCodecValueType { - kNull = 0, - kTrue, - kFalse, - kInt32, - kInt64, - kLargeInt, // treat as kString - kFloat64, - kString, - kUInt8Array, - kInt32Array, - kInt64Array, - kFloat64Array, - kList, - kMap +enum std_value_type { + kStdNull = 0, + kStdTrue, + kStdFalse, + kStdInt32, + kStdInt64, + kStdLargeInt, // treat as kString + kStdFloat64, + kStdString, + kStdUInt8Array, + kStdInt32Array, + kStdInt64Array, + kStdFloat64Array, + kStdList, + kStdMap }; -struct StdMsgCodecValue { - enum StdMsgCodecValueType type; +struct std_value { + enum std_value_type type; union { bool bool_value; int32_t int32_value; @@ -86,39 +92,51 @@ struct StdMsgCodecValue { int32_t* int32array; int64_t* int64array; double* float64array; - struct StdMsgCodecValue* list; + struct std_value* list; struct { - struct StdMsgCodecValue* keys; - struct StdMsgCodecValue* values; + struct std_value* keys; + struct std_value* values; }; }; }; }; }; -#define STDVALUE_IS_NULL(value) ((value).type == kNull) -#define STDVALUE_IS_BOOL(value) (((value).type == kTrue) || ((value).type == kFalse)) -#define STDVALUE_AS_BOOL(value) ((value).type == kTrue) +#define STDVALUE_IS_NULL(value) ((value).type == kStdNull) +#define STDNULL ((struct std_value) {.type = kStdNull}) -#define STDVALUE_IS_INT(value) (((value).type == kInt32) || ((value).type == kInt64)) -#define STDVALUE_AS_INT(value) ((value).type == kInt32 ? (int64_t) (value).int32_value : (value).int64_value) -#define STDVALUE_IS_FLOAT(value) ((value).type == kFloat64) +#define STDVALUE_IS_BOOL(value) (((value).type == kStdTrue) || ((value).type == kStdFalse)) +#define STDVALUE_AS_BOOL(value) ((value).type == kStdTrue) +#define STDBOOL(bool_value) ((struct std_value) {.type = (bool_value) ? kStdTrue : kStdFalse}) + +#define STDVALUE_IS_INT(value) (((value).type == kStdInt32) || ((value).type == kStdInt64)) +#define STDVALUE_AS_INT(value) ((value).type == kStdInt32 ? (int64_t) (value).int32_value : (value).int64_value) +#define STDINT32(_int32_value) ((struct std_value) {.type = kStdInt32, .int32_value = (_int32_value)}) +#define STDINT64(_int64_value) ((struct std_value) {.type = kStdInt64, .int64_value = (_int64_value)}) + +#define STDVALUE_IS_FLOAT(value) ((value).type == kStdFloat64) #define STDVALUE_AS_FLOAT(value) ((value).float64_value) +#define STDFLOAT64(double_value) ((struct std_value) {.type = kStdFloat64, .float64_value = (double_value)}) + #define STDVALUE_IS_NUM(value) (STDVALUE_IS_INT(value) || STDVALUE_IS_FLOAT(value)) #define STDVALUE_AS_NUM(value) (STDVALUE_IS_INT(value) ? STDVALUE_AS_INT(value) : STDVALUE_AS_FLOAT(value)) -#define STDVALUE_IS_LIST(value) ((value).type == kList) +#define STDVALUE_IS_STRING(value) ((value).type == kStdString) +#define STDVALUE_AS_STRING(value) ((value).string_value) +#define STDSTRING(str) ((struct std_value) {.type = kStdString, .string_value = str}) + +#define STDVALUE_IS_LIST(value) ((value).type == kStdList) #define STDVALUE_IS_SIZE(value, _size) ((value).size == (_size)) #define STDVALUE_IS_SIZED_LIST(value, _size) (STDVALUE_IS_LIST(value) && STDVALUE_IS_SIZE(value, _size)) -#define STDVALUE_IS_INT_ARRAY(value) (((value).type == kInt32Array) || ((value).type == kInt64Array) || ((value).type == kUInt8Array)) -#define STDVALUE_IS_FLOAT_ARRAY(value) ((value).type == kFloat64Array) +#define STDVALUE_IS_INT_ARRAY(value) (((value).type == kStdInt32Array) || ((value).type == kStdInt64Array) || ((value).type == kStdUInt8Array)) +#define STDVALUE_IS_FLOAT_ARRAY(value) ((value).type == kStdFloat64Array) #define STDVALUE_IS_NUM_ARRAY(value) (STDVALUE_IS_INT_ARRAY(value) || STDVALUE_IS_FLOAT_ARRAY(value)) /// codec of an abstract channel object /// These tell this API how it should encode ChannelObjects -> platform messages /// and how to decode platform messages -> ChannelObjects. -enum ChannelCodec { +enum platch_codec { kNotImplemented, kStringCodec, kBinaryCodec, @@ -130,7 +148,7 @@ enum ChannelCodec { kJSONMethodCallResponse }; -/// Abstract Channel Object. +/// Platform Channel Object. /// Different properties are "valid" for different codecs: /// kNotImplemented: /// no values associated with this "codec". @@ -139,57 +157,58 @@ enum ChannelCodec { /// - string_value is the raw byte data of a platform message, but with an additional null-byte at the end. /// kBinaryCodec: /// - binarydata is an array of the raw byte data of a platform message, -/// - binarydata_size is the size of that byte data in uint8_t's. +/// - binarydata_size is the size of that byte data in bytes. /// kJSONMessageCodec: -/// - jsonmsgcodec_value +/// - json_value /// kStdMsgCodecValue: -/// - stdmsgcodec_value +/// - std_value /// kStandardMethodCall: /// - "method" is the method you'd like to call, or the method that was called /// by flutter. -/// - stdarg contains the argument to that method call. +/// - std_arg contains the argument to that method call. /// kJSONMethodCall: /// - "method" is the method you'd like to call, or the method that was called /// by flutter. -/// - jsarg contains the argument to that method call. +/// - json_arg contains the argument to that method call. /// kStandardMethodCallResponse or kJSONMethodCallResponse: -/// - "success" is whether the method call (send to flutter or received from flutter) -/// was succesful, i.e. no errors ocurred. +/// - "success" is whether the method call (called by flutter or by called by you) /// if success is false, -/// - errorcode must be set (by you or by flutter) to point to a valid null-terminated string, -/// - errormessage is either pointing to a valid null-terminated string or is set to NULL, +/// - error_code must be set to point to a valid null-terminated string, +/// - error_msg is either pointing to a valid null-terminated string or is set to NULL, /// - if the codec is kStandardMethodCallResponse, -/// stderrordetails may be set to any StdMsgCodecValue or NULL. +/// std_error_details must be a valid std_value +/// ({.type = kStdNull} is possible, but not NULL). /// - if the codec is kJSONMethodCallResponse, -/// jserrordetails may be set to any JSONMSgCodecValue or NULL. -struct ChannelObject { - enum ChannelCodec codec; +/// json_error_details must be a valid json_value +/// ({.type = kJsonNull} is possible, but not NULL) +struct platch_obj { + enum platch_codec codec; union { char *string_value; struct { size_t binarydata_size; uint8_t *binarydata; }; - struct JSONMsgCodecValue jsonmsgcodec_value; - struct StdMsgCodecValue stdmsgcodec_value; + struct json_value json_value; + struct std_value std_value; struct { char *method; union { - struct StdMsgCodecValue stdarg; - struct JSONMsgCodecValue jsarg; + struct std_value std_arg; + struct json_value json_arg; }; }; struct { bool success; union { - struct StdMsgCodecValue stdresult; - struct JSONMsgCodecValue jsresult; + struct std_value std_result; + struct json_value json_result; }; - char *errorcode; - char *errormessage; + char *error_code; + char *error_msg; union { - struct StdMsgCodecValue stderrordetails; - struct JSONMsgCodecValue jserrordetails; + struct std_value std_error_details; + struct json_value json_error_details; }; }; }; @@ -198,7 +217,7 @@ struct ChannelObject { /// A Callback that is called when a response to a platform message you send to flutter /// arrives. "object" is the platform message decoded using the "codec" you gave to PlatformChannel_send, /// "userdata" is the userdata you gave to PlatformChannel_send. -typedef int (*PlatformMessageResponseCallback)(struct ChannelObject *object, void *userdata); +typedef int (*platch_msg_resp_callback)(struct platch_obj *object, void *userdata); /// decodes a platform message (represented by `buffer` and `size`) as the given codec, @@ -210,16 +229,13 @@ typedef int (*PlatformMessageResponseCallback)(struct ChannelObject *object, voi /// is freed by flutter, the contents of object_out will in many cases be bogus. /// If you'd like object_out to be persistent and not depend on the lifetime of the buffer, /// you'd have to manually deep-copy it. -int PlatformChannel_decode(uint8_t *buffer, size_t size, enum ChannelCodec codec, struct ChannelObject *object_out); - -/// decodes a JSON String into a JSONMsgCodecValue -int PlatformChannel_decodeJSON(char *string, struct JSONMsgCodecValue *out); +int platch_decode(uint8_t *buffer, size_t size, enum platch_codec codec, struct platch_obj *object_out); /// Encodes a generic ChannelObject into a buffer (that is, too, allocated by PlatformChannel_encode) /// A pointer to the buffer is put into buffer_out and the size of that buffer into size_out. /// The lifetime of the buffer is independent of the ChannelObject, so contents of the ChannelObject /// can be freed after the object was encoded. -int PlatformChannel_encode(struct ChannelObject *object, uint8_t **buffer_out, size_t *size_out); +int platch_encode(struct platch_obj *object, uint8_t **buffer_out, size_t *size_out); /// Encodes a generic ChannelObject (anything, string/binary codec or Standard/JSON Method Calls and responses) as a platform message /// and sends it to flutter on channel `channel` @@ -228,24 +244,38 @@ int PlatformChannel_encode(struct ChannelObject *object, uint8_t **buffer_out, s /// Then, on_response is called with the decoded ChannelObject and the userdata as an argument. /// It's possible that flutter won't respond to your platform message, like when sending events via an EventChannel. /// userdata can be NULL. -int PlatformChannel_send(char *channel, struct ChannelObject *object, enum ChannelCodec response_codec, PlatformMessageResponseCallback on_response, void *userdata); +int platch_send(char *channel, + struct platch_obj *object, + enum platch_codec response_codec, + platch_msg_resp_callback on_response, + void *userdata); /// Encodes a StandardMethodCodec method call as a platform message and sends it to flutter /// on channel `channel`. This is just a wrapper around PlatformChannel_send /// that builds the ChannelObject for you. /// The response_codec is kStandardMethodCallResponse. userdata can be NULL. -int PlatformChannel_stdcall(char *channel, char *method, struct StdMsgCodecValue *argument, PlatformMessageResponseCallback on_response, void *userdata); - -/// Encodes a JSONMethodCodec method call as a platform message and sends it to flutter -/// on channel `channel`. This is just a wrapper around PlatformChannel_send +int platch_call_std(char *channel, + char *method, + struct std_value *argument, + platch_msg_resp_callback on_response, + void *userdata); + +/// Encodes the arguments as a JSON method call and sends it to flutter +/// on channel [channel]. This is just a wrapper around platch_send /// that builds the ChannelObject for you. -/// The response_codec is kJSONMethodCallResponse. userdata can be NULL. -int PlatformChannel_jsoncall(char *channel, char *method, struct JSONMsgCodecValue *argument, PlatformMessageResponseCallback on_response, void *userdata); +/// The response is automatically decoded as a JSON method call response and +/// supplied to [on_response] as an argument. userdata can be NULL. +int platch_call_json(char *channel, + char *method, + struct json_value *argument, + platch_msg_resp_callback on_response, + void *userdata); /// Responds to a platform message. You can (of course) only respond once to a platform message, /// i.e. a FlutterPlatformMessageResponseHandle can only be used once. /// The codec of `response` can be any of the available codecs. -int PlatformChannel_respond(FlutterPlatformMessageResponseHandle *handle, struct ChannelObject *response); +int platch_respond(FlutterPlatformMessageResponseHandle *handle, + struct platch_obj *response); /// Tells flutter that the platform message that was sent to you was not handled. /// (for example, there's no plugin that is using this channel, or there is a plugin @@ -254,43 +284,85 @@ int PlatformChannel_respond(FlutterPlatformMessageResponseHandle *handle, struct /// When flutter receives this response, it will throw a MissingPluginException. /// For most channel used by the ServicesPlugin, this is not too bad since it /// specifies many of the channels used as OptionalMethodChannels. (which will silently catch the MissingPluginException) -int PlatformChannel_respondNotImplemented(FlutterPlatformMessageResponseHandle *handle); +int platch_respond_not_implemented(FlutterPlatformMessageResponseHandle *handle); + +int platch_respond_success_std(FlutterPlatformMessageResponseHandle *handle, + struct std_value *return_value); + +int platch_respond_error_std(FlutterPlatformMessageResponseHandle *handle, + char *error_code, + char *error_msg, + struct std_value *error_details); + +int platch_respond_illegal_arg_std(FlutterPlatformMessageResponseHandle *handle, + char *error_msg); + +int platch_respond_native_error_std(FlutterPlatformMessageResponseHandle *handle, + int _errno); + + +int platch_respond_success_json(FlutterPlatformMessageResponseHandle *handle, + struct json_value *return_value); + +int platch_respond_error_json(FlutterPlatformMessageResponseHandle *handle, + char *error_code, + char *error_msg, + struct json_value *error_details); + +int platch_respond_illegal_arg_json(FlutterPlatformMessageResponseHandle *handle, + char *error_msg); + +int platch_respond_native_error_json(FlutterPlatformMessageResponseHandle *handle, + int _errno); + +/// Sends a success event with value `event_value` to an event channel +/// that uses the standard method codec. +int platch_send_success_event_std(char *channel, + struct std_value *event_value); + +/// Sends an error event to an event channel that uses the standard method codec. +int platch_send_error_event_std(char *channel, + char *error_code, + char *error_msg, + struct std_value *error_details); +/// Sends a success event with value `event_value` to an event channel +/// that uses the JSON method codec. +int platch_send_success_event_json(char *channel, + struct json_value *event_value); -/// Tells flutter that the method that was called caused an error. -/// errorcode MUST be non-null, errormessage can be null. -/// when codec is one of kStandardMethodCall, kStandardMethodCallResponse, kStandardMessageCodec: -/// errordetails must either be NULL or a pointer to a struct StdMsgCodecValue. -/// when codec is one of kJSONMethodCall, kJSONMethodCallResponse or kJSONMessageCodec: -/// errordetails must either be NULL or a pointer to a struct JSONMsgCodecValue. -int PlatformChannel_respondError(FlutterPlatformMessageResponseHandle *handle, enum ChannelCodec codec, char *errorcode, char *errormessage, void *errordetails); +/// Sends an error event to an event channel that uses the JSON method codec. +int platch_send_error_event_json(char *channel, + char *error_code, + char *error_msg, + struct json_value *error_details); /// frees a ChannelObject that was decoded using PlatformChannel_decode. /// not freeing ChannelObjects may result in a memory leak. -int PlatformChannel_free(struct ChannelObject *object); +int platch_free_obj(struct platch_obj *object); -int PlatformChannel_freeJSONMsgCodecValue(struct JSONMsgCodecValue *value, bool shallow); +int platch_free_json_value(struct json_value *value, bool shallow); /// returns true if values a and b are equal. /// for JS arrays, the order of the values is relevant /// (so two arrays are only equal if the same values appear in exactly same order) /// for objects, the order of the entries is irrelevant. -bool jsvalue_equals(struct JSONMsgCodecValue *a, struct JSONMsgCodecValue *b); +bool jsvalue_equals(struct json_value *a, struct json_value *b); /// given a JS object as an argument, it searches for an entry with key "key" /// and returns the value associated with it. /// if the key is not found, returns NULL. -struct JSONMsgCodecValue *jsobject_get(struct JSONMsgCodecValue *object, char *key); +struct json_value *jsobject_get(struct json_value *object, char *key); /// StdMsgCodecValue equivalent of jsvalue_equals. /// again, for lists, the order of values is relevant /// for maps, it's not. -bool stdvalue_equals(struct StdMsgCodecValue *a, struct StdMsgCodecValue *b); +bool stdvalue_equals(struct std_value *a, struct std_value *b); /// StdMsgCodecValue equivalent of jsobject_get, just that the key can be /// any arbitrary StdMsgCodecValue (and must not be a string as for jsobject_get) -struct StdMsgCodecValue *stdmap_get(struct StdMsgCodecValue *map, struct StdMsgCodecValue *key); +struct std_value *stdmap_get(struct std_value *map, struct std_value *key); -struct StdMsgCodecValue *stdmap_get_str(struct StdMsgCodecValue *map, char *key); +struct std_value *stdmap_get_str(struct std_value *map, char *key); /// Andrew: Definitions static inline int __alignmentDiff(uint32_t value, int alignment) { diff --git a/include/pluginregistry.h b/include/pluginregistry.h index 51a66435..38e0214a 100644 --- a/include/pluginregistry.h +++ b/include/pluginregistry.h @@ -1,9 +1,9 @@ #ifndef FLUTTER_PI_REGISTRY_H_ #define FLUTTER_PI_REGISTRY_H_ 1 -#include -#include -#include +#include +#include +#include #include @@ -12,43 +12,43 @@ /// Callback for Initialization or Deinitialization. /// Return value is 0 for success, or anything else for an error /// (uses the errno error codes) -typedef int (*InitDeinitCallback)(void); +typedef int (*init_deinit_cb)(void); /// A Callback that gets called when a platform message /// arrives on a channel you registered it with. /// channel is the method channel that received a platform message, /// object is the object that is the result of automatically decoding -/// the platform message using the codec given to PluginRegistry_setReceiver. +/// the platform message using the codec given to plugin_registry_set_receiver. /// BE AWARE that object->type can be kNotImplemented, REGARDLESS of the codec -/// passed to PluginRegistry_setReceiver. -typedef int (*ChannelObjectReceiveCallback)(char *channel, struct ChannelObject *object, FlutterPlatformMessageResponseHandle *responsehandle); +/// passed to plugin_registry_set_receiver. +typedef int (*platch_obj_recv_callback)(char *channel, struct platch_obj *object, FlutterPlatformMessageResponseHandle *responsehandle); /// details of a plugin for flutter-pi. /// All plugins are initialized (i.e. get their "init" callbacks called) -/// when PluginRegistry_init() is called by flutter-pi. +/// when plugin_registry_init() is called by flutter-pi. /// In the init callback, you probably want to do stuff like /// register callbacks for some method channels your plugin uses, /// or dynamically allocate memory for your plugin if you need to. -/// PluginRegistry_init() and thus every plugins init is called +/// plugin_registry_init() and thus every plugins init is called /// BEFORE the flutter engine is set up and running. The "engine" /// global may even be NULL at the time "init" is called. Sending flutter messages /// will probably cause the application to crash. /// deinit is also called AFTER the engine is shut down. -struct FlutterPiPlugin { +struct flutterpi_plugin { const char const* name; - InitDeinitCallback init; - InitDeinitCallback deinit; + init_deinit_cb init; + init_deinit_cb deinit; }; -int PluginRegistry_init(); -int PluginRegistry_onPlatformMessage(FlutterPlatformMessage *message); +int plugin_registry_init(); +int plugin_registry_on_platform_message(FlutterPlatformMessage *message); /// Sets the callback that should be called when a platform message arrives on channel "channel", /// and the codec used to automatically decode the platform message. /// Call this method with NULL as the callback parameter to remove the current listener on that channel. -int PluginRegistry_setReceiver(char *channel, enum ChannelCodec codec, ChannelObjectReceiveCallback callback); +int plugin_registry_set_receiver(char *channel, enum platch_codec codec, platch_obj_recv_callback callback); -int PluginRegistry_deinit(); +int plugin_registry_deinit(); #endif \ No newline at end of file diff --git a/src/plugins/elm327plugin.h b/include/plugins/elm327plugin.h similarity index 100% rename from src/plugins/elm327plugin.h rename to include/plugins/elm327plugin.h diff --git a/include/plugins/gpiod.h b/include/plugins/gpiod.h new file mode 100644 index 00000000..ce12b85b --- /dev/null +++ b/include/plugins/gpiod.h @@ -0,0 +1,43 @@ +#ifndef _GPIO_PLUGIN_H +#define _GPIO_PLUGIN_H + +#include + +#ifndef GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE + +# define GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE GPIOD_BIT(2) +# define GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN GPIOD_BIT(3) +# define GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP GPIOD_BIT(4) +enum { + GPIOD_LINE_BIAS_AS_IS = 1, + GPIOD_LINE_BIAS_DISABLE, + GPIOD_LINE_BIAS_PULL_UP, + GPIOD_LINE_BIAS_PULL_DOWN +}; + +#endif + +#define GPIOD_PLUGIN_METHOD_CHANNEL "plugins.flutter.io/gpiod" +#define GPIOD_PLUGIN_EVENT_CHANNEL "plugins.flutter.io/gpiod_events" + +#define GPIO_PLUGIN_MAX_CHIPS 8 + +// a basic macro that loads a symbol from libgpiod, puts it into the libgpiod struct +// and returns the errno if an error ocurred + +#define LOAD_GPIOD_PROC(name) \ + do { \ + libgpiod.name = dlsym(libgpiod.handle, "gpiod_" #name); \ + if (!libgpiod.name) {\ + perror("could not resolve libgpiod procedure gpiod_" #name); \ + return errno; \ + } \ + } while (false) + +#define LOAD_GPIOD_PROC_OPTIONAL(name) \ + libgpiod.name = dlsym(libgpiod.handle, "gpiod_" #name) + +extern int gpiodp_init(void); +extern int gpiodp_deinit(void); + +#endif \ No newline at end of file diff --git a/include/plugins/raw_keyboard.h b/include/plugins/raw_keyboard.h new file mode 100644 index 00000000..9ee20ea8 --- /dev/null +++ b/include/plugins/raw_keyboard.h @@ -0,0 +1,11 @@ +#ifndef _KEY_EVENT_H +#define _KEY_EVENT_H + +#define KEY_EVENT_CHANNEL "flutter/keyevent" + +int rawkb_on_keyevent(glfw_key key, uint32_t scan_code, glfw_key_action action); + +int rawkb_init(void); +int rawkb_deinit(void); + +#endif \ No newline at end of file diff --git a/src/plugins/services-plugin.h b/include/plugins/services.h similarity index 89% rename from src/plugins/services-plugin.h rename to include/plugins/services.h index 99be5867..e5f76a26 100644 --- a/src/plugins/services-plugin.h +++ b/include/plugins/services.h @@ -10,7 +10,7 @@ strcmp(str, "DeviceOrientation.portraitDown") == 0 ? kPortraitDown :\ strcmp(str, "DeviceOrientation.landscapeRight") == 0 ? kLandscapeRight : -1) -int Services_init(void); -int Services_deinit(void); +int services_init(void); +int services_deinit(void); #endif \ No newline at end of file diff --git a/include/plugins/spidev.h b/include/plugins/spidev.h new file mode 100644 index 00000000..98d85846 --- /dev/null +++ b/include/plugins/spidev.h @@ -0,0 +1,12 @@ +#ifndef _SPI_PLUGIN_H +#define _SPI_PLUGIN_H + +#include +#include + +#define SPI_PLUGIN_METHOD_CHANNEL "plugins.flutter.io/spidev" + +int spidevp_init(void); +int spidevp_deinit(void); + +#endif \ No newline at end of file diff --git a/src/plugins/testplugin.h b/include/plugins/testplugin.h similarity index 78% rename from src/plugins/testplugin.h rename to include/plugins/testplugin.h index 4ca1f0eb..d6d54ad6 100644 --- a/src/plugins/testplugin.h +++ b/include/plugins/testplugin.h @@ -8,7 +8,7 @@ #define TESTPLUGIN_CHANNEL_STD "flutter-pi/teststd" #define TESTPLUGIN_CHANNEL_PING "flutter-pi/ping" -extern int TestPlugin_init(void); -extern int TestPlugin_deinit(void); +extern int testp_init(void); +extern int testp_deinit(void); #endif \ No newline at end of file diff --git a/src/plugins/text_input.h b/include/plugins/text_input.h similarity index 67% rename from src/plugins/text_input.h rename to include/plugins/text_input.h index 01395938..d6e8f849 100644 --- a/src/plugins/text_input.h +++ b/include/plugins/text_input.h @@ -40,26 +40,26 @@ struct text_input_configuration { enum text_input_action input_action; }; -int TextInput_syncEditingState(void); -int TextInput_performAction(enum text_input_action action); -int TextInput_onConnectionClosed(void); +int textin_sync_editing_state(void); +int textin_perform_action(enum text_input_action action); +int textin_on_connection_closed(void); // TextInput model functions (updating the text editing state) -bool TextInput_deleteSelected(void); -bool TextInput_addUtf8Char(char *c); -bool TextInput_backspace(void); -bool TextInput_delete(void); -bool TextInput_moveCursorToBeginning(void); -bool TextInput_moveCursorToEnd(void); -bool TextInput_moveCursorForward(void); -bool TextInput_moveCursorBack(void); +bool textin_delete_selected(void); +bool textin_add_utf8_char(char *c); +bool textin_backspace(void); +bool textin_delete(void); +bool textin_move_cursor_to_beginning(void); +bool textin_move_cursor_to_end(void); +bool textin_move_cursor_forward(void); +bool textin_move_cursor_back(void); // parses the input string as linux terminal input and calls the TextInput model functions // accordingly. -int TextInput_onUtf8Char(char *c); -int TextInput_onKey(glfw_key key); +int textin_on_utf8_char(char *c); +int textin_on_key(glfw_key key); -int TextInput_init(void); -int TextInput_deinit(void); +int textin_init(void); +int textin_deinit(void); #endif \ No newline at end of file diff --git a/src/flutter-pi.c b/src/flutter-pi.c index 293c0d3d..25cdde24 100644 --- a/src/flutter-pi.c +++ b/src/flutter-pi.c @@ -36,9 +36,9 @@ #include #include #include -#include "plugins/services-plugin.h" -#include "plugins/text_input.h" -#include "plugins/raw_keyboard.h" +//#include +#include +#include char* usage ="\ @@ -430,8 +430,8 @@ void *proc_resolver(void* userdata, const char* name) { } void on_platform_message(const FlutterPlatformMessage* message, void* userdata) { int ok; - if ((ok = PluginRegistry_onPlatformMessage((FlutterPlatformMessage *)message)) != 0) - fprintf(stderr, "PluginRegistry_onPlatformMessage failed: %s\n", strerror(ok)); + if ((ok = plugin_registry_on_platform_message((FlutterPlatformMessage *)message)) != 0) + fprintf(stderr, "plugin_registry_on_platform_message failed: %s\n", strerror(ok)); } void vsync_callback(void* userdata, intptr_t baton) { post_platform_task(&(struct flutterpi_task) { @@ -1086,7 +1086,7 @@ bool init_application(void) { int ok; printf("Initializing Plugin Registry...\n"); - ok = PluginRegistry_init(); + ok = plugin_registry_init(); if (ok != 0) { fprintf(stderr, "Could not initialize plugin registry: %s\n", strerror(ok)); return false; @@ -1162,7 +1162,7 @@ void destroy_application(void) { engine = NULL; } - if ((ok = PluginRegistry_deinit()) != 0) { + if ((ok = plugin_registry_deinit()) != 0) { fprintf(stderr, "Could not deinitialize plugin registry: %s\n", strerror(ok)); } } @@ -1450,7 +1450,7 @@ void on_evdev_input(fd_set fds, size_t n_ready_fds) { default: action = -1; break; } - RawKeyboard_onKeyEvent(EVDEV_KEY_TO_GLFW_KEY(e->code), 0, action); + rawkb_on_keyevent(EVDEV_KEY_TO_GLFW_KEY(e->code), 0, action); } else if (e->code != BTN_TOUCH || device->is_direct) { if (e->value == 1) device->active_buttons |= FLUTTER_BUTTON_FROM_EVENT_CODE(e->code); else device->active_buttons &= ~FLUTTER_BUTTON_FROM_EVENT_CODE(e->code); @@ -1547,9 +1547,9 @@ void on_console_input(void) { cursor = buffer; while (*cursor) { if (key = console_try_get_key(cursor, &cursor), key != GLFW_KEY_UNKNOWN) { - TextInput_onKey(key); + textin_on_key(key); } else if (c = console_try_get_utf8char(cursor, &cursor), c != NULL) { - TextInput_onUtf8Char(c); + textin_on_utf8_char(c); } else { // neither a char nor a (function) key. we don't know when // we can start parsing the buffer again, so just stop here diff --git a/src/platformchannel.c b/src/platformchannel.c index 1eb6fcaf..72a5faa7 100644 --- a/src/platformchannel.c +++ b/src/platformchannel.c @@ -13,31 +13,31 @@ #include -struct ResponseHandlerData { - enum ChannelCodec codec; - PlatformMessageResponseCallback on_response; +struct platch_msg_resp_handler_data { + enum platch_codec codec; + platch_msg_resp_callback on_response; void *userdata; }; -int PlatformChannel_freeStdMsgCodecValue(struct StdMsgCodecValue *value) { +int platch_free_value_std(struct std_value *value) { int ok; switch (value->type) { - case kString: + case kStdString: free(value->string_value); break; - case kList: + case kStdList: for (int i=0; i < value->size; i++) { - ok = PlatformChannel_freeStdMsgCodecValue(&(value->list[i])); + ok = platch_free_value_std(&(value->list[i])); if (ok != 0) return ok; } free(value->list); break; - case kMap: + case kStdMap: for (int i=0; i < value->size; i++) { - ok = PlatformChannel_freeStdMsgCodecValue(&(value->keys[i])); + ok = platch_free_value_std(&(value->keys[i])); if (ok != 0) return ok; - ok = PlatformChannel_freeStdMsgCodecValue(&(value->values[i])); + ok = platch_free_value_std(&(value->values[i])); if (ok != 0) return ok; } free(value->keys); @@ -48,24 +48,24 @@ int PlatformChannel_freeStdMsgCodecValue(struct StdMsgCodecValue *value) { return 0; } -int PlatformChannel_freeJSONMsgCodecValue(struct JSONMsgCodecValue *value, bool shallow) { +int platch_free_json_value(struct json_value *value, bool shallow) { int ok; switch (value->type) { - case kJSArray: + case kJsonArray: if (!shallow) { for (int i = 0; i < value->size; i++) { - ok = PlatformChannel_freeJSONMsgCodecValue(&(value->array[i]), false); + ok = platch_free_json_value(&(value->array[i]), false); if (ok != 0) return ok; } } free(value->array); break; - case kJSObject: + case kJsonObject: if (!shallow) { for (int i = 0; i < value->size; i++) { - ok = PlatformChannel_freeJSONMsgCodecValue(&(value->values[i]), false); + ok = platch_free_json_value(&(value->values[i]), false); if (ok != 0) return ok; } } @@ -78,7 +78,7 @@ int PlatformChannel_freeJSONMsgCodecValue(struct JSONMsgCodecValue *value, bool return 0; } -int PlatformChannel_free(struct ChannelObject *object) { +int platch_free_obj(struct platch_obj *object) { switch (object->codec) { case kStringCodec: free(object->string_value); @@ -86,54 +86,57 @@ int PlatformChannel_free(struct ChannelObject *object) { case kBinaryCodec: break; case kJSONMessageCodec: - PlatformChannel_freeJSONMsgCodecValue(&(object->jsonmsgcodec_value), false); + platch_free_json_value(&(object->json_value), false); break; case kStandardMessageCodec: - PlatformChannel_freeStdMsgCodecValue(&(object->stdmsgcodec_value)); + platch_free_value_std(&(object->std_value)); break; case kStandardMethodCall: free(object->method); - PlatformChannel_freeStdMsgCodecValue(&(object->stdarg)); + platch_free_value_std(&(object->std_arg)); break; case kJSONMethodCall: - PlatformChannel_freeJSONMsgCodecValue(&(object->jsarg), false); + platch_free_json_value(&(object->json_arg), false); + break; + default: + break; } return 0; } -int PlatformChannel_calculateStdMsgCodecValueSize(struct StdMsgCodecValue* value, size_t* psize) { - enum StdMsgCodecValueType type = value->type; +int platch_calc_value_size_std(struct std_value* value, size_t* psize) { + enum std_value_type type = value->type; size_t size; int ok; // Type Byte advance(psize, 1); switch (type) { - case kNull: - case kTrue: - case kFalse: + case kStdNull: + case kStdTrue: + case kStdFalse: break; - case kInt32: + case kStdInt32: advance(psize, 4); break; - case kInt64: + case kStdInt64: advance(psize, 8); break; - case kFloat64: + case kStdFloat64: align8 (psize); advance(psize, 8); break; - case kString: - case kLargeInt: + case kStdString: + case kStdLargeInt: size = strlen(value->string_value); advance(psize, size + nSizeBytes(size)); break; - case kUInt8Array: + case kStdUInt8Array: size = value->size; advance(psize, size + nSizeBytes(size)); break; - case kInt32Array: + case kStdInt32Array: size = value->size; advance(psize, nSizeBytes(size)); @@ -141,7 +144,7 @@ int PlatformChannel_calculateStdMsgCodecValueSize(struct StdMsgCodecValue* value advance(psize, size*4); break; - case kInt64Array: + case kStdInt64Array: size = value->size; advance(psize, nSizeBytes(size)); @@ -149,7 +152,7 @@ int PlatformChannel_calculateStdMsgCodecValueSize(struct StdMsgCodecValue* value advance(psize, size*8); break; - case kFloat64Array: + case kStdFloat64Array: size = value->size; advance(psize, nSizeBytes(size)); @@ -157,21 +160,21 @@ int PlatformChannel_calculateStdMsgCodecValueSize(struct StdMsgCodecValue* value advance(psize, size*8); break; - case kList: + case kStdList: size = value->size; advance(psize, nSizeBytes(size)); for (int i = 0; ilist[i]), psize)) != 0) return ok; + if ((ok = platch_calc_value_size_std(&(value->list[i]), psize)) != 0) return ok; break; - case kMap: + case kStdMap: size = value->size; advance(psize, nSizeBytes(size)); for (int i = 0; ikeys[i]), psize)) != 0) return ok; - if ((ok = PlatformChannel_calculateStdMsgCodecValueSize(&(value->values[i]), psize)) != 0) return ok; + if ((ok = platch_calc_value_size_std(&(value->keys[i]), psize)) != 0) return ok; + if ((ok = platch_calc_value_size_std(&(value->values[i]), psize)) != 0) return ok; } break; @@ -181,7 +184,7 @@ int PlatformChannel_calculateStdMsgCodecValueSize(struct StdMsgCodecValue* value return 0; } -int PlatformChannel_writeStdMsgCodecValueToBuffer(struct StdMsgCodecValue* value, uint8_t **pbuffer) { +int platch_write_value_to_buffer_std(struct std_value* value, uint8_t **pbuffer) { uint8_t* byteArray; size_t size; int ok; @@ -190,30 +193,30 @@ int PlatformChannel_writeStdMsgCodecValueToBuffer(struct StdMsgCodecValue* value advance(pbuffer, 1); switch (value->type) { - case kNull: - case kTrue: - case kFalse: + case kStdNull: + case kStdTrue: + case kStdFalse: break; - case kInt32: + case kStdInt32: write32(pbuffer, value->int32_value); advance(pbuffer, 4); break; - case kInt64: + case kStdInt64: write64(pbuffer, value->int64_value); advance(pbuffer, 8); break; - case kFloat64: + case kStdFloat64: align8(pbuffer); write64(pbuffer, *((uint64_t*) &(value->float64_value))); advance(pbuffer, 8); break; - case kLargeInt: - case kString: - case kUInt8Array: - if ((value->type == kLargeInt) || (value->type == kString)) { + case kStdLargeInt: + case kStdString: + case kStdUInt8Array: + if ((value->type == kStdLargeInt) || (value->type == kStdString)) { size = strlen(value->string_value); byteArray = (uint8_t*) value->string_value; - } else if (value->type == kUInt8Array) { + } else if (value->type == kStdUInt8Array) { size = value->size; byteArray = value->uint8array; } @@ -224,7 +227,7 @@ int PlatformChannel_writeStdMsgCodecValueToBuffer(struct StdMsgCodecValue* value advance(pbuffer, 1); } break; - case kInt32Array: + case kStdInt32Array: size = value->size; writeSize(pbuffer, size); @@ -235,7 +238,7 @@ int PlatformChannel_writeStdMsgCodecValueToBuffer(struct StdMsgCodecValue* value advance(pbuffer, 4); } break; - case kInt64Array: + case kStdInt64Array: size = value->size; writeSize(pbuffer, size); @@ -245,7 +248,7 @@ int PlatformChannel_writeStdMsgCodecValueToBuffer(struct StdMsgCodecValue* value advance(pbuffer, 8); } break; - case kFloat64Array: + case kStdFloat64Array: size = value->size; writeSize(pbuffer, size); @@ -256,21 +259,21 @@ int PlatformChannel_writeStdMsgCodecValueToBuffer(struct StdMsgCodecValue* value advance(pbuffer, 8); } break; - case kList: + case kStdList: size = value->size; writeSize(pbuffer, size); for (int i=0; ilist[i]), pbuffer)) != 0) return ok; + if ((ok = platch_write_value_to_buffer_std(&(value->list[i]), pbuffer)) != 0) return ok; break; - case kMap: + case kStdMap: size = value->size; writeSize(pbuffer, size); for (int i=0; ikeys[i]), pbuffer)) != 0) return ok; - if ((ok = PlatformChannel_writeStdMsgCodecValueToBuffer(&(value->values[i]), pbuffer)) != 0) return ok; + if ((ok = platch_write_value_to_buffer_std(&(value->keys[i]), pbuffer)) != 0) return ok; + if ((ok = platch_write_value_to_buffer_std(&(value->values[i]), pbuffer)) != 0) return ok; } break; default: @@ -279,19 +282,19 @@ int PlatformChannel_writeStdMsgCodecValueToBuffer(struct StdMsgCodecValue* value return 0; } -size_t PlatformChannel_calculateJSONMsgCodecValueSize(struct JSONMsgCodecValue *value) { +size_t platch_calc_value_size_json(struct json_value *value) { size_t size = 0; switch (value->type) { - case kJSNull: - case kJSTrue: + case kJsonNull: + case kJsonTrue: return 4; - case kJSFalse: + case kJsonFalse: return 5; - case kJSNumber: ; + case kJsonNumber: ; char numBuffer[32]; return sprintf(numBuffer, "%g", value->number_value); - case kJSString: + case kJsonString: size = 2; // we need to count how many characters we need to escape. @@ -313,17 +316,17 @@ size_t PlatformChannel_calculateJSONMsgCodecValueSize(struct JSONMsgCodecValue * } return size; - case kJSArray: + case kJsonArray: size += 2; for (int i=0; i < value->size; i++) { - size += PlatformChannel_calculateJSONMsgCodecValueSize(&(value->array[i])); + size += platch_calc_value_size_json(&(value->array[i])); if (i+1 != value->size) size += 1; } return size; - case kJSObject: + case kJsonObject: size += 2; for (int i=0; i < value->size; i++) { - size += strlen(value->keys[i]) + 3 + PlatformChannel_calculateJSONMsgCodecValueSize(&(value->values[i])); + size += strlen(value->keys[i]) + 3 + platch_calc_value_size_json(&(value->values[i])); if (i+1 != value->size) size += 1; } return size; @@ -333,21 +336,21 @@ size_t PlatformChannel_calculateJSONMsgCodecValueSize(struct JSONMsgCodecValue * return 0; } -int PlatformChannel_writeJSONMsgCodecValueToBuffer(struct JSONMsgCodecValue* value, uint8_t **pbuffer) { +int platch_write_value_to_buffer_json(struct json_value* value, uint8_t **pbuffer) { switch (value->type) { - case kJSNull: + case kJsonNull: *pbuffer += sprintf((char*) *pbuffer, "null"); break; - case kJSTrue: + case kJsonTrue: *pbuffer += sprintf((char*) *pbuffer, "true"); break; - case kJSFalse: + case kJsonFalse: *pbuffer += sprintf((char*) *pbuffer, "false"); break; - case kJSNumber: + case kJsonNumber: *pbuffer += sprintf((char*) *pbuffer, "%g", value->number_value); break; - case kJSString: + case kJsonString: *((*pbuffer)++) = '\"'; for (char *s = value->string_value; *s; s++) { @@ -389,19 +392,19 @@ int PlatformChannel_writeJSONMsgCodecValueToBuffer(struct JSONMsgCodecValue* val *((*pbuffer)++) = '\"'; break; - case kJSArray: + case kJsonArray: *pbuffer += sprintf((char*) *pbuffer, "["); for (int i=0; i < value->size; i++) { - PlatformChannel_writeJSONMsgCodecValueToBuffer(&(value->array[i]), pbuffer); + platch_write_value_to_buffer_json(&(value->array[i]), pbuffer); if (i+1 != value->size) *pbuffer += sprintf((char*) *pbuffer, ","); } *pbuffer += sprintf((char*) *pbuffer, "]"); break; - case kJSObject: + case kJsonObject: *pbuffer += sprintf((char*) *pbuffer, "{"); for (int i=0; i < value->size; i++) { *pbuffer += sprintf((char*) *pbuffer, "\"%s\":", value->keys[i]); - PlatformChannel_writeJSONMsgCodecValueToBuffer(&(value->values[i]), pbuffer); + platch_write_value_to_buffer_json(&(value->values[i]), pbuffer); if (i+1 != value->size) *pbuffer += sprintf((char*) *pbuffer, ","); } *pbuffer += sprintf((char*) *pbuffer, "}"); @@ -412,7 +415,7 @@ int PlatformChannel_writeJSONMsgCodecValueToBuffer(struct JSONMsgCodecValue* val return 0; } -int PlatformChannel_decodeStdMsgCodecValue(uint8_t **pbuffer, size_t *premaining, struct StdMsgCodecValue *value_out) { +int platch_decode_value_std(uint8_t **pbuffer, size_t *premaining, struct std_value *value_out) { int64_t *longArray = 0; int32_t *intArray = 0; uint8_t *byteArray = 0; @@ -420,30 +423,30 @@ int PlatformChannel_decodeStdMsgCodecValue(uint8_t **pbuffer, size_t *premaining size_t size = 0; int ok; - enum StdMsgCodecValueType type = read8(pbuffer); + enum std_value_type type = read8(pbuffer); advance(pbuffer, 1, premaining); value_out->type = type; switch (type) { - case kNull: - case kTrue: - case kFalse: + case kStdNull: + case kStdTrue: + case kStdFalse: break; - case kInt32: + case kStdInt32: if (*premaining < 4) return EBADMSG; value_out->int32_value = (int32_t) read32(pbuffer); advance(pbuffer, 4, premaining); break; - case kInt64: + case kStdInt64: if (*premaining < 8) return EBADMSG; value_out->int64_value = (int64_t) read64(pbuffer); advance(pbuffer, 8, premaining); break; - case kFloat64: + case kStdFloat64: if (*premaining < (8 + alignmentDiff(*pbuffer, 8))) return EBADMSG; align8(pbuffer, premaining); @@ -452,8 +455,8 @@ int PlatformChannel_decodeStdMsgCodecValue(uint8_t **pbuffer, size_t *premaining advance(pbuffer, 8, premaining); break; - case kLargeInt: - case kString: + case kStdLargeInt: + case kStdString: if ((ok = readSize(pbuffer, premaining, &size)) != 0) return ok; if (*premaining < size) return EBADMSG; @@ -463,7 +466,7 @@ int PlatformChannel_decodeStdMsgCodecValue(uint8_t **pbuffer, size_t *premaining advance(pbuffer, size, premaining); break; - case kUInt8Array: + case kStdUInt8Array: if ((ok = readSize(pbuffer, premaining, &size)) != 0) return ok; if (*premaining < size) return EBADMSG; @@ -472,7 +475,7 @@ int PlatformChannel_decodeStdMsgCodecValue(uint8_t **pbuffer, size_t *premaining advance(pbuffer, size, premaining); break; - case kInt32Array: + case kStdInt32Array: if ((ok = readSize(pbuffer, premaining, &size)) != 0) return ok; if (*premaining < (size*4 + alignmentDiff(*pbuffer, 4))) return EBADMSG; @@ -482,7 +485,7 @@ int PlatformChannel_decodeStdMsgCodecValue(uint8_t **pbuffer, size_t *premaining advance(pbuffer, size*4, premaining); break; - case kInt64Array: + case kStdInt64Array: if ((ok = readSize(pbuffer, premaining, &size)) != 0) return ok; if (*premaining < (size*8 + alignmentDiff(*pbuffer, 8))) return EBADMSG; @@ -492,7 +495,7 @@ int PlatformChannel_decodeStdMsgCodecValue(uint8_t **pbuffer, size_t *premaining advance(pbuffer, size*8, premaining); break; - case kFloat64Array: + case kStdFloat64Array: if ((ok = readSize(pbuffer, premaining, &size)) != 0) return ok; if (*premaining < (size*8 + alignmentDiff(*pbuffer, 8))) return EBADMSG; @@ -502,31 +505,31 @@ int PlatformChannel_decodeStdMsgCodecValue(uint8_t **pbuffer, size_t *premaining advance(pbuffer, size*8, premaining); break; - case kList: + case kStdList: if ((ok = readSize(pbuffer, premaining, &size)) != 0) return ok; value_out->size = size; - value_out->list = calloc(size, sizeof(struct StdMsgCodecValue)); + value_out->list = calloc(size, sizeof(struct std_value)); for (int i = 0; i < size; i++) { - ok = PlatformChannel_decodeStdMsgCodecValue(pbuffer, premaining, &(value_out->list[i])); + ok = platch_decode_value_std(pbuffer, premaining, &(value_out->list[i])); if (ok != 0) return ok; } break; - case kMap: + case kStdMap: if ((ok = readSize(pbuffer, premaining, &size)) != 0) return ok; value_out->size = size; - value_out->keys = calloc(size*2, sizeof(struct StdMsgCodecValue)); + value_out->keys = calloc(size*2, sizeof(struct std_value)); if (!value_out->keys) return ENOMEM; value_out->values = &(value_out->keys[size]); for (int i = 0; i < size; i++) { - ok = PlatformChannel_decodeStdMsgCodecValue(pbuffer, premaining, &(value_out->keys[i])); + ok = platch_decode_value_std(pbuffer, premaining, &(value_out->keys[i])); if (ok != 0) return ok; - ok = PlatformChannel_decodeStdMsgCodecValue(pbuffer, premaining, &(value_out->values[i])); + ok = platch_decode_value_std(pbuffer, premaining, &(value_out->values[i])); if (ok != 0) return ok; } @@ -537,7 +540,7 @@ int PlatformChannel_decodeStdMsgCodecValue(uint8_t **pbuffer, size_t *premaining return 0; } -int PlatformChannel_decodeJSONMsgCodecValue(char *message, size_t size, jsmntok_t **pptoken, size_t *ptokensremaining, struct JSONMsgCodecValue *value_out) { +int platch_decode_value_json(char *message, size_t size, jsmntok_t **pptoken, size_t *ptokensremaining, struct json_value *value_out) { jsmntok_t *ptoken; int result, ok; @@ -557,7 +560,7 @@ int PlatformChannel_decodeJSONMsgCodecValue(char *message, size_t size, jsmntok_ tokensremaining = (size_t) result; ptoken = tokens; - ok = PlatformChannel_decodeJSONMsgCodecValue(message, size, &ptoken, &tokensremaining, value_out); + ok = platch_decode_value_json(message, size, &ptoken, &tokensremaining, value_out); if (ok != 0) return ok; } else { // message is already tokenized @@ -572,13 +575,13 @@ int PlatformChannel_decodeJSONMsgCodecValue(char *message, size_t size, jsmntok_ return EBADMSG; case JSMN_PRIMITIVE: if (message[ptoken->start] == 'n') { - value_out->type = kJSNull; + value_out->type = kJsonNull; } else if (message[ptoken->start] == 't') { - value_out->type = kJSTrue; + value_out->type = kJsonTrue; } else if (message[ptoken->start] == 'f') { - value_out->type = kJSFalse; + value_out->type = kJsonFalse; } else { - value_out->type = kJSNumber; + value_out->type = kJsonNumber; // hacky, but should work in normal circumstances. If the platform message solely consists // of this number and nothing else, this could fail. @@ -595,42 +598,42 @@ int PlatformChannel_decodeJSONMsgCodecValue(char *message, size_t size, jsmntok_ message[ptoken->end] = '\0'; char *string = message + ptoken->start; - value_out->type = kJSString; + value_out->type = kJsonString; value_out->string_value = string; break; case JSMN_ARRAY: ; - struct JSONMsgCodecValue *array = calloc(ptoken->size, sizeof(struct JSONMsgCodecValue)); + struct json_value *array = calloc(ptoken->size, sizeof(struct json_value)); if (!array) return ENOMEM; for (int i=0; i < ptoken->size; i++) { - ok = PlatformChannel_decodeJSONMsgCodecValue(message, size, pptoken, ptokensremaining, &array[i]); + ok = platch_decode_value_json(message, size, pptoken, ptokensremaining, &array[i]); if (ok != 0) return ok; } - value_out->type = kJSArray; + value_out->type = kJsonArray; value_out->size = ptoken->size; value_out->array = array; break; case JSMN_OBJECT: ; - struct JSONMsgCodecValue key; + struct json_value key; char **keys = calloc(ptoken->size, sizeof(char *)); - struct JSONMsgCodecValue *values = calloc(ptoken->size, sizeof(struct JSONMsgCodecValue)); + struct json_value *values = calloc(ptoken->size, sizeof(struct json_value)); if ((!keys) || (!values)) return ENOMEM; for (int i=0; i < ptoken->size; i++) { - ok = PlatformChannel_decodeJSONMsgCodecValue(message, size, pptoken, ptokensremaining, &key); + ok = platch_decode_value_json(message, size, pptoken, ptokensremaining, &key); if (ok != 0) return ok; - if (key.type != kJSString) return EBADMSG; + if (key.type != kJsonString) return EBADMSG; keys[i] = key.string_value; - ok = PlatformChannel_decodeJSONMsgCodecValue(message, size, pptoken, ptokensremaining, &values[i]); + ok = platch_decode_value_json(message, size, pptoken, ptokensremaining, &values[i]); if (ok != 0) return ok; } - value_out->type = kJSObject; + value_out->type = kJsonObject; value_out->size = ptoken->size; value_out->keys = keys; value_out->values = values; @@ -644,12 +647,12 @@ int PlatformChannel_decodeJSONMsgCodecValue(char *message, size_t size, jsmntok_ return 0; } -int PlatformChannel_decodeJSON(char *string, struct JSONMsgCodecValue *out) { - return PlatformChannel_decodeJSONMsgCodecValue(string, strlen(string), NULL, NULL, out); +int platch_decode_json(char *string, struct json_value *out) { + return platch_decode_value_json(string, strlen(string), NULL, NULL, out); } -int PlatformChannel_decode(uint8_t *buffer, size_t size, enum ChannelCodec codec, struct ChannelObject *object_out) { - struct JSONMsgCodecValue root_jsvalue; +int platch_decode(uint8_t *buffer, size_t size, enum platch_codec codec, struct platch_obj *object_out) { + struct json_value root_jsvalue; uint8_t *buffer_cursor = buffer; size_t remaining = size; int ok; @@ -679,65 +682,65 @@ int PlatformChannel_decode(uint8_t *buffer, size_t size, enum ChannelCodec codec break; case kJSONMessageCodec: - ok = PlatformChannel_decodeJSONMsgCodecValue((char *) buffer, size, NULL, NULL, &(object_out->jsonmsgcodec_value)); + ok = platch_decode_value_json((char *) buffer, size, NULL, NULL, &(object_out->json_value)); if (ok != 0) return ok; break; case kJSONMethodCall: ; - ok = PlatformChannel_decodeJSONMsgCodecValue((char *) buffer, size, NULL, NULL, &root_jsvalue); + ok = platch_decode_value_json((char *) buffer, size, NULL, NULL, &root_jsvalue); if (ok != 0) return ok; - if (root_jsvalue.type != kJSObject) return EBADMSG; + if (root_jsvalue.type != kJsonObject) return EBADMSG; for (int i=0; i < root_jsvalue.size; i++) { - if ((strcmp(root_jsvalue.keys[i], "method") == 0) && (root_jsvalue.values[i].type == kJSString)) { + if ((strcmp(root_jsvalue.keys[i], "method") == 0) && (root_jsvalue.values[i].type == kJsonString)) { object_out->method = root_jsvalue.values[i].string_value; } else if (strcmp(root_jsvalue.keys[i], "args") == 0) { - object_out->jsarg = root_jsvalue.values[i]; + object_out->json_arg = root_jsvalue.values[i]; } else return EBADMSG; } - PlatformChannel_freeJSONMsgCodecValue(&root_jsvalue, true); + platch_free_json_value(&root_jsvalue, true); break; case kJSONMethodCallResponse: ; - ok = PlatformChannel_decodeJSONMsgCodecValue((char *) buffer, size, NULL, NULL, &root_jsvalue); + ok = platch_decode_value_json((char *) buffer, size, NULL, NULL, &root_jsvalue); if (ok != 0) return ok; - if (root_jsvalue.type != kJSArray) return EBADMSG; + if (root_jsvalue.type != kJsonArray) return EBADMSG; if (root_jsvalue.size == 1) { object_out->success = true; - object_out->jsresult = root_jsvalue.array[0]; - return PlatformChannel_freeJSONMsgCodecValue(&root_jsvalue, true); + object_out->json_result = root_jsvalue.array[0]; + return platch_free_json_value(&root_jsvalue, true); } else if ((root_jsvalue.size == 3) && - (root_jsvalue.array[0].type == kJSString) && - ((root_jsvalue.array[1].type == kJSString) || (root_jsvalue.array[1].type == kJSNull))) { + (root_jsvalue.array[0].type == kJsonString) && + ((root_jsvalue.array[1].type == kJsonString) || (root_jsvalue.array[1].type == kJsonNull))) { object_out->success = false; - object_out->errorcode = root_jsvalue.array[0].string_value; - object_out->errormessage = root_jsvalue.array[1].string_value; - object_out->jserrordetails = root_jsvalue.array[2]; - return PlatformChannel_freeJSONMsgCodecValue(&root_jsvalue, true); + object_out->error_code = root_jsvalue.array[0].string_value; + object_out->error_msg = root_jsvalue.array[1].string_value; + object_out->json_error_details = root_jsvalue.array[2]; + return platch_free_json_value(&root_jsvalue, true); } else return EBADMSG; break; case kStandardMessageCodec: - ok = PlatformChannel_decodeStdMsgCodecValue(&buffer_cursor, &remaining, &(object_out->stdmsgcodec_value)); + ok = platch_decode_value_std(&buffer_cursor, &remaining, &(object_out->std_value)); if (ok != 0) return ok; break; case kStandardMethodCall: ; - struct StdMsgCodecValue methodname; + struct std_value methodname; - ok = PlatformChannel_decodeStdMsgCodecValue(&buffer_cursor, &remaining, &methodname); + ok = platch_decode_value_std(&buffer_cursor, &remaining, &methodname); if (ok != 0) return ok; - if (methodname.type != kString) { - PlatformChannel_freeStdMsgCodecValue(&methodname); + if (methodname.type != kStdString) { + platch_free_value_std(&methodname); return EPROTO; } object_out->method = methodname.string_value; - ok = PlatformChannel_decodeStdMsgCodecValue(&buffer_cursor, &remaining, &(object_out->stdarg)); + ok = platch_decode_value_std(&buffer_cursor, &remaining, &(object_out->std_arg)); if (ok != 0) return ok; break; @@ -746,23 +749,23 @@ int PlatformChannel_decode(uint8_t *buffer, size_t size, enum ChannelCodec codec advance(&buffer_cursor, 1, &remaining); if (object_out->success) { - struct StdMsgCodecValue result; + struct std_value result; - ok = PlatformChannel_decodeStdMsgCodecValue(&buffer_cursor, &remaining, &(object_out->stdresult)); + ok = platch_decode_value_std(&buffer_cursor, &remaining, &(object_out->std_result)); if (ok != 0) return ok; } else { - struct StdMsgCodecValue errorcode, errormessage; + struct std_value error_code, error_msg; - ok = PlatformChannel_decodeStdMsgCodecValue(&buffer_cursor, &remaining, &errorcode); + ok = platch_decode_value_std(&buffer_cursor, &remaining, &error_code); if (ok != 0) return ok; - ok = PlatformChannel_decodeStdMsgCodecValue(&buffer_cursor, &remaining, &errormessage); + ok = platch_decode_value_std(&buffer_cursor, &remaining, &error_msg); if (ok != 0) return ok; - ok = PlatformChannel_decodeStdMsgCodecValue(&buffer_cursor, &remaining, &(object_out->stderrordetails)); + ok = platch_decode_value_std(&buffer_cursor, &remaining, &(object_out->std_error_details)); if (ok != 0) return ok; - if ((errorcode.type == kString) && ((errormessage.type == kString) || (errormessage.type == kNull))) { - object_out->errorcode = errorcode.string_value; - object_out->errormessage = (errormessage.type == kString) ? errormessage.string_value : NULL; + if ((error_code.type == kStdString) && ((error_msg.type == kStdString) || (error_msg.type == kStdNull))) { + object_out->error_code = error_code.string_value; + object_out->error_msg = (error_msg.type == kStdString) ? error_msg.string_value : NULL; } else { return EBADMSG; } @@ -774,9 +777,9 @@ int PlatformChannel_decode(uint8_t *buffer, size_t size, enum ChannelCodec codec return 0; } -int PlatformChannel_encode(struct ChannelObject *object, uint8_t **buffer_out, size_t *size_out) { - struct StdMsgCodecValue stdmethod, stderrcode, stderrmessage; - struct JSONMsgCodecValue jsmethod, jserrcode, jserrmessage, jsroot; +int platch_encode(struct platch_obj *object, uint8_t **buffer_out, size_t *size_out) { + struct std_value stdmethod, stderrcode, stderrmessage; + struct json_value jsmethod, jserrcode, jserrmessage, jsroot; uint8_t *buffer, *buffer_cursor; size_t size = 0; int ok = 0; @@ -797,24 +800,24 @@ int PlatformChannel_encode(struct ChannelObject *object, uint8_t **buffer_out, s *size_out = object->binarydata_size; return 0; case kJSONMessageCodec: - size = PlatformChannel_calculateJSONMsgCodecValueSize(&(object->jsonmsgcodec_value)); + size = platch_calc_value_size_json(&(object->json_value)); size += 1; // JSONMsgCodec uses sprintf, which null-terminates strings, // so lets allocate one more byte for the last null-terminator. // this is decremented again in the second switch-case, so flutter // doesn't complain about a malformed message. break; case kStandardMessageCodec: - ok = PlatformChannel_calculateStdMsgCodecValueSize(&(object->stdmsgcodec_value), &size); + ok = platch_calc_value_size_std(&(object->std_value), &size); if (ok != 0) return ok; break; case kStandardMethodCall: - stdmethod.type = kString; + stdmethod.type = kStdString; stdmethod.string_value = object->method; - ok = PlatformChannel_calculateStdMsgCodecValueSize(&stdmethod, &size); + ok = platch_calc_value_size_std(&stdmethod, &size); if (ok != 0) return ok; - ok = PlatformChannel_calculateStdMsgCodecValueSize(&(object->stdarg), &size); + ok = platch_calc_value_size_std(&(object->std_arg), &size); if (ok != 0) return ok; break; @@ -822,55 +825,55 @@ int PlatformChannel_encode(struct ChannelObject *object, uint8_t **buffer_out, s size += 1; if (object->success) { - ok = PlatformChannel_calculateStdMsgCodecValueSize(&(object->stdresult), &size); + ok = platch_calc_value_size_std(&(object->std_result), &size); if (ok != 0) return ok; } else { - stderrcode = (struct StdMsgCodecValue) { - .type = kString, - .string_value = object->errorcode + stderrcode = (struct std_value) { + .type = kStdString, + .string_value = object->error_code }; - stderrmessage = (struct StdMsgCodecValue) { - .type = kString, - .string_value = object->errormessage + stderrmessage = (struct std_value) { + .type = kStdString, + .string_value = object->error_msg }; - ok = PlatformChannel_calculateStdMsgCodecValueSize(&stderrcode, &size); + ok = platch_calc_value_size_std(&stderrcode, &size); if (ok != 0) return ok; - ok = PlatformChannel_calculateStdMsgCodecValueSize(&stderrmessage, &size); + ok = platch_calc_value_size_std(&stderrmessage, &size); if (ok != 0) return ok; - ok = PlatformChannel_calculateStdMsgCodecValueSize(&(object->stderrordetails), &size); + ok = platch_calc_value_size_std(&(object->std_error_details), &size); if (ok != 0) return ok; } break; case kJSONMethodCall: - jsroot.type = kJSObject; + jsroot.type = kJsonObject; jsroot.size = 2; jsroot.keys = (char*[]) {"method", "args"}; - jsroot.values = (struct JSONMsgCodecValue[]) { - {.type = kJSString, .string_value = object->method}, - object->jsarg + jsroot.values = (struct json_value[]) { + {.type = kJsonString, .string_value = object->method}, + object->json_arg }; - size = PlatformChannel_calculateJSONMsgCodecValueSize(&jsroot); + size = platch_calc_value_size_json(&jsroot); size += 1; break; case kJSONMethodCallResponse: - jsroot.type = kJSArray; + jsroot.type = kJsonArray; if (object->success) { jsroot.size = 1; - jsroot.array = (struct JSONMsgCodecValue[]) { - object->jsresult + jsroot.array = (struct json_value[]) { + object->json_result }; } else { jsroot.size = 3; - jsroot.array = (struct JSONMsgCodecValue[]) { - {.type = kJSString, .string_value = object->errorcode}, - {.type = (object->errormessage != NULL) ? kJSString : kJSNull, .string_value = object->errormessage}, - object->jserrordetails + jsroot.array = (struct json_value[]) { + {.type = kJsonString, .string_value = object->error_code}, + {.type = (object->error_msg != NULL) ? kJsonString : kJsonNull, .string_value = object->error_msg}, + object->json_error_details }; } - size = PlatformChannel_calculateJSONMsgCodecValueSize(&jsroot); + size = platch_calc_value_size_json(&jsroot); size += 1; break; default: @@ -885,14 +888,14 @@ int PlatformChannel_encode(struct ChannelObject *object, uint8_t **buffer_out, s memcpy(buffer, object->string_value, size); break; case kStandardMessageCodec: - ok = PlatformChannel_writeStdMsgCodecValueToBuffer(&(object->stdmsgcodec_value), &buffer_cursor); + ok = platch_write_value_to_buffer_std(&(object->std_value), &buffer_cursor); if (ok != 0) goto free_buffer_and_return_ok; break; case kStandardMethodCall: - ok = PlatformChannel_writeStdMsgCodecValueToBuffer(&stdmethod, &buffer_cursor); + ok = platch_write_value_to_buffer_std(&stdmethod, &buffer_cursor); if (ok != 0) goto free_buffer_and_return_ok; - ok = PlatformChannel_writeStdMsgCodecValueToBuffer(&(object->stdarg), &buffer_cursor); + ok = platch_write_value_to_buffer_std(&(object->std_arg), &buffer_cursor); if (ok != 0) goto free_buffer_and_return_ok; break; @@ -901,29 +904,29 @@ int PlatformChannel_encode(struct ChannelObject *object, uint8_t **buffer_out, s write8(&buffer_cursor, 0x00); advance(&buffer_cursor, 1); - ok = PlatformChannel_writeStdMsgCodecValueToBuffer(&(object->stdresult), &buffer_cursor); + ok = platch_write_value_to_buffer_std(&(object->std_result), &buffer_cursor); if (ok != 0) goto free_buffer_and_return_ok; } else { write8(&buffer_cursor, 0x01); advance(&buffer_cursor, 1); - ok = PlatformChannel_writeStdMsgCodecValueToBuffer(&stderrcode, &buffer_cursor); + ok = platch_write_value_to_buffer_std(&stderrcode, &buffer_cursor); if (ok != 0) goto free_buffer_and_return_ok; - ok = PlatformChannel_writeStdMsgCodecValueToBuffer(&stderrmessage, &buffer_cursor); + ok = platch_write_value_to_buffer_std(&stderrmessage, &buffer_cursor); if (ok != 0) goto free_buffer_and_return_ok; - ok = PlatformChannel_writeStdMsgCodecValueToBuffer(&(object->stderrordetails), &buffer_cursor); + ok = platch_write_value_to_buffer_std(&(object->std_error_details), &buffer_cursor); if (ok != 0) goto free_buffer_and_return_ok; } break; case kJSONMessageCodec: size -= 1; - ok = PlatformChannel_writeJSONMsgCodecValueToBuffer(&(object->jsonmsgcodec_value), &buffer_cursor); + ok = platch_write_value_to_buffer_json(&(object->json_value), &buffer_cursor); if (ok != 0) goto free_buffer_and_return_ok; break; case kJSONMethodCall: ; size -= 1; - ok = PlatformChannel_writeJSONMsgCodecValueToBuffer(&jsroot, &buffer_cursor); + ok = platch_write_value_to_buffer_json(&jsroot, &buffer_cursor); if (ok != 0) goto free_buffer_and_return_ok; break; default: @@ -939,13 +942,13 @@ int PlatformChannel_encode(struct ChannelObject *object, uint8_t **buffer_out, s return ok; } -void PlatformChannel_internalOnResponse(const uint8_t *buffer, size_t size, void *userdata) { - struct ResponseHandlerData *handlerdata; - struct ChannelObject object; +void platch_on_response_internal(const uint8_t *buffer, size_t size, void *userdata) { + struct platch_msg_resp_handler_data *handlerdata; + struct platch_obj object; int ok; - handlerdata = (struct ResponseHandlerData *) userdata; - ok = PlatformChannel_decode((uint8_t*) buffer, size, handlerdata->codec, &object); + handlerdata = (struct platch_msg_resp_handler_data *) userdata; + ok = platch_decode((uint8_t*) buffer, size, handlerdata->codec, &object); if (ok != 0) return; ok = handlerdata->on_response(&object, handlerdata->userdata); @@ -953,29 +956,30 @@ void PlatformChannel_internalOnResponse(const uint8_t *buffer, size_t size, void free(handlerdata); - ok = PlatformChannel_free(&object); + ok = platch_free_obj(&object); if (ok != 0) return; } -int PlatformChannel_send(char *channel, struct ChannelObject *object, enum ChannelCodec response_codec, PlatformMessageResponseCallback on_response, void *userdata) { - struct ResponseHandlerData *handlerdata = NULL; + +int platch_send(char *channel, struct platch_obj *object, enum platch_codec response_codec, platch_msg_resp_callback on_response, void *userdata) { + struct platch_msg_resp_handler_data *handlerdata = NULL; FlutterPlatformMessageResponseHandle *response_handle = NULL; FlutterEngineResult result; uint8_t *buffer; size_t size; int ok; - ok = PlatformChannel_encode(object, &buffer, &size); + ok = platch_encode(object, &buffer, &size); if (ok != 0) return ok; if (on_response) { - handlerdata = malloc(sizeof(struct ResponseHandlerData)); + handlerdata = malloc(sizeof(struct platch_msg_resp_handler_data)); if (!handlerdata) return ENOMEM; handlerdata->codec = response_codec; handlerdata->on_response = on_response; handlerdata->userdata = userdata; - result = FlutterPlatformMessageCreateResponseHandle(engine, PlatformChannel_internalOnResponse, handlerdata, &response_handle); + result = FlutterPlatformMessageCreateResponseHandle(engine, platch_on_response_internal, handlerdata, &response_handle); if (result != kSuccess) return EINVAL; } @@ -1007,33 +1011,36 @@ int PlatformChannel_send(char *channel, struct ChannelObject *object, enum Chann return (result == kSuccess) ? 0 : EINVAL; } -int PlatformChannel_stdcall(char *channel, char *method, struct StdMsgCodecValue *argument, PlatformMessageResponseCallback on_response, void *userdata) { - struct ChannelObject object = { + +int platch_call_std(char *channel, char *method, struct std_value *argument, platch_msg_resp_callback on_response, void *userdata) { + struct platch_obj object = { .codec = kStandardMethodCall, .method = method, - .stdarg = *argument + .std_arg = *argument }; - return PlatformChannel_send(channel, &object, kStandardMethodCallResponse, on_response, userdata); + return platch_send(channel, &object, kStandardMethodCallResponse, on_response, userdata); } -int PlatformChannel_jsoncall(char *channel, char *method, struct JSONMsgCodecValue *argument, PlatformMessageResponseCallback on_response, void *userdata) { - return PlatformChannel_send(channel, - &(struct ChannelObject) { + +int platch_call_json(char *channel, char *method, struct json_value *argument, platch_msg_resp_callback on_response, void *userdata) { + return platch_send(channel, + &(struct platch_obj) { .codec = kJSONMethodCall, .method = method, - .jsarg = *argument + .json_arg = *argument }, kJSONMethodCallResponse, on_response, userdata); } -int PlatformChannel_respond(FlutterPlatformMessageResponseHandle *handle, struct ChannelObject *response) { + +int platch_respond(FlutterPlatformMessageResponseHandle *handle, struct platch_obj *response) { FlutterEngineResult result; uint8_t *buffer = NULL; size_t size = 0; int ok; - ok = PlatformChannel_encode(response, &buffer, &size); + ok = platch_encode(response, &buffer, &size); if (ok != 0) return ok; result = FlutterEngineSendPlatformMessageResponse(engine, (const FlutterPlatformMessageResponseHandle*) handle, (const uint8_t*) buffer, size); @@ -1042,61 +1049,188 @@ int PlatformChannel_respond(FlutterPlatformMessageResponseHandle *handle, struct return (result == kSuccess) ? 0 : EINVAL; } -int PlatformChannel_respondNotImplemented(FlutterPlatformMessageResponseHandle *handle) { - return PlatformChannel_respond( + +int platch_respond_not_implemented(FlutterPlatformMessageResponseHandle *handle) { + return platch_respond( (FlutterPlatformMessageResponseHandle *) handle, - &(struct ChannelObject) { + &(struct platch_obj) { .codec = kNotImplemented }); } -int PlatformChannel_respondError(FlutterPlatformMessageResponseHandle *handle, enum ChannelCodec codec, char *errorcode, char *errormessage, void *errordetails) { - if ((codec == kStandardMessageCodec) || (codec == kStandardMethodCall) || (codec == kStandardMethodCallResponse)) { - if (errordetails == NULL) - errordetails = &(struct StdMsgCodecValue) {.type = kNull}; - - return PlatformChannel_respond(handle, &(struct ChannelObject) { + + +int platch_respond_success_std(FlutterPlatformMessageResponseHandle *handle, + struct std_value *return_value) { + return platch_respond( + handle, + &(struct platch_obj) { + .codec = kStandardMethodCallResponse, + .success = true, + .std_result = return_value? *return_value : STDNULL + } + ); +} + +int platch_respond_error_std(FlutterPlatformMessageResponseHandle *handle, + char *error_code, + char *error_msg, + struct std_value *error_details) { + return platch_respond(handle, &(struct platch_obj) { + .codec = kStandardMethodCallResponse, + .success = false, + .error_code = error_code, + .error_msg = error_msg, + .std_error_details = error_details? *error_details : STDNULL + }); +} + +/// Sends a platform message to `handle` with error code "illegalargument" +/// and error message `errmsg`. +int platch_respond_illegal_arg_std(FlutterPlatformMessageResponseHandle *handle, + char *error_msg) { + return platch_respond_error_std(handle, "illegalargument", error_msg, NULL); +} + +/// Sends a platform message to `handle` with error code "nativeerror" +/// and error messsage `strerror(_errno)` +int platch_respond_native_error_std(FlutterPlatformMessageResponseHandle *handle, + int _errno) { + return platch_respond_error_std( + handle, + "nativeerror", + strerror(_errno), + &STDINT32(_errno) + ); +} + + +int platch_respond_success_json(FlutterPlatformMessageResponseHandle *handle, + struct json_value *return_value) { + return platch_respond( + handle, + &(struct platch_obj) { + .codec = kJSONMethodCallResponse, + .success = true, + .json_result = return_value? *return_value + : (struct json_value) {.type = kJsonNull} + } + ); +} + +int platch_respond_error_json(FlutterPlatformMessageResponseHandle *handle, + char *error_code, + char *error_msg, + struct json_value *error_details) { + return platch_respond(handle, &(struct platch_obj) { + .codec = kJSONMethodCallResponse, + .success = false, + .error_code = error_code, + .error_msg = error_msg, + .json_error_details = (error_details) ? + *error_details : + (struct json_value) {.type = kJsonNull} + }); +} + +int platch_respond_illegal_arg_json(FlutterPlatformMessageResponseHandle *handle, + char *error_msg) { + return platch_respond_error_json(handle, "illegalargument", error_msg, NULL); +} + +int platch_respond_native_error_json(FlutterPlatformMessageResponseHandle *handle, + int _errno) { + return platch_respond_error_json( + handle, + "nativeerror", + strerror(_errno), + &(struct json_value) {.type = kJsonNumber, .number_value = _errno} + ); +} + + +int platch_send_success_event_std(char *channel, struct std_value *event_value) { + return platch_send( + channel, + &(struct platch_obj) { + .codec = kStandardMethodCallResponse, + .success = true, + .std_result = event_value? *event_value : STDNULL + }, + 0, NULL, NULL + ); +} + +int platch_send_error_event_std(char *channel, + char *error_code, + char *error_msg, + struct std_value *error_details) { + return platch_send( + channel, + &(struct platch_obj) { .codec = kStandardMethodCallResponse, .success = false, - .errorcode = errorcode, - .errormessage = errormessage, - .stderrordetails = *((struct StdMsgCodecValue *) errordetails) - }); - } else if ((codec == kJSONMessageCodec) || (codec == kJSONMethodCall) || (codec == kJSONMethodCallResponse)) { - if (errordetails == NULL) - errordetails = &(struct JSONMsgCodecValue) {.type = kJSNull}; - - return PlatformChannel_respond(handle, &(struct ChannelObject) { + .error_code = error_code, + .error_msg = error_msg, + .std_error_details = error_details? *error_details : STDNULL + }, + 0, NULL, NULL + ); +} + + +int platch_send_success_event_json(char *channel, struct json_value *event_value) { + return platch_send(channel, + &(struct platch_obj) { + .codec = kJSONMethodCallResponse, + .success = true, + .json_result = event_value? *event_value : (struct json_value) {.type = kJsonNull} + }, + 0, NULL, NULL + ); +} + +int platch_send_error_event_json(char *channel, + char *error_code, + char *error_msg, + struct json_value *error_details) { + return platch_send( + channel, + &(struct platch_obj) { .codec = kJSONMethodCallResponse, .success = false, - .errorcode = errorcode, - .errormessage = errormessage, - .jserrordetails = *((struct JSONMsgCodecValue *) errordetails) - }); - } else return EINVAL; + .error_code = error_code, + .error_msg = error_msg, + .json_error_details = error_details? + *error_details : + (struct json_value) {.type = kJsonNull} + }, + 0, NULL, NULL + ); } -bool jsvalue_equals(struct JSONMsgCodecValue *a, struct JSONMsgCodecValue *b) { + +bool jsvalue_equals(struct json_value *a, struct json_value *b) { if (a == b) return true; if ((a == NULL) ^ (b == NULL)) return false; if (a->type != b->type) return false; switch (a->type) { - case kJSNull: - case kJSTrue: - case kJSFalse: + case kJsonNull: + case kJsonTrue: + case kJsonFalse: return true; - case kJSNumber: + case kJsonNumber: return a->number_value == b->number_value; - case kJSString: + case kJsonString: return strcmp(a->string_value, b->string_value) == 0; - case kJSArray: + case kJsonArray: if (a->size != b->size) return false; if (a->array == b->array) return true; for (int i = 0; i < a->size; i++) if (!jsvalue_equals(&a->array[i], &b->array[i])) return false; return true; - case kJSObject: + case kJsonObject: if (a->size != b->size) return false; if ((a->keys == b->keys) && (a->values == b->values)) return true; @@ -1127,7 +1261,7 @@ bool jsvalue_equals(struct JSONMsgCodecValue *a, struct JSONMsgCodecValue *b) { return true; } } -struct JSONMsgCodecValue *jsobject_get(struct JSONMsgCodecValue *object, char *key) { +struct json_value *jsobject_get(struct json_value *object, char *key) { int i; for (i=0; i < object->size; i++) if (strcmp(object->keys[i], key) == 0) break; @@ -1136,54 +1270,54 @@ struct JSONMsgCodecValue *jsobject_get(struct JSONMsgCodecValue *object, char *k if (i != object->size) return &(object->values[i]); return NULL; } -bool stdvalue_equals(struct StdMsgCodecValue *a, struct StdMsgCodecValue *b) { +bool stdvalue_equals(struct std_value *a, struct std_value *b) { if (a == b) return true; if ((a == NULL) ^ (b == NULL)) return false; if (a->type != b->type) return false; switch (a->type) { - case kNull: - case kTrue: - case kFalse: + case kStdNull: + case kStdTrue: + case kStdFalse: return true; - case kInt32: + case kStdInt32: return a->int32_value == b->int32_value; - case kInt64: + case kStdInt64: return a->int64_value == b->int64_value; - case kLargeInt: - case kString: + case kStdLargeInt: + case kStdString: return strcmp(a->string_value, b->string_value) == 0; - case kFloat64: + case kStdFloat64: return a->float64_value == b->float64_value; - case kUInt8Array: + case kStdUInt8Array: if (a->size != b->size) return false; if (a->uint8array == b->uint8array) return true; for (int i = 0; i < a->size; i++) if (a->uint8array[i] != b->uint8array[i]) return false; return true; - case kInt32Array: + case kStdInt32Array: if (a->size != b->size) return false; if (a->int32array == b->int32array) return true; for (int i = 0; i < a->size; i++) if (a->int32array[i] != b->int32array[i]) return false; return true; - case kInt64Array: + case kStdInt64Array: if (a->size != b->size) return false; if (a->int64array == b->int64array) return true; for (int i = 0; i < a->size; i++) if (a->int64array[i] != b->int64array[i]) return false; return true; - case kFloat64Array: + case kStdFloat64Array: if (a->size != b->size) return false; if (a->float64array == b->float64array) return true; for (int i = 0; i < a->size; i++) if (a->float64array[i] != b->float64array[i]) return false; return true; - case kList: + case kStdList: // the order of list elements is important if (a->size != b->size) return false; if (a->list == b->list) return true; @@ -1193,7 +1327,7 @@ bool stdvalue_equals(struct StdMsgCodecValue *a, struct StdMsgCodecValue *b) { return false; return true; - case kMap: { + case kStdMap: { // the order is not important here, which makes it a bit difficult to compare if (a->size != b->size) return false; if ((a->keys == b->keys) && (a->values == b->values)) return true; @@ -1206,7 +1340,7 @@ bool stdvalue_equals(struct StdMsgCodecValue *a, struct StdMsgCodecValue *b) { for (int i = 0; i < a->size; i++) { // The key we're searching for in b. - struct StdMsgCodecValue *key = &(a->keys[i]); + struct std_value *key = &(a->keys[i]); int j = 0; while (j < a->size) { @@ -1232,13 +1366,13 @@ bool stdvalue_equals(struct StdMsgCodecValue *a, struct StdMsgCodecValue *b) { return false; } -struct StdMsgCodecValue *stdmap_get(struct StdMsgCodecValue *map, struct StdMsgCodecValue *key) { +struct std_value *stdmap_get(struct std_value *map, struct std_value *key) { for (int i=0; i < map->size; i++) if (stdvalue_equals(&map->keys[i], key)) return &map->values[i]; return NULL; } -struct StdMsgCodecValue *stdmap_get_str(struct StdMsgCodecValue *map, char *key) { - return stdmap_get(map, &(struct StdMsgCodecValue) {.type = kString, .string_value = key}); +struct std_value *stdmap_get_str(struct std_value *map, char *key) { + return stdmap_get(map, &(struct std_value) {.type = kStdString, .string_value = key}); } \ No newline at end of file diff --git a/src/pluginregistry.c b/src/pluginregistry.c index ab244df3..58cbffb6 100644 --- a/src/pluginregistry.c +++ b/src/pluginregistry.c @@ -1,47 +1,50 @@ -#include +#include #include +#include #include #include -#include "plugins/services-plugin.h" -#include "plugins/text_input.h" -#include "plugins/raw_keyboard.h" +#include +#include +#include #ifdef BUILD_TEST_PLUGIN -# include "plugins/testplugin.h" +# include #endif #ifdef BUILD_ELM327_PLUGIN -# include "plugins/elm327plugin.h" +# include #endif #ifdef BUILD_GPIO_PLUGIN -# include "plugins/gpio-plugin.h" +# include #endif #ifdef BUILD_SPI_PLUGIN -# include "plugins/spi_plugin.h" +# include #endif - -struct ChannelObjectReceiverData { +struct platch_obj_recv_data { char *channel; - enum ChannelCodec codec; - ChannelObjectReceiveCallback callback; + enum platch_codec codec; + platch_obj_recv_callback callback; }; struct { - struct FlutterPiPlugin *plugins; + struct flutterpi_plugin *plugins; size_t plugin_count; - struct ChannelObjectReceiverData *callbacks; - size_t callbacks_size; + + // platch_obj callbacks + struct platch_obj_recv_data *platch_obj_cbs; + size_t platch_obj_cbs_size; + } pluginregistry; /// array of plugins that are statically included in flutter-pi. -struct FlutterPiPlugin hardcoded_plugins[] = { - {.name = "services", .init = Services_init, .deinit = Services_deinit}, - {.name = "text_input", .init = TextInput_init, .deinit = TextInput_deinit}, - {.name = "raw_keyboard", .init = RawKeyboard_init, .deinit = RawKeyboard_deinit}, +struct flutterpi_plugin hardcoded_plugins[] = { + {.name = "services", .init = services_init, .deinit = services_deinit}, + {.name = "text_input", .init = textin_init, .deinit = textin_deinit}, + {.name = "raw_keyboard", .init = rawkb_init, .deinit = rawkb_deinit}, #ifdef BUILD_TEST_PLUGIN - {.name = "testplugin", .init = TestPlugin_init, .deinit = TestPlugin_deinit}, + {.name = "testplugin", .init = testp_init, .deinit = testp_deinit}, #endif #ifdef BUILD_ELM327_PLUGIN @@ -49,26 +52,30 @@ struct FlutterPiPlugin hardcoded_plugins[] = { #endif #ifdef BUILD_GPIO_PLUGIN - {.name = "gpio-plugin", .init = GpioPlugin_init, .deinit = GpioPlugin_deinit}, + {.name = "flutter_gpiod", .init = gpiodp_init, .deinit = gpiodp_deinit}, #endif #ifdef BUILD_SPI_PLUGIN - {.name = "spi_plugin", .init = SPIPlugin_init, .deinit = SPIPlugin_deinit} + {.name = "flutter_spidev", .init = spidevp_init, .deinit = spidevp_deinit} #endif }; -//size_t hardcoded_plugins_count; -int PluginRegistry_init() { +int plugin_registry_init() { int ok; memset(&pluginregistry, 0, sizeof(pluginregistry)); - pluginregistry.callbacks_size = 20; - pluginregistry.callbacks = calloc(pluginregistry.callbacks_size, sizeof(struct ChannelObjectReceiverData)); + pluginregistry.platch_obj_cbs_size = 20; + pluginregistry.platch_obj_cbs = calloc(pluginregistry.platch_obj_cbs_size, sizeof(struct platch_obj_recv_data)); + + if (!pluginregistry.platch_obj_cbs) { + fprintf(stderr, "[plugin-registry] Could not allocate memory for platform channel message callbacks.\n"); + return ENOMEM; + } pluginregistry.plugins = hardcoded_plugins; - pluginregistry.plugin_count = sizeof(hardcoded_plugins) / sizeof(struct FlutterPiPlugin); + pluginregistry.plugin_count = sizeof(hardcoded_plugins) / sizeof(struct flutterpi_plugin); // insert code for dynamically loading plugins here @@ -82,18 +89,18 @@ int PluginRegistry_init() { return 0; } -int PluginRegistry_onPlatformMessage(FlutterPlatformMessage *message) { - struct ChannelObject object; +int plugin_registry_on_platform_message(FlutterPlatformMessage *message) { + struct platch_obj object; int ok; - for (int i = 0; i < pluginregistry.callbacks_size; i++) { - if ((pluginregistry.callbacks[i].callback) && (strcmp(pluginregistry.callbacks[i].channel, message->channel) == 0)) { - ok = PlatformChannel_decode((uint8_t*) message->message, message->message_size, pluginregistry.callbacks[i].codec, &object); + for (int i = 0; i < pluginregistry.platch_obj_cbs_size; i++) { + if ((pluginregistry.platch_obj_cbs[i].callback) && (strcmp(pluginregistry.platch_obj_cbs[i].channel, message->channel) == 0)) { + ok = platch_decode((uint8_t*) message->message, message->message_size, pluginregistry.platch_obj_cbs[i].codec, &object); if (ok != 0) return ok; - pluginregistry.callbacks[i].callback((char*) message->channel, &object, (FlutterPlatformMessageResponseHandle*) message->response_handle); + pluginregistry.platch_obj_cbs[i].callback((char*) message->channel, &object, (FlutterPlatformMessageResponseHandle*) message->response_handle); - PlatformChannel_free(&object); + platch_free_obj(&object); return 0; } } @@ -102,19 +109,19 @@ int PluginRegistry_onPlatformMessage(FlutterPlatformMessage *message) { // just respond with a null buffer to tell the VM-side // that the feature is not implemented. - return PlatformChannel_respondNotImplemented((FlutterPlatformMessageResponseHandle *) message->response_handle); + return platch_respond_not_implemented((FlutterPlatformMessageResponseHandle *) message->response_handle); } -int PluginRegistry_setReceiver(char *channel, enum ChannelCodec codec, ChannelObjectReceiveCallback callback) { - /// the index in 'callback' of the ChannelObjectReceiverData that will be added / updated. +int plugin_registry_set_receiver(char *channel, enum platch_codec codec, platch_obj_recv_callback callback) { + /// the index in 'callback' of the platch_obj_recv_data that will be added / updated. int index = -1; /// find the index with channel name 'channel', or else, the first unoccupied index. - for (int i = 0; i < pluginregistry.callbacks_size; i++) { - if (pluginregistry.callbacks[i].channel == NULL) { + for (int i = 0; i < pluginregistry.platch_obj_cbs_size; i++) { + if (pluginregistry.platch_obj_cbs[i].channel == NULL) { if (index == -1) { index = i; } - } else if (strcmp(channel, pluginregistry.callbacks[i].channel) == 0) { + } else if (strcmp(channel, pluginregistry.platch_obj_cbs[i].channel) == 0) { index = i; break; } @@ -125,13 +132,13 @@ int PluginRegistry_setReceiver(char *channel, enum ChannelCodec codec, ChannelOb if (!callback) return 0; /// expand array - size_t currentsize = pluginregistry.callbacks_size * sizeof(struct ChannelObjectReceiverData); + size_t currentsize = pluginregistry.platch_obj_cbs_size * sizeof(struct platch_obj_recv_data); - pluginregistry.callbacks = realloc(pluginregistry.callbacks, 2 * currentsize); - memset(&pluginregistry.callbacks[pluginregistry.callbacks_size], currentsize, 0); + pluginregistry.platch_obj_cbs = realloc(pluginregistry.platch_obj_cbs, 2 * currentsize); + memset(&pluginregistry.platch_obj_cbs[pluginregistry.platch_obj_cbs_size], currentsize, 0); - index = pluginregistry.callbacks_size; - pluginregistry.callbacks_size = 2*pluginregistry.callbacks_size; + index = pluginregistry.platch_obj_cbs_size; + pluginregistry.platch_obj_cbs_size = 2*pluginregistry.platch_obj_cbs_size; } if (callback) { @@ -139,19 +146,19 @@ int PluginRegistry_setReceiver(char *channel, enum ChannelCodec codec, ChannelOb if (!channelCopy) return ENOMEM; strcpy(channelCopy, channel); - pluginregistry.callbacks[index].channel = channelCopy; - pluginregistry.callbacks[index].codec = codec; - pluginregistry.callbacks[index].callback = callback; - } else if (pluginregistry.callbacks[index].callback) { - free(pluginregistry.callbacks[index].channel); - pluginregistry.callbacks[index].channel = NULL; - pluginregistry.callbacks[index].callback = NULL; + pluginregistry.platch_obj_cbs[index].channel = channelCopy; + pluginregistry.platch_obj_cbs[index].codec = codec; + pluginregistry.platch_obj_cbs[index].callback = callback; + } else if (pluginregistry.platch_obj_cbs[index].callback) { + free(pluginregistry.platch_obj_cbs[index].channel); + pluginregistry.platch_obj_cbs[index].channel = NULL; + pluginregistry.platch_obj_cbs[index].callback = NULL; } return 0; } -int PluginRegistry_deinit() { +int plugin_registry_deinit() { int i, ok; /// call each plugins 'deinit' @@ -163,11 +170,11 @@ int PluginRegistry_deinit() { } /// free all the channel names from the callback list. - for (int i=0; i < pluginregistry.callbacks_size; i++) { - if (pluginregistry.callbacks[i].channel) - free(pluginregistry.callbacks[i].channel); + for (int i=0; i < pluginregistry.platch_obj_cbs_size; i++) { + if (pluginregistry.platch_obj_cbs[i].channel) + free(pluginregistry.platch_obj_cbs[i].channel); } /// free the rest - free(pluginregistry.callbacks); + free(pluginregistry.platch_obj_cbs); } diff --git a/src/plugins/elm327plugin.c b/src/plugins/elm327plugin.c index fab968b9..b59db52f 100644 --- a/src/plugins/elm327plugin.c +++ b/src/plugins/elm327plugin.c @@ -17,7 +17,7 @@ #include #include -#include "elm327plugin.h" +#include struct elm327 elm; @@ -484,11 +484,11 @@ void *run_pidqq_processor(void* arg) { *****************/ void ELM327Plugin_onPidQueryCompletion(struct pidqq_element query, uint32_t result, enum elm327plugin_errno elm_errno) { // channel object that will be returned to flutter. - struct ChannelObject obj = { + struct platch_obj obj = { .codec = kStandardMethodCallResponse, .success = true, - .stdresult = { - .type = kFloat64, + .std_result = { + .type = kStdFloat64, .float64_value = 0.0 } }; @@ -498,40 +498,40 @@ void ELM327Plugin_onPidQueryCompletion(struct pidqq_element query, uint32_t resu switch (pid) { case OBDII_PID_ENGINE_RPM: - obj.stdresult.float64_value = (double) result / (double) 4.0; + obj.std_result.float64_value = (double) result / (double) 4.0; break; case OBDII_PID_ENGINE_LOAD: case OBDII_PID_THROTTLE_POSITION: - obj.stdresult.float64_value = result * 100.0 / 255.0; + obj.std_result.float64_value = result * 100.0 / 255.0; break; case OBDII_PID_ENGINE_COOLANT_TEMP: case OBDII_PID_INTAKE_AIR_TEMP: - obj.stdresult.type = kInt32; - obj.stdresult.int32_value = (int32_t) result - 40; + obj.std_result.type = kStdInt32; + obj.std_result.int32_value = (int32_t) result - 40; break; case OBDII_PID_VEHICLE_SPEED: - obj.stdresult.type = kInt32; - obj.stdresult.int32_value = (int32_t) result; + obj.std_result.type = kStdInt32; + obj.std_result.int32_value = (int32_t) result; break; default: break; } } else { obj.success = false; - obj.errorcode = "queryfailed"; - obj.errormessage = "ELM327 PID query failed. Reason could be a timeout on the connection between Pi and ELM or between ELM and ECU, or something else."; - obj.stderrordetails.type = kNull; + obj.error_code = "queryfailed"; + obj.error_msg = "ELM327 PID query failed. Reason could be a timeout on the connection between Pi and ELM or between ELM and ECU, or something else."; + obj.std_error_details.type = kStdNull; } - PlatformChannel_send(query.channel, &obj, kBinaryCodec, NULL, NULL); + platch_send(query.channel, &obj, kBinaryCodec, NULL, NULL); } int ELM327Plugin_onEventChannelListen(char *channel, uint8_t pid, FlutterPlatformMessageResponseHandle *handle) { printf("[elm327plugin] listener registered on event channel %s with pid 0x%02X\n", channel, pid); // check if pid is supported, if not, respond with an error envelope if (!elm_pid_supported(pid)) { - return PlatformChannel_respondError( - handle, kStandardMethodCallResponse, + return platch_respond_error_std( + handle, "notsupported", "The vehicle doesn't support the PID used for this channel.", NULL @@ -559,10 +559,10 @@ int ELM327Plugin_onEventChannelListen(char *channel, uint8_t pid, FlutterPlatfor pthread_cond_signal(&pidqq_added); // respond with null - return PlatformChannel_respond(handle, &(struct ChannelObject) { + return platch_respond(handle, &(struct platch_obj) { .codec = kStandardMethodCallResponse, .success = true, - .stdresult = {.type = kNull} + .std_result = {.type = kStdNull} }); } int ELM327Plugin_onEventChannelCancel(char *channel, uint8_t pid, FlutterPlatformMessageResponseHandle *handle) { @@ -574,13 +574,13 @@ int ELM327Plugin_onEventChannelCancel(char *channel, uint8_t pid, FlutterPlatfor pthread_mutex_unlock(&pidqq_lock); // respond with null. - return PlatformChannel_respond(handle, &(struct ChannelObject) { + return platch_respond(handle, &(struct platch_obj) { .codec = kStandardMethodCallResponse, .success = true, - .stdresult = {.type = kNull} + .std_result = {.type = kStdNull} }); } -int ELM327Plugin_onReceive(char *channel, struct ChannelObject *object, FlutterPlatformMessageResponseHandle *handle) { +int ELM327Plugin_onReceive(char *channel, struct platch_obj *object, FlutterPlatformMessageResponseHandle *handle) { bool isListen = false; if ((object->codec == kStandardMethodCall) && ((isListen = (strcmp(object->method, "listen") == 0)) || (strcmp(object->method, "cancel") == 0))) { uint8_t pid = (strcmp(channel, ELM327PLUGIN_RPM_CHANNEL) == 0) ? OBDII_PID_ENGINE_RPM : @@ -597,13 +597,15 @@ int ELM327Plugin_onReceive(char *channel, struct ChannelObject *object, FlutterP if (isListen) ELM327Plugin_onEventChannelListen(channel, pid, handle); else ELM327Plugin_onEventChannelCancel(channel, pid, handle); } else { - return PlatformChannel_respondError( - handle, kStandardMethodCallResponse, - "noelm", "elm.is_online == false. No communication to ELM327 possible, or initialization failed.", NULL + return platch_respond_error_std( + handle, + "noelm", + "elm.is_online == false. No communication to ELM327 possible, or initialization failed.", + NULL ); } } else { - return PlatformChannel_respondNotImplemented(handle); + return platch_respond_not_implemented(handle); } } @@ -624,12 +626,14 @@ int ELM327Plugin_init(void) { pidqq_processor_shouldrun = true; pthread_create(&pidqq_processor_thread, NULL, run_pidqq_processor, NULL); - PluginRegistry_setReceiver(ELM327PLUGIN_CHANNEL, kStandardMethodCall, ELM327Plugin_onReceive); - PluginRegistry_setReceiver(ELM327PLUGIN_RPM_CHANNEL, kStandardMethodCall, ELM327Plugin_onReceive); - PluginRegistry_setReceiver(ELM327PLUGIN_ENGINELOAD_CHANNEL, kStandardMethodCall, ELM327Plugin_onReceive); - PluginRegistry_setReceiver(ELM327PLUGIN_COOLANTTEMP_CHANNEL, kStandardMethodCall, ELM327Plugin_onReceive); - PluginRegistry_setReceiver(ELM327PLUGIN_SPEED_CHANNEL, kStandardMethodCall, ELM327Plugin_onReceive); - PluginRegistry_setReceiver(ELM327PLUGIN_THROTTLE_CHANNEL, kStandardMethodCall, ELM327Plugin_onReceive); + plugin_registry_set_receiver(ELM327PLUGIN_CHANNEL, kStandardMethodCall, ELM327Plugin_onReceive); + plugin_registry_set_receiver(ELM327PLUGIN_RPM_CHANNEL, kStandardMethodCall, ELM327Plugin_onReceive); + plugin_registry_set_receiver(ELM327PLUGIN_ENGINELOAD_CHANNEL, kStandardMethodCall, ELM327Plugin_onReceive); + plugin_registry_set_receiver(ELM327PLUGIN_COOLANTTEMP_CHANNEL, kStandardMethodCall, ELM327Plugin_onReceive); + plugin_registry_set_receiver(ELM327PLUGIN_SPEED_CHANNEL, kStandardMethodCall, ELM327Plugin_onReceive); + plugin_registry_set_receiver(ELM327PLUGIN_THROTTLE_CHANNEL, kStandardMethodCall, ELM327Plugin_onReceive); + + return 0; } int ELM327Plugin_deinit(void) { pidqq_processor_shouldrun = false; @@ -638,4 +642,6 @@ int ELM327Plugin_deinit(void) { elm_destroy(); free(pidqq); + + return 0; } \ No newline at end of file diff --git a/src/plugins/gpio-plugin.c b/src/plugins/gpio-plugin.c deleted file mode 100644 index 33676e84..00000000 --- a/src/plugins/gpio-plugin.c +++ /dev/null @@ -1,434 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include - -#include -#include "gpio-plugin.h" - - - -struct { - bool initialized; - - struct gpiod_chip *chips[GPIO_PLUGIN_MAX_CHIPS]; - size_t n_chips; - - // complete list of GPIO lines - struct gpiod_line **lines; - size_t n_lines; - - // GPIO lines that flutter is currently listening to - pthread_mutex_t listening_lines_mutex; - pthread_cond_t listening_line_added; - struct gpiod_line_bulk *listening_lines; -} gpio_plugin; - -struct { - void *handle; - - // GPIO chips - void (*chip_close)(struct gpiod_chip *chip); - const char *(*chip_name)(struct gpiod_chip *chip); - const char *(*chip_label)(struct gpiod_chip *chip); - unsigned int (*chip_num_lines)(struct gpiod_chip *chip); - - // GPIO lines - unsigned int (*line_offset)(struct gpiod_line *line); - const char *(*line_name)(struct gpiod_line *line); - const char *(*line_consumer)(struct gpiod_line *line); - int (*line_direction)(struct gpiod_line *line); - int (*line_active_state)(struct gpiod_line *line); - int (*line_bias)(struct gpiod_line *line); - bool (*line_is_used)(struct gpiod_line *line); - bool (*line_is_open_drain)(struct gpiod_line *line); - bool (*line_is_open_source)(struct gpiod_line *line); - int (*line_update)(struct gpiod_line *line); - int (*line_request)(struct gpiod_line *line, const struct gpiod_line_request_config *config, int default_val); - bool (*line_is_requested)(struct gpiod_line *line); - bool (*line_is_free)(struct gpiod_line *line); - int (*line_get_value)(struct gpiod_line *line); - int (*line_set_value)(struct gpiod_line *line, int value); - int (*line_set_config)(struct gpiod_line *line, int direction, int flags, int value); - int (*line_event_wait_bulk)(struct gpiod_line_bulk *bulk, const struct timespec *timeout, struct gpiod_line_bulk *event_bulk); - int (*line_event_read_multiple)(struct gpiod_line *line, struct gpiod_line_event *events, unsigned int num_events); - - // chip iteration - struct gpiod_chip_iter *(*chip_iter_new)(void); - void (*chip_iter_free_noclose)(struct gpiod_chip_iter *iter); - struct gpiod_chip *(*chip_iter_next_noclose)(struct gpiod_chip_iter *iter); - - // line iteration - struct gpiod_line_iter *(*line_iter_new)(struct gpiod_chip *chip); - void (*line_iter_free)(struct gpiod_line_iter *iter); - struct gpiod_line *(*line_iter_next)(struct gpiod_line_iter *iter); -} libgpiod; - -//#define gpiod_chip_iter_next_noclose libgpiod.chip_iter_next_noclose -//#define gpiod_line_iter_next libgpiod.line_iter_next - -int GpioPlugin_ensureGpiodInitialized() { - struct gpiod_chip_iter *chipiter; - struct gpiod_line_iter *lineiter; - struct gpiod_chip *chip; - struct gpiod_line *line; - int ok, i, j; - - if (gpio_plugin.initialized) return 0; - - libgpiod.handle = dlopen("libgpiod.so", RTLD_LOCAL | RTLD_LAZY); - if (!libgpiod.handle) { - perror("could not load libgpiod.so"); - return errno; - } - - LOAD_GPIOD_PROC(chip_close); - LOAD_GPIOD_PROC(chip_name); - LOAD_GPIOD_PROC(chip_label); - LOAD_GPIOD_PROC(chip_num_lines); - - LOAD_GPIOD_PROC(line_name); - LOAD_GPIOD_PROC(line_consumer); - LOAD_GPIOD_PROC(line_direction); - LOAD_GPIOD_PROC(line_active_state); - LOAD_GPIOD_PROC(line_bias); - LOAD_GPIOD_PROC(line_is_used); - LOAD_GPIOD_PROC(line_is_open_drain); - LOAD_GPIOD_PROC(line_is_open_source); - LOAD_GPIOD_PROC(line_update); - LOAD_GPIOD_PROC(line_request); - LOAD_GPIOD_PROC(line_is_requested); - LOAD_GPIOD_PROC(line_is_free); - LOAD_GPIOD_PROC(line_get_value); - LOAD_GPIOD_PROC(line_set_value); - LOAD_GPIOD_PROC(line_set_config); - - LOAD_GPIOD_PROC(chip_iter_new); - LOAD_GPIOD_PROC(chip_iter_free_noclose); - LOAD_GPIOD_PROC(chip_iter_next_noclose); - - LOAD_GPIOD_PROC(line_iter_new); - LOAD_GPIOD_PROC(line_iter_free); - LOAD_GPIOD_PROC(line_iter_next); - - - // iterate through the GPIO chips - chipiter = libgpiod.chip_iter_new(); - if (!chipiter) { - perror("could not create GPIO chip iterator"); - return errno; - } - - for (gpio_plugin.n_chips = 0, gpio_plugin.n_lines = 0, chip = libgpiod.chip_iter_next_noclose(chipiter); - chip; - gpio_plugin.n_chips++, chip = libgpiod.chip_iter_next_noclose(chipiter)) - { - gpio_plugin.chips[gpio_plugin.n_chips] = chip; - gpio_plugin.n_lines += libgpiod.chip_num_lines(chip); - } - libgpiod.chip_iter_free_noclose(chipiter); - - - // prepare the GPIO line list - gpio_plugin.lines = calloc(gpio_plugin.n_lines, sizeof(struct gpiod_line*)); - if (!gpio_plugin.lines) { - perror("could not allocate memory for GPIO line list"); - return errno; - } - - // iterate through the chips and put all lines into the list - for (i = 0, j = 0; i < gpio_plugin.n_chips; i++) { - lineiter = libgpiod.line_iter_new(gpio_plugin.chips[i]); - if (!lineiter) { - perror("could not create new GPIO line iterator"); - return errno; - } - - for (line = libgpiod.line_iter_next(lineiter); line; line = libgpiod.line_iter_next(lineiter), j++) - gpio_plugin.lines[j] = line; - - libgpiod.line_iter_free(lineiter); - } - - gpio_plugin.initialized = true; - return 0; -} - -int GpioPlugin_onGpiodMethodCall(char *channel, struct ChannelObject *object, FlutterPlatformMessageResponseHandle *responsehandle) { - unsigned int chip_index, line_index; - int ok; - - if STREQ("getNumChips", object->method) { - // check arg - if (!STDVALUE_IS_NULL(object->stdarg)) { - return PlatformChannel_respondError( - responsehandle, - kStandardMethodCallResponse, - "illegalargument", - "expected null as the argument", - NULL - ); - } - - // init GPIO - ok = GpioPlugin_ensureGpiodInitialized(); - if (ok != 0) { - return PlatformChannel_respondError( - responsehandle, - kStandardMethodCallResponse, - "couldnotinit", - "gpio-plugin failed to initialize. see flutter-pi log for details.", - NULL - ); - } - - // return num chips - return PlatformChannel_respond( - responsehandle, - &(struct ChannelObject) { - .codec = kStandardMethodCallResponse, - .success = true, - .stdresult = { - .type = kInt32, - .int32_value = gpio_plugin.n_chips - } - } - ); - - } else if STREQ("getChipDetails", object->method) { - // check arg - if (!STDVALUE_IS_INT(object->stdarg)) { - return PlatformChannel_respondError( - responsehandle, - kStandardMethodCallResponse, - "illegalargument", - "expected chip index as an integer argument.", - NULL - ); - } - - // init GPIO - ok = GpioPlugin_ensureGpiodInitialized(); - if (ok != 0) { - return PlatformChannel_respondError( - responsehandle, - kStandardMethodCallResponse, - "couldnotinit", - "gpio-plugin failed to initialize. see flutter-pi log for details.", - NULL - ); - } - - chip_index = (unsigned int) STDVALUE_AS_INT(object->stdarg); - if (chip_index >= gpio_plugin.n_chips) { - return PlatformChannel_respondError( - responsehandle, - kStandardMethodCallResponse, - "illegalargument", - "chip index out of range", - NULL - ); - } - - // return chip details - return PlatformChannel_respond( - responsehandle, - &(struct ChannelObject) { - .codec = kStandardMethodCallResponse, - .success = true, - .stdresult = { - .type = kMap, - .size = 3, - .keys = (struct StdMsgCodecValue[3]) { - {.type = kString, .string_value = "name"}, - {.type = kString, .string_value = "label"}, - {.type = kString, .string_value = "numLines"}, - }, - .values = (struct StdMsgCodecValue[3]) { - {.type = kString, .string_value = libgpiod.chip_name(gpio_plugin.chips[chip_index])}, - {.type = kString, .string_value = libgpiod.chip_label(gpio_plugin.chips[chip_index])}, - {.type = kString, .string_value = libgpiod.chip_num_lines(gpio_plugin.chips[chip_index])}, - } - } - } - ); - } else if STREQ("getLineHandle", object->method) { - // check arg - if (!(STDVALUE_IS_SIZED_LIST(object->stdarg, 2) && STDVALUE_IS_INT(object->stdarg.list[0]) - && STDVALUE_IS_INT(object->stdarg.list[0]))) { - return PlatformChannel_respondError( - responsehandle, - kStandardMethodCallResponse, - "illegalargument", - "expected list containing two integers as the argument", - NULL - ); - } - - // init GPIO - ok = GpioPlugin_ensureGpiodInitialized(); - if (ok != 0) { - return PlatformChannel_respondError( - responsehandle, - kStandardMethodCallResponse, - "couldnotinit", - "gpio-plugin failed to initialize. see flutter-pi log for details.", - NULL - ); - } - - chip_index = STDVALUE_AS_INT(object->stdarg.list[0]); - line_index = STDVALUE_AS_INT(object->stdarg.list[1]); - - if (chip_index >= gpio_plugin.n_chips) { - return PlatformChannel_respondError( - responsehandle, - kStandardMethodCallResponse, - "illegalargument", - "chip index out of range", - NULL - ); - } - - if (line_index >= libgpiod.chip_num_lines(gpio_plugin.chips[chip_index])) { - return PlatformChannel_respondError( - responsehandle, - kStandardMethodCallResponse, - "illegalargument", - "line index out of range", - NULL - ); - } - - for (int i = 0; i < chip_index; i++) - line_index += libgpiod.chip_num_lines(gpio_plugin.chips[i]); - - return PlatformChannel_respond( - responsehandle, - &(struct ChannelObject) { - .codec = kStandardMethodCallResponse, - .success = true, - .stdresult = { - .type = kInt32, - .int32_value = line_index - } - } - ); - } else if STREQ("getLineDetails", object->method) { - // check arg - if (!STDVALUE_IS_INT(object->stdarg)) { - return PlatformChannel_respondError( - responsehandle, - kStandardMethodCallResponse, - "illegalargument", - "expected line handle (integer) as the argument", - NULL - ); - } - - // init GPIO - ok = GpioPlugin_ensureGpiodInitialized(); - if (ok != 0) { - return PlatformChannel_respondError( - responsehandle, - kStandardMethodCallResponse, - "couldnotinit", - "gpio-plugin failed to initialize. see flutter-pi log for details.", - NULL - ); - } - - line_index = STDVALUE_AS_INT(object->stdarg); - if (line_index >= gpio_plugin.n_lines) { - return PlatformChannel_respondError( - responsehandle, - kStandardMethodCallResponse, - "illegalargument", - "invalid line handle", - NULL - ); - } - - struct gpiod_line *line = gpio_plugin.lines[line_index]; - - // if we don't own the line, update it - if (!libgpiod.line_is_requested(line)) - libgpiod.line_update(line); - - char *direction = libgpiod.line_direction(line) == GPIOD_LINE_DIRECTION_INPUT ? - "GpioLineDirection.input" : "GpioLineDirection.output"; - char *activeState = libgpiod.line_active_state(line) == GPIOD_LINE_ACTIVE_STATE_HIGH ? - "GpioLineActiveState.high" : "GpioLineActiveState.low"; - - char *biasStr = "GpioLineBias.asIs"; - if (libgpiod.line_bias) { - int bias = libgpiod.line_bias(line); - biasStr = bias == GPIOD_LINE_BIAS_DISABLE ? "GpioLineBias.disable" : - bias == GPIOD_LINE_BIAS_PULL_UP ? "GpioLineBias.pullUp" : - "GpioLineBias.pullDown"; - } - - // return chip details - return PlatformChannel_respond( - responsehandle, - &(struct ChannelObject) { - .codec = kStandardMethodCallResponse, - .success = true, - .stdresult = { - .type = kMap, - .size = 10, - .keys = (struct StdMsgCodecValue[10]) { - {.type = kString, .string_value = "name"}, - {.type = kString, .string_value = "consumer"}, - {.type = kString, .string_value = "direction"}, - {.type = kString, .string_value = "activeState"}, - {.type = kString, .string_value = "bias"}, - {.type = kString, .string_value = "isUsed"}, - {.type = kString, .string_value = "openDrain"}, - {.type = kString, .string_value = "openSource"}, - {.type = kString, .string_value = "isRequested"}, - {.type = kString, .string_value = "isFree"} - }, - .values = (struct StdMsgCodecValue[10]) { - {.type = kString, .string_value = libgpiod.line_name(line)}, - {.type = kString, .string_value = libgpiod.line_consumer(line)}, - {.type = kString, .string_value = direction}, - {.type = kString, .string_value = activeState}, - {.type = kString, .string_value = biasStr}, - {.type = libgpiod.line_is_used(line) ? kTrue : kFalse}, - {.type = libgpiod.line_is_open_drain(line) ? kTrue : kFalse}, - {.type = libgpiod.line_is_open_source(line) ? kTrue : kFalse}, - {.type = libgpiod.line_is_requested(line) ? kTrue : kFalse}, - {.type = libgpiod.line_is_free(line) ? kTrue : kFalse} - } - } - } - ); - } else if STREQ("requestLine", object->method) { - - } else if STREQ("releaseLine", object->method) { - - } else if STREQ("reconfigureLine", object->method) { - - } else if STREQ("getLineValue", object->method) { - - } else if STREQ("setLineValue", object->method) { - - } -} - -int GpioPlugin_init(void) { - printf("[gpio-plugin] init.\n"); - - gpio_plugin.initialized = false; - - PluginRegistry_setReceiver(GPIO_PLUGIN_GPIOD_METHOD_CHANNEL, kStandardMethodCall, GpioPlugin_onGpiodMethodCall); -} - -int GpioPlugin_deinit(void) { - printf("[gpio-plugin] deinit.\n"); -} \ No newline at end of file diff --git a/src/plugins/gpio-plugin.h b/src/plugins/gpio-plugin.h deleted file mode 100644 index d3f013ab..00000000 --- a/src/plugins/gpio-plugin.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef _GPIO_PLUGIN_H -#define _GPIO_PLUGIN_H - -#include - -#define GPIO_PLUGIN_GPIOD_METHOD_CHANNEL "flutter-pi/gpio/gpiod" -#define GPIO_PLUGIN_GPIOD_EVENT_CHANNEL "flutter-pi/gpio/gpiod_events" - -#define GPIO_PLUGIN_MAX_CHIPS 8 - -// a basic macro that loads a symbol from libgpiod, puts it into the libgpiod struct -// and returns the errno if an error ocurred - -#define LOAD_GPIOD_PROC(name) \ - do { \ - libgpiod.name = dlsym(libgpiod.handle, "gpiod_" #name); \ - if (!libgpiod.name) {\ - perror("could not resolve libgpiod procedure gpiod_" #name); \ - return errno; \ - } \ - } while (false) - -// because libgpiod doesn't provide it, but it's useful -static inline void gpiod_line_bulk_remove(struct gpiod_line_bulk *bulk, unsigned int index) { - memmove(&bulk->lines[index], &bulk->lines[index+1], sizeof(struct gpiod_line*) * (bulk->num_lines - index - 1)); - bulk->num_lines--; -} - -extern int GpioPlugin_init(void); -extern int GpioPlugin_deinit(void); - -#endif \ No newline at end of file diff --git a/src/plugins/gpiod.c b/src/plugins/gpiod.c new file mode 100644 index 00000000..553606a9 --- /dev/null +++ b/src/plugins/gpiod.c @@ -0,0 +1,1139 @@ +#include +#include +#include +#include +#include + +#include + +#include +#include + + + +struct { + bool initialized; + bool line_event_listener_should_run; + + struct gpiod_chip *chips[GPIO_PLUGIN_MAX_CHIPS]; + size_t n_chips; + + // complete list of GPIO lines + struct gpiod_line **lines; + size_t n_lines; + + // GPIO lines that flutter is currently listening to + pthread_mutex_t listening_lines_mutex; + pthread_cond_t listening_line_added; + struct gpiod_line_bulk listening_lines; + pthread_t line_event_listener_thread; + bool should_emit_events; +} gpio_plugin; + +struct { + void *handle; + + // GPIO chips + void (*chip_close)(struct gpiod_chip *chip); + const char *(*chip_name)(struct gpiod_chip *chip); + const char *(*chip_label)(struct gpiod_chip *chip); + unsigned int (*chip_num_lines)(struct gpiod_chip *chip); + + // GPIO lines + unsigned int (*line_offset)(struct gpiod_line *line); + const char *(*line_name)(struct gpiod_line *line); + const char *(*line_consumer)(struct gpiod_line *line); + int (*line_direction)(struct gpiod_line *line); + int (*line_active_state)(struct gpiod_line *line); + int (*line_bias)(struct gpiod_line *line); + bool (*line_is_used)(struct gpiod_line *line); + bool (*line_is_open_drain)(struct gpiod_line *line); + bool (*line_is_open_source)(struct gpiod_line *line); + int (*line_update)(struct gpiod_line *line); + int (*line_request)(struct gpiod_line *line, const struct gpiod_line_request_config *config, int default_val); + int (*line_release)(struct gpiod_line *line); + bool (*line_is_requested)(struct gpiod_line *line); + bool (*line_is_free)(struct gpiod_line *line); + int (*line_get_value)(struct gpiod_line *line); + int (*line_set_value)(struct gpiod_line *line, int value); + int (*line_set_config)(struct gpiod_line *line, int direction, int flags, int value); + int (*line_event_wait_bulk)(struct gpiod_line_bulk *bulk, const struct timespec *timeout, struct gpiod_line_bulk *event_bulk); + int (*line_event_read)(struct gpiod_line *line, struct gpiod_line_event *event); + int (*line_event_get_fd)(struct gpiod_line *line); + struct gpiod_chip *(*line_get_chip)(struct gpiod_line *line); + + // chip iteration + struct gpiod_chip_iter *(*chip_iter_new)(void); + void (*chip_iter_free_noclose)(struct gpiod_chip_iter *iter); + struct gpiod_chip *(*chip_iter_next_noclose)(struct gpiod_chip_iter *iter); + + // line iteration + struct gpiod_line_iter *(*line_iter_new)(struct gpiod_chip *chip); + void (*line_iter_free)(struct gpiod_line_iter *iter); + struct gpiod_line *(*line_iter_next)(struct gpiod_line_iter *iter); + + // misc + const char *(*version_string)(void); +} libgpiod; + +struct line_config { + struct gpiod_line *line; + int direction; + int request_type; + int initial_value; + uint8_t flags; +}; + +// because libgpiod doesn't provide it, but it's useful +static inline void gpiod_line_bulk_remove(struct gpiod_line_bulk *bulk, unsigned int index) { + memmove(&bulk->lines[index], &bulk->lines[index+1], sizeof(struct gpiod_line*) * (bulk->num_lines - index - 1)); + bulk->num_lines--; +} + +void *gpiodp_io_loop(void *userdata); + +/// ensures the libgpiod binding and the `gpio_plugin` chips list and line map is initialized. +int gpiodp_ensure_gpiod_initialized(void) { + struct gpiod_chip_iter *chipiter; + struct gpiod_line_iter *lineiter; + struct gpiod_chip *chip; + struct gpiod_line *line; + int ok, i, j; + + if (gpio_plugin.initialized) return 0; + + libgpiod.handle = dlopen("libgpiod.so", RTLD_LOCAL | RTLD_LAZY); + if (!libgpiod.handle) { + perror("could not load libgpiod.so"); + return errno; + } + + LOAD_GPIOD_PROC(chip_close); + LOAD_GPIOD_PROC(chip_name); + LOAD_GPIOD_PROC(chip_label); + LOAD_GPIOD_PROC(chip_num_lines); + + LOAD_GPIOD_PROC(line_offset); + LOAD_GPIOD_PROC(line_name); + LOAD_GPIOD_PROC(line_consumer); + LOAD_GPIOD_PROC(line_direction); + LOAD_GPIOD_PROC(line_active_state); + LOAD_GPIOD_PROC_OPTIONAL(line_bias); + LOAD_GPIOD_PROC(line_is_used); + LOAD_GPIOD_PROC(line_is_open_drain); + LOAD_GPIOD_PROC(line_is_open_source); + LOAD_GPIOD_PROC(line_update); + LOAD_GPIOD_PROC(line_request); + LOAD_GPIOD_PROC(line_release); + LOAD_GPIOD_PROC(line_is_requested); + LOAD_GPIOD_PROC(line_is_free); + LOAD_GPIOD_PROC(line_get_value); + LOAD_GPIOD_PROC(line_set_value); + LOAD_GPIOD_PROC_OPTIONAL(line_set_config); + LOAD_GPIOD_PROC(line_event_wait_bulk); + LOAD_GPIOD_PROC(line_event_read); + LOAD_GPIOD_PROC(line_event_get_fd); + LOAD_GPIOD_PROC(line_get_chip); + + LOAD_GPIOD_PROC(chip_iter_new); + LOAD_GPIOD_PROC(chip_iter_free_noclose); + LOAD_GPIOD_PROC(chip_iter_next_noclose); + + LOAD_GPIOD_PROC(line_iter_new); + LOAD_GPIOD_PROC(line_iter_free); + LOAD_GPIOD_PROC(line_iter_next); + + LOAD_GPIOD_PROC(version_string); + + + // iterate through the GPIO chips + chipiter = libgpiod.chip_iter_new(); + if (!chipiter) { + perror("could not create GPIO chip iterator"); + return errno; + } + + for (gpio_plugin.n_chips = 0, gpio_plugin.n_lines = 0, chip = libgpiod.chip_iter_next_noclose(chipiter); + chip; + gpio_plugin.n_chips++, chip = libgpiod.chip_iter_next_noclose(chipiter)) + { + gpio_plugin.chips[gpio_plugin.n_chips] = chip; + gpio_plugin.n_lines += libgpiod.chip_num_lines(chip); + } + libgpiod.chip_iter_free_noclose(chipiter); + + + // prepare the GPIO line list + gpio_plugin.lines = calloc(gpio_plugin.n_lines, sizeof(struct gpiod_line*)); + if (!gpio_plugin.lines) { + perror("could not allocate memory for GPIO line list"); + return errno; + } + + // iterate through the chips and put all lines into the list + for (i = 0, j = 0; i < gpio_plugin.n_chips; i++) { + lineiter = libgpiod.line_iter_new(gpio_plugin.chips[i]); + if (!lineiter) { + perror("could not create new GPIO line iterator"); + return errno; + } + + for (line = libgpiod.line_iter_next(lineiter); line; line = libgpiod.line_iter_next(lineiter), j++) + gpio_plugin.lines[j] = line; + + libgpiod.line_iter_free(lineiter); + } + + gpio_plugin.listening_lines = (struct gpiod_line_bulk) GPIOD_LINE_BULK_INITIALIZER; + gpio_plugin.listening_lines_mutex = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER; + gpio_plugin.listening_line_added = (pthread_cond_t) PTHREAD_COND_INITIALIZER; + gpio_plugin.line_event_listener_should_run = true; + + ok = pthread_create( + &gpio_plugin.line_event_listener_thread, + NULL, + gpiodp_io_loop, + NULL + ); + if (ok == -1) { + perror("[gpiodp] could not create line event listener thread"); + return errno; + } + + gpio_plugin.initialized = true; + return 0; +} + +/// Sends a platform message to `handle` saying that the libgpiod binding has failed to initialize. +/// Should be called when `gpiodp_ensure_gpiod_initialized()` has failed. +int gpiodp_respond_init_failed(FlutterPlatformMessageResponseHandle *handle) { + return platch_respond_error_std( + handle, + "couldnotinit", + "gpio_plugin failed to initialize libgpiod bindings. see flutter-pi log for details.", + NULL + ); +} + +/// Sends a platform message to `handle` with error code "illegalargument" +/// and error messsage "supplied line handle is not valid". +int gpiodp_respond_illegal_line_handle(FlutterPlatformMessageResponseHandle *handle) { + return platch_respond_illegal_arg_std(handle, "supplied line handle is not valid"); +} + +int gpiodp_respond_not_supported(FlutterPlatformMessageResponseHandle *handle, char *msg) { + return platch_respond_error_std(handle, "notsupported", msg, NULL); +} + +int gpiodp_get_config(struct std_value *value, + struct line_config *conf_out, + FlutterPlatformMessageResponseHandle *responsehandle) { + struct std_value *temp; + unsigned int line_handle; + bool has_bias; + int ok; + + conf_out->direction = 0; + conf_out->request_type = 0; + conf_out->flags = 0; + + if ((!value) || (value->type != kStdMap)) { + ok = platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg` to be a `Map`" + ); + if (ok != 0) return ok; + + return EINVAL; + } + + // get the line handle from the argument map + temp = stdmap_get_str(value, "lineHandle"); + if (temp && STDVALUE_IS_INT(*temp)) { + line_handle = STDVALUE_AS_INT(*temp); + } else { + ok = platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg['lineHandle']` to be an integer." + ); + if (ok != 0) return ok; + + return EINVAL; + } + + // get the corresponding gpiod line + if (line_handle < gpio_plugin.n_lines) { + conf_out->line = gpio_plugin.lines[line_handle]; + } else { + ok = gpiodp_respond_illegal_line_handle(responsehandle); + if (ok != 0) return ok; + + return EINVAL; + } + + // get the direction + temp = stdmap_get_str(value, "direction"); + if (temp && (temp->type == kStdString)) { + if STREQ("LineDirection.input", temp->string_value) { + conf_out->direction = GPIOD_LINE_DIRECTION_INPUT; + conf_out->request_type = GPIOD_LINE_REQUEST_DIRECTION_INPUT; + } else if STREQ("LineDirection.output", temp->string_value) { + conf_out->direction = GPIOD_LINE_DIRECTION_OUTPUT; + conf_out->request_type = GPIOD_LINE_REQUEST_DIRECTION_OUTPUT; + } else { + goto invalid_direction; + } + } else { + invalid_direction: + + ok = platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg['direction']` to be a string-ification of `LineDirection`." + ); + if (ok != 0) return ok; + + return EINVAL; + } + + // get the output mode + temp = stdmap_get_str(value, "outputMode"); + if ((!temp) || STDVALUE_IS_NULL(*temp)) { + if (conf_out->direction == GPIOD_LINE_DIRECTION_OUTPUT) { + goto invalid_output_mode; + } + } else if (temp && temp->type == kStdString) { + if (conf_out->direction == GPIOD_LINE_DIRECTION_INPUT) { + goto invalid_output_mode; + } + + if STREQ("OutputMode.pushPull", temp->string_value) { + // do nothing + } else if STREQ("OutputMode.openDrain", temp->string_value) { + conf_out->flags |= GPIOD_LINE_REQUEST_FLAG_OPEN_DRAIN; + } else if STREQ("OutputMode.openSource", temp->string_value) { + conf_out->flags |= GPIOD_LINE_REQUEST_FLAG_OPEN_SOURCE; + } else { + goto invalid_output_mode; + } + } else { + invalid_output_mode: + + ok = platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg['outputMode']` to be a string-ification " + "of [OutputMode] when direction is output, " + "null when direction is input." + ); + if (ok != 0) return ok; + + return EINVAL; + } + + // get the bias + has_bias = false; + temp = stdmap_get_str(value, "bias"); + if ((!temp) || STDVALUE_IS_NULL(*temp)) { + // don't need to set any flags + } else if (temp && temp->type == kStdString) { + if STREQ("Bias.disable", temp->string_value) { + conf_out->flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_DISABLE; + has_bias = true; + } else if STREQ("Bias.pullUp", temp->string_value) { + conf_out->flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP; + has_bias = true; + } else if STREQ("Bias.pullDown", temp->string_value) { + conf_out->flags |= GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_DOWN; + has_bias = true; + } else { + goto invalid_bias; + } + } else { + invalid_bias: + + ok = platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg['bias']` to be a stringification of [Bias] or null." + ); + if (ok != 0) return ok; + + return EINVAL; + } + + if (has_bias && !libgpiod.line_bias) { + ok = gpiodp_respond_not_supported( + responsehandle, + "Setting line bias is not supported on this platform. " + "Expected `arg['bias']` to be null." + ); + + if (ok != 0) return ok; + return ENOTSUP; + } + + // get the initial value + conf_out->initial_value = 0; + temp = stdmap_get_str(value, "initialValue"); + if ((!temp) || STDVALUE_IS_NULL(*temp)) { + if (conf_out->direction == GPIOD_LINE_DIRECTION_INPUT) { + // do nothing. + } else if (conf_out->direction == GPIOD_LINE_DIRECTION_OUTPUT) { + goto invalid_initial_value; + } + } else if (temp && STDVALUE_IS_BOOL(*temp)) { + if (conf_out->direction == GPIOD_LINE_DIRECTION_INPUT) { + goto invalid_initial_value; + } else if (conf_out->direction == GPIOD_LINE_DIRECTION_OUTPUT) { + conf_out->initial_value = STDVALUE_AS_BOOL(*temp) ? 1 : 0; + } + } else { + invalid_initial_value: + + ok = platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg['initialValue']` to be null if direction is input, " + "a bool if direction is output." + ); + if (ok != 0) return ok; + + return EINVAL; + } + + // get the active state + temp = stdmap_get_str(value, "activeState"); + if (temp && (temp->type == kStdString)) { + if STREQ("ActiveState.low", temp->string_value) { + conf_out->flags |= GPIOD_LINE_REQUEST_FLAG_ACTIVE_LOW; + } else if STREQ("ActiveState.high", temp->string_value) { + // do nothing + } else { + goto invalid_active_state; + } + } else { + invalid_active_state: + + ok = platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg['activeState']` to be a stringification of [ActiveState]." + ); + if (ok != 0) return ok; + + return EINVAL; + } + + return 0; +} + +/// Runs on it's own thread. Waits for events +/// on any of the lines in `gpio_plugin.listening_lines` +/// and sends them on to the event channel, if someone +/// is listening on it. +void *gpiodp_io_loop(void *userdata) { + struct gpiod_line_event event; + struct gpiod_line_bulk lines, events; + struct gpiod_line *line, **cursor; + struct gpiod_chip *chip; + struct pollfd fds[GPIOD_LINE_BULK_MAX_LINES] = {0}; + unsigned int line_handle, offset, num_lines; + int ok; + + while (gpio_plugin.line_event_listener_should_run) { + do { + pthread_mutex_lock(&gpio_plugin.listening_lines_mutex); + + // if we're currently not listening to any lines, wait + // for a line to listen to. + while (gpiod_line_bulk_num_lines(&gpio_plugin.listening_lines) == 0) { + pthread_cond_wait(&gpio_plugin.listening_line_added, + &gpio_plugin.listening_lines_mutex); + } + + lines = gpio_plugin.listening_lines; + events = (struct gpiod_line_bulk) GPIOD_LINE_BULK_INITIALIZER; + + // TODO: use our own polling function here. + ok = libgpiod.line_event_wait_bulk( + &gpio_plugin.listening_lines, + &(const struct timespec) {.tv_sec = 0, .tv_nsec = 100000}, + &events + ); + + pthread_mutex_unlock(&gpio_plugin.listening_lines_mutex); + + + } while (gpiod_line_bulk_num_lines(&events) == 0); + + + // we got events. go through each line in `events` + // and read the gpio line events. + gpiod_line_bulk_foreach_line(&events, line, cursor) { + ok = libgpiod.line_event_read(line, &event); + if (ok != 0) { + fprintf(stderr, "[gpiodp] Could not read events from gpio line.\n"); + continue; + } + + // If there's currently noone listening to the + // flutter_gpiod event channel, we bail out here + // and don't send anything on the channel. + if (!gpio_plugin.should_emit_events) { + continue; + } + + // convert the gpiod_line to a flutter_gpiod line handle. + line_handle = libgpiod.line_offset(line); + chip = libgpiod.line_get_chip(line); + for (int i = 0; gpio_plugin.chips[i] != chip; i++) + line_handle += libgpiod.chip_num_lines(chip); + + // finally send the event to the event channel. + ok = platch_send_success_event_std( + GPIOD_PLUGIN_EVENT_CHANNEL, + &(struct std_value) { + .type = kStdList, + .size = 3, + .list = (struct std_value[3]) { + {.type = kStdInt32, .int32_value = line_handle}, + { + .type = kStdString, + .string_value = + event.event_type == GPIOD_LINE_EVENT_FALLING_EDGE? + "SignalEdge.falling" : + "SignalEdge.rising" + }, + { + .type = kStdInt64Array, // use int64's here so we don't get any unexpected overflows. + .size = 2, + .int64array = (int64_t[2]) {event.ts.tv_sec, event.ts.tv_nsec} + } + } + } + ); + } + } + + return NULL; +} + + +int gpiodp_get_num_chips(struct platch_obj *object, + FlutterPlatformMessageResponseHandle *responsehandle) { + int ok; + + ok = gpiodp_ensure_gpiod_initialized(); + if (ok != 0) { + return gpiodp_respond_init_failed(responsehandle); + } + + return platch_respond_success_std(responsehandle, &STDINT32(gpio_plugin.n_chips)); +} + +int gpiodp_get_chip_details(struct platch_obj *object, + FlutterPlatformMessageResponseHandle *responsehandle) { + struct gpiod_chip *chip; + unsigned int chip_index; + int ok; + + // check the argument + if (STDVALUE_IS_INT(object->std_arg)) { + chip_index = STDVALUE_AS_INT(object->std_arg); + } else { + return platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg` to be an integer." + ); + } + + // init GPIO + ok = gpiodp_ensure_gpiod_initialized(); + if (ok != 0) { + return gpiodp_respond_init_failed(responsehandle); + } + + // get the chip index + if (chip_index < gpio_plugin.n_chips) { + chip = gpio_plugin.chips[chip_index]; + } else { + return platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg` to be valid chip index." + ); + } + + // return chip details + return platch_respond_success_std( + responsehandle, + &(struct std_value) { + .type = kStdMap, + .size = 3, + .keys = (struct std_value[3]) { + {.type = kStdString, .string_value = "name"}, + {.type = kStdString, .string_value = "label"}, + {.type = kStdString, .string_value = "numLines"}, + }, + .values = (struct std_value[3]) { + {.type = kStdString, .string_value = (char*) libgpiod.chip_name(chip)}, + {.type = kStdString, .string_value = (char*) libgpiod.chip_label(chip)}, + {.type = kStdInt32, .int32_value = libgpiod.chip_num_lines(chip)}, + } + } + ); +} + +int gpiodp_get_line_handle(struct platch_obj *object, + FlutterPlatformMessageResponseHandle *responsehandle) { + struct gpiod_chip *chip; + unsigned int chip_index, line_index; + int ok; + + // check arg + if (STDVALUE_IS_LIST(object->std_arg)) { + if (STDVALUE_IS_INT(object->std_arg.list[0])) { + chip_index = STDVALUE_AS_INT(object->std_arg.list[0]); + } else { + return platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg[0]` to be an integer." + ); + } + + if (STDVALUE_IS_INT(object->std_arg.list[1])) { + line_index = STDVALUE_AS_INT(object->std_arg.list[1]); + } else { + return platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg[1]` to be an integer." + ); + } + } else { + return platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg` to be a list with length 2." + ); + } + + // try to init GPIO + ok = gpiodp_ensure_gpiod_initialized(); + if (ok != 0) { + return gpiodp_respond_init_failed(responsehandle); + } + + // try to get the chip correspondig to the chip index + if (chip_index < gpio_plugin.n_chips) { + chip = gpio_plugin.chips[chip_index]; + } else { + return platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg[0]` to be a valid chip index." + ); + } + + // check if the line index is in range + if (line_index >= libgpiod.chip_num_lines(chip)) { + return platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg[1]` to be a valid line index." + ); + } + + // transform the line index into a line handle + for (int i = 0; i < chip_index; i++) + line_index += libgpiod.chip_num_lines(gpio_plugin.chips[i]); + + return platch_respond_success_std(responsehandle, &STDINT32(line_index)); +} + +int gpiodp_get_line_details(struct platch_obj *object, + FlutterPlatformMessageResponseHandle *responsehandle) { + struct gpiod_line *line; + unsigned int line_handle; + char *name, *consumer; + char *direction_str, *bias_str, *output_mode_str, *active_state_str; + bool open_source, open_drain; + int direction, bias; + int ok; + + // check arg + if (STDVALUE_IS_INT(object->std_arg)) { + line_handle = STDVALUE_AS_INT(object->std_arg); + } else { + return platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg` to be an integer." + ); + } + + // init GPIO + ok = gpiodp_ensure_gpiod_initialized(); + if (ok != 0) { + return gpiodp_respond_init_failed(responsehandle); + } + + // try to get the gpiod line corresponding to the line handle + if (line_handle < gpio_plugin.n_lines) { + line = gpio_plugin.lines[line_handle]; + } else { + return gpiodp_respond_illegal_line_handle(responsehandle); + } + + // if we don't own the line, update it + if (!libgpiod.line_is_requested(line)) { + libgpiod.line_update(line); + } + + direction = libgpiod.line_direction(line); + direction_str = direction == GPIOD_LINE_DIRECTION_INPUT ? + "LineDirection.input" : "LineDirection.output"; + + active_state_str = libgpiod.line_active_state(line) == GPIOD_LINE_ACTIVE_STATE_HIGH ? + "ActiveState.high" : "ActiveState.low"; + + bias_str = NULL; + if (libgpiod.line_bias) { + bias = libgpiod.line_bias(line); + if (bias == GPIOD_LINE_BIAS_DISABLE) { + bias_str = "Bias.disable"; + } else if (bias == GPIOD_LINE_BIAS_PULL_UP) { + bias_str = "Bias.pullUp"; + } else { + bias_str = "Bias.pullDown"; + } + } + + output_mode_str = NULL; + if (direction == GPIOD_LINE_DIRECTION_OUTPUT) { + open_source = libgpiod.line_is_open_source(line); + open_drain = libgpiod.line_is_open_drain(line); + + if (open_source) { + output_mode_str = "OutputMode.openSource"; + } else if (open_drain) { + output_mode_str = "OutputMode.openDrain"; + } else { + output_mode_str = "OutputMode.pushPull"; + } + } + + + name = (char*) libgpiod.line_name(line); + consumer = (char*) libgpiod.line_consumer(line); + + // return line details + return platch_respond_success_std( + responsehandle, + &(struct std_value) { + .type = kStdMap, + .size = 9, + .keys = (struct std_value[9]) { + {.type = kStdString, .string_value = "name"}, + {.type = kStdString, .string_value = "consumer"}, + {.type = kStdString, .string_value = "isUsed"}, + {.type = kStdString, .string_value = "isRequested"}, + {.type = kStdString, .string_value = "isFree"}, + {.type = kStdString, .string_value = "direction"}, + {.type = kStdString, .string_value = "outputMode"}, + {.type = kStdString, .string_value = "bias"}, + {.type = kStdString, .string_value = "activeState"} + }, + .values = (struct std_value[9]) { + {.type = name? kStdString : kStdNull, .string_value = name}, + {.type = consumer? kStdString : kStdNull, .string_value = consumer}, + {.type = libgpiod.line_is_used(line) ? kStdTrue : kStdFalse}, + {.type = libgpiod.line_is_requested(line) ? kStdTrue : kStdFalse}, + {.type = libgpiod.line_is_free(line) ? kStdTrue : kStdFalse}, + {.type = kStdString, .string_value = direction_str}, + { + .type = output_mode_str? kStdString : kStdNull, + .string_value = output_mode_str + }, + { + .type = bias_str? kStdString : kStdNull, + .string_value = bias_str + }, + {.type = kStdString, .string_value = active_state_str} + } + } + ); +} + +int gpiodp_request_line(struct platch_obj *object, + FlutterPlatformMessageResponseHandle *responsehandle) { + struct line_config config; + struct std_value *temp; + bool is_event_line = false; + char *consumer; + int ok; + + // check that the arg is a map + if (object->std_arg.type != kStdMap) { + return platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg` to be a `Map`" + ); + } + + // ensure GPIO is initialized + ok = gpiodp_ensure_gpiod_initialized(); + if (ok != 0) { + return gpiodp_respond_init_failed(responsehandle); + } + + temp = stdmap_get_str(&object->std_arg, "consumer"); + if (!temp || STDVALUE_IS_NULL(*temp)) { + consumer = NULL; + } else if (temp && (temp->type == kStdString)) { + consumer = temp->string_value; + } else { + return platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg['consumer']` to be a string or null." + ); + } + + // get the line config + ok = gpiodp_get_config(&object->std_arg, &config, responsehandle); + if (ok != 0) return ok; + + // get the triggers + temp = stdmap_get_str(&object->std_arg, "triggers"); + if ((!temp) || STDVALUE_IS_NULL(*temp)) { + if (config.direction == GPIOD_LINE_DIRECTION_INPUT) { + goto invalid_triggers; + } + } else if (temp && STDVALUE_IS_LIST(*temp)) { + if (config.direction == GPIOD_LINE_DIRECTION_OUTPUT) { + goto invalid_triggers; + } + + // iterate through elements in the trigger list. + for (int i = 0; i < temp->size; i++) { + if (temp->list[i].type != kStdString) { + goto invalid_triggers; + } + + // now update config.request_type accordingly. + if STREQ("SignalEdge.falling", temp->list[i].string_value) { + is_event_line = true; + switch (config.request_type) { + case GPIOD_LINE_REQUEST_DIRECTION_INPUT: + config.request_type = GPIOD_LINE_REQUEST_EVENT_FALLING_EDGE; + break; + case GPIOD_LINE_REQUEST_EVENT_FALLING_EDGE: + break; + case GPIOD_LINE_REQUEST_EVENT_RISING_EDGE: + case GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES: + config.request_type = GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES; + break; + default: break; + } + } else if STREQ("SignalEdge.rising", temp->list[i].string_value) { + is_event_line = true; + switch (config.request_type) { + case GPIOD_LINE_REQUEST_DIRECTION_INPUT: + config.request_type = GPIOD_LINE_REQUEST_EVENT_RISING_EDGE; + break; + case GPIOD_LINE_REQUEST_EVENT_RISING_EDGE: + break; + case GPIOD_LINE_REQUEST_EVENT_FALLING_EDGE: + case GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES: + config.request_type = GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES; + break; + default: break; + } + } else { + goto invalid_triggers; + } + } + } else { + invalid_triggers: + return platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg['triggers']` to be a `List` of " + "string-ifications of [SignalEdge] when direction is input " + "(no null values in the list), null when direction is output." + ); + } + + // finally temp the line + ok = libgpiod.line_request( + config.line, + &(struct gpiod_line_request_config) { + .consumer = consumer, + .request_type = config.request_type, + .flags = config.flags + }, + config.initial_value + ); + if (ok == -1) { + return platch_respond_native_error_std(responsehandle, errno); + } + + if (is_event_line) { + pthread_mutex_lock(&gpio_plugin.listening_lines_mutex); + + gpiod_line_bulk_add(&gpio_plugin.listening_lines, config.line); + + pthread_mutex_unlock(&gpio_plugin.listening_lines_mutex); + pthread_cond_signal(&gpio_plugin.listening_line_added); + } + + return platch_respond_success_std(responsehandle, NULL); +} + +int gpiodp_release_line(struct platch_obj *object, + FlutterPlatformMessageResponseHandle *responsehandle) { + struct gpiod_line *line, *current; + unsigned int line_handle; + unsigned int offset; + bool found; + int ok; + + // get the line handle + if (STDVALUE_IS_INT(object->std_arg)) { + line_handle = STDVALUE_AS_INT(object->std_arg); + } else { + return platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg` to be an integer." + ); + } + + // get the corresponding gpiod line + if (line_handle < gpio_plugin.n_lines) { + line = gpio_plugin.lines[line_handle]; + } else { + return gpiodp_respond_illegal_line_handle(responsehandle); + } + + pthread_mutex_lock(&gpio_plugin.listening_lines_mutex); + found = false; + gpiod_line_bulk_foreach_line_off(&gpio_plugin.listening_lines, current, offset) { + if (current == line) { + found = true; + break; + } + } + if (found) { + gpiod_line_bulk_remove(&gpio_plugin.listening_lines, offset); + } + pthread_mutex_unlock(&gpio_plugin.listening_lines_mutex); + + ok = libgpiod.line_release(line); + if (ok == -1) { + perror("[flutter_gpiod] Could not release line"); + return platch_respond_native_error_std(responsehandle, errno); + } + + return platch_respond_success_std(responsehandle, NULL); +} + +int gpiodp_reconfigure_line(struct platch_obj *object, + FlutterPlatformMessageResponseHandle *responsehandle) { + struct line_config config; + int ok; + + // ensure GPIO is initialized + ok = gpiodp_ensure_gpiod_initialized(); + if (ok != 0) { + return gpiodp_respond_init_failed(responsehandle); + } + + ok = gpiodp_get_config(&object->std_arg, &config, responsehandle); + if (ok != 0) return ok; + + if (!libgpiod.line_set_config) { + return gpiodp_respond_not_supported( + responsehandle, + "Line reconfiguration is not supported on this platform." + ); + } + + // finally temp the line + ok = libgpiod.line_set_config( + config.line, + config.direction, + config.flags, + config.initial_value + ); + if (ok == -1) { + return platch_respond_native_error_std(responsehandle, errno); + } + + return platch_respond_success_std(responsehandle, NULL); +} + +int gpiodp_get_line_value(struct platch_obj *object, + FlutterPlatformMessageResponseHandle *responsehandle) { + struct gpiod_line *line; + unsigned int line_handle; + int ok; + + // get the line handle + if (STDVALUE_IS_INT(object->std_arg)) { + line_handle = STDVALUE_AS_INT(object->std_arg); + } else { + return platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg` to be an integer." + ); + } + + // get the corresponding gpiod line + if (line_handle < gpio_plugin.n_lines) { + line = gpio_plugin.lines[line_handle]; + } else { + return gpiodp_respond_illegal_line_handle(responsehandle); + } + + // get the line value + ok = libgpiod.line_get_value(line); + if (ok == -1) { + return platch_respond_native_error_std(responsehandle, errno); + } + + return platch_respond_success_std(responsehandle, &STDBOOL(ok)); +} + +int gpiodp_set_line_value(struct platch_obj *object, + FlutterPlatformMessageResponseHandle *responsehandle) { + struct std_value *temp; + struct gpiod_line *line; + unsigned int line_handle; + bool value; + int ok; + + if (STDVALUE_IS_SIZED_LIST(object->std_arg, 2)) { + if (STDVALUE_IS_INT(object->std_arg.list[0])) { + line_handle = STDVALUE_AS_INT(object->std_arg.list[0]); + } else { + return platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg[0]` to be an integer." + ); + } + + if (STDVALUE_IS_BOOL(object->std_arg.list[1])) { + value = STDVALUE_AS_BOOL(object->std_arg.list[1]); + } else { + return platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg[1]` to be a bool." + ); + } + } else { + return platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg` to be a list." + ); + } + + // get the corresponding gpiod line + if (line_handle < gpio_plugin.n_lines) { + line = gpio_plugin.lines[line_handle]; + } else { + return gpiodp_respond_illegal_line_handle(responsehandle); + } + + // get the line value + ok = libgpiod.line_set_value(line, value ? 1 : 0); + if (ok == -1) { + return platch_respond_native_error_std(responsehandle, errno); + } + + return platch_respond_success_std(responsehandle, NULL); +} + +int gpiodp_supports_bias(struct platch_obj *object, + FlutterPlatformMessageResponseHandle *responsehandle) { + int ok; + + // ensure GPIO is initialized + ok = gpiodp_ensure_gpiod_initialized(); + if (ok != 0) { + return gpiodp_respond_init_failed(responsehandle); + } + + return platch_respond_success_std(responsehandle, &STDBOOL(libgpiod.line_bias)); +} + +int gpiodp_supports_reconfiguration(struct platch_obj *object, + FlutterPlatformMessageResponseHandle *responsehandle) { + int ok; + + // ensure GPIO is initialized + ok = gpiodp_ensure_gpiod_initialized(); + if (ok != 0) { + return gpiodp_respond_init_failed(responsehandle); + } + + return platch_respond_success_std(responsehandle, &STDBOOL(libgpiod.line_set_config)); +} + +/// Handles incoming platform messages. Calls the above methods. +int gpiodp_on_receive(char *channel, struct platch_obj *object, FlutterPlatformMessageResponseHandle *responsehandle) { + unsigned int chip_index, line_index; + bool is_legal_arg; + int ok; + + + if STREQ("getNumChips", object->method) { + return gpiodp_get_num_chips(object, responsehandle); + } else if STREQ("getChipDetails", object->method) { + return gpiodp_get_chip_details(object, responsehandle); + } else if STREQ("getLineHandle", object->method) { + return gpiodp_get_line_handle(object, responsehandle); + } else if STREQ("getLineDetails", object->method) { + return gpiodp_get_line_details(object, responsehandle); + } else if STREQ("requestLine", object->method) { + return gpiodp_request_line(object, responsehandle); + } else if STREQ("releaseLine", object->method) { + return gpiodp_release_line(object, responsehandle); + } else if STREQ("reconfigureLine", object->method) { + return gpiodp_reconfigure_line(object, responsehandle); + } else if STREQ("getLineValue", object->method) { + return gpiodp_get_line_value(object, responsehandle); + } else if STREQ("setLineValue", object->method) { + return gpiodp_set_line_value(object, responsehandle); + } else if STREQ("supportsBias", object->method) { + return gpiodp_supports_bias(object, responsehandle); + } else if STREQ("supportsLineReconfiguration", object->method) { + return gpiodp_supports_reconfiguration(object, responsehandle); + } + + return platch_respond_not_implemented(responsehandle); +} + +int gpiodp_on_receive_evch(char *channel, struct platch_obj *object, FlutterPlatformMessageResponseHandle *responsehandle) { + if STREQ("listen", object->method) { + gpio_plugin.should_emit_events = true; + return platch_respond_success_std(responsehandle, NULL); + } else if STREQ("cancel", object->method) { + gpio_plugin.should_emit_events = false; + return platch_respond_success_std(responsehandle, NULL); + } + + return platch_respond_not_implemented(responsehandle); +} + + +int gpiodp_init(void) { + int ok; + + printf("[flutter_gpiod] Initializing...\n"); + + gpio_plugin.initialized = false; + + ok = plugin_registry_set_receiver(GPIOD_PLUGIN_METHOD_CHANNEL, kStandardMethodCall, gpiodp_on_receive); + if (ok != 0) return ok; + + plugin_registry_set_receiver(GPIOD_PLUGIN_EVENT_CHANNEL, kStandardMethodCall, gpiodp_on_receive_evch); + if (ok != 0) return ok; + + printf("[flutter_gpiod] Done.\n"); + + return 0; +} + +int gpiodp_deinit(void) { + printf("[gpio-plugin] deinit.\n"); + return 0; +} \ No newline at end of file diff --git a/src/plugins/raw_keyboard.c b/src/plugins/raw_keyboard.c index 6786b27c..cbe67252 100644 --- a/src/plugins/raw_keyboard.c +++ b/src/plugins/raw_keyboard.c @@ -7,7 +7,7 @@ #include #include #include -#include "raw_keyboard.h" +#include struct { // same as mods, just that it differentiates between left and right-sided modifiers. @@ -16,26 +16,26 @@ struct { bool initialized; } raw_keyboard = {.initialized = false}; -int RawKeyboard_sendGlfwKeyEvent(uint32_t code_point, glfw_key key_code, uint32_t scan_code, glfw_keymod_map mods, bool is_down) { - return PlatformChannel_send( +int rawkb_send_glfw_keyevent(uint32_t code_point, glfw_key key_code, uint32_t scan_code, glfw_keymod_map mods, bool is_down) { + return platch_send( KEY_EVENT_CHANNEL, - &(struct ChannelObject) { + &(struct platch_obj) { .codec = kJSONMessageCodec, - .jsonmsgcodec_value = { - .type = kJSObject, + .json_value = { + .type = kJsonObject, .size = 7, .keys = (char*[7]) { "keymap", "toolkit", "unicodeScalarValues", "keyCode", "scanCode", "modifiers", "type" }, - .values = (struct JSONMsgCodecValue[7]) { - {.type = kJSString, .string_value = "linux"}, - {.type = kJSString, .string_value = "glfw"}, - {.type = kJSNumber, .number_value = code_point}, - {.type = kJSNumber, .number_value = key_code}, - {.type = kJSNumber, .number_value = scan_code}, - {.type = kJSNumber, .number_value = mods}, - {.type = kJSString, .string_value = is_down? "keydown" : "keyup"} + .values = (struct json_value[7]) { + {.type = kJsonString, .string_value = "linux"}, + {.type = kJsonString, .string_value = "glfw"}, + {.type = kJsonNumber, .number_value = code_point}, + {.type = kJsonNumber, .number_value = key_code}, + {.type = kJsonNumber, .number_value = scan_code}, + {.type = kJsonNumber, .number_value = mods}, + {.type = kJsonString, .string_value = is_down? "keydown" : "keyup"} } } }, @@ -45,7 +45,7 @@ int RawKeyboard_sendGlfwKeyEvent(uint32_t code_point, glfw_key key_code, uint32_ ); } -int RawKeyboard_onKeyEvent(glfw_key key, uint32_t scan_code, glfw_key_action action) { +int rawkb_on_keyevent(glfw_key key, uint32_t scan_code, glfw_key_action action) { glfw_keymod_map mods_after = raw_keyboard.mods; uint16_t lrmods_after = raw_keyboard.leftright_mods; glfw_keymod mod; @@ -108,23 +108,25 @@ int RawKeyboard_onKeyEvent(glfw_key key, uint32_t scan_code, glfw_key_action act } if (send) { - RawKeyboard_sendGlfwKeyEvent(0, key, scan_code, raw_keyboard.mods, action != GLFW_RELEASE); + rawkb_send_glfw_keyevent(0, key, scan_code, raw_keyboard.mods, action != GLFW_RELEASE); } raw_keyboard.leftright_mods = lrmods_after; raw_keyboard.mods = mods_after; } -int RawKeyboard_init(void) { +int rawkb_init(void) { + printf("[raw_keyboard] Initializing...\n"); + raw_keyboard.leftright_mods = 0; raw_keyboard.mods = 0; raw_keyboard.initialized = true; - printf("[raw_keyboard] init.\n"); + printf("[raw_keyboard] Done.\n"); return 0; } -int RawKeyboard_deinit(void) { +int rawkb_deinit(void) { raw_keyboard.initialized = false; printf("[raw_keyboard] deinit.\n"); diff --git a/src/plugins/raw_keyboard.h b/src/plugins/raw_keyboard.h deleted file mode 100644 index f9fb3fc8..00000000 --- a/src/plugins/raw_keyboard.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef _KEY_EVENT_H -#define _KEY_EVENT_H - -#define KEY_EVENT_CHANNEL "flutter/keyevent" - -int RawKeyboard_onKeyEvent(glfw_key key, uint32_t scan_code, glfw_key_action action); - -int RawKeyboard_init(void); -int RawKeyboard_deinit(void); - -#endif \ No newline at end of file diff --git a/src/plugins/services-plugin.c b/src/plugins/services.c similarity index 67% rename from src/plugins/services-plugin.c rename to src/plugins/services.c index dc4fea39..bef73337 100644 --- a/src/plugins/services-plugin.c +++ b/src/plugins/services.c @@ -3,29 +3,29 @@ #include #include -#include "services-plugin.h" +#include struct { char label[256]; - uint32_t primaryColor; // ARGB8888 (blue is the lowest byte) - char isolateId[32]; + uint32_t primary_color; // ARGB8888 (blue is the lowest byte) + char isolate_id[32]; } services = {0}; -int Services_onReceiveNavigation(char *channel, struct ChannelObject *object, FlutterPlatformMessageResponseHandle *responsehandle) { - return PlatformChannel_respondNotImplemented(responsehandle); +int services_on_receive_navigation(char *channel, struct platch_obj *object, FlutterPlatformMessageResponseHandle *responsehandle) { + return platch_respond_not_implemented(responsehandle); } -int Services_onReceiveIsolate(char *channel, struct ChannelObject *object, FlutterPlatformMessageResponseHandle *responsehandle) { - memset(&(services.isolateId), sizeof(services.isolateId), 0); - memcpy(services.isolateId, object->binarydata, object->binarydata_size); +int services_on_receive_isolate(char *channel, struct platch_obj *object, FlutterPlatformMessageResponseHandle *responsehandle) { + memset(&(services.isolate_id), sizeof(services.isolate_id), 0); + memcpy(services.isolate_id, object->binarydata, object->binarydata_size); - return PlatformChannel_respondNotImplemented(responsehandle); + return platch_respond_not_implemented(responsehandle); } -int Services_onReceivePlatform(char *channel, struct ChannelObject *object, FlutterPlatformMessageResponseHandle *responsehandle) { - struct JSONMsgCodecValue *value; - struct JSONMsgCodecValue *arg = &(object->jsarg); +int services_on_receive_platform(char *channel, struct platch_obj *object, FlutterPlatformMessageResponseHandle *responsehandle) { + struct json_value *value; + struct json_value *arg = &(object->json_arg); int ok; if (strcmp(object->method, "Clipboard.setData") == 0) { @@ -64,34 +64,33 @@ int Services_onReceivePlatform(char *channel, struct ChannelObject *object, Flut * } */ - value = &object->jsarg; + value = &object->json_arg; - if (value->type != kJSArray) - return PlatformChannel_respondError(responsehandle, kJSONMethodCallResponse, "illegalargument", "Expected List as argument", NULL); - - if (value->size == 0) - return PlatformChannel_respondError(responsehandle, kJSONMethodCallResponse, "illegalargument", "Argument List must have at least one value", NULL); - + if ((value->type != kJsonArray) || (value->size == 0)) { + return platch_respond_illegal_arg_json( + responsehandle, + "Expected `arg` to be an array with minimum size 1." + ); + } bool preferred_orientations[kLandscapeRight+1] = {0}; for (int i = 0; i < value->size; i++) { - if (value->array[i].type != kJSString) { - return PlatformChannel_respondError( - responsehandle, kJSONMethodCallResponse, - "illegalargument", "Argument List should only contain strings", NULL + if (value->array[i].type != kJsonString) { + return platch_respond_illegal_arg_json( + responsehandle, + "Expected `arg` to to only contain strings." ); } enum device_orientation o = ORIENTATION_FROM_STRING(value->array[i].string_value); if (o == -1) { - return PlatformChannel_respondError( - responsehandle, kJSONMethodCallResponse, - "illegalargument", - "Argument List elements should values of the DeviceOrientation enum", - NULL + return platch_respond_illegal_arg_json( + responsehandle, + "Expected `arg` to only contain stringifications of the " + "`DeviceOrientation` enum." ); } @@ -128,16 +127,10 @@ int Services_onReceivePlatform(char *channel, struct ChannelObject *object, Flut */ value = jsobject_get(arg, "label"); - if (value && (value->type == kJSString)) + if (value && (value->type == kJsonString)) snprintf(services.label, sizeof(services.label), "%s", value->string_value); - return PlatformChannel_respond(responsehandle, &(struct ChannelObject) { - .codec = kJSONMethodCallResponse, - .success = true, - .jsresult = { - .type = kNull - } - }); + return platch_respond_success_json(responsehandle, NULL); } else if (strcmp(object->method, "SystemChrome.setEnabledSystemUIOverlays") == 0) { /* * SystemChrome.setEnabledSystemUIOverlays(List overlays) @@ -172,45 +165,50 @@ int Services_onReceivePlatform(char *channel, struct ChannelObject *object, Flut printf("flutter requested application exit\n"); } - return PlatformChannel_respondNotImplemented(responsehandle); + return platch_respond_not_implemented(responsehandle); } -int Services_onReceiveAccessibility(char *channel, struct ChannelObject *object, FlutterPlatformMessageResponseHandle *responsehandle) { - return PlatformChannel_respondNotImplemented(responsehandle); +int services_on_receive_accessibility(char *channel, struct platch_obj *object, FlutterPlatformMessageResponseHandle *responsehandle) { + return platch_respond_not_implemented(responsehandle); } -int Services_init(void) { +int services_init(void) { int ok; - printf("[services-plugin] init.\n"); + printf("[services] Initializing...\n"); - ok = PluginRegistry_setReceiver("flutter/navigation", kJSONMethodCall, Services_onReceiveNavigation); + ok = plugin_registry_set_receiver("flutter/navigation", kJSONMethodCall, services_on_receive_navigation); if (ok != 0) { fprintf(stderr, "[services-plugin] could not set \"flutter/navigation\" ChannelObject receiver: %s\n", strerror(ok)); return ok; } - ok = PluginRegistry_setReceiver("flutter/isolate", kBinaryCodec, Services_onReceiveIsolate); + ok = plugin_registry_set_receiver("flutter/isolate", kBinaryCodec, services_on_receive_isolate); if (ok != 0) { fprintf(stderr, "[services-plugin] could not set \"flutter/isolate\" ChannelObject receiver: %s\n", strerror(ok)); return ok; } - ok = PluginRegistry_setReceiver("flutter/platform", kJSONMethodCall, Services_onReceivePlatform); + ok = plugin_registry_set_receiver("flutter/platform", kJSONMethodCall, services_on_receive_platform); if (ok != 0) { fprintf(stderr, "[services-plugin] could not set \"flutter/platform\" ChannelObject receiver: %s\n", strerror(ok)); return ok; } - ok = PluginRegistry_setReceiver("flutter/accessibility", kBinaryCodec, Services_onReceiveAccessibility); + ok = plugin_registry_set_receiver("flutter/accessibility", kBinaryCodec, services_on_receive_accessibility); if (ok != 0) { fprintf(stderr, "[services-plugin] could not set \"flutter/accessibility\" ChannelObject receiver: %s\n", strerror(ok)); return ok; } + + printf("[services] Done.\n"); + + return 0; } -int Services_deinit(void) { - printf("[services-plugin] deinit.\n"); +int services_deinit(void) { + printf("[services] deinit.\n"); + return 0; } \ No newline at end of file diff --git a/src/plugins/spi_plugin.c b/src/plugins/spi_plugin.c deleted file mode 100644 index 42440993..00000000 --- a/src/plugins/spi_plugin.c +++ /dev/null @@ -1,544 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "spi_plugin.h" - -enum spi_task_type { - kSpiTaskClose, - kSpiTaskRdMode, - kSpiTaskWrMode, - kSpiTaskWrBitsPerWord, - kSpiTaskRdBitsPerWord, - kSpiTaskWrMaxSpeedHz, - kSpiTaskRdMaxSpeedHz, - kSpiTaskTransmit -}; - -struct spi_task { - enum spi_task_type type; - union { - uint8_t mode; - uint8_t bits; - uint64_t speed; - struct spi_ioc_transfer transfer; - }; - FlutterPlatformMessageResponseHandle *responsehandle; -}; - -struct spi_thread { - int fd; - bool has_task; - struct spi_task task; - pthread_mutex_t mutex; - pthread_cond_t task_added; -}; - -#define SPI_THREAD_INITIALIZER \ - ((struct spi_thread) { \ - .fd = -1, .has_task = false, \ - .mutex = PTHREAD_MUTEX_INITIALIZER, .task_added = PTHREAD_COND_INITIALIZER \ - }) - -struct { - struct spi_thread *threads; - pthread_mutex_t threadlist_mutex; - size_t size_threads; - size_t num_threads; -} spi_plugin = { - .threads = NULL, - .threadlist_mutex = PTHREAD_MUTEX_INITIALIZER, - .size_threads = 0, - .num_threads = 0 -}; - -void *SPIPlugin_run_spi_thread(struct spi_thread *thread) { - bool running = true; - int fd = thread->fd; - int err = 0; - int ok; - - while (running) { - pthread_mutex_lock(&thread->mutex); - while (!thread->has_task) - pthread_cond_wait(&thread->task_added, &thread->mutex); - - switch (thread->task.type) { - case kSpiTaskClose: - ok = close(fd); - if (ok == -1) { - err = errno; - pthread_mutex_unlock(&thread->mutex); - break; - } - - running = false; - thread->fd = -1; - - pthread_mutex_unlock(&thread->mutex); - PlatformChannel_respond( - thread->task.responsehandle, - &(struct ChannelObject) {.codec = kStandardMethodCallResponse, .success = true, .stdresult = {.type = kNull}} - ); - break; - - case kSpiTaskRdMode: - ok = ioctl(fd, SPI_IOC_RD_MODE, &thread->task.mode); - if (ok == -1) { - err = errno; - pthread_mutex_unlock(&thread->mutex); - break; - } - - int32_t result = thread->task.mode; - - pthread_mutex_unlock(&thread->mutex); - PlatformChannel_respond( - thread->task.responsehandle, - &(struct ChannelObject) { - .codec = kStandardMethodCallResponse, .success = true, - .stdresult = {.type = kInt32, .int32_value = result} - } - ); - break; - - case kSpiTaskWrMode: - ok = ioctl(fd, SPI_IOC_WR_MODE, &thread->task.mode); - if (ok == -1) { - err = errno; - pthread_mutex_unlock(&thread->mutex); - break; - } - - pthread_mutex_unlock(&thread->mutex); - PlatformChannel_respond( - thread->task.responsehandle, - &(struct ChannelObject) {.codec = kStandardMethodCallResponse, .success = true, .stdresult = {.type = kNull}} - ); - break; - - case kSpiTaskWrBitsPerWord: - ok = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &thread->task.bits); - if (ok == -1) { - err = errno; - pthread_mutex_unlock(&thread->mutex); - break; - } - - pthread_mutex_unlock(&thread->mutex); - PlatformChannel_respond( - thread->task.responsehandle, - &(struct ChannelObject) {.codec = kStandardMethodCallResponse, .success = true, .stdresult = {.type = kNull}} - ); - break; - - case kSpiTaskRdBitsPerWord: - ok = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &thread->task.bits); - if (ok == -1) { - err = errno; - pthread_mutex_unlock(&thread->mutex); - break; - } - - int32_t result = thread->task.bits; - - pthread_mutex_unlock(&thread->mutex); - PlatformChannel_respond( - thread->task.responsehandle, - &(struct ChannelObject) { - .codec = kStandardMethodCallResponse, .success = true, - .stdresult = {.type = kInt32, .int32_value = result} - } - ); - break; - - case kSpiTaskWrMaxSpeedHz: - ok = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &thread->task.speed); - if (ok == -1) { - err = errno; - pthread_mutex_unlock(&thread->mutex); - break; - } - - pthread_mutex_unlock(&thread->mutex); - PlatformChannel_respond( - thread->task.responsehandle, - &(struct ChannelObject) {.codec = kStandardMethodCallResponse, .success = true, .stdresult = {.type = kNull}} - ); - break; - - case kSpiTaskRdMaxSpeedHz: - ok = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &thread->task.speed); - if (ok == -1) { - err = errno; - pthread_mutex_unlock(&thread->mutex); - break; - } - - int32_t result = thread->task.speed; - - pthread_mutex_unlock(&thread->mutex); - PlatformChannel_respond( - thread->task.responsehandle, - &(struct ChannelObject) { - .codec = kStandardMethodCallResponse, .success = true, - .stdresult = {.type = kInt64, .int64_value = result} - } - ); - break; - - case kSpiTaskTransmit: - ok = ioctl(fd, SPI_IOC_MESSAGE(1), thread->task.transfer); - if (ok == -1) { - err = errno; - free(thread->task.transfer.tx_buf); - pthread_mutex_unlock(&thread->mutex); - break; - } - - size_t len = thread->task.transfer.len; - uint8_t *buf = thread->task.transfer.rx_buf; - - pthread_mutex_unlock(&thread->mutex); - PlatformChannel_respond( - thread->task.responsehandle, - &(struct ChannelObject) { - .codec = kStandardMethodCallResponse, .success = true, - .stdresult = { - .type = kUInt8Array, - .size = len, - .uint8array = buf - } - } - ); - - free(buf); - - break; - - default: - break; - } - - thread->has_task = false; - if (err != 0) { - PlatformChannel_respondError( - thread->task.responsehandle, - kStandardMethodCallResponse, - "nativeerror", - strerror(err), - NULL - ); - err = 0; - } - } -} - -struct spi_thread *SPIPlugin_get_thread(const int fd) { - pthread_mutex_lock(&spi_plugin.threadlist_mutex); - - for (int i = 0; i < spi_plugin.num_threads; i++) { - if (spi_plugin.threads[i].fd == fd) - return &spi_plugin.threads[i]; - } - - pthread_mutex_unlock(&spi_plugin.threadlist_mutex); - return NULL; -} - -struct spi_thread *SPIPlugin_new_thread(const int fd) { - struct spi_thread *thread; - int ok; - - pthread_mutex_lock(&spi_plugin.threadlist_mutex); - - thread = &spi_plugin.threads[spi_plugin.num_threads++]; - thread->fd = fd; - - pthread_mutex_unlock(&spi_plugin.threadlist_mutex); - - ok = pthread_create(NULL, NULL, SPIPlugin_run_spi_thread, thread); - if (ok == -1) return errno; - - return 0; -} - -int SPIPlugin_assign_task(const int fd, const struct spi_task *const task) { - struct spi_thread *thread; - int ok; - - thread = SPIPlugin_get_thread(fd); - if (!thread) { - return EBADF; - } - - ok = pthread_mutex_trylock(&thread->mutex); - if (ok == -1) { - return errno; - } else if (ok == 0) { - thread->task = *task; - thread->has_task = true; - pthread_mutex_unlock(&thread->mutex); - pthread_cond_signal(&thread->task_added); - return 0; - } -} -[] -int SPIPlugin_onReceive(char *channel, struct ChannelObject *object, FlutterPlatformMessageResponseHandle *responsehandle) { - struct StdMsgCodecValue *temp; - struct spi_thread *thread; - struct spi_task task; - bool has_task = false; - int ok, fd; - - if STREQ("open", object->method) { - if (object->stdarg.type != kString) { - errormsg = "expected string as argument"; - goto respond_error; - } - - char *path = object->stdarg.string_value; - - fd = open(path, O_RDWR); - if (fd == -1) { - errorcode = "nativerror"; - errormsg = strerror(errno); - goto respond_error; - } - - ok = SPIPlugin_new_thread(fd); - if (ok != 0) { - errorcode = "nativerror"; - errormsg = strerror(ok); - goto respond_error; - } - - } else if STREQ("setMode", object->method) { - if ((object->stdarg.type == kList) && (object->stdarg.size == 2) && - (object->stdarg.list[0].type == kInt32) && (object->stdarg.list[1].type == kInt32)) { - fd = object->stdarg.list[0].int32_value; - task.mode = object->stdarg.int32_value; - } else if ((object->stdarg.type == kInt32Array) && (object->stdarg.size == 2)) { - fd = object->stdarg.int32array[0]; - task.mode = object->stdarg.int32array[1]; - } else { - return PlatformChannel_respondError( - responsehandle, - kStandardMethodCallResponse, - "invalidargument", - "expected list containing two int32's or an int32 array with size 2 as argument", - NULL - ); - } - - task.type = kSpiTaskWrMode; - has_task = true; - } else if STREQ("getMode", object->method) { - if (object->stdarg.type == kInt32) { - fd = object->stdarg.int32_value; - } else { - return PlatformChannel_respondError( - responsehandle, - kStandardMethodCallResponse, - "invalidargument", - "expected int32 as argument", - NULL - ); - } - - task.type = kSpiTaskRdMode; - has_task = true; - } else if STREQ("setMaxSpeed", object->method) { - if ((object->stdarg.type == kList) && (object->stdarg.size == 2) && - (object->stdarg.list[0].type == kInt32) && (object->stdarg.list[1].type == kInt32)) { - fd = object->stdarg.list[0].int32_value; - task.speed = object->stdarg.int32_value; - } else if ((object->stdarg.type == kInt32Array) && (object->stdarg.size == 2)) { - fd = object->stdarg.int32array[0]; - task.speed = object->stdarg.int32array[1]; - } else { - return PlatformChannel_respondError( - responsehandle, - kStandardMethodCallResponse, - "invalidargument", - "expected list containing two int32's or an int32 array with size 2 as argument", - NULL - ); - } - - task.type = kSpiTaskWrMaxSpeedHz; - has_task = true; - } else if STREQ("getMaxSpeed", object->method) { - if (object->stdarg.type == kInt32) { - fd = object->stdarg.int32_value; - } else { - return PlatformChannel_respondError( - responsehandle, - kStandardMethodCallResponse, - "invalidargument", - "expected int32 as argument", - NULL - ); - } - - task.type = kSpiTaskRdMaxSpeedHz; - has_task = true; - } else if STREQ("setWordSize", object->method) { - if ((object->stdarg.type == kList) && (object->stdarg.size == 2) && - (object->stdarg.list[0].type == kInt32) && (object->stdarg.list[1].type == kInt32)) { - fd = object->stdarg.list[0].int32_value; - task.bits = object->stdarg.int32_value; - } else if ((object->stdarg.type == kInt32Array) && (object->stdarg.size == 2)) { - fd = object->stdarg.int32array[0]; - task.bits = object->stdarg.int32array[1]; - } else { - return PlatformChannel_respondError( - responsehandle, - kStandardMethodCallResponse, - "invalidargument", - "expected list containing two int32's or an int32 array with size 2 as argument", - NULL - ); - } - - task.type = kSpiTaskWrBitsPerWord; - has_task = true; - } else if STREQ("getWordSize", object->method) { - if (object->stdarg.type == kInt32) { - fd = object->stdarg.int32_value; - } else { - return PlatformChannel_respondError( - responsehandle, - kStandardMethodCallResponse, - "invalidargument", - "expected int32 as argument", - NULL - ); - } - - task.type = kSpiTaskRdBitsPerWord; - has_task = true; - } else if STREQ("transmit", object->method) { - bool is_valid = false; - - if (object->stdarg.type == kMap) { - is_valid = true; - - temp = stdmap_get_str(&object->stdarg, "fd"); - if (temp && (temp->type == kInt32)) { - fd = temp->int32_value; - } else { - is_valid = false; - } - - temp = stdmap_get_str(&object->stdarg, "speed"); - if ((!temp) || (temp && temp->type == kInt32)) { - task.transfer.speed_hz = temp ? temp->int32_value : 0; - } else { - is_valid = false; - } - - temp = stdmap_get_str(&object->stdarg, "delay"); - if ((!temp) || (temp && temp->type == kInt32)) { - task.transfer.delay_usecs = temp ? temp->int32_value : 0; - } else { - is_valid = false; - } - - temp = stdmap_get_str(&object->stdarg, "wordSize"); - if ((!temp) || (temp && temp->type == kInt32)) { - task.transfer.bits_per_word = temp ? temp->int32_value : 0; - } else { - is_valid = false; - } - - temp = stdmap_get_str(&object->stdarg, "csChange"); - if (!temp || (temp && (temp->type == kTrue || temp->type == kFalse))) { - task.transfer.cs_change = temp && temp->type == kTrue; - } else { - is_valid = false; - } - - if (is_valid) { - temp = stdmap_get_str(&object->stdarg, "buffer"); - if (temp && temp->type == kUInt8Array) { - task.transfer.len = temp->size; - task.transfer.tx_buf = malloc(temp->size); - task.transfer.rx_buf = task.transfer.tx_buf; - - memcpy(task.transfer.tx_buf, temp->uint8array, temp->size); - } else { - is_valid = false; - } - } - } - - if (!is_valid) { - return PlatformChannel_respondError( - responsehandle, - kStandardMethodCallResponse, - "invalidargument", - "", - NULL - ); - } - - task.type = kSpiTaskTransmit; - has_task = true; - } else if STREQ("close", object->method) { - task.type = kSpiTaskClose; - has_task = true; - } - - if (has_task) { - ok = SPIPlugin_assign_task(fd, &task); - if (ok == 0) { - return; - } else if (ok == EBUSY) { - return PlatformChannel_respondError( - responsehandle, - kStandardMethodCallResponse, - "busy", - "a different task is running on the fd already", - NULL - ); - } else { - return PlatformChannel_respondError( - responsehandle, - kStandardMethodCallResponse, - "nativeerror", - strerror(ok), - NULL - ); - } - } - - return PlatformChannel_respondNotImplemented(responsehandle); -} - -int SPIPlugin_init(void) { - printf("[spi-plugin] init.\n"); - - spi_plugin.size_threads = 1; - spi_plugin.threads = calloc(spi_plugin.size_threads, sizeof(struct spi_thread)); - - for (int i = 0; i < spi_plugin.size_threads; i++) - spi_plugin.threads[i] = SPI_THREAD_INITIALIZER; - - PluginRegistry_setReceiver(SPI_PLUGIN_METHOD_CHANNEL, kStandardMethodCall, SPIPlugin_onReceive); - return 0; -} - -int SPIPlugin_deinit(void) { - printf("[spi-plugin] deinit.\n"); - return 0; -} \ No newline at end of file diff --git a/src/plugins/spi_plugin.h b/src/plugins/spi_plugin.h deleted file mode 100644 index 7cca599d..00000000 --- a/src/plugins/spi_plugin.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef _SPI_PLUGIN_H -#define _SPI_PLUGIN_H - -#include -#include - -#define SPI_PLUGIN_METHOD_CHANNEL "flutter-pi/spi" - -int SPIPlugin_init(void); -int SPIPlugin_deinit(void); - -#endif \ No newline at end of file diff --git a/src/plugins/spidev.c b/src/plugins/spidev.c new file mode 100644 index 00000000..2cd734d7 --- /dev/null +++ b/src/plugins/spidev.c @@ -0,0 +1,483 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +enum spidevp_task_type { + kSpiTaskClose, + kSpiTaskRdMode, + kSpiTaskWrMode, + kSpiTaskWrBitsPerWord, + kSpiTaskRdBitsPerWord, + kSpiTaskWrMaxSpeedHz, + kSpiTaskRdMaxSpeedHz, + kSpiTaskTransmit +}; + +struct spidevp_task { + enum spidevp_task_type type; + union { + uint8_t mode; + uint8_t bits; + uint64_t speed; + struct spi_ioc_transfer transfer; + }; + FlutterPlatformMessageResponseHandle *responsehandle; +}; + +struct spidevp_thread { + int fd; + bool has_task; + struct spidevp_task task; + pthread_mutex_t mutex; + pthread_cond_t task_added; +}; + +#define SPI_THREAD_INITIALIZER \ + ((struct spidevp_thread) { \ + .fd = -1, .has_task = false, \ + .mutex = PTHREAD_MUTEX_INITIALIZER, .task_added = PTHREAD_COND_INITIALIZER \ + }) + +struct { + struct spidevp_thread *threads; + pthread_mutex_t threadlist_mutex; + size_t size_threads; + size_t num_threads; +} spi_plugin = { + .threads = NULL, + .threadlist_mutex = PTHREAD_MUTEX_INITIALIZER, + .size_threads = 0, + .num_threads = 0 +}; + +void *spidevp_run_spi_thread(void *_thread) { + struct spidevp_thread *thread = (struct spidevp_thread*) _thread; + int32_t result; + bool running = true; + int fd = thread->fd; + int err = 0; + int ok; + + while (running) { + pthread_mutex_lock(&thread->mutex); + while (!thread->has_task) + pthread_cond_wait(&thread->task_added, &thread->mutex); + + switch (thread->task.type) { + case kSpiTaskClose: + ok = close(fd); + if (ok == -1) { + err = errno; + pthread_mutex_unlock(&thread->mutex); + break; + } + + running = false; + thread->fd = -1; + + pthread_mutex_unlock(&thread->mutex); + platch_respond_success_std(thread->task.responsehandle, NULL); + break; + + case kSpiTaskRdMode: + ok = ioctl(fd, SPI_IOC_RD_MODE, &thread->task.mode); + if (ok == -1) { + err = errno; + pthread_mutex_unlock(&thread->mutex); + break; + } + + result = thread->task.mode; + + pthread_mutex_unlock(&thread->mutex); + platch_respond_success_std(thread->task.responsehandle, NULL); + break; + + case kSpiTaskWrMode: + ok = ioctl(fd, SPI_IOC_WR_MODE, &thread->task.mode); + if (ok == -1) { + err = errno; + pthread_mutex_unlock(&thread->mutex); + break; + } + + pthread_mutex_unlock(&thread->mutex); + platch_respond_success_std(thread->task.responsehandle, NULL); + break; + + case kSpiTaskWrBitsPerWord: + ok = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &thread->task.bits); + if (ok == -1) { + err = errno; + pthread_mutex_unlock(&thread->mutex); + break; + } + + pthread_mutex_unlock(&thread->mutex); + platch_respond_success_std(thread->task.responsehandle, NULL); + break; + + case kSpiTaskRdBitsPerWord: + ok = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &thread->task.bits); + if (ok == -1) { + err = errno; + pthread_mutex_unlock(&thread->mutex); + break; + } + + result = thread->task.bits; + + pthread_mutex_unlock(&thread->mutex); + platch_respond_success_std(thread->task.responsehandle, NULL); + break; + + case kSpiTaskWrMaxSpeedHz: + ok = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &thread->task.speed); + if (ok == -1) { + err = errno; + pthread_mutex_unlock(&thread->mutex); + break; + } + + pthread_mutex_unlock(&thread->mutex); + platch_respond_success_std(thread->task.responsehandle, NULL); + break; + + case kSpiTaskRdMaxSpeedHz: + ok = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &thread->task.speed); + if (ok == -1) { + err = errno; + pthread_mutex_unlock(&thread->mutex); + break; + } + + result = thread->task.speed; + + pthread_mutex_unlock(&thread->mutex); + platch_respond_success_std(thread->task.responsehandle, NULL); + break; + + case kSpiTaskTransmit: ; + size_t len = thread->task.transfer.len; + uint8_t *buf = (void*) ((uintptr_t) thread->task.transfer.rx_buf); + + ok = ioctl(fd, SPI_IOC_MESSAGE(1), thread->task.transfer); + if (ok == -1) { + err = errno; + free(buf); + pthread_mutex_unlock(&thread->mutex); + break; + } + + pthread_mutex_unlock(&thread->mutex); + platch_respond_success_std(thread->task.responsehandle, NULL); + + free(buf); + + break; + + default: + break; + } + + thread->has_task = false; + if (err != 0) { + platch_respond_native_error_std(thread->task.responsehandle, err); + err = 0; + } + } +} + +struct spidevp_thread *spidevp_get_thread(const int fd) { + pthread_mutex_lock(&spi_plugin.threadlist_mutex); + + for (int i = 0; i < spi_plugin.num_threads; i++) { + if (spi_plugin.threads[i].fd == fd) + return &spi_plugin.threads[i]; + } + + pthread_mutex_unlock(&spi_plugin.threadlist_mutex); + return NULL; +} + +int spidevp_new_thread(const int fd, struct spidevp_thread **thread_out) { + struct spidevp_thread *thread; + int ok; + + pthread_mutex_lock(&spi_plugin.threadlist_mutex); + + thread = &spi_plugin.threads[spi_plugin.num_threads++]; + thread->fd = fd; + + pthread_mutex_unlock(&spi_plugin.threadlist_mutex); + + ok = pthread_create(NULL, NULL, spidevp_run_spi_thread, thread); + if (ok == -1) return errno; + + *thread_out = thread; + + return 0; +} + +int spidevp_assign_task(const int fd, const struct spidevp_task *const task) { + struct spidevp_thread *thread; + int ok; + + thread = spidevp_get_thread(fd); + if (!thread) { + return EBADF; + } + + ok = pthread_mutex_trylock(&thread->mutex); + if (ok == -1) { + return errno; + } else if (ok == 0) { + thread->task = *task; + thread->has_task = true; + pthread_mutex_unlock(&thread->mutex); + pthread_cond_signal(&thread->task_added); + return 0; + } +} + +int spidevp_open(struct platch_obj *object, FlutterPlatformMessageResponseHandle *responsehandle) { + struct spidevp_thread *thread; + char *path; + int fd, ok; + + if (object->std_arg.type == kStdString) { + path = object->std_arg.string_value; + } else { + return platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg` to be a string." + ); + } + + fd = open(path, O_RDWR); + if (fd == -1) { + return platch_respond_native_error_std(responsehandle, errno); + } + + ok = spidevp_new_thread(fd, &thread); + if (ok != 0) { + return platch_respond_native_error_std(responsehandle, ok); + } + + return platch_respond_success_std(responsehandle, NULL); +} + +int spidevp_onReceive(char *channel, struct platch_obj *object, FlutterPlatformMessageResponseHandle *responsehandle) { + struct std_value *temp; + struct spidevp_thread *thread; + struct spidevp_task task; + bool has_task = false; + int ok, fd; + + if STREQ("open", object->method) { + return spidevp_open(object, responsehandle); + } else if STREQ("setMode", object->method) { + if (STDVALUE_IS_SIZED_LIST(object->std_arg, 2) && STDVALUE_IS_INT(object->std_arg.list[0]) + && STDVALUE_IS_INT(object->std_arg.list[1])) { + fd = STDVALUE_AS_INT(object->std_arg.list[0]); + task.mode = STDVALUE_AS_INT(object->std_arg.list[1]); + } else { + return platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg` to be a List with size 2." + ); + } + + task.type = kSpiTaskWrMode; + has_task = true; + } else if STREQ("getMode", object->method) { + if (STDVALUE_IS_INT(object->std_arg)) { + fd = STDVALUE_AS_INT(object->std_arg); + } else { + return platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg` to be an integer." + ); + } + + task.type = kSpiTaskRdMode; + has_task = true; + } else if STREQ("setMaxSpeed", object->method) { + if (STDVALUE_IS_SIZED_LIST(object->std_arg, 2) && STDVALUE_IS_INT(object->std_arg.list[0]) + && STDVALUE_IS_INT(object->std_arg.list[1])) { + fd = STDVALUE_AS_INT(object->std_arg.list[0]); + task.speed = STDVALUE_AS_INT(object->std_arg.list[1]); + } else { + return platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg` to be a List with size 2." + ); + } + + task.type = kSpiTaskWrMaxSpeedHz; + has_task = true; + } else if STREQ("getMaxSpeed", object->method) { + if (STDVALUE_IS_INT(object->std_arg)) { + fd = STDVALUE_AS_INT(object->std_arg); + } else { + return platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg` to be an integer." + ); + } + + task.type = kSpiTaskRdMaxSpeedHz; + has_task = true; + } else if STREQ("setWordSize", object->method) { + if (STDVALUE_IS_SIZED_LIST(object->std_arg, 2) && STDVALUE_IS_INT(object->std_arg.list[0]) + && STDVALUE_IS_INT(object->std_arg.list[1])) { + fd = STDVALUE_AS_INT(object->std_arg.list[0]); + task.bits = STDVALUE_AS_INT(object->std_arg.list[1]); + } else { + return platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg` to be a List with size 2." + ); + } + + task.type = kSpiTaskWrBitsPerWord; + has_task = true; + } else if STREQ("getWordSize", object->method) { + if (STDVALUE_IS_INT(object->std_arg)) { + fd = STDVALUE_AS_INT(object->std_arg); + } else { + return platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg` to be an integer." + ); + } + + task.type = kSpiTaskRdBitsPerWord; + has_task = true; + } else if STREQ("transmit", object->method) { + if (object->std_arg.type == kStdMap) { + temp = stdmap_get_str(&object->std_arg, "fd"); + if (temp && STDVALUE_IS_INT(*temp)) { + fd = STDVALUE_AS_INT(*temp); + } else { + return platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg['fd']` to be an integer." + ); + } + + temp = stdmap_get_str(&object->std_arg, "speed"); + if (temp && STDVALUE_IS_INT(*temp)) { + task.transfer.speed_hz = STDVALUE_AS_INT(*temp); + } else { + return platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg['speed']` to be an integer." + ); + } + + temp = stdmap_get_str(&object->std_arg, "delay"); + if (temp && STDVALUE_IS_INT(*temp)) { + task.transfer.delay_usecs = STDVALUE_AS_INT(*temp); + } else { + return platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg['delay']` to be an integer." + ); + } + + temp = stdmap_get_str(&object->std_arg, "wordSize"); + if (temp && STDVALUE_IS_INT(*temp)) { + task.transfer.bits_per_word = STDVALUE_AS_INT(*temp); + } else { + return platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg['wordSize']` to be an integer." + ); + } + + temp = stdmap_get_str(&object->std_arg, "csChange"); + if (temp && STDVALUE_IS_BOOL(*temp)) { + task.transfer.cs_change = STDVALUE_AS_BOOL(*temp); + } else { + return platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg['csChange']` to be an integer." + ); + } + + temp = stdmap_get_str(&object->std_arg, "buffer"); + if (temp && temp->type == kStdUInt8Array) { + task.transfer.len = temp->size; + + void *buf = malloc(temp->size); + + task.transfer.tx_buf = (__u64) ((uintptr_t) buf); + task.transfer.rx_buf = task.transfer.tx_buf; + + memcpy(buf, temp->uint8array, temp->size); + } else { + return platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg['buffer']` to be a uint8 array." + ); + } + } + + task.type = kSpiTaskTransmit; + has_task = true; + } else if STREQ("close", object->method) { + task.type = kSpiTaskClose; + has_task = true; + } + + if (has_task) { + ok = spidevp_assign_task(fd, &task); + if (ok == 0) { + return 0; + } else if (ok == EBUSY) { + return platch_respond_error_std( + responsehandle, + "busy", + "a different task is running on the fd already", + NULL + ); + } else { + return platch_respond_native_error_std(responsehandle, ok); + } + } + + return platch_respond_not_implemented(responsehandle); +} + +int spidevp_init(void) { + printf("[flutter_spidev] Initializing...\n"); + + spi_plugin.size_threads = 1; + spi_plugin.threads = calloc(spi_plugin.size_threads, sizeof(struct spidevp_thread)); + + for (int i = 0; i < spi_plugin.size_threads; i++) + spi_plugin.threads[i] = SPI_THREAD_INITIALIZER; + + plugin_registry_set_receiver(SPI_PLUGIN_METHOD_CHANNEL, kStandardMethodCall, spidevp_onReceive); + + printf("[flutter_spidev] Done.\n"); + return 0; +} + +int spidevp_deinit(void) { + printf("[flutter_spidev] deinit.\n"); + return 0; +} \ No newline at end of file diff --git a/src/plugins/testplugin.c b/src/plugins/testplugin.c index 4eb91c97..42a12cd1 100644 --- a/src/plugins/testplugin.c +++ b/src/plugins/testplugin.c @@ -1,30 +1,31 @@ #include #include +#include #include #include -#include "testplugin.h" +#include #define INDENT_STRING " " -int __printJSON(struct JSONMsgCodecValue *value, int indent) { +int __printJSON(struct json_value *value, int indent) { switch (value->type) { - case kJSNull: + case kJsonNull: printf("null"); break; - case kJSTrue: + case kJsonTrue: printf("true"); break; - case kJSFalse: + case kJsonFalse: printf("false"); break; - case kJSNumber: + case kJsonNumber: printf("%f", value->number_value); break; - case kJSString: + case kJsonString: printf("\"%s\"", value->string_value); break; - case kJSArray: + case kJsonArray: printf("[\n"); for (int i = 0; i < value->size; i++) { printf("%.*s", indent + 2, INDENT_STRING); @@ -33,7 +34,7 @@ int __printJSON(struct JSONMsgCodecValue *value, int indent) { } printf("\n%.*s]", indent, INDENT_STRING); break; - case kJSObject: + case kJsonObject: printf("{\n"); for (int i = 0; i < value->size; i++) { printf("%.*s\"%s\": ", indent + 2, INDENT_STRING, value->keys[i]); @@ -47,36 +48,36 @@ int __printJSON(struct JSONMsgCodecValue *value, int indent) { return 0; } -int printJSON(struct JSONMsgCodecValue *value, int indent) { +int printJSON(struct json_value *value, int indent) { printf("%.*s", indent, INDENT_STRING); __printJSON(value, indent); printf("\n"); } -int __printStd(struct StdMsgCodecValue *value, int indent) { +int __printStd(struct std_value *value, int indent) { switch (value->type) { - case kNull: + case kStdNull: printf("null"); break; - case kTrue: + case kStdTrue: printf("true"); break; - case kFalse: + case kStdFalse: printf("false"); break; - case kInt32: + case kStdInt32: printf("%" PRIi32, value->int32_value); break; - case kInt64: + case kStdInt64: printf("%" PRIi64, value->int64_value); break; - case kFloat64: + case kStdFloat64: printf("%lf", value->float64_value); break; - case kString: - case kLargeInt: + case kStdString: + case kStdLargeInt: printf("\"%s\"", value->string_value); break; - case kUInt8Array: + case kStdUInt8Array: printf("(uint8_t) ["); for (int i = 0; i < value->size; i++) { printf("0x%02X", value->uint8array[i]); @@ -84,7 +85,7 @@ int __printStd(struct StdMsgCodecValue *value, int indent) { } printf("]"); break; - case kInt32Array: + case kStdInt32Array: printf("(int32_t) ["); for (int i = 0; i < value->size; i++) { printf("%" PRIi32, value->int32array[i]); @@ -92,7 +93,7 @@ int __printStd(struct StdMsgCodecValue *value, int indent) { } printf("]"); break; - case kInt64Array: + case kStdInt64Array: printf("(int64_t) ["); for (int i = 0; i < value->size; i++) { printf("%" PRIi64, value->int64array[i]); @@ -100,7 +101,7 @@ int __printStd(struct StdMsgCodecValue *value, int indent) { } printf("]"); break; - case kFloat64Array: + case kStdFloat64Array: printf("(double) ["); for (int i = 0; i < value->size; i++) { printf("%ld", value->float64array[i]); @@ -108,7 +109,7 @@ int __printStd(struct StdMsgCodecValue *value, int indent) { } printf("]"); break; - case kList: + case kStdList: printf("[\n"); for (int i = 0; i < value->size; i++) { printf("%.*s", indent + 2, INDENT_STRING); @@ -117,7 +118,7 @@ int __printStd(struct StdMsgCodecValue *value, int indent) { } printf("\n%.*s]", indent, INDENT_STRING); break; - case kMap: + case kStdMap: printf("{\n"); for (int i = 0; i < value->size; i++) { printf("%.*s", indent + 2, INDENT_STRING); @@ -132,7 +133,7 @@ int __printStd(struct StdMsgCodecValue *value, int indent) { break; } } -int printStd(struct StdMsgCodecValue *value, int indent) { +int printStd(struct std_value *value, int indent) { printf("%.*s", indent, INDENT_STRING); __printStd(value, indent); printf("\n"); @@ -142,7 +143,7 @@ int printStd(struct StdMsgCodecValue *value, int indent) { uint64_t testplugin_time_offset; -int TestPlugin_onReceiveResponseJSON(struct ChannelObject *object, void *userdata) { +int testp_on_response_json(struct platch_obj *object, void *userdata) { uint64_t dt = FlutterEngineGetCurrentTime() - *((uint64_t*) userdata); free(userdata); @@ -152,28 +153,28 @@ int TestPlugin_onReceiveResponseJSON(struct ChannelObject *object, void *userdat } if (object->success) { - printf("TestPlugin_onReceiveResponseJSON(dt: %lluns)\n" + printf("testp_on_response_json(dt: %lluns)\n" " success\n" " result:\n", dt); - printJSON(&object->jsresult, 4); + printJSON(&object->json_result, 4); } else { - printf("TestPlugin_onReceiveResponseJSON(dt: %lluns)\n", dt); + printf("testp_on_response_json(dt: %lluns)\n", dt); printf(" failure\n" " error code: %s\n" " error message: %s\n" - " error details:\n", object->errorcode, (object->errormessage != NULL) ? object->errormessage : "null"); - printJSON(&object->jsresult, 4); + " error details:\n", object->error_code, (object->error_msg != NULL) ? object->error_msg : "null"); + printJSON(&object->json_result, 4); } return 0; } -int TestPlugin_sendJSON() { +int testp_send_json() { uint64_t* time = malloc(sizeof(uint64_t)); *time = FlutterEngineGetCurrentTime(); char *method = "test"; - struct JSONMsgCodecValue argument = { - .type = kJSObject, + struct json_value argument = { + .type = kJsonObject, .size = 5, .keys = (char*[]) { "key1", @@ -182,24 +183,24 @@ int TestPlugin_sendJSON() { "key4", "array" }, - .values = (struct JSONMsgCodecValue[]) { - {.type = kJSString, .string_value = "value1"}, - {.type = kJSTrue}, - {.type = kJSNumber, .number_value = -1000}, - {.type = kJSNumber, .number_value = -5.0005}, - {.type = kJSArray, .size = 2, .array = (struct JSONMsgCodecValue[]) { - {.type = kJSString, .string_value = "array1"}, - {.type = kJSNumber, .number_value = 2} + .values = (struct json_value[]) { + {.type = kJsonString, .string_value = "value1"}, + {.type = kJsonTrue}, + {.type = kJsonNumber, .number_value = -1000}, + {.type = kJsonNumber, .number_value = -5.0005}, + {.type = kJsonArray, .size = 2, .array = (struct json_value[]) { + {.type = kJsonString, .string_value = "array1"}, + {.type = kJsonNumber, .number_value = 2} }} }, }; - int ok = PlatformChannel_jsoncall(TESTPLUGIN_CHANNEL_JSON, method, &argument, TestPlugin_onReceiveResponseJSON, time); + int ok = platch_call_json(TESTPLUGIN_CHANNEL_JSON, method, &argument, testp_on_response_json, time); if (ok != 0) { printf("Could not MethodCall JSON: %s\n", strerror(ok)); } } -int TestPlugin_onReceiveResponseStd(struct ChannelObject *object, void *userdata) { +int testp_on_response_std(struct platch_obj *object, void *userdata) { uint64_t dt = FlutterEngineGetCurrentTime() - *((uint64_t*) userdata); free(userdata); @@ -209,96 +210,96 @@ int TestPlugin_onReceiveResponseStd(struct ChannelObject *object, void *userdata } if (object->success) { - printf("TestPlugin_onReceiveResponseStd(dt: %lluns)\n" + printf("testp_on_response_std(dt: %lluns)\n" " success\n" " result:\n", dt); - printStd(&object->stdresult, 4); + printStd(&object->std_result, 4); } else { - printf("TestPlugin_onReceiveResponseStd(dt: %lluns)\n", dt); + printf("testp_on_response_std(dt: %lluns)\n", dt); printf(" failure\n" " error code: %s\n" " error message: %s\n" - " error details:\n", object->errorcode, (object->errormessage != NULL) ? object->errormessage : "null"); - printStd(&object->stdresult, 4); + " error details:\n", object->error_code, (object->error_msg != NULL) ? object->error_msg : "null"); + printStd(&object->std_error_details, 4); } return 0; } -int TestPlugin_sendStd() { +int testp_send_std() { uint64_t *time = malloc(sizeof(uint64_t)); *time = FlutterEngineGetCurrentTime(); char *method = "test"; - struct StdMsgCodecValue argument = { - .type = kMap, + struct std_value argument = { + .type = kStdMap, .size = 7, - .keys = (struct StdMsgCodecValue[]) { - {.type = kString, .string_value = "key1"}, - {.type = kString, .string_value = "key2"}, - {.type = kString, .string_value = "key3"}, - {.type = kString, .string_value = "key4"}, - {.type = kInt32, .int32_value = 5}, - {.type = kString, .string_value = "timestamp"}, - {.type = kString, .string_value = "array"} + .keys = (struct std_value[]) { + {.type = kStdString, .string_value = "key1"}, + {.type = kStdString, .string_value = "key2"}, + {.type = kStdString, .string_value = "key3"}, + {.type = kStdString, .string_value = "key4"}, + {.type = kStdInt32, .int32_value = 5}, + {.type = kStdString, .string_value = "timestamp"}, + {.type = kStdString, .string_value = "array"} }, - .values = (struct StdMsgCodecValue[]) { - {.type = kString, .string_value = "value1"}, - {.type = kTrue}, - {.type = kInt32, .int32_value = -1000}, - {.type = kFloat64, .float64_value = -5.0005}, - {.type = kUInt8Array, .uint8array = (uint8_t[]) {0x00, 0x01, 0x02, 0x03, 0xFF}, .size = 5}, - {.type = kInt64, .int64_value = *time & 0x7FFFFFFFFFFFFFFF}, - {.type = kList, .size = 2, .list = (struct StdMsgCodecValue[]) { - {.type = kString, .string_value = "array1"}, - {.type = kInt32, .int32_value = 2} + .values = (struct std_value[]) { + {.type = kStdString, .string_value = "value1"}, + {.type = kStdTrue}, + {.type = kStdInt32, .int32_value = -1000}, + {.type = kStdFloat64, .float64_value = -5.0005}, + {.type = kStdUInt8Array, .uint8array = (uint8_t[]) {0x00, 0x01, 0x02, 0x03, 0xFF}, .size = 5}, + {.type = kStdInt64, .int64_value = *time & 0x7FFFFFFFFFFFFFFF}, + {.type = kStdList, .size = 2, .list = (struct std_value[]) { + {.type = kStdString, .string_value = "array1"}, + {.type = kStdInt32, .int32_value = 2} }} }, }; - PlatformChannel_stdcall(TESTPLUGIN_CHANNEL_STD, method, &argument, TestPlugin_onReceiveResponseStd, time); + platch_call_std(TESTPLUGIN_CHANNEL_STD, method, &argument, testp_on_response_std, time); } -int TestPlugin_onReceiveJSON(char *channel, struct ChannelObject *object, FlutterPlatformMessageResponseHandle *responsehandle) { - printf("TestPlugin_onReceiveJSON(channel: %s)\n" +int testp_on_receive_json(char *channel, struct platch_obj *object, FlutterPlatformMessageResponseHandle *responsehandle) { + printf("testp_on_receive_json(channel: %s)\n" " method: %s\n" " args: \n", channel, object->method); - printJSON(&(object->jsarg), 4); + printJSON(&(object->json_arg), 4); - TestPlugin_sendJSON(); + testp_send_json(); - return PlatformChannel_respond(responsehandle, &(struct ChannelObject) { + return platch_respond(responsehandle, &(struct platch_obj) { .codec = kJSONMethodCallResponse, .success = true, - .jsresult = { - .type = kJSTrue + .json_result = { + .type = kJsonTrue } }); } -int TestPlugin_onReceiveStd(char *channel, struct ChannelObject *object, FlutterPlatformMessageResponseHandle *responsehandle) { +int testp_on_receive_std(char *channel, struct platch_obj *object, FlutterPlatformMessageResponseHandle *responsehandle) { printf("TestPlugin_onReceiveStd(channel: %s)\n" " method: %s\n" " args: \n", channel, object->method); - printStd(&(object->stdarg), 4); + printStd(&(object->std_arg), 4); - TestPlugin_sendStd(); + testp_send_std(); - return PlatformChannel_respond( + return platch_respond( responsehandle, - &(struct ChannelObject) { + &(struct platch_obj) { .codec = kStandardMethodCallResponse, .success = true, - .stdresult = { - .type = kTrue + .std_result = { + .type = kStdTrue } } ); } -int TestPlugin_onReceivePing(char *channel, struct ChannelObject *object, FlutterPlatformMessageResponseHandle *responsehandle) { - return PlatformChannel_respond( +int testp_on_receive_ping(char *channel, struct platch_obj *object, FlutterPlatformMessageResponseHandle *responsehandle) { + return platch_respond( responsehandle, - &(struct ChannelObject) { + &(struct platch_obj) { .codec = kStringCodec, .string_value = "pong" } @@ -306,14 +307,24 @@ int TestPlugin_onReceivePing(char *channel, struct ChannelObject *object, Flutte } -int TestPlugin_init(void) { - printf("[test-plugin] init.\n"); - PluginRegistry_setReceiver(TESTPLUGIN_CHANNEL_JSON, kJSONMethodCall, TestPlugin_onReceiveJSON); - PluginRegistry_setReceiver(TESTPLUGIN_CHANNEL_STD, kStandardMethodCall, TestPlugin_onReceiveStd); - PluginRegistry_setReceiver(TESTPLUGIN_CHANNEL_PING, kStringCodec, TestPlugin_onReceivePing); +int testp_init(void) { + int ok; + + printf("[test_plugin] Initializing...\n"); + + ok = plugin_registry_set_receiver(TESTPLUGIN_CHANNEL_JSON, kJSONMethodCall, testp_on_receive_json); + if (ok != 0) return ok; + + ok = plugin_registry_set_receiver(TESTPLUGIN_CHANNEL_STD, kStandardMethodCall, testp_on_receive_std); + if (ok != 0) return ok; + + ok = plugin_registry_set_receiver(TESTPLUGIN_CHANNEL_PING, kStringCodec, testp_on_receive_ping); + if (ok != 0) return ok; + + printf("[test_plugin] Done.\n"); return 0; } -int TestPlugin_deinit(void) { - printf("[test-plugin] deinit.\n"); +int testp_deinit(void) { + printf("[test_plugin] deinit.\n"); return 0; } \ No newline at end of file diff --git a/src/plugins/text_input.c b/src/plugins/text_input.c index ac6ff83c..f0b96e55 100644 --- a/src/plugins/text_input.c +++ b/src/plugins/text_input.c @@ -6,7 +6,7 @@ #include #include -#include "text_input.h" +#include struct { int32_t transaction_id; @@ -23,12 +23,10 @@ struct { .transaction_id = -1 }; -int TextInput_onReceive(char *channel, struct ChannelObject *object, FlutterPlatformMessageResponseHandle *responsehandle) { - struct JSONMsgCodecValue jsvalue, *temp, *temp2, *state, *config; +int textin_on_receive(char *channel, struct platch_obj *object, FlutterPlatformMessageResponseHandle *responsehandle) { + struct json_value jsvalue, *temp, *temp2, *state, *config; int ok; - printf("[text_input] got method call: %s\n", object->method); - if STREQ("TextInput.setClient", object->method) { /* * TextInput.setClient(List) @@ -40,45 +38,33 @@ int TextInput_onReceive(char *channel, struct ChannelObject *object, FlutterPlat * others (except `TextInput.hide`). See [TextInput.attach]. */ - if ((object->jsarg.type != kJSArray) || (object->jsarg.size != 2)) { - return PlatformChannel_respondError( + if ((object->json_arg.type != kJsonArray) || (object->json_arg.size != 2)) { + return platch_respond_illegal_arg_json( responsehandle, - kJSONMethodCallResponse, - "illegalargument", - "Expected JSON Array with length 2 as the argument.", - NULL + "Expected `arg` to be an array with length 2." ); } - if (object->jsarg.array[0].type != kJSNumber) { - return PlatformChannel_respondError( + if (object->json_arg.array[0].type != kJsonNumber) { + return platch_respond_illegal_arg_json( responsehandle, - kJSONMethodCallResponse, - "illegalargument", - "Expected transaction id to be a number.", - NULL + "Expected transaction id to be a number." ); } - if (object->jsarg.array[1].type != kJSObject) { - return PlatformChannel_respondError( + if (object->json_arg.array[1].type != kJsonObject) { + return platch_respond_illegal_arg_json( responsehandle, - kJSONMethodCallResponse, - "illegalargument", - "Expected text input configuration to be a String", - NULL + "Expected text input configuration to be a String" ); } - struct JSONMsgCodecValue *config = &object->jsarg.array[1]; + struct json_value *config = &object->json_arg.array[1]; - if (config->type != kJSObject) { - return PlatformChannel_respondError( + if (config->type != kJsonObject) { + return platch_respond_illegal_arg_json( responsehandle, - kJSONMethodCallResponse, - "illegalargument", - "Expected decoded text input configuration to be an Object", - NULL + "Expected decoded text input configuration to be an Object" ); } @@ -88,14 +74,14 @@ int TextInput_onReceive(char *channel, struct ChannelObject *object, FlutterPlat // AUTOCORRECT temp = jsobject_get(config, "autocorrect"); - if (!(temp && ((temp->type == kJSTrue) || (temp->type == kJSFalse)))) + if (!(temp && ((temp->type == kJsonTrue) || (temp->type == kJsonFalse)))) goto invalid_config; - autocorrect = temp->type == kJSTrue; + autocorrect = temp->type == kJsonTrue; // INPUT ACTION temp = jsobject_get(config, "inputAction"); - if (!(temp && (temp->type == kJSString))) + if (!(temp && (temp->type == kJsonString))) goto invalid_config; if STREQ("TextInputAction.none", temp->string_value) @@ -131,13 +117,13 @@ int TextInput_onReceive(char *channel, struct ChannelObject *object, FlutterPlat // INPUT TYPE temp = jsobject_get(config, "inputType"); - if (!temp || temp->type != kJSObject) + if (!temp || temp->type != kJsonObject) goto invalid_config; temp2 = jsobject_get(temp, "name"); - if (!temp2 || temp2->type != kJSString) + if (!temp2 || temp2->type != kJsonString) goto invalid_config; if STREQ("TextInputType.text", temp2->string_value) { @@ -161,7 +147,7 @@ int TextInput_onReceive(char *channel, struct ChannelObject *object, FlutterPlat } // TRANSACTION ID - int32_t new_id = (int32_t) object->jsarg.array[0].number_value; + int32_t new_id = (int32_t) object->json_arg.array[0].number_value; // everything okay, apply the new text editing config text_input.transaction_id = new_id; @@ -175,24 +161,21 @@ int TextInput_onReceive(char *channel, struct ChannelObject *object, FlutterPlat text_input.warned_about_autocorrect = true; } - return PlatformChannel_respond( + return platch_respond( responsehandle, - &(struct ChannelObject) { + &(struct platch_obj) { .codec = kJSONMethodCallResponse, .success = true, - .jsresult = {.type = kJSNull} + .json_result = {.type = kJsonNull} } ); // invalid config given to setClient invalid_config: - return PlatformChannel_respondError( + return platch_respond_illegal_arg_json( responsehandle, - kJSONMethodCallResponse, - "illegalargument", "Expected decoded text input configuration to at least contain values for \"autocorrect\"" - " and \"inputAction\"", - NULL + " and \"inputAction\"" ); } else if STREQ("TextInput.show", object->method) { @@ -203,12 +186,12 @@ int TextInput_onReceive(char *channel, struct ChannelObject *object, FlutterPlat */ // do nothing since we use a physical keyboard. - return PlatformChannel_respond( + return platch_respond( responsehandle, - &(struct ChannelObject) { + &(struct platch_obj) { .codec = kJSONMethodCallResponse, .success = true, - .jsresult = {.type = kJSNull} + .json_result = {.type = kJsonNull} } ); } else if STREQ("TextInput.setEditingState", object->method) { @@ -221,15 +204,12 @@ int TextInput_onReceive(char *channel, struct ChannelObject *object, FlutterPlat * */ - state = &object->jsarg; + state = &object->json_arg; - if (state->type != kJSObject) { - return PlatformChannel_respondError( + if (state->type != kJsonObject) { + return platch_respond_illegal_arg_json( responsehandle, - kJSONMethodCallResponse, - "illegalargument", - "Expected decoded text editing value to be an Object", - NULL + "Expected decoded text editing value to be an Object" ); } @@ -238,19 +218,19 @@ int TextInput_onReceive(char *channel, struct ChannelObject *object, FlutterPlat bool selection_affinity_is_downstream, selection_is_directional; temp = jsobject_get(state, "text"); - if (temp && (temp->type == kJSString)) text = temp->string_value; + if (temp && (temp->type == kJsonString)) text = temp->string_value; else goto invalid_editing_value; temp = jsobject_get(state, "selectionBase"); - if (temp && (temp->type == kJSNumber)) selection_base = (int) temp->number_value; + if (temp && (temp->type == kJsonNumber)) selection_base = (int) temp->number_value; else goto invalid_editing_value; temp = jsobject_get(state, "selectionExtent"); - if (temp && (temp->type == kJSNumber)) selection_extent = (int) temp->number_value; + if (temp && (temp->type == kJsonNumber)) selection_extent = (int) temp->number_value; else goto invalid_editing_value; temp = jsobject_get(state, "selectionAffinity"); - if (temp && (temp->type == kJSString)) { + if (temp && (temp->type == kJsonString)) { if STREQ("TextAffinity.downstream", temp->string_value) { selection_affinity_is_downstream = true; } else if STREQ("TextAffinity.upstream", temp->string_value) { @@ -263,32 +243,21 @@ int TextInput_onReceive(char *channel, struct ChannelObject *object, FlutterPlat } temp = jsobject_get(state, "selectionIsDirectional"); - if (temp && (temp->type == kJSTrue || temp->type == kJSFalse)) { - selection_is_directional = temp->type == kJSTrue; + if (temp && (temp->type == kJsonTrue || temp->type == kJsonFalse)) { + selection_is_directional = temp->type == kJsonTrue; } else { goto invalid_editing_value; } temp = jsobject_get(state, "composingBase"); - if (temp && (temp->type == kJSNumber)) composing_base = (int) temp->number_value; + if (temp && (temp->type == kJsonNumber)) composing_base = (int) temp->number_value; else goto invalid_editing_value; temp = jsobject_get(state, "composingExtent"); - if (temp && (temp->type == kJSNumber)) composing_extent = (int) temp->number_value; + if (temp && (temp->type == kJsonNumber)) composing_extent = (int) temp->number_value; else goto invalid_editing_value; - // text editing value seems to be valid. - // apply it. - printf("[text_input] TextInput.setEditingState\n" - " text = \"%s\",\n" - " selectionBase = %i, selectionExtent = %i, selectionAffinity = %s\n" - " selectionIsDirectional = %s, composingBase = %i, composingExtent = %i\n", - text, selection_base, selection_extent, - selection_affinity_is_downstream? "downstream" : "upstream", - selection_is_directional? "true" : "false", composing_base, composing_extent - ); - snprintf(text_input.text, sizeof(text_input.text), "%s", text); text_input.selection_base = selection_base; text_input.selection_extent = selection_extent; @@ -297,23 +266,20 @@ int TextInput_onReceive(char *channel, struct ChannelObject *object, FlutterPlat text_input.composing_base = composing_base; text_input.composing_extent = composing_extent; - return PlatformChannel_respond( + return platch_respond( responsehandle, - &(struct ChannelObject) { + &(struct platch_obj) { .codec = kJSONMethodCallResponse, .success = true, - .jsresult = {.type = kJSNull} + .json_result = {.type = kJsonNull} } ); invalid_editing_value: - return PlatformChannel_respondError( + return platch_respond_illegal_arg_json( responsehandle, - kJSONMethodCallResponse, - "illegalargument", "Expected decoded text editing value to be a valid" - " JSON representation of a text editing value", - NULL + " JSON representation of a text editing value" ); } else if STREQ("TextInput.clearClient", object->method) { @@ -327,12 +293,12 @@ int TextInput_onReceive(char *channel, struct ChannelObject *object, FlutterPlat text_input.transaction_id = -1; - return PlatformChannel_respond( + return platch_respond( responsehandle, - &(struct ChannelObject) { + &(struct platch_obj) { .codec = kJSONMethodCallResponse, .success = true, - .jsresult = {.type = kJSNull} + .json_result = {.type = kJsonNull} } ); } else if STREQ("TextInput.hide", object->method) { @@ -344,57 +310,48 @@ int TextInput_onReceive(char *channel, struct ChannelObject *object, FlutterPlat */ // do nothing since we use a physical keyboard. - return PlatformChannel_respond( + return platch_respond( responsehandle, - &(struct ChannelObject) { + &(struct platch_obj) { .codec = kJSONMethodCallResponse, .success = true, - .jsresult = {.type = kJSNull} + .json_result = {.type = kJsonNull} } ); } - return PlatformChannel_respondNotImplemented(responsehandle); + return platch_respond_not_implemented(responsehandle); } -int TextInput_syncEditingState() { - printf("[text_input] TextInputClient.updateEditingState\n" - " text = \"%s\",\n" - " selectionBase = %i, selectionExtent = %i, selectionAffinity = %s\n" - " selectionIsDirectional = %s, composingBase = %i, composingExtent = %i\n", - text_input.text, text_input.selection_base, text_input.selection_extent, - text_input.selection_affinity_is_downstream? "downstream" : "upstream", - text_input.selection_is_directional? "true" : "false", text_input.composing_base, text_input.composing_extent - ); - - return PlatformChannel_send( +int textin_sync_editing_state() { + return platch_send( TEXT_INPUT_CHANNEL, - &(struct ChannelObject) { + &(struct platch_obj) { .codec = kJSONMethodCall, .method = "TextInputClient.updateEditingState", - .jsarg = { - .type = kJSArray, + .json_arg = { + .type = kJsonArray, .size = 2, - .array = (struct JSONMsgCodecValue[2]) { - {.type = kJSNumber, .number_value = text_input.transaction_id}, - {.type = kJSObject, .size = 7, + .array = (struct json_value[2]) { + {.type = kJsonNumber, .number_value = text_input.transaction_id}, + {.type = kJsonObject, .size = 7, .keys = (char*[7]) { "text", "selectionBase", "selectionExtent", "selectionAffinity", "selectionIsDirectional", "composingBase", "composingExtent" }, - .values = (struct JSONMsgCodecValue[7]) { - {.type = kJSString, .string_value = text_input.text}, - {.type = kJSNumber, .number_value = text_input.selection_base}, - {.type = kJSNumber, .number_value = text_input.selection_extent}, + .values = (struct json_value[7]) { + {.type = kJsonString, .string_value = text_input.text}, + {.type = kJsonNumber, .number_value = text_input.selection_base}, + {.type = kJsonNumber, .number_value = text_input.selection_extent}, { - .type = kJSString, + .type = kJsonString, .string_value = text_input.selection_affinity_is_downstream ? "TextAffinity.downstream" : "TextAffinity.upstream" }, - {.type = text_input.selection_is_directional? kJSTrue : kJSFalse}, - {.type = kJSNumber, .number_value = text_input.composing_base}, - {.type = kJSNumber, .number_value = text_input.composing_extent} + {.type = text_input.selection_is_directional? kJsonTrue : kJsonFalse}, + {.type = kJsonNumber, .number_value = text_input.composing_base}, + {.type = kJsonNumber, .number_value = text_input.composing_extent} } } } @@ -406,7 +363,7 @@ int TextInput_syncEditingState() { ); } -int TextInput_performAction(enum text_input_action action) { +int textin_perform_action(enum text_input_action action) { char *action_str = (action == kTextInputActionNone) ? "TextInputAction.none" : @@ -423,17 +380,17 @@ int TextInput_performAction(enum text_input_action action) { (action == kTextInputActionEmergencyCall) ? "TextInputAction.emergencyCall" : "TextInputAction.newline"; - return PlatformChannel_send( + return platch_send( TEXT_INPUT_CHANNEL, - &(struct ChannelObject) { + &(struct platch_obj) { .codec = kJSONMethodCall, .method = "TextInputClient.performAction", - .jsarg = { - .type = kJSArray, + .json_arg = { + .type = kJsonArray, .size = 2, - .array = (struct JSONMsgCodecValue[2]) { - {.type = kJSNumber, .number_value = text_input.transaction_id}, - {.type = kJSString, .string_value = action_str} + .array = (struct json_value[2]) { + {.type = kJsonNumber, .number_value = text_input.transaction_id}, + {.type = kJsonString, .string_value = action_str} } } }, @@ -441,15 +398,15 @@ int TextInput_performAction(enum text_input_action action) { ); } -int TextInput_onConnectionClosed(void) { +int textin_on_connection_closed(void) { text_input.transaction_id = -1; - return PlatformChannel_send( + return platch_send( TEXT_INPUT_CHANNEL, - &(struct ChannelObject) { + &(struct platch_obj) { .codec = kJSONMethodCall, .method = "TextInputClient.onConnectionClosed", - .jsarg = {.type = kJSNull} + .json_arg = {.type = kJsonNull} }, kBinaryCodec, NULL, NULL ); @@ -468,7 +425,7 @@ inline int to_byte_index(unsigned int symbol_index) { } // start and end index are both inclusive. -int TextInput_erase(unsigned int start, unsigned int end) { +int textin_erase(unsigned int start, unsigned int end) { // 0 <= start <= end < len char *start_str = utf8_symbol_at(text_input.text, start); @@ -479,18 +436,18 @@ int TextInput_erase(unsigned int start, unsigned int end) { return start; } -bool TextInput_deleteSelected(void) { +bool textin_delete_selected(void) { // erase selected text - text_input.selection_base = TextInput_erase(text_input.selection_base, text_input.selection_extent-1); + text_input.selection_base = textin_erase(text_input.selection_base, text_input.selection_extent-1); text_input.selection_extent = text_input.selection_base; return true; } -bool TextInput_addUtf8Char(char *c) { +bool textin_add_utf8_char(char *c) { size_t symbol_length; char *to_move; if (text_input.selection_base != text_input.selection_extent) - TextInput_deleteSelected(); + textin_delete_selected(); // find out where in our string we need to insert the utf8 symbol @@ -516,32 +473,32 @@ bool TextInput_addUtf8Char(char *c) { return true; } -bool TextInput_backspace(void) { +bool textin_backspace(void) { if (text_input.selection_base != text_input.selection_extent) - return TextInput_deleteSelected(); + return textin_delete_selected(); if (text_input.selection_base != 0) { int base = text_input.selection_base - 1; - text_input.selection_base = TextInput_erase(base, base); + text_input.selection_base = textin_erase(base, base); text_input.selection_extent = text_input.selection_base; return true; } return false; } -bool TextInput_delete(void) { +bool textin_delete(void) { if (text_input.selection_base != text_input.selection_extent) - return TextInput_deleteSelected(); + return textin_delete_selected(); if (text_input.selection_base < strlen(text_input.text)) { - text_input.selection_base = TextInput_erase(text_input.selection_base, text_input.selection_base); + text_input.selection_base = textin_erase(text_input.selection_base, text_input.selection_base); text_input.selection_extent = text_input.selection_base; return true; } return false; } -bool TextInput_moveCursorToBeginning(void) { +bool textin_move_cursor_to_beginning(void) { if ((text_input.selection_base != 0) || (text_input.selection_extent != 0)) { text_input.selection_base = 0; text_input.selection_extent = 0; @@ -550,7 +507,7 @@ bool TextInput_moveCursorToBeginning(void) { return false; } -bool TextInput_moveCursorToEnd(void) { +bool textin_move_cursor_to_end(void) { int end = strlen(text_input.text); if (text_input.selection_base != end) { @@ -561,7 +518,7 @@ bool TextInput_moveCursorToEnd(void) { return false; } -bool TextInput_moveCursorForward(void) { +bool textin_move_cursor_forward(void) { if (text_input.selection_base != text_input.selection_extent) { text_input.selection_base = text_input.selection_extent; return true; @@ -575,7 +532,7 @@ bool TextInput_moveCursorForward(void) { return false; } -bool TextInput_moveCursorBack(void) { +bool textin_move_cursor_back(void) { if (text_input.selection_base != text_input.selection_extent) { text_input.selection_extent = text_input.selection_base; return true; @@ -592,20 +549,20 @@ bool TextInput_moveCursorBack(void) { // these two functions automatically sync the editing state with flutter if -// a change ocurred, so you don't explicitly need to call TextInput_syncEditingState(). +// a change ocurred, so you don't explicitly need to call textin_sync_editing_state(). // `c` doesn't need to be NULL-terminated, the length of the char will be calculated // using the start byte. -int TextInput_onUtf8Char(char *c) { +int textin_on_utf8_char(char *c) { if (text_input.transaction_id == -1) return 0; - if (TextInput_addUtf8Char(c)) - return TextInput_syncEditingState(); + if (textin_add_utf8_char(c)) + return textin_sync_editing_state(); return 0; } -int TextInput_onKey(glfw_key key) { +int textin_on_key(glfw_key key) { bool needs_sync = false; bool perform_action = false; int ok; @@ -615,26 +572,26 @@ int TextInput_onKey(glfw_key key) { switch (key) { case GLFW_KEY_LEFT: - needs_sync = TextInput_moveCursorBack(); + needs_sync = textin_move_cursor_back(); break; case GLFW_KEY_RIGHT: - needs_sync = TextInput_moveCursorForward(); + needs_sync = textin_move_cursor_forward(); break; case GLFW_KEY_END: - needs_sync = TextInput_moveCursorToEnd(); + needs_sync = textin_move_cursor_to_end(); break; case GLFW_KEY_HOME: - needs_sync = TextInput_moveCursorToBeginning(); + needs_sync = textin_move_cursor_to_beginning(); break; case GLFW_KEY_BACKSPACE: - needs_sync = TextInput_backspace(); + needs_sync = textin_backspace(); break; case GLFW_KEY_DELETE: - needs_sync = TextInput_delete(); + needs_sync = textin_delete(); break; case GLFW_KEY_ENTER: if (text_input.input_type == kInputTypeMultiline) - needs_sync = TextInput_addUtf8Char("\n"); + needs_sync = textin_add_utf8_char("\n"); perform_action = true; break; @@ -643,12 +600,12 @@ int TextInput_onKey(glfw_key key) { } if (needs_sync) { - ok = TextInput_syncEditingState(); + ok = textin_sync_editing_state(); if (ok != 0) return ok; } if (perform_action) { - ok = TextInput_performAction(text_input.input_action); + ok = textin_perform_action(text_input.input_action); if (ok != 0) return ok; } @@ -656,18 +613,23 @@ int TextInput_onKey(glfw_key key) { } -int TextInput_init(void) { +int textin_init(void) { + int ok; + + printf("[test_input] Initializing...\n"); + text_input.text[0] = '\0'; text_input.warned_about_autocorrect = false; - PluginRegistry_setReceiver(TEXT_INPUT_CHANNEL, kJSONMethodCall, TextInput_onReceive); + ok = plugin_registry_set_receiver(TEXT_INPUT_CHANNEL, kJSONMethodCall, textin_on_receive); + if (ok != 0) return ok; - printf("[text_input] init.\n"); + printf("[text_input] Done.\n"); return 0; } -int TextInput_deinit(void) { +int textin_deinit(void) { printf("[text_input] deinit.\n"); return 0; From e318f35c4682dbc033942101e401298554204b85 Mon Sep 17 00:00:00 2001 From: Hannes Winkler Date: Thu, 20 Feb 2020 16:51:28 +0100 Subject: [PATCH 5/8] change gpio signal listening to epoll fix missing include for spidev --- src/plugins/gpiod.c | 194 ++++++++++++++++++++++++------------------- src/plugins/spidev.c | 1 + 2 files changed, 109 insertions(+), 86 deletions(-) diff --git a/src/plugins/gpiod.c b/src/plugins/gpiod.c index 553606a9..f42e2e60 100644 --- a/src/plugins/gpiod.c +++ b/src/plugins/gpiod.c @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -23,8 +24,8 @@ struct { size_t n_lines; // GPIO lines that flutter is currently listening to + int epollfd; pthread_mutex_t listening_lines_mutex; - pthread_cond_t listening_line_added; struct gpiod_line_bulk listening_lines; pthread_t line_event_listener_thread; bool should_emit_events; @@ -85,26 +86,33 @@ struct line_config { }; // because libgpiod doesn't provide it, but it's useful -static inline void gpiod_line_bulk_remove(struct gpiod_line_bulk *bulk, unsigned int index) { - memmove(&bulk->lines[index], &bulk->lines[index+1], sizeof(struct gpiod_line*) * (bulk->num_lines - index - 1)); - bulk->num_lines--; +static inline void gpiod_line_bulk_remove(struct gpiod_line_bulk *bulk, struct gpiod_line *line) { + struct gpiod_line *linetemp, **cursor; + struct gpiod_line_bulk new_bulk = GPIOD_LINE_BULK_INITIALIZER; + + gpiod_line_bulk_foreach_line(bulk, linetemp, cursor) { + if (linetemp != line) + gpiod_line_bulk_add(&new_bulk, linetemp); + } + + memcpy(bulk, &new_bulk, sizeof(struct gpiod_line_bulk)); } -void *gpiodp_io_loop(void *userdata); +static void *gpiodp_io_loop(void *userdata); /// ensures the libgpiod binding and the `gpio_plugin` chips list and line map is initialized. -int gpiodp_ensure_gpiod_initialized(void) { +static int gpiodp_ensure_gpiod_initialized(void) { struct gpiod_chip_iter *chipiter; struct gpiod_line_iter *lineiter; struct gpiod_chip *chip; struct gpiod_line *line; - int ok, i, j; + int ok, i, j, fd; if (gpio_plugin.initialized) return 0; libgpiod.handle = dlopen("libgpiod.so", RTLD_LOCAL | RTLD_LAZY); if (!libgpiod.handle) { - perror("could not load libgpiod.so"); + perror("[flutter_gpiod] could not load libgpiod.so. dlopen"); return errno; } @@ -149,7 +157,7 @@ int gpiodp_ensure_gpiod_initialized(void) { // iterate through the GPIO chips chipiter = libgpiod.chip_iter_new(); if (!chipiter) { - perror("could not create GPIO chip iterator"); + perror("[flutter_gpiod] could not create GPIO chip iterator. gpiod_chip_iter_new"); return errno; } @@ -184,9 +192,14 @@ int gpiodp_ensure_gpiod_initialized(void) { libgpiod.line_iter_free(lineiter); } + fd = epoll_create1(0); + if (fd == -1) { + perror("[flutter_gpiod] Could not create line event listen epoll"); + return errno; + } + gpio_plugin.listening_lines = (struct gpiod_line_bulk) GPIOD_LINE_BULK_INITIALIZER; gpio_plugin.listening_lines_mutex = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER; - gpio_plugin.listening_line_added = (pthread_cond_t) PTHREAD_COND_INITIALIZER; gpio_plugin.line_event_listener_should_run = true; ok = pthread_create( @@ -196,7 +209,7 @@ int gpiodp_ensure_gpiod_initialized(void) { NULL ); if (ok == -1) { - perror("[gpiodp] could not create line event listener thread"); + perror("[flutter_gpiod] could not create line event listener thread"); return errno; } @@ -206,26 +219,26 @@ int gpiodp_ensure_gpiod_initialized(void) { /// Sends a platform message to `handle` saying that the libgpiod binding has failed to initialize. /// Should be called when `gpiodp_ensure_gpiod_initialized()` has failed. -int gpiodp_respond_init_failed(FlutterPlatformMessageResponseHandle *handle) { +static int gpiodp_respond_init_failed(FlutterPlatformMessageResponseHandle *handle) { return platch_respond_error_std( handle, "couldnotinit", - "gpio_plugin failed to initialize libgpiod bindings. see flutter-pi log for details.", + "flutter_gpiod failed to initialize libgpiod bindings. See flutter-pi log for details.", NULL ); } /// Sends a platform message to `handle` with error code "illegalargument" /// and error messsage "supplied line handle is not valid". -int gpiodp_respond_illegal_line_handle(FlutterPlatformMessageResponseHandle *handle) { +static int gpiodp_respond_illegal_line_handle(FlutterPlatformMessageResponseHandle *handle) { return platch_respond_illegal_arg_std(handle, "supplied line handle is not valid"); } -int gpiodp_respond_not_supported(FlutterPlatformMessageResponseHandle *handle, char *msg) { +static int gpiodp_respond_not_supported(FlutterPlatformMessageResponseHandle *handle, char *msg) { return platch_respond_error_std(handle, "notsupported", msg, NULL); } -int gpiodp_get_config(struct std_value *value, +static int gpiodp_get_config(struct std_value *value, struct line_config *conf_out, FlutterPlatformMessageResponseHandle *responsehandle) { struct std_value *temp; @@ -427,61 +440,56 @@ int gpiodp_get_config(struct std_value *value, /// on any of the lines in `gpio_plugin.listening_lines` /// and sends them on to the event channel, if someone /// is listening on it. -void *gpiodp_io_loop(void *userdata) { +static void *gpiodp_io_loop(void *userdata) { struct gpiod_line_event event; - struct gpiod_line_bulk lines, events; struct gpiod_line *line, **cursor; struct gpiod_chip *chip; - struct pollfd fds[GPIOD_LINE_BULK_MAX_LINES] = {0}; - unsigned int line_handle, offset, num_lines; - int ok; + struct epoll_event fdevents[10]; + unsigned int line_handle; + bool is_ready; + int ok, n_fdevents; while (gpio_plugin.line_event_listener_should_run) { - do { - pthread_mutex_lock(&gpio_plugin.listening_lines_mutex); - - // if we're currently not listening to any lines, wait - // for a line to listen to. - while (gpiod_line_bulk_num_lines(&gpio_plugin.listening_lines) == 0) { - pthread_cond_wait(&gpio_plugin.listening_line_added, - &gpio_plugin.listening_lines_mutex); - } - - lines = gpio_plugin.listening_lines; - events = (struct gpiod_line_bulk) GPIOD_LINE_BULK_INITIALIZER; - - // TODO: use our own polling function here. - ok = libgpiod.line_event_wait_bulk( - &gpio_plugin.listening_lines, - &(const struct timespec) {.tv_sec = 0, .tv_nsec = 100000}, - &events - ); + // epoll luckily is concurrent. Other threads can add and remove fd's from this + // epollfd while we're waiting on it. + ok = epoll_wait(gpio_plugin.epollfd, fdevents, 10, -1); + if ((ok == -1) && (errno != EINTR)) { + perror("[flutter_gpiod] error while waiting for line events, epoll"); + continue; + } else { + n_fdevents = ok; + } - pthread_mutex_unlock(&gpio_plugin.listening_lines_mutex); + pthread_mutex_lock(&gpio_plugin.listening_lines_mutex); - - } while (gpiod_line_bulk_num_lines(&events) == 0); + // Go through all the lines were listening to right now and find out, + // check for each line whether an event ocurred on the line's fd. + // If that's the case, read the events and send them to flutter. + gpiod_line_bulk_foreach_line(&gpio_plugin.listening_lines, line, cursor) { + for (int i = 0, is_ready = false; i < n_fdevents; i++) { + if (fdevents[i].data.fd == libgpiod.line_event_get_fd(line)) { + is_ready = true; + break; + } + } + if (!is_ready) continue; - - // we got events. go through each line in `events` - // and read the gpio line events. - gpiod_line_bulk_foreach_line(&events, line, cursor) { + // read the line events ok = libgpiod.line_event_read(line, &event); - if (ok != 0) { - fprintf(stderr, "[gpiodp] Could not read events from gpio line.\n"); + if (ok == -1) { + perror("[flutter_gpiod] Could not read events from GPIO line. gpiod_line_event_read"); continue; } - // If there's currently noone listening to the - // flutter_gpiod event channel, we bail out here - // and don't send anything on the channel. - if (!gpio_plugin.should_emit_events) { - continue; - } + // if currently noone's listening to the + // flutter_gpiod event channel, we don't send anything + // to flutter and discard the events. + if (!gpio_plugin.should_emit_events) continue; // convert the gpiod_line to a flutter_gpiod line handle. - line_handle = libgpiod.line_offset(line); chip = libgpiod.line_get_chip(line); + + line_handle = libgpiod.line_offset(line); for (int i = 0; gpio_plugin.chips[i] != chip; i++) line_handle += libgpiod.chip_num_lines(chip); @@ -509,13 +517,15 @@ void *gpiodp_io_loop(void *userdata) { } ); } + + pthread_mutex_unlock(&gpio_plugin.listening_lines_mutex); } return NULL; } -int gpiodp_get_num_chips(struct platch_obj *object, +static int gpiodp_get_num_chips(struct platch_obj *object, FlutterPlatformMessageResponseHandle *responsehandle) { int ok; @@ -527,7 +537,7 @@ int gpiodp_get_num_chips(struct platch_obj *object, return platch_respond_success_std(responsehandle, &STDINT32(gpio_plugin.n_chips)); } -int gpiodp_get_chip_details(struct platch_obj *object, +static int gpiodp_get_chip_details(struct platch_obj *object, FlutterPlatformMessageResponseHandle *responsehandle) { struct gpiod_chip *chip; unsigned int chip_index; @@ -579,7 +589,7 @@ int gpiodp_get_chip_details(struct platch_obj *object, ); } -int gpiodp_get_line_handle(struct platch_obj *object, +static int gpiodp_get_line_handle(struct platch_obj *object, FlutterPlatformMessageResponseHandle *responsehandle) { struct gpiod_chip *chip; unsigned int chip_index, line_index; @@ -642,7 +652,7 @@ int gpiodp_get_line_handle(struct platch_obj *object, return platch_respond_success_std(responsehandle, &STDINT32(line_index)); } -int gpiodp_get_line_details(struct platch_obj *object, +static int gpiodp_get_line_details(struct platch_obj *object, FlutterPlatformMessageResponseHandle *responsehandle) { struct gpiod_line *line; unsigned int line_handle; @@ -755,7 +765,7 @@ int gpiodp_get_line_details(struct platch_obj *object, ); } -int gpiodp_request_line(struct platch_obj *object, +static int gpiodp_request_line(struct platch_obj *object, FlutterPlatformMessageResponseHandle *responsehandle) { struct line_config config; struct std_value *temp; @@ -853,7 +863,7 @@ int gpiodp_request_line(struct platch_obj *object, ); } - // finally temp the line + // finally request the line ok = libgpiod.line_request( config.line, &(struct gpiod_line_request_config) { @@ -870,22 +880,30 @@ int gpiodp_request_line(struct platch_obj *object, if (is_event_line) { pthread_mutex_lock(&gpio_plugin.listening_lines_mutex); + ok = epoll_ctl(gpio_plugin.epollfd, + EPOLL_CTL_ADD, + libgpiod.line_event_get_fd(config.line), + &(struct epoll_event) {.events = EPOLLPRI | EPOLLIN} + ); + if (ok == -1) { + perror("[flutter_gpiod] Could not add GPIO line to epollfd. epoll_ctl"); + libgpiod.line_release(config.line); + return platch_respond_native_error_std(responsehandle, errno); + } + gpiod_line_bulk_add(&gpio_plugin.listening_lines, config.line); pthread_mutex_unlock(&gpio_plugin.listening_lines_mutex); - pthread_cond_signal(&gpio_plugin.listening_line_added); } return platch_respond_success_std(responsehandle, NULL); } -int gpiodp_release_line(struct platch_obj *object, +static int gpiodp_release_line(struct platch_obj *object, FlutterPlatformMessageResponseHandle *responsehandle) { - struct gpiod_line *line, *current; + struct gpiod_line *line; unsigned int line_handle; - unsigned int offset; - bool found; - int ok; + int ok, fd; // get the line handle if (STDVALUE_IS_INT(object->std_arg)) { @@ -904,29 +922,33 @@ int gpiodp_release_line(struct platch_obj *object, return gpiodp_respond_illegal_line_handle(responsehandle); } - pthread_mutex_lock(&gpio_plugin.listening_lines_mutex); - found = false; - gpiod_line_bulk_foreach_line_off(&gpio_plugin.listening_lines, current, offset) { - if (current == line) { - found = true; - break; - } - } - if (found) { - gpiod_line_bulk_remove(&gpio_plugin.listening_lines, offset); + // Try to get the line associated fd and remove + // it from the listening thread + fd = libgpiod.line_event_get_fd(line); + if (fd != -1) { + pthread_mutex_lock(&gpio_plugin.listening_lines_mutex); + + gpiod_line_bulk_remove(&gpio_plugin.listening_lines, line); + + ok = epoll_ctl(gpio_plugin.epollfd, EPOLL_CTL_DEL, fd, NULL); + if (ok == -1) { + perror("[flutter_gpiod] Could not remove GPIO line from epollfd. epoll_ctl"); + return platch_respond_native_error_std(responsehandle, errno); } - pthread_mutex_unlock(&gpio_plugin.listening_lines_mutex); + + pthread_mutex_unlock(&gpio_plugin.listening_lines_mutex); + } ok = libgpiod.line_release(line); if (ok == -1) { - perror("[flutter_gpiod] Could not release line"); + perror("[flutter_gpiod] Could not release line. gpiod_line_release"); return platch_respond_native_error_std(responsehandle, errno); } return platch_respond_success_std(responsehandle, NULL); } -int gpiodp_reconfigure_line(struct platch_obj *object, +static int gpiodp_reconfigure_line(struct platch_obj *object, FlutterPlatformMessageResponseHandle *responsehandle) { struct line_config config; int ok; @@ -961,7 +983,7 @@ int gpiodp_reconfigure_line(struct platch_obj *object, return platch_respond_success_std(responsehandle, NULL); } -int gpiodp_get_line_value(struct platch_obj *object, +static int gpiodp_get_line_value(struct platch_obj *object, FlutterPlatformMessageResponseHandle *responsehandle) { struct gpiod_line *line; unsigned int line_handle; @@ -993,7 +1015,7 @@ int gpiodp_get_line_value(struct platch_obj *object, return platch_respond_success_std(responsehandle, &STDBOOL(ok)); } -int gpiodp_set_line_value(struct platch_obj *object, +static int gpiodp_set_line_value(struct platch_obj *object, FlutterPlatformMessageResponseHandle *responsehandle) { struct std_value *temp; struct gpiod_line *line; @@ -1042,7 +1064,7 @@ int gpiodp_set_line_value(struct platch_obj *object, return platch_respond_success_std(responsehandle, NULL); } -int gpiodp_supports_bias(struct platch_obj *object, +static int gpiodp_supports_bias(struct platch_obj *object, FlutterPlatformMessageResponseHandle *responsehandle) { int ok; @@ -1055,7 +1077,7 @@ int gpiodp_supports_bias(struct platch_obj *object, return platch_respond_success_std(responsehandle, &STDBOOL(libgpiod.line_bias)); } -int gpiodp_supports_reconfiguration(struct platch_obj *object, +static int gpiodp_supports_reconfiguration(struct platch_obj *object, FlutterPlatformMessageResponseHandle *responsehandle) { int ok; @@ -1134,6 +1156,6 @@ int gpiodp_init(void) { } int gpiodp_deinit(void) { - printf("[gpio-plugin] deinit.\n"); + printf("[flutter_gpiod] deinit.\n"); return 0; } \ No newline at end of file diff --git a/src/plugins/spidev.c b/src/plugins/spidev.c index 2cd734d7..adcbee37 100644 --- a/src/plugins/spidev.c +++ b/src/plugins/spidev.c @@ -1,3 +1,4 @@ +#include #include #include #include From 56a996498952128faf3afbd0d0edb21cf69bdeb9 Mon Sep 17 00:00:00 2001 From: Hannes Winkler Date: Tue, 25 Feb 2020 13:56:07 +0100 Subject: [PATCH 6/8] make text_input plugin optional, so it works better with debuggers fix bugs in gpiod and spidev plugins --- include/flutter-pi.h | 30 ++++- include/plugins/raw_keyboard.h | 2 + include/plugins/spidev.h | 2 +- src/flutter-pi.c | 108 +++++++++++++++- src/pluginregistry.c | 10 +- src/plugins/gpiod.c | 16 ++- src/plugins/raw_keyboard.c | 1 + src/plugins/spidev.c | 219 ++++++++++++++++++++++----------- 8 files changed, 302 insertions(+), 86 deletions(-) diff --git a/include/flutter-pi.h b/include/flutter-pi.h index e8c91de6..52a07ee7 100644 --- a/include/flutter-pi.h +++ b/include/flutter-pi.h @@ -34,6 +34,8 @@ typedef enum { kVBlankRequest, kVBlankReply, kUpdateOrientation, + kSendPlatformMessage, + kRespondToPlatformMessage, kFlutterTask } flutterpi_task_type; @@ -47,11 +49,26 @@ struct flutterpi_task { intptr_t baton; }; enum device_orientation orientation; + struct { + char *channel; + const FlutterPlatformMessageResponseHandle *responsehandle; + size_t message_size; + uint8_t *message; + }; }; uint64_t target_time; }; -void post_platform_task(struct flutterpi_task *task); +static inline void *memdup(const void *restrict src, const size_t n) { + void *__restrict__ dest; + + if ((src == NULL) || (n == 0)) return NULL; + + dest = malloc(n); + if (dest == NULL) return NULL; + + return memcpy(dest, src, n); +} struct drm_fb { struct gbm_bo *bo; @@ -145,4 +162,15 @@ extern struct mousepointer_mtslot mousepointer; extern FlutterEngine engine; +void post_platform_task(struct flutterpi_task *task); + +int flutterpi_send_platform_message(const char *channel, + const uint8_t *restrict message, + size_t message_size, + FlutterPlatformMessageResponseHandle *responsehandle); + +int flutterpi_respond_to_platform_message(FlutterPlatformMessageResponseHandle *handle, + const uint8_t *restrict message, + size_t message_size); + #endif \ No newline at end of file diff --git a/include/plugins/raw_keyboard.h b/include/plugins/raw_keyboard.h index 9ee20ea8..b552f9e1 100644 --- a/include/plugins/raw_keyboard.h +++ b/include/plugins/raw_keyboard.h @@ -3,6 +3,8 @@ #define KEY_EVENT_CHANNEL "flutter/keyevent" +#include + int rawkb_on_keyevent(glfw_key key, uint32_t scan_code, glfw_key_action action); int rawkb_init(void); diff --git a/include/plugins/spidev.h b/include/plugins/spidev.h index 98d85846..9e7d16d3 100644 --- a/include/plugins/spidev.h +++ b/include/plugins/spidev.h @@ -4,7 +4,7 @@ #include #include -#define SPI_PLUGIN_METHOD_CHANNEL "plugins.flutter.io/spidev" +#define SPI_PLUGIN_METHOD_CHANNEL "plugins.flutter.io/flutter_spidev" int spidevp_init(void); int spidevp_deinit(void); diff --git a/src/flutter-pi.c b/src/flutter-pi.c index 0214d6ff..6ef80608 100644 --- a/src/flutter-pi.c +++ b/src/flutter-pi.c @@ -561,6 +561,30 @@ bool message_loop(void) { .pixel_ratio = pixel_ratio }); + } else if (task->type == kSendPlatformMessage || task->type == kRespondToPlatformMessage) { + if (task->type == kSendPlatformMessage) { + FlutterEngineSendPlatformMessage( + engine, + &(const FlutterPlatformMessage) { + .struct_size = sizeof(FlutterPlatformMessage), + .channel = task->channel, + .message = task->message, + .message_size = task->message_size, + .response_handle = task->responsehandle + } + ); + + free(task->channel); + } else if (task->type == kRespondToPlatformMessage) { + FlutterEngineSendPlatformMessageResponse( + engine, + task->responsehandle, + task->message, + task->message_size + ); + } + + free(task->message); } else if (FlutterEngineRunTask(engine, &task->task) != kSuccess) { fprintf(stderr, "Error running platform task\n"); return false; @@ -598,6 +622,88 @@ void flutter_post_platform_task(FlutterTask task, uint64_t target_time, void* u bool runs_platform_tasks_on_current_thread(void* userdata) { return pthread_equal(pthread_self(), platform_thread_id) != 0; } +int flutterpi_send_platform_message(const char *channel, + const uint8_t *restrict message, + size_t message_size, + FlutterPlatformMessageResponseHandle *responsehandle) { + struct flutterpi_task *task; + int ok; + + if (runs_platform_tasks_on_current_thread(NULL)) { + ok = kSuccess == FlutterEngineSendPlatformMessage( + engine, + &(const FlutterPlatformMessage) { + .struct_size = sizeof(FlutterPlatformMessage), + .channel = channel, + .message = message, + .message_size = message_size, + .response_handle = responsehandle + } + ); + + return ok? 0 : 1; + } else { + task = malloc(sizeof(struct flutterpi_task)); + if (task == NULL) return ENOMEM; + + task->type = kSendPlatformMessage; + task->channel = strdup(channel); + task->responsehandle = responsehandle; + + if (message && message_size) { + task->message_size = message_size; + task->message = memdup(message, message_size); + if (!task->message) { + free(task->channel); + return ENOMEM; + } + } else { + task->message_size = 0; + task->message = 0; + } + + post_platform_task(task); + } + + return 0; +} +int flutterpi_respond_to_platform_message(FlutterPlatformMessageResponseHandle *handle, + const uint8_t *restrict message, + size_t message_size) { + struct flutterpi_task *task; + int ok; + + if (runs_platform_tasks_on_current_thread(NULL)) { + ok = kSuccess == FlutterEngineSendPlatformMessageResponse( + engine, + handle, + message, + message_size + ); + + return ok? 0 : 1; + } else { + task = malloc(sizeof(struct flutterpi_task)); + if (task == NULL) return ENOMEM; + + task->type = kRespondToPlatformMessage; + task->channel = NULL; + task->responsehandle = handle; + + if (message && message_size) { + task->message_size = message_size; + task->message = memdup(message, message_size); + if (!task->message) return ENOMEM; + } else { + task->message_size = 0; + task->message = 0; + } + + post_platform_task(task); + } + + return 0; +} @@ -1606,7 +1712,7 @@ void *io_loop(void *userdata) { FD_SET(drm.fd, &fds); if (drm.fd + 1 > nfds) nfds = drm.fd + 1; - FD_SET(STDIN_FILENO, &fds); + //FD_SET(STDIN_FILENO, &fds); const fd_set const_fds = fds; diff --git a/src/pluginregistry.c b/src/pluginregistry.c index 58cbffb6..c73ed87b 100644 --- a/src/pluginregistry.c +++ b/src/pluginregistry.c @@ -6,9 +6,12 @@ #include #include -#include + #include +#ifdef BUILD_TEXT_INPUT_PLUGIN +# include +#endif #ifdef BUILD_TEST_PLUGIN # include #endif @@ -40,9 +43,12 @@ struct { /// array of plugins that are statically included in flutter-pi. struct flutterpi_plugin hardcoded_plugins[] = { {.name = "services", .init = services_init, .deinit = services_deinit}, - {.name = "text_input", .init = textin_init, .deinit = textin_deinit}, {.name = "raw_keyboard", .init = rawkb_init, .deinit = rawkb_deinit}, +#ifdef BUILD_TEXT_INPUT_PLUGIN + {.name = "text_input", .init = textin_init, .deinit = textin_deinit}, +#endif + #ifdef BUILD_TEST_PLUGIN {.name = "testplugin", .init = testp_init, .deinit = testp_deinit}, #endif diff --git a/src/plugins/gpiod.c b/src/plugins/gpiod.c index f42e2e60..deeae4e1 100644 --- a/src/plugins/gpiod.c +++ b/src/plugins/gpiod.c @@ -198,6 +198,7 @@ static int gpiodp_ensure_gpiod_initialized(void) { return errno; } + gpio_plugin.epollfd = fd; gpio_plugin.listening_lines = (struct gpiod_line_bulk) GPIOD_LINE_BULK_INITIALIZER; gpio_plugin.listening_lines_mutex = (pthread_mutex_t) PTHREAD_MUTEX_INITIALIZER; gpio_plugin.line_event_listener_should_run = true; @@ -452,6 +453,7 @@ static void *gpiodp_io_loop(void *userdata) { while (gpio_plugin.line_event_listener_should_run) { // epoll luckily is concurrent. Other threads can add and remove fd's from this // epollfd while we're waiting on it. + ok = epoll_wait(gpio_plugin.epollfd, fdevents, 10, -1); if ((ok == -1) && (errno != EINTR)) { perror("[flutter_gpiod] error while waiting for line events, epoll"); @@ -466,14 +468,15 @@ static void *gpiodp_io_loop(void *userdata) { // check for each line whether an event ocurred on the line's fd. // If that's the case, read the events and send them to flutter. gpiod_line_bulk_foreach_line(&gpio_plugin.listening_lines, line, cursor) { - for (int i = 0, is_ready = false; i < n_fdevents; i++) { + is_ready = false; + for (int i = 0; i < n_fdevents; i++) { if (fdevents[i].data.fd == libgpiod.line_event_get_fd(line)) { is_ready = true; break; } } if (!is_ready) continue; - + // read the line events ok = libgpiod.line_event_read(line, &event); if (ok == -1) { @@ -771,7 +774,7 @@ static int gpiodp_request_line(struct platch_obj *object, struct std_value *temp; bool is_event_line = false; char *consumer; - int ok; + int ok, fd; // check that the arg is a map if (object->std_arg.type != kStdMap) { @@ -862,7 +865,7 @@ static int gpiodp_request_line(struct platch_obj *object, "(no null values in the list), null when direction is output." ); } - + // finally request the line ok = libgpiod.line_request( config.line, @@ -880,10 +883,11 @@ static int gpiodp_request_line(struct platch_obj *object, if (is_event_line) { pthread_mutex_lock(&gpio_plugin.listening_lines_mutex); + fd = libgpiod.line_event_get_fd(config.line); ok = epoll_ctl(gpio_plugin.epollfd, EPOLL_CTL_ADD, - libgpiod.line_event_get_fd(config.line), - &(struct epoll_event) {.events = EPOLLPRI | EPOLLIN} + fd, + &(struct epoll_event) {.events = EPOLLPRI | EPOLLIN, .data.fd = fd} ); if (ok == -1) { perror("[flutter_gpiod] Could not add GPIO line to epollfd. epoll_ctl"); diff --git a/src/plugins/raw_keyboard.c b/src/plugins/raw_keyboard.c index cbe67252..4983d565 100644 --- a/src/plugins/raw_keyboard.c +++ b/src/plugins/raw_keyboard.c @@ -7,6 +7,7 @@ #include #include #include + #include struct { diff --git a/src/plugins/spidev.c b/src/plugins/spidev.c index adcbee37..60b81c9b 100644 --- a/src/plugins/spidev.c +++ b/src/plugins/spidev.c @@ -41,149 +41,174 @@ struct spidevp_thread { int fd; bool has_task; struct spidevp_task task; - pthread_mutex_t mutex; + pthread_t thread; + pthread_mutex_t task_mutex; pthread_cond_t task_added; }; #define SPI_THREAD_INITIALIZER \ ((struct spidevp_thread) { \ .fd = -1, .has_task = false, \ - .mutex = PTHREAD_MUTEX_INITIALIZER, .task_added = PTHREAD_COND_INITIALIZER \ + .task_mutex = PTHREAD_MUTEX_INITIALIZER, .task_added = PTHREAD_COND_INITIALIZER \ }) struct { - struct spidevp_thread *threads; - pthread_mutex_t threadlist_mutex; + struct spidevp_thread **threads; + pthread_mutex_t threads_mutex; size_t size_threads; size_t num_threads; } spi_plugin = { .threads = NULL, - .threadlist_mutex = PTHREAD_MUTEX_INITIALIZER, - .size_threads = 0, - .num_threads = 0 + .threads_mutex = PTHREAD_MUTEX_INITIALIZER, + .size_threads = 0 }; -void *spidevp_run_spi_thread(void *_thread) { +static void *spidevp_run_spi_thread(void *_thread) { + FlutterPlatformMessageResponseHandle *responsehandle; struct spidevp_thread *thread = (struct spidevp_thread*) _thread; int32_t result; bool running = true; - int fd = thread->fd; - int err = 0; - int ok; + int ok, err = 0, fd = thread->fd; while (running) { - pthread_mutex_lock(&thread->mutex); - while (!thread->has_task) - pthread_cond_wait(&thread->task_added, &thread->mutex); - + pthread_mutex_lock(&thread->task_mutex); + while (!thread->has_task) { + pthread_cond_wait(&thread->task_added, &thread->task_mutex); + } + + responsehandle = thread->task.responsehandle; switch (thread->task.type) { case kSpiTaskClose: ok = close(fd); if (ok == -1) { err = errno; - pthread_mutex_unlock(&thread->mutex); + thread->has_task = false; + pthread_mutex_unlock(&thread->task_mutex); break; } running = false; + thread->has_task = false; thread->fd = -1; - - pthread_mutex_unlock(&thread->mutex); - platch_respond_success_std(thread->task.responsehandle, NULL); + pthread_mutex_unlock(&thread->task_mutex); + platch_respond_success_std(responsehandle, NULL); break; case kSpiTaskRdMode: ok = ioctl(fd, SPI_IOC_RD_MODE, &thread->task.mode); if (ok == -1) { err = errno; - pthread_mutex_unlock(&thread->mutex); + thread->has_task = false; + pthread_mutex_unlock(&thread->task_mutex); break; } result = thread->task.mode; - pthread_mutex_unlock(&thread->mutex); - platch_respond_success_std(thread->task.responsehandle, NULL); + thread->has_task = false; + pthread_mutex_unlock(&thread->task_mutex); + ok = platch_respond_success_std(responsehandle, &STDINT32(result)); + break; case kSpiTaskWrMode: ok = ioctl(fd, SPI_IOC_WR_MODE, &thread->task.mode); if (ok == -1) { err = errno; - pthread_mutex_unlock(&thread->mutex); + thread->has_task = false; + pthread_mutex_unlock(&thread->task_mutex); break; } - pthread_mutex_unlock(&thread->mutex); - platch_respond_success_std(thread->task.responsehandle, NULL); + thread->has_task = false; + pthread_mutex_unlock(&thread->task_mutex); + platch_respond_success_std(responsehandle, NULL); break; case kSpiTaskWrBitsPerWord: ok = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &thread->task.bits); if (ok == -1) { err = errno; - pthread_mutex_unlock(&thread->mutex); + thread->has_task = false; + pthread_mutex_unlock(&thread->task_mutex); break; } - pthread_mutex_unlock(&thread->mutex); - platch_respond_success_std(thread->task.responsehandle, NULL); + thread->has_task = false; + pthread_mutex_unlock(&thread->task_mutex); + platch_respond_success_std(responsehandle, NULL); break; case kSpiTaskRdBitsPerWord: ok = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &thread->task.bits); if (ok == -1) { err = errno; - pthread_mutex_unlock(&thread->mutex); + thread->has_task = false; + pthread_mutex_unlock(&thread->task_mutex); break; } result = thread->task.bits; - pthread_mutex_unlock(&thread->mutex); - platch_respond_success_std(thread->task.responsehandle, NULL); + thread->has_task = false; + pthread_mutex_unlock(&thread->task_mutex); + platch_respond_success_std(responsehandle, &STDINT32(result)); break; case kSpiTaskWrMaxSpeedHz: ok = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &thread->task.speed); if (ok == -1) { err = errno; - pthread_mutex_unlock(&thread->mutex); + thread->has_task = false; + pthread_mutex_unlock(&thread->task_mutex); break; } - pthread_mutex_unlock(&thread->mutex); - platch_respond_success_std(thread->task.responsehandle, NULL); + thread->has_task = false; + pthread_mutex_unlock(&thread->task_mutex); + platch_respond_success_std(responsehandle, NULL); break; case kSpiTaskRdMaxSpeedHz: ok = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &thread->task.speed); if (ok == -1) { err = errno; - pthread_mutex_unlock(&thread->mutex); + thread->has_task = false; + pthread_mutex_unlock(&thread->task_mutex); break; } result = thread->task.speed; - pthread_mutex_unlock(&thread->mutex); - platch_respond_success_std(thread->task.responsehandle, NULL); + thread->has_task = false; + pthread_mutex_unlock(&thread->task_mutex); + platch_respond_success_std(responsehandle, &STDINT64(result)); break; case kSpiTaskTransmit: ; size_t len = thread->task.transfer.len; uint8_t *buf = (void*) ((uintptr_t) thread->task.transfer.rx_buf); - ok = ioctl(fd, SPI_IOC_MESSAGE(1), thread->task.transfer); + ok = ioctl(fd, SPI_IOC_MESSAGE(1), &thread->task.transfer); if (ok == -1) { err = errno; free(buf); - pthread_mutex_unlock(&thread->mutex); + + thread->has_task = false; + pthread_mutex_unlock(&thread->task_mutex); break; } - pthread_mutex_unlock(&thread->mutex); - platch_respond_success_std(thread->task.responsehandle, NULL); + thread->has_task = false; + pthread_mutex_unlock(&thread->task_mutex); + platch_respond_success_std( + responsehandle, + &(struct std_value) { + .type = kStdUInt8Array, + .size = len, + .uint8array = buf + } + ); free(buf); @@ -193,38 +218,64 @@ void *spidevp_run_spi_thread(void *_thread) { break; } - thread->has_task = false; if (err != 0) { - platch_respond_native_error_std(thread->task.responsehandle, err); + platch_respond_native_error_std(responsehandle, err); err = 0; } } + + return NULL; } -struct spidevp_thread *spidevp_get_thread(const int fd) { - pthread_mutex_lock(&spi_plugin.threadlist_mutex); +static struct spidevp_thread *spidevp_get_thread(const int fd) { + pthread_mutex_lock(&spi_plugin.threads_mutex); - for (int i = 0; i < spi_plugin.num_threads; i++) { - if (spi_plugin.threads[i].fd == fd) - return &spi_plugin.threads[i]; + for (int i = 0; i < spi_plugin.size_threads; i++) { + if (spi_plugin.threads[i]->fd == fd) { + struct spidevp_thread *result = spi_plugin.threads[i]; + pthread_mutex_unlock(&spi_plugin.threads_mutex); + return result; + } } - pthread_mutex_unlock(&spi_plugin.threadlist_mutex); + pthread_mutex_unlock(&spi_plugin.threads_mutex); return NULL; } -int spidevp_new_thread(const int fd, struct spidevp_thread **thread_out) { +static int spidevp_new_thread(const int fd, struct spidevp_thread **thread_out) { struct spidevp_thread *thread; int ok; - pthread_mutex_lock(&spi_plugin.threadlist_mutex); + pthread_mutex_lock(&spi_plugin.threads_mutex); + + thread = NULL; + for (int i=0; i < spi_plugin.size_threads; i++) { + if (spi_plugin.threads[i]->fd == -1) { + thread = spi_plugin.threads[i]; + break; + } + } + + if (thread == NULL) { + size_t old = spi_plugin.size_threads; + size_t new = old*2; + + spi_plugin.threads = realloc(spi_plugin.threads, new * sizeof(struct spidevp_thread)); + spi_plugin.size_threads = new; + + for (int i=old; i < spi_plugin.size_threads; i++) { + spi_plugin.threads[i] = malloc(sizeof(struct spidevp_thread)); + *(spi_plugin.threads[i]) = SPI_THREAD_INITIALIZER; + } + + thread = spi_plugin.threads[old]; + } - thread = &spi_plugin.threads[spi_plugin.num_threads++]; thread->fd = fd; - pthread_mutex_unlock(&spi_plugin.threadlist_mutex); + pthread_mutex_unlock(&spi_plugin.threads_mutex); - ok = pthread_create(NULL, NULL, spidevp_run_spi_thread, thread); + ok = pthread_create(&thread->thread, NULL, spidevp_run_spi_thread, thread); if (ok == -1) return errno; *thread_out = thread; @@ -232,7 +283,7 @@ int spidevp_new_thread(const int fd, struct spidevp_thread **thread_out) { return 0; } -int spidevp_assign_task(const int fd, const struct spidevp_task *const task) { +static int spidevp_assign_task(const int fd, const struct spidevp_task *const task) { struct spidevp_thread *thread; int ok; @@ -241,19 +292,24 @@ int spidevp_assign_task(const int fd, const struct spidevp_task *const task) { return EBADF; } - ok = pthread_mutex_trylock(&thread->mutex); + ok = pthread_mutex_trylock(&thread->task_mutex); if (ok == -1) { return errno; } else if (ok == 0) { - thread->task = *task; - thread->has_task = true; - pthread_mutex_unlock(&thread->mutex); - pthread_cond_signal(&thread->task_added); - return 0; + if (thread->fd == -1) { + return EBADF; + } else { + thread->task = *task; + thread->has_task = true; + pthread_mutex_unlock(&thread->task_mutex); + pthread_cond_signal(&thread->task_added); + } } + + return 0; } -int spidevp_open(struct platch_obj *object, FlutterPlatformMessageResponseHandle *responsehandle) { +static int spidevp_open(struct platch_obj *object, FlutterPlatformMessageResponseHandle *responsehandle) { struct spidevp_thread *thread; char *path; int fd, ok; @@ -277,13 +333,13 @@ int spidevp_open(struct platch_obj *object, FlutterPlatformMessageResponseHandle return platch_respond_native_error_std(responsehandle, ok); } - return platch_respond_success_std(responsehandle, NULL); + return platch_respond_success_std(responsehandle, &STDINT32(fd)); } -int spidevp_onReceive(char *channel, struct platch_obj *object, FlutterPlatformMessageResponseHandle *responsehandle) { +static int spidevp_on_receive(char *channel, struct platch_obj *object, FlutterPlatformMessageResponseHandle *responsehandle) { struct std_value *temp; struct spidevp_thread *thread; - struct spidevp_task task; + struct spidevp_task task = {0}; bool has_task = false; int ok, fd; @@ -300,7 +356,7 @@ int spidevp_onReceive(char *channel, struct platch_obj *object, FlutterPlatformM "Expected `arg` to be a List with size 2." ); } - + task.type = kSpiTaskWrMode; has_task = true; } else if STREQ("getMode", object->method) { @@ -440,39 +496,52 @@ int spidevp_onReceive(char *channel, struct platch_obj *object, FlutterPlatformM task.type = kSpiTaskTransmit; has_task = true; } else if STREQ("close", object->method) { + if (STDVALUE_IS_INT(object->std_arg)) { + fd = STDVALUE_AS_INT(object->std_arg); + } else { + return platch_respond_illegal_arg_std( + responsehandle, + "Expected `arg` to be an integer." + ); + } + task.type = kSpiTaskClose; has_task = true; } if (has_task) { + task.responsehandle = responsehandle; + ok = spidevp_assign_task(fd, &task); - if (ok == 0) { - return 0; - } else if (ok == EBUSY) { + if (ok == EBUSY) { return platch_respond_error_std( responsehandle, "busy", "a different task is running on the fd already", NULL ); - } else { + } else if (ok != 0) { return platch_respond_native_error_std(responsehandle, ok); } + } else { + return platch_respond_not_implemented(responsehandle); } - return platch_respond_not_implemented(responsehandle); + return 0; } int spidevp_init(void) { printf("[flutter_spidev] Initializing...\n"); spi_plugin.size_threads = 1; - spi_plugin.threads = calloc(spi_plugin.size_threads, sizeof(struct spidevp_thread)); + spi_plugin.threads = malloc(spi_plugin.size_threads * sizeof(struct spidevp_thread *)); - for (int i = 0; i < spi_plugin.size_threads; i++) - spi_plugin.threads[i] = SPI_THREAD_INITIALIZER; + for (int i = 0; i < spi_plugin.size_threads; i++) { + spi_plugin.threads[i] = malloc(sizeof(struct spidevp_thread)); + *(spi_plugin.threads[i]) = SPI_THREAD_INITIALIZER; + } - plugin_registry_set_receiver(SPI_PLUGIN_METHOD_CHANNEL, kStandardMethodCall, spidevp_onReceive); + plugin_registry_set_receiver(SPI_PLUGIN_METHOD_CHANNEL, kStandardMethodCall, spidevp_on_receive); printf("[flutter_spidev] Done.\n"); return 0; From f0b39d4bf20cbb1a4c934b9d1a99ac1e9921988b Mon Sep 17 00:00:00 2001 From: Hannes Winkler Date: Tue, 25 Feb 2020 15:55:16 +0100 Subject: [PATCH 7/8] 64 bit support (untested) --- include/flutter-pi.h | 2 + include/platformchannel.h | 196 +++++++++++++++++++---------- src/platformchannel.c | 257 ++++++++++++++++++++++---------------- 3 files changed, 277 insertions(+), 178 deletions(-) diff --git a/include/flutter-pi.h b/include/flutter-pi.h index 52a07ee7..318e5ead 100644 --- a/include/flutter-pi.h +++ b/include/flutter-pi.h @@ -9,6 +9,8 @@ #include #include #include +#include +#include #define EGL_PLATFORM_GBM_KHR 0x31D7 diff --git a/include/platformchannel.h b/include/platformchannel.h index a73c097f..817bfe9d 100644 --- a/include/platformchannel.h +++ b/include/platformchannel.h @@ -9,15 +9,15 @@ // andrew // only 32bit support for now. -#define __ALIGN4_REMAINING(value, remaining, ...) __align((uint32_t*) (value), 4, remaining) -#define __ALIGN8_REMAINING(value, remaining, ...) __align((uint32_t*) (value), 8, remaining) -#define align4(...) __ALIGN4_REMAINING(__VA_ARGS__, NULL) -#define align8(...) __ALIGN8_REMAINING(__VA_ARGS__, NULL) +//#define __ALIGN4_REMAINING(value, remaining, ...) __align(value, 4, remaining) +//#define __ALIGN8_REMAINING(value, remaining, ...) __align(value, 8, remaining) +//#define align4(...) __ALIGN4_REMAINING(__VA_ARGS__, NULL) +//#define align8(...) __ALIGN8_REMAINING(__VA_ARGS__, NULL) -#define alignmentDiff(value, alignment) __alignmentDiff((uint32_t) value, alignment) +//#define alignmentDiff(value, alignment) __alignmentDiff(value, alignment) -#define __ADVANCE_REMAINING(value, n, remaining, ...) __advance((uint32_t*) (value), n, remaining) -#define advance(...) __ADVANCE_REMAINING(__VA_ARGS__, NULL) +//#define __ADVANCE_REMAINING(value, n, remaining, ...) __advance(value, n, remaining) +//#define advance(...) __ADVANCE_REMAINING(__VA_ARGS__, NULL) /* @@ -364,90 +364,150 @@ struct std_value *stdmap_get(struct std_value *map, struct std_value *key); struct std_value *stdmap_get_str(struct std_value *map, char *key); -/// Andrew: Definitions -static inline int __alignmentDiff(uint32_t value, int alignment) { - alignment--; - return value - (((((uint32_t) value) + alignment) | alignment) - alignment); +static inline int _advance(uintptr_t *value, int n_bytes, size_t *remaining) { + if (remaining != NULL) { + if (*remaining < n_bytes) return EBADMSG; + *remaining -= n_bytes; + } + + *value += n_bytes; + return 0; } -static inline void __align(uint32_t *value, int alignment, size_t *remaining) { - if (remaining != NULL) - *remaining -= alignmentDiff((uint32_t) *value, alignment); - alignment--; +static inline int _align(uintptr_t *value, int alignment, size_t *remaining) { + int diff; + + alignment--; + diff = ((((*value) + alignment) | alignment) - alignment) - *value; - *value = (uint32_t) (((*value + alignment) | alignment) - alignment); + return _advance(value, diff, remaining); } -static inline void __advance(uint32_t *value, int n_bytes, size_t *remaining) { - if (remaining != NULL) - *remaining -= n_bytes; - - *value += n_bytes; +static inline int _advance_size_bytes(uintptr_t *value, size_t size, size_t *remaining) { + if (size < 254) { + return _advance(value, 1, remaining); + } else if (size <= 0xFFFF) { + return _advance(value, 3, remaining); + } else { + return _advance(value, 5, remaining); + } } -static inline void write8(uint8_t **pbuffer, uint8_t value) { + +static inline int _write8(uint8_t **pbuffer, uint8_t value, size_t *remaining) { + if ((remaining != NULL) && (*remaining < 1)) { + return EBADMSG; + } + *(uint8_t*) *pbuffer = value; + + return _advance((uintptr_t*) pbuffer, 1, remaining); } -static inline void write16(uint8_t **pbuffer, uint16_t value) { +static inline int _write16(uint8_t **pbuffer, uint16_t value, size_t *remaining) { + if ((remaining != NULL) && (*remaining < 2)) { + return EBADMSG; + } + *(uint16_t*) *pbuffer = value; + + return _advance((uintptr_t*) pbuffer, 2, remaining); } -static inline void write32(uint8_t **pbuffer, uint32_t value) { +static inline int _write32(uint8_t **pbuffer, uint32_t value, size_t *remaining) { + if ((remaining != NULL) && (*remaining < 4)) { + return EBADMSG; + } + *(uint32_t*) *pbuffer = value; + + return _advance((uintptr_t*) pbuffer, 4, remaining); } -static inline void write64(uint8_t **pbuffer, uint64_t value) { - *(uint64_t*) *pbuffer = value; +static inline int _write64(uint8_t **pbuffer, uint64_t value, size_t *remaining) { + if ((remaining != NULL) && (*remaining < 8)) { + return EBADMSG; + } + + *(uint64_t*) *pbuffer = value; + + return _advance((uintptr_t*) pbuffer, 8, remaining); } -static inline uint8_t read8(uint8_t **pbuffer) { - return *(uint8_t *) *pbuffer; +static inline int _read8(uint8_t **pbuffer, uint8_t* value_out, size_t *remaining) { + if ((remaining != NULL) && (*remaining < 1)) { + return EBADMSG; + } + + *value_out = *(uint8_t *) *pbuffer; + + return _advance((uintptr_t*) pbuffer, 1, remaining); } -static inline uint16_t read16(uint8_t **pbuffer) { - return *(uint16_t *) *pbuffer; +static inline int _read16(uint8_t **pbuffer, uint16_t *value_out, size_t *remaining) { + if ((remaining != NULL) && (*remaining < 2)) { + return EBADMSG; + } + + *value_out = *(uint16_t *) *pbuffer; + + return _advance((uintptr_t*) pbuffer, 2, remaining); } -static inline uint32_t read32(uint8_t **pbuffer) { - return *(int32_t *) *pbuffer; +static inline int _read32(uint8_t **pbuffer, uint32_t *value_out, size_t *remaining) { + if ((remaining != NULL) && (*remaining < 4)) { + return EBADMSG; + } + + *value_out = *(uint32_t *) *pbuffer; + + return _advance((uintptr_t*) pbuffer, 4, remaining); } -static inline uint64_t read64(uint8_t **pbuffer) { - return *(int64_t *) *pbuffer; +static inline int _read64(uint8_t **pbuffer, uint64_t *value_out, size_t *remaining) { + if ((remaining != NULL) && (*remaining < 8)) { + return EBADMSG; + } + + *value_out = *(uint64_t *) *pbuffer; + + return _advance((uintptr_t*) pbuffer, 8, remaining); } -static inline int nSizeBytes(int size) { - return (size < 254) ? 1 : (size <= 0xFFFF) ? 3 : 5; -} -static inline void writeSize(uint8_t **pbuffer, int size) { - if (size < 254) { - write8(pbuffer, (uint8_t) size); - advance(pbuffer, 1); +static inline int _writeSize(uint8_t **pbuffer, int size, size_t *remaining) { + int ok; + + if (size < 254) { + return _write8(pbuffer, (uint8_t) size, remaining); } else if (size <= 0xFFFF) { - write8(pbuffer, 0xFE); - advance(pbuffer, 1); + ok = _write8(pbuffer, 0xFE, remaining); + if (ok != 0) return ok; - write16(pbuffer, (uint16_t) size); - advance(pbuffer, 2); + ok = _write16(pbuffer, (uint16_t) size, remaining); + if (ok != 0) return ok; } else { - write8(pbuffer, 0xFF); - advance(pbuffer, 1); + ok = _write8(pbuffer, 0xFF, remaining); + if (ok != 0) return ok; - write32(pbuffer, (uint32_t) size); - advance(pbuffer, 4); - } + ok = _write32(pbuffer, (uint32_t) size, remaining); + if (ok != 0) return ok; + } } -static inline int readSize(uint8_t **pbuffer, size_t *premaining, uint32_t *psize) { - if (*premaining < 1) return EBADMSG; - - *psize = read8(pbuffer); - advance(pbuffer, 1, premaining); - - if (*psize == 254) { - if (*premaining < 2) return EBADMSG; - - *psize = read16(pbuffer); - advance(pbuffer, 2, premaining); - } else if (*psize == 255) { - if (*premaining < 4) return EBADMSG; - - *psize = read32(pbuffer); - advance(pbuffer, 4, premaining); +static inline int _readSize(uint8_t **pbuffer, uint32_t *psize, size_t *remaining) { + int ok; + uint8_t size8; + uint16_t size16; + + ok = _read8(pbuffer, &size8, remaining); + if (ok != 0) return ok; + + if (size8 <= 253) { + *psize = size8; + + return 0; + } else if (size8 == 254) { + ok = _read16(pbuffer, &size16, remaining); + if (ok != 0) return ok; + + *psize = size16; + return 0; + } else if (size8 == 255) { + return _read32(pbuffer, psize, remaining); } - return 0; + return 0; } -#endif + +#endif \ No newline at end of file diff --git a/src/platformchannel.c b/src/platformchannel.c index 72a5faa7..c13b312e 100644 --- a/src/platformchannel.c +++ b/src/platformchannel.c @@ -105,76 +105,92 @@ int platch_free_obj(struct platch_obj *object) { return 0; } -int platch_calc_value_size_std(struct std_value* value, size_t* psize) { +int platch_calc_value_size_std(struct std_value* value, size_t* size_out) { enum std_value_type type = value->type; - size_t size; + uintptr_t size = (uintptr_t) *size_out; + size_t element_size, sizet_size = 0; int ok; // Type Byte - advance(psize, 1); + _advance(&size, 1, NULL); switch (type) { case kStdNull: case kStdTrue: case kStdFalse: break; case kStdInt32: - advance(psize, 4); + _advance(&size, 4, NULL); break; case kStdInt64: - advance(psize, 8); + _advance(&size, 8, NULL); break; case kStdFloat64: - align8 (psize); - advance(psize, 8); + _align (&size, 8, NULL); + _advance(&size, 8, NULL); break; case kStdString: case kStdLargeInt: - size = strlen(value->string_value); - advance(psize, size + nSizeBytes(size)); + element_size = strlen(value->string_value); + _advance_size_bytes(&size, element_size, NULL); + _advance(&size, element_size, NULL); break; case kStdUInt8Array: - size = value->size; - advance(psize, size + nSizeBytes(size)); + element_size = value->size; + _advance_size_bytes(&size, element_size, NULL); + _advance(&size, element_size, NULL); break; case kStdInt32Array: - size = value->size; + element_size = value->size; - advance(psize, nSizeBytes(size)); - align4 (psize); - advance(psize, size*4); + _advance_size_bytes(&size, element_size, NULL); + _align (&size, 4, NULL); + _advance(&size, element_size*4, NULL); break; case kStdInt64Array: - size = value->size; + element_size = value->size; - advance(psize, nSizeBytes(size)); - align8 (psize); - advance(psize, size*8); + _advance_size_bytes(&size, element_size, NULL); + _align (&size, 8, NULL); + _advance(&size, element_size*8, NULL); break; case kStdFloat64Array: - size = value->size; + element_size = value->size; - advance(psize, nSizeBytes(size)); - align8 (psize); - advance(psize, size*8); + _advance_size_bytes(&size, element_size, NULL); + _align (&size, 8, NULL); + _advance(&size, element_size*8, NULL); break; case kStdList: - size = value->size; + element_size = value->size; + + _advance_size_bytes(&size, element_size, NULL); + for (int i = 0; ilist[i]), &sizet_size); + if (ok != 0) return ok; + + size = (uintptr_t) sizet_size; + } - advance(psize, nSizeBytes(size)); - for (int i = 0; ilist[i]), psize)) != 0) return ok; - break; case kStdMap: - size = value->size; + element_size = value->size; + + _advance_size_bytes(&size, element_size, NULL); + for (int i = 0; ikeys[i]), &sizet_size); + if (ok != 0) return ok; - advance(psize, nSizeBytes(size)); - for (int i = 0; ikeys[i]), psize)) != 0) return ok; - if ((ok = platch_calc_value_size_std(&(value->values[i]), psize)) != 0) return ok; + ok = platch_calc_value_size_std(&(value->values[i]), &sizet_size); + if (ok != 0) return ok; + + size = (uintptr_t) sizet_size; } break; @@ -182,6 +198,8 @@ int platch_calc_value_size_std(struct std_value* value, size_t* psize) { return EINVAL; } + *size_out = (size_t) size; + return 0; } int platch_write_value_to_buffer_std(struct std_value* value, uint8_t **pbuffer) { @@ -189,8 +207,7 @@ int platch_write_value_to_buffer_std(struct std_value* value, uint8_t **pbuffer) size_t size; int ok; - write8(pbuffer, value->type); - advance(pbuffer, 1); + _write8(pbuffer, value->type, NULL); switch (value->type) { case kStdNull: @@ -198,17 +215,14 @@ int platch_write_value_to_buffer_std(struct std_value* value, uint8_t **pbuffer) case kStdFalse: break; case kStdInt32: - write32(pbuffer, value->int32_value); - advance(pbuffer, 4); + _write32(pbuffer, value->int32_value, NULL); break; case kStdInt64: - write64(pbuffer, value->int64_value); - advance(pbuffer, 8); + _write64(pbuffer, value->int64_value, NULL); break; case kStdFloat64: - align8(pbuffer); - write64(pbuffer, *((uint64_t*) &(value->float64_value))); - advance(pbuffer, 8); + _align ((uintptr_t*) pbuffer, 8, NULL); + _write64(pbuffer, *((uint64_t*) &(value->float64_value)), NULL); break; case kStdLargeInt: case kStdString: @@ -221,59 +235,61 @@ int platch_write_value_to_buffer_std(struct std_value* value, uint8_t **pbuffer) byteArray = value->uint8array; } - writeSize(pbuffer, size); + _writeSize(pbuffer, size, NULL); for (int i=0; isize; - writeSize(pbuffer, size); - align4(pbuffer); + _writeSize(pbuffer, size, NULL); + _align ((uintptr_t*) pbuffer, 4, NULL); for (int i=0; iint32array[i]); - advance(pbuffer, 4); + _write32(pbuffer, value->int32array[i], NULL); } break; case kStdInt64Array: size = value->size; - writeSize(pbuffer, size); - align8(pbuffer); + _writeSize(pbuffer, size, NULL); + _align((uintptr_t*) pbuffer, 8, NULL); for (int i=0; iint64array[i]); - advance(pbuffer, 8); + _write64(pbuffer, value->int64array[i], NULL); } break; case kStdFloat64Array: size = value->size; - writeSize(pbuffer, size); - align8(pbuffer); + _writeSize(pbuffer, size, NULL); + _align((uintptr_t*) pbuffer, 8, NULL); for (int i=0; ifloat64array[i]); - advance(pbuffer, 8); + _write64(pbuffer, value->float64array[i], NULL); + _advance((uintptr_t*) pbuffer, 8, NULL); } break; case kStdList: size = value->size; - writeSize(pbuffer, size); - for (int i=0; ilist[i]), pbuffer)) != 0) return ok; - + _writeSize(pbuffer, size, NULL); + for (int i=0; i < size; i++) { + ok = platch_write_value_to_buffer_std(&value->list[i], pbuffer); + if (ok != 0) return ok; + } + break; case kStdMap: size = value->size; - writeSize(pbuffer, size); + _writeSize(pbuffer, size, NULL); for (int i=0; ikeys[i]), pbuffer)) != 0) return ok; - if ((ok = platch_write_value_to_buffer_std(&(value->values[i]), pbuffer)) != 0) return ok; + ok = platch_write_value_to_buffer_std(&value->keys[i], pbuffer); + if (ok != 0) return ok; + + ok = platch_write_value_to_buffer_std(&value->values[i], pbuffer); + if (ok != 0) return ok; } break; default: @@ -416,16 +432,18 @@ int platch_write_value_to_buffer_json(struct json_value* value, uint8_t **pbuffe return 0; } int platch_decode_value_std(uint8_t **pbuffer, size_t *premaining, struct std_value *value_out) { + enum std_value_type type = 0; int64_t *longArray = 0; int32_t *intArray = 0; - uint8_t *byteArray = 0; + uint8_t *byteArray = 0, type_byte = 0; char *c_string = 0; size_t size = 0; int ok; - enum std_value_type type = read8(pbuffer); - advance(pbuffer, 1, premaining); + ok = _read8(pbuffer, &type_byte, premaining); + if (ok != 0) return ok; + type = type_byte; value_out->type = type; switch (type) { case kStdNull: @@ -433,97 +451,119 @@ int platch_decode_value_std(uint8_t **pbuffer, size_t *premaining, struct std_va case kStdFalse: break; case kStdInt32: - if (*premaining < 4) return EBADMSG; - - value_out->int32_value = (int32_t) read32(pbuffer); - advance(pbuffer, 4, premaining); + ok = _read32(pbuffer, &value_out->int32_value, premaining); + if (ok != 0) return ok; break; case kStdInt64: - if (*premaining < 8) return EBADMSG; - - value_out->int64_value = (int64_t) read64(pbuffer); - advance(pbuffer, 8, premaining); + ok = _read64(pbuffer, &value_out->int64_value, premaining); + if (ok != 0) return ok; break; case kStdFloat64: - if (*premaining < (8 + alignmentDiff(*pbuffer, 8))) return EBADMSG; + ok = _align((uintptr_t*) pbuffer, 8, premaining); + if (ok != 0) return ok; - align8(pbuffer, premaining); - uint64_t temp = read64(pbuffer); - value_out->float64_value = *((double*) (&temp)); - advance(pbuffer, 8, premaining); + ok = _read64(pbuffer, (uint64_t*) &value_out->float64_value, premaining); + if (ok != 0) return ok; break; case kStdLargeInt: case kStdString: - if ((ok = readSize(pbuffer, premaining, &size)) != 0) return ok; + ok = _readSize(pbuffer, &size, premaining); + if (ok != 0) return ok; if (*premaining < size) return EBADMSG; value_out->string_value = calloc(size+1, sizeof(char)); if (!value_out->string_value) return ENOMEM; + memcpy(value_out->string_value, *pbuffer, size); - advance(pbuffer, size, premaining); + _advance((uintptr_t*) pbuffer, size, premaining); break; case kStdUInt8Array: - if ((ok = readSize(pbuffer, premaining, &size)) != 0) return ok; + ok = _readSize(pbuffer, &size, premaining); + if (ok != 0) return ok; if (*premaining < size) return EBADMSG; value_out->size = size; value_out->uint8array = *pbuffer; - advance(pbuffer, size, premaining); + + ok = _advance((uintptr_t*) pbuffer, size, premaining); + if (ok != 0) return ok; break; case kStdInt32Array: - if ((ok = readSize(pbuffer, premaining, &size)) != 0) return ok; - if (*premaining < (size*4 + alignmentDiff(*pbuffer, 4))) return EBADMSG; + ok = _readSize(pbuffer, &size, premaining); + if (ok != 0) return ok; + + ok = _align((uintptr_t*) pbuffer, 4, premaining); + if (ok != 0) return ok; + + if (*premaining < size*4) return EBADMSG; - align4(pbuffer, premaining); value_out->size = size; value_out->int32array = (int32_t*) *pbuffer; - advance(pbuffer, size*4, premaining); + + ok = _advance((uintptr_t*) pbuffer, size*4, premaining); + if (ok != 0) return ok; break; case kStdInt64Array: - if ((ok = readSize(pbuffer, premaining, &size)) != 0) return ok; - if (*premaining < (size*8 + alignmentDiff(*pbuffer, 8))) return EBADMSG; + ok = _readSize(pbuffer, &size, premaining); + if (ok != 0) return ok; + + ok = _align((uintptr_t*) pbuffer, 8, premaining); + if (ok != 0) return ok; + + if (*premaining < size*8) return EBADMSG; - align8(pbuffer, premaining); value_out->size = size; value_out->int64array = (int64_t*) *pbuffer; - advance(pbuffer, size*8, premaining); + + ok = _advance((uintptr_t*) pbuffer, size*8, premaining); + if (ok != 0) return ok; break; case kStdFloat64Array: - if ((ok = readSize(pbuffer, premaining, &size)) != 0) return ok; - if (*premaining < (size*8 + alignmentDiff(*pbuffer, 8))) return EBADMSG; + ok = _readSize(pbuffer, &size, premaining); + if (ok != 0) return ok; + + ok = _align((uintptr_t*) pbuffer, 8, premaining); + if (ok != 0) return ok; + + if (*premaining < size*8) return EBADMSG; - align8(pbuffer, premaining); value_out->size = size; value_out->float64array = (double*) *pbuffer; - advance(pbuffer, size*8, premaining); + ok = _advance((uintptr_t*) pbuffer, size*8, premaining); + if (ok != 0) return ok; + break; case kStdList: - if ((ok = readSize(pbuffer, premaining, &size)) != 0) return ok; + ok = _readSize(pbuffer, &size, premaining); + if (ok != 0) return ok; value_out->size = size; value_out->list = calloc(size, sizeof(struct std_value)); for (int i = 0; i < size; i++) { - ok = platch_decode_value_std(pbuffer, premaining, &(value_out->list[i])); + ok = platch_decode_value_std(pbuffer, premaining, &value_out->list[i]); if (ok != 0) return ok; } break; case kStdMap: - if ((ok = readSize(pbuffer, premaining, &size)) != 0) return ok; + ok = _readSize(pbuffer, &size, premaining); + if (ok != 0) return ok; value_out->size = size; + value_out->keys = calloc(size*2, sizeof(struct std_value)); if (!value_out->keys) return ENOMEM; - value_out->values = &(value_out->keys[size]); + + value_out->values = &value_out->keys[size]; for (int i = 0; i < size; i++) { ok = platch_decode_value_std(pbuffer, premaining, &(value_out->keys[i])); @@ -726,7 +766,7 @@ int platch_decode(uint8_t *buffer, size_t size, enum platch_codec codec, struct break; case kStandardMessageCodec: - ok = platch_decode_value_std(&buffer_cursor, &remaining, &(object_out->std_value)); + ok = platch_decode_value_std(&buffer_cursor, &remaining, &object_out->std_value); if (ok != 0) return ok; break; case kStandardMethodCall: ; @@ -736,17 +776,16 @@ int platch_decode(uint8_t *buffer, size_t size, enum platch_codec codec, struct if (ok != 0) return ok; if (methodname.type != kStdString) { platch_free_value_std(&methodname); - return EPROTO; + return EBADMSG; } object_out->method = methodname.string_value; - ok = platch_decode_value_std(&buffer_cursor, &remaining, &(object_out->std_arg)); + ok = platch_decode_value_std(&buffer_cursor, &remaining, &object_out->std_arg); if (ok != 0) return ok; break; case kStandardMethodCallResponse: ; - object_out->success = read8(&buffer_cursor) == 0; - advance(&buffer_cursor, 1, &remaining); + ok = _read8(&buffer_cursor, (uint8_t*) &object_out->success, &remaining); if (object_out->success) { struct std_value result; @@ -901,15 +940,13 @@ int platch_encode(struct platch_obj *object, uint8_t **buffer_out, size_t *size_ break; case kStandardMethodCallResponse: if (object->success) { - write8(&buffer_cursor, 0x00); - advance(&buffer_cursor, 1); + _write8(&buffer_cursor, 0x00, NULL); ok = platch_write_value_to_buffer_std(&(object->std_result), &buffer_cursor); if (ok != 0) goto free_buffer_and_return_ok; } else { - write8(&buffer_cursor, 0x01); - advance(&buffer_cursor, 1); - + _write8(&buffer_cursor, 0x01, NULL); + ok = platch_write_value_to_buffer_std(&stderrcode, &buffer_cursor); if (ok != 0) goto free_buffer_and_return_ok; ok = platch_write_value_to_buffer_std(&stderrmessage, &buffer_cursor); From ba3fc262a7a6d02d0956a304d09affad13f0a7b9 Mon Sep 17 00:00:00 2001 From: Hannes Winkler Date: Wed, 26 Feb 2020 01:01:22 +0100 Subject: [PATCH 8/8] Rename gpiod- and spidev-plugin build flags --- Makefile | 2 +- src/pluginregistry.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index fc90fba4..d9303e3d 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ CC = cc LD = cc -REAL_CFLAGS = -I./include $(shell pkg-config --cflags gbm libdrm glesv2 egl) -DBUILD_ELM327_PLUGIN -DBUILD_GPIO_PLUGIN -DBUILD_SPI_PLUGIN -DBUILD_TEST_PLUGIN -ggdb $(CFLAGS) +REAL_CFLAGS = -I./include $(shell pkg-config --cflags gbm libdrm glesv2 egl) -DBUILD_ELM327_PLUGIN -DBUILD_GPIOD_PLUGIN -DBUILD_SPIDEV_PLUGIN -DBUILD_TEST_PLUGIN -ggdb $(CFLAGS) REAL_LDFLAGS = $(shell pkg-config --libs gbm libdrm glesv2 egl) -lrt -lflutter_engine -lpthread -ldl $(LDFLAGS) SOURCES = src/flutter-pi.c src/platformchannel.c src/pluginregistry.c src/console_keyboard.c \ diff --git a/src/pluginregistry.c b/src/pluginregistry.c index c73ed87b..7c4f0faa 100644 --- a/src/pluginregistry.c +++ b/src/pluginregistry.c @@ -18,10 +18,10 @@ #ifdef BUILD_ELM327_PLUGIN # include #endif -#ifdef BUILD_GPIO_PLUGIN +#ifdef BUILD_GPIOD_PLUGIN # include #endif -#ifdef BUILD_SPI_PLUGIN +#ifdef BUILD_SPIDEV_PLUGIN # include #endif @@ -57,11 +57,11 @@ struct flutterpi_plugin hardcoded_plugins[] = { {.name = "elm327plugin", .init = ELM327Plugin_init, .deinit = ELM327Plugin_deinit}, #endif -#ifdef BUILD_GPIO_PLUGIN +#ifdef BUILD_GPIOD_PLUGIN {.name = "flutter_gpiod", .init = gpiodp_init, .deinit = gpiodp_deinit}, #endif -#ifdef BUILD_SPI_PLUGIN +#ifdef BUILD_SPIDEV_PLUGIN {.name = "flutter_spidev", .init = spidevp_init, .deinit = spidevp_deinit} #endif };