static void on_connect(void *data, struct sol_mqtt *mqtt) { if (sol_mqtt_get_connection_status(mqtt) != SOL_MQTT_CONNECTED) { SOL_WRN("Unable to connect, retrying..."); sol_timeout_add(1000, try_reconnect, mqtt); return; } if (sol_mqtt_subscribe(mqtt, topic, SOL_MQTT_QOS_AT_MOST_ONCE)) SOL_ERR("Unable to subscribe to topic %s", topic); }
static int watchdog_start(const struct sol_platform_linux_micro_module *mod, const char *service) { int err = 0; int timeout = 60; unsigned int timeout_ms; if (watchdog_fd >= 0) return 0; service_name = service; watchdog_fd = open("/dev/watchdog", O_CLOEXEC | O_WRONLY); if (watchdog_fd < 0) { err = -errno; SOL_WRN("could not open /dev/watchdog: %s", sol_util_strerrora(errno)); goto end; } if (ioctl(watchdog_fd, WDIOC_GETTIMEOUT, &timeout) < 0 || timeout < 1) { timeout = WATCHDOG_TIMEOUT_DEFAULT_SECS; SOL_WRN("could not query watchdog timeout, use %ds", timeout); if (ioctl(watchdog_fd, WDIOC_SETTIMEOUT, &timeout) < 0) { SOL_WRN("could not set watchdog timeout to default %ds: %s. Ignored", timeout, sol_util_strerrora(errno)); } } if (timeout > 5) timeout_ms = (unsigned)(timeout - 5) * 1000U; else timeout_ms = (unsigned)timeout * 900U; watchdog_timeout = sol_timeout_add(timeout_ms, watchdog_keep_alive, NULL); if (!watchdog_timeout) { err = -ENOMEM; SOL_WRN("could not create watchdog_timeout"); close(watchdog_fd); watchdog_fd = -1; goto end; } watchdog_show_info(); end: if (err == 0) sol_platform_linux_micro_inform_service_state(service, SOL_PLATFORM_SERVICE_STATE_ACTIVE); else sol_platform_linux_micro_inform_service_state(service, SOL_PLATFORM_SERVICE_STATE_FAILED); return err; }
static void _reset(void *data) { struct irange_buffer_data *mdata = data; mdata->cur_len = 0; if (mdata->timer) sol_timeout_del(mdata->timer); if (mdata->timeout) mdata->timer = sol_timeout_add(mdata->timeout, _timeout, mdata); }
static int tune_start(struct piezo_speaker_data *mdata) { int r; mdata->curr_idx = 0; r = sol_pwm_set_enabled(mdata->pwm, true); SOL_INT_CHECK(r, < 0, r); mdata->timer = sol_timeout_add(0, timeout_do, mdata); SOL_INT_CHECK(r, < 0, r); return 0; }
static int aio_reader_open(struct sol_flow_node *node, void *data, const struct sol_flow_node_options *options) { int device, pin; struct aio_data *mdata = data; const struct sol_flow_node_type_aio_reader_options *opts = (const struct sol_flow_node_type_aio_reader_options *)options; SOL_FLOW_NODE_OPTIONS_SUB_API_CHECK(opts, SOL_FLOW_NODE_TYPE_AIO_READER_OPTIONS_API_VERSION, -EINVAL); mdata->aio = NULL; mdata->is_first = true; mdata->node = node; if (!opts->pin || *opts->pin == '\0') { SOL_WRN("aio: Option 'pin' cannot be neither 'null' nor empty."); return -EINVAL; } if (opts->mask <= 0) { SOL_WRN("aio (%s): Invalid bit mask value=%" PRId32 ".", opts->pin, opts->mask); return -EINVAL; } if (opts->poll_timeout <= 0) { SOL_WRN("aio (%s): Invalid polling time=%" PRId32 ".", opts->pin, opts->poll_timeout); return -EINVAL; } if (opts->raw) { if (sscanf(opts->pin, "%d %d", &device, &pin) == 2) { mdata->aio = sol_aio_open(device, pin, opts->mask); } else { SOL_WRN("aio (%s): 'raw' option was set, but 'pin' value=%s couldn't be parsed as " "\"<device> <pin>\" pair.", opts->pin, opts->pin); } } else { mdata->aio = sol_aio_open_by_label(opts->pin, opts->mask); } SOL_NULL_CHECK_MSG(mdata->aio, -EINVAL, "aio (%s): Couldn't be open. Maybe you used an invalid 'pin'=%s?", opts->pin, opts->pin); mdata->pin = opts->pin ? strdup(opts->pin) : NULL; mdata->mask = (0x01 << opts->mask) - 1; mdata->timer = sol_timeout_add(opts->poll_timeout, _on_reader_timeout, mdata); return 0; }
static int start_timer(struct timer_data *mdata) { if (mdata->timer) { sol_timeout_del(mdata->timer); mdata->timer = NULL; } if (mdata->interval < 1) return 0; mdata->timer = sol_timeout_add(mdata->interval, timer_tick, mdata); SOL_NULL_CHECK(mdata->timer, -errno); return 0; }
static int flow_delay_send(struct sol_flow_node *flow, struct flow_static_data *fsd) { if (!fsd->delay_send) { /* We want to ensure that all packets will be processed in the * main loop iteration immediately following the current one, even * when the system is loaded enough that it barely has any idle time, * thus a timeout with a 0 value instead of an idler. */ fsd->delay_send = sol_timeout_add(0, flow_send_idle, flow); SOL_NULL_CHECK(fsd->delay_send, -ENOMEM); } return 0; }
static int gyro_timer_resched(struct gyroscope_l3g4200d_data *mdata, unsigned int timeout_ms, bool (*cb)(void *data), const void *cb_data) { SOL_NULL_CHECK(cb, -EINVAL); if (mdata->timer) sol_timeout_del(mdata->timer); mdata->timer = sol_timeout_add(timeout_ms, cb, cb_data); SOL_NULL_CHECK(mdata->timer, -ENOMEM); return 0; }
int main(int argc, char *argv[]) { struct light_context context = { .resource = &light }; struct sol_coap_server *server; char old_led_state; struct sol_network_link_addr servaddr = { .family = SOL_NETWORK_FAMILY_INET6, .port = DEFAULT_UDP_PORT }; sol_init(); server = sol_coap_server_new(&servaddr); if (!server) { SOL_WRN("Could not create a coap server using port %d.", DEFAULT_UDP_PORT); return -1; } if (sol_coap_server_register_resource(server, &light, NULL) < 0) { SOL_WRN("Could not register light resource"); return -1; } console_fd = open("/dev/console", O_RDWR); if (console_fd < 0) { perror("Could not open '/dev/console'"); return -1; } if (ioctl(console_fd, KDGETLED, (char *)&old_led_state)) { perror("Could not get the keyboard leds state"); return -1; } context.server = server; sol_timeout_add(5000, update_light, &context); sol_run(); sol_coap_server_unref(server); if (ioctl(console_fd, KDSETLED, old_led_state)) { perror("Could not return the leds to the old state"); return -1; } return 0; }
static void startup(void) { guint id; if (pipe2(pfd, O_CLOEXEC) < 0) { SOL_WRN("pipe()"); goto error; } if (!sol_glib_integration()) { SOL_WRN("sol_glib_integration()"); goto error; } fork_run = sol_platform_linux_fork_run(on_fork, on_child_exit, NULL); if (!fork_run) { SOL_WRN("sol_platform_linux_fork_run()"); goto error; } id = g_idle_add(on_idle, NULL); if (id == 0) { SOL_WRN("g_idle_add()"); goto error; } id = g_timeout_add(100, on_timeout, NULL); if (id == 0) { SOL_WRN("g_timeout_add()"); goto error; } id = g_unix_fd_add(pfd[0], G_IO_IN, on_fd, NULL); if (id == 0) { SOL_WRN("g_unix_fd_add()"); goto error; } sol_timeout_add(5000, on_watchdog, NULL); return; error: sol_quit_with_code(EXIT_FAILURE); return; }
static bool timeout_do(void *data) { struct piezo_speaker_data *mdata = data; //activate a note (or not, if curr_idx is for a delay) and return //the state mdata->curr_state = tune_iterate(mdata); if (mdata->curr_state == ITER_ERROR) { tune_stop(mdata); return false; } //hold that note for the given delay mdata->timer = sol_timeout_add(mdata->delays_us[mdata->curr_idx] / 1000, be_quiet, mdata); return false; }
//pause between notes for half the tempo static bool be_quiet(void *data) { struct piezo_speaker_data *mdata = data; int r; r = stop_sound(mdata); if (r < 0 || mdata->curr_state == ITER_LAST) { tune_stop(mdata); return false; } mdata->curr_idx = (mdata->curr_idx + 1) % mdata->num_entries; mdata->timer = sol_timeout_add(mdata->tempo_ms / 2, timeout_do, mdata); return false; }
int test_result_open( struct sol_flow_node *node, void *data, const struct sol_flow_node_options *options) { struct test_result_data *d = data; const struct sol_flow_node_type_test_result_options *opts = (const struct sol_flow_node_type_test_result_options *)options; d->timer = sol_timeout_add(opts->timeout.val, on_timeout, node); SOL_NULL_CHECK_GOTO(d->timer, error); node_count++; d->done = false; return 0; error: return -ENOMEM; }
int string_generator_open( struct sol_flow_node *node, void *data, const struct sol_flow_node_options *options) { struct string_generator_data *mdata = data; const struct sol_flow_node_type_test_string_generator_options *opts = (const struct sol_flow_node_type_test_string_generator_options *)options; SOL_FLOW_NODE_OPTIONS_SUB_API_CHECK(options, SOL_FLOW_NODE_TYPE_TEST_STRING_GENERATOR_OPTIONS_API_VERSION, -EINVAL); sol_vector_init(&mdata->values, sizeof(struct sol_str_slice)); if (opts->sequence == NULL || *opts->sequence == '\0') { SOL_ERR("Option 'sequence' is either NULL or empty."); return -EINVAL; } mdata->sequence = strdup(opts->sequence); SOL_NULL_CHECK_GOTO(mdata->sequence, no_memory); if (opts->interval < 0) SOL_WRN("Option 'interval' < 0, setting it to 0."); mdata->interval = opts->interval >= 0 ? opts->interval : 0; mdata->next_index = 0; mdata->values = sol_str_slice_split(sol_str_slice_from_str (mdata->sequence), opts->separator, SIZE_MAX); mdata->timer = sol_timeout_add(mdata->interval, timer_tick, node); SOL_NULL_CHECK_GOTO(mdata->timer, error); return 0; no_memory: errno = -ENOMEM; error: sol_vector_clear(&mdata->values); return errno; }
static int dbus_start(const struct sol_platform_linux_micro_module *mod, const char *service) { if (fork_run) return 0; name = service; fork_run = sol_platform_linux_fork_run(on_fork, on_fork_exit, NULL); if (!fork_run) { sol_platform_linux_micro_inform_service_state(service, SOL_PLATFORM_SERVICE_STATE_FAILED); return -errno; } SOL_DBG("dbus-daemon started as pid=%" PRIu64, (uint64_t)sol_platform_linux_fork_run_get_pid(fork_run)); /* TODO: change to use inotify */ check_timeout = sol_timeout_add(200, on_timeout, NULL); return 0; }
SOL_API bool sol_spi_transfer(struct sol_spi *spi, const uint8_t *tx_user, uint8_t *rx, size_t count, void (*transfer_cb)(void *cb_data, struct sol_spi *spi, const uint8_t *tx, uint8_t *rx, ssize_t status), const void *cb_data) { uint8_t *tx = (uint8_t *)tx_user; SOL_NULL_CHECK(spi, false); SOL_EXP_CHECK(spi->transfer.timeout, false); spi->transfer.intern_allocated_buffer_flags = 0; if (tx == NULL) { tx = calloc(count, sizeof(uint8_t)); SOL_NULL_CHECK(tx, false); spi->transfer.intern_allocated_buffer_flags = INTERN_ALLOCATED_TX_BUFFER; } if (rx == NULL) { rx = calloc(count, sizeof(uint8_t)); SOL_NULL_CHECK_GOTO(rx, rx_alloc_fail); spi->transfer.intern_allocated_buffer_flags = INTERN_ALLOCATED_RX_BUFFER; } spi->transfer.tx = tx; spi->transfer.rx = rx; spi->transfer.count = count; spi->transfer.status = -1; spi->transfer.cb = transfer_cb; spi->transfer.cb_data = cb_data; spi->transfer.timeout = sol_timeout_add(0, spi_timeout_cb, spi); SOL_NULL_CHECK_GOTO(spi->transfer.timeout, timeout_fail); return true; timeout_fail: if (spi->transfer.intern_allocated_buffer_flags & INTERN_ALLOCATED_RX_BUFFER) free(rx); rx_alloc_fail: if (spi->transfer.intern_allocated_buffer_flags & INTERN_ALLOCATED_TX_BUFFER) free(tx); return false; }
SOL_API bool sol_spi_transfer(struct sol_spi *spi, const uint8_t *tx, uint8_t *rx, size_t size, void (*transfer_cb)(void *cb_data, struct sol_spi *spi, const uint8_t *tx, uint8_t *rx, ssize_t status), const void *cb_data) { #ifdef PTHREAD struct sol_worker_thread_spec spec = { .api_version = SOL_WORKER_THREAD_SPEC_API_VERSION, .setup = NULL, .cleanup = NULL, .iterate = spi_worker_thread_iterate, .finished = spi_worker_thread_finished, .feedback = NULL, .data = spi }; #endif SOL_NULL_CHECK(spi, false); SOL_INT_CHECK(size, == 0, false); #ifdef PTHREAD SOL_EXP_CHECK(spi->transfer.worker, false); #else SOL_EXP_CHECK(spi->transfer.timeout, false); #endif spi->transfer.tx = tx; spi->transfer.rx = rx; spi->transfer.count = size; spi->transfer.cb = transfer_cb; spi->transfer.cb_data = cb_data; spi->transfer.status = -1; #ifdef PTHREAD spi->transfer.worker = sol_worker_thread_new(&spec); SOL_NULL_CHECK(spi->transfer.worker, false); #else spi->transfer.timeout = sol_timeout_add(0, spi_timeout_cb, spi); SOL_NULL_CHECK(spi->transfer.timeout, false); #endif return true; }
static int irange_buffer_timeout(struct sol_flow_node *node, void *data, uint16_t port, uint16_t conn_id, const struct sol_flow_packet *packet) { int r; int32_t timeout; struct irange_buffer_data *mdata = data; r = sol_flow_packet_get_irange_value(packet, &timeout); SOL_INT_CHECK(r, < 0, r); if (timeout < 0) SOL_WRN("Invalid 'timeout' value: '%" PRId32 "'. Skipping it.", timeout); mdata->timeout = timeout; if (mdata->timer) sol_timeout_del(mdata->timer); if (mdata->timeout) mdata->timer = sol_timeout_add(mdata->timeout, _timeout, mdata); return r; }
static void on_disconnect(void *data, struct sol_mqtt *mqtt) { SOL_INF("Reconnecting..."); sol_timeout_add(1000, try_reconnect, mqtt); }
static int mytype_func(struct sol_flow_node *node, const struct sol_flow_simplectype_event *ev, void *data) { struct mytype_context *ctx = data; switch (ev->type) { case SOL_FLOW_SIMPLECTYPE_EVENT_TYPE_OPEN: { if (ev->options #ifndef SOL_NO_API_VERSION && ev->options->sub_api == MYTYPE_OPTIONS_SUB_API #endif ) { struct mytype_options *opt = (struct mytype_options *)ev->options; ctx->someint = opt->someint; ctx->somebool = opt->somebool; } /* every 500ms send out a string representing our someint + somebool */ ctx->timer = sol_timeout_add(500, on_timeout, node); if (!ctx->timer) return -ENOMEM; printf("simplectype opened ctx=%p, someint=%d, somebool=%d\n", ctx, ctx->someint, ctx->somebool); return 0; } case SOL_FLOW_SIMPLECTYPE_EVENT_TYPE_CLOSE: { printf("simplectype closed ctx=%p\n", ctx); sol_timeout_del(ctx->timer); return 0; } case SOL_FLOW_SIMPLECTYPE_EVENT_TYPE_PORT_IN_PROCESS: { /* this is to show the port names, ideally one would keep the * indexes and use them here, doing integer comparisons * instead of strcmp() */ if (strcmp(ev->port_name, "IRANGE") == 0) { int32_t val; if (sol_flow_packet_get_irange_value(ev->packet, &val) == 0) { printf("simplectype updated integer from %d to %d\n", ctx->someint, val); ctx->someint = val; return 0; } } else if (strcmp(ev->port_name, "BOOLEAN") == 0) { bool val; if (sol_flow_packet_get_boolean(ev->packet, &val) == 0) { printf("simplectype updated boolean from %d to %d\n", ctx->somebool, val); ctx->somebool = val; return 0; } } printf("simplectype port '%s' got unexpected data!\n", ev->port_name); return -EINVAL; } case SOL_FLOW_SIMPLECTYPE_EVENT_TYPE_PORT_IN_CONNECT: printf("simplectype port IN '%s' id=%d conn=%d connected ctx=%p\n", ev->port_name, ev->port, ev->conn_id, ctx); return 0; case SOL_FLOW_SIMPLECTYPE_EVENT_TYPE_PORT_IN_DISCONNECT: printf("simplectype port IN '%s' id=%d conn=%d disconnected ctx=%p\n", ev->port_name, ev->port, ev->conn_id, ctx); return 0; case SOL_FLOW_SIMPLECTYPE_EVENT_TYPE_PORT_OUT_CONNECT: printf("simplectype port OUT '%s' id=%d conn=%d connected ctx=%p\n", ev->port_name, ev->port, ev->conn_id, ctx); return 0; case SOL_FLOW_SIMPLECTYPE_EVENT_TYPE_PORT_OUT_DISCONNECT: printf("simplectype port OUT '%s' id=%d conn=%d disconnected ctx=%p\n", ev->port_name, ev->port, ev->conn_id, ctx); return 0; } return -EINVAL; }
#include <soletta.h> #include <sol-gpio.h> static struct sol_gpio *led; static struct sol_timeout *timer; static bool timer_cb(void *data) { static bool toggle; toggle = !toggle; sol_gpio_write(led, toggle); return true; } static void startup(void) { struct sol_gpio_config led_conf = { SOL_SET_API_VERSION(.api_version = SOL_GPIO_CONFIG_API_VERSION, ) .dir = SOL_GPIO_DIR_OUT }; led = sol_gpio_open(25, &led_conf); SOL_NULL_CHECK(led); timer = sol_timeout_add(1000, timer_cb, NULL); } SOL_MAIN_DEFAULT(startup, NULL)
if (pin < 0) pin = parse_kcmdline_pin(); if (pin >= 0) { struct sol_gpio_config cfg = { SOL_SET_API_VERSION(.api_version = SOL_GPIO_CONFIG_API_VERSION, ) .dir = SOL_GPIO_DIR_OUT, }; gpio = sol_gpio_open(pin, &cfg); if (gpio) printf("blinking led on gpio pin=%d\n", pin); else fprintf(stderr, "failed to open gpio pin=%d for writing.\n", pin); } timeout = sol_timeout_add(1000, on_timeout, NULL); sol_platform_add_state_monitor(on_platform_state_change, NULL); printf("platform state: %d\n", sol_platform_get_state()); for (itr = services; *itr != NULL; itr++) { sol_platform_add_service_monitor(on_service_change, *itr, NULL); printf("service %s state: %d\n", *itr, sol_platform_get_service_state(*itr)); } } static void shutdown(void) { const char **itr;
errno = -EBUSY; BUSY_CHECK(aio, NULL); aio->async.value = 0; aio->async.read_cb.cb = read_cb; aio->async.dispatch = _aio_read_dispatch; aio->async.cb_data = cb_data; #ifdef WORKER_THREAD aio->async.worker = sol_worker_thread_new(&config); SOL_NULL_CHECK_GOTO(aio->async.worker, err_no_mem); pending = (struct sol_aio_pending *)aio->async.worker; #else aio->async.timeout = sol_timeout_add(0, aio_get_value_timeout_cb, aio); SOL_NULL_CHECK_GOTO(aio->async.timeout, err_no_mem); pending = (struct sol_aio_pending *)aio->async.timeout; #endif errno = 0; return pending; err_no_mem: errno = -ENOMEM; return NULL; } SOL_API void sol_aio_pending_cancel(struct sol_aio *aio, struct sol_aio_pending *pending)
static int32_t _i2c_smbus_ioctl(int dev, uint8_t rw, uint8_t command, size_t size, union i2c_smbus_data *data) { struct i2c_smbus_ioctl_data ioctldata = { .read_write = rw, .command = command, .size = 0, .data = data }; switch (size) { case 1: ioctldata.size = I2C_SMBUS_BYTE_DATA; break; case 2: ioctldata.size = I2C_SMBUS_WORD_DATA; break; default: ioctldata.size = I2C_SMBUS_BLOCK_DATA; } if (ioctl(dev, I2C_SMBUS, &ioctldata) == -1) { return -errno; } return 0; } static void _i2c_write_quick(struct sol_i2c *i2c, bool rw) { struct i2c_smbus_ioctl_data ioctldata = { .read_write = rw, .command = 0, .size = I2C_SMBUS_QUICK, .data = NULL }; if (ioctl(i2c->dev, I2C_SMBUS, &ioctldata) == -1) { SOL_WRN("Unable to perform I2C-SMBus write quick (bus = %u," " device address = %u): %s", i2c->bus, i2c->addr, sol_util_strerrora(errno)); return; } i2c->async.status = 1; } static void _i2c_write_quick_dispatch(struct sol_i2c *i2c) { if (!i2c->async.write_quick_cb.cb) return; i2c->async.write_quick_cb.cb((void *)i2c->async.cb_data, i2c, i2c->async.status); } #ifdef WORKER_THREAD static bool i2c_write_quick_worker_thread_iterate(void *data) { struct sol_i2c *i2c = data; _i2c_write_quick(i2c, (bool)(intptr_t)i2c->async.data); return false; } static void i2c_worker_thread_finished(void *data) { struct sol_i2c *i2c = data; i2c->async.worker = NULL; i2c->async.dispatch(i2c); } #else static bool i2c_write_quick_timeout_cb(void *data) { struct sol_i2c *i2c = data; _i2c_write_quick(i2c, (bool)(intptr_t)i2c->async.data); i2c->async.timeout = NULL; i2c->async.dispatch(i2c); return false; } #endif SOL_API struct sol_i2c_pending * sol_i2c_write_quick(struct sol_i2c *i2c, bool rw, void (*write_quick_cb)(void *cb_data, struct sol_i2c *i2c, ssize_t status), const void *cb_data) { #ifdef WORKER_THREAD struct sol_worker_thread_spec spec = { .api_version = SOL_WORKER_THREAD_SPEC_API_VERSION, .setup = NULL, .cleanup = NULL, .iterate = i2c_write_quick_worker_thread_iterate, .finished = i2c_worker_thread_finished, .feedback = NULL, .data = i2c }; #endif SOL_NULL_CHECK(i2c, NULL); SOL_INT_CHECK(i2c->dev, == 0, NULL); BUSY_CHECK(i2c, NULL); i2c->async.data = (uint8_t *)(long)rw; i2c->async.status = -1; i2c->async.write_quick_cb.cb = write_quick_cb; i2c->async.dispatch = _i2c_write_quick_dispatch; i2c->async.cb_data = cb_data; #ifdef WORKER_THREAD i2c->async.worker = sol_worker_thread_new(&spec); SOL_NULL_CHECK(i2c->async.worker, NULL); return (struct sol_i2c_pending *)i2c->async.worker; #else i2c->async.timeout = sol_timeout_add(0, i2c_write_quick_timeout_cb, i2c); SOL_NULL_CHECK(i2c->async.timeout, NULL); return (struct sol_i2c_pending *)i2c->async.timeout; #endif } static bool write_byte(const struct sol_i2c *i2c, uint8_t byte) { struct i2c_smbus_ioctl_data ioctldata = { .read_write = I2C_SMBUS_WRITE, .command = byte, .size = I2C_SMBUS_BYTE, .data = NULL }; if (ioctl(i2c->dev, I2C_SMBUS, &ioctldata) == -1) { SOL_WRN("Unable to perform I2C-SMBus write byte (bus = %u," " device address = %u): %s", i2c->bus, i2c->addr, sol_util_strerrora(errno)); return false; } return true; } static bool read_byte(const struct sol_i2c *i2c, uint8_t *byte) { union i2c_smbus_data data; struct i2c_smbus_ioctl_data ioctldata = { .read_write = I2C_SMBUS_READ, .command = 0, .size = I2C_SMBUS_BYTE, .data = &data, }; if (ioctl(i2c->dev, I2C_SMBUS, &ioctldata) == -1) { SOL_WRN("Unable to perform I2C-SMBus read byte (bus = %u," " device address = %u): %s", i2c->bus, i2c->addr, sol_util_strerrora(errno)); return false; } *byte = data.byte; return true; } static void _i2c_read(struct sol_i2c *i2c, uint8_t *values) { size_t i; for (i = 0; i < i2c->async.count; i++) { uint8_t byte; if (!read_byte(i2c, &byte)) return; *values = byte; values++; } i2c->async.status = i2c->async.count; } static void _i2c_read_write_dispatch(struct sol_i2c *i2c) { if (!i2c->async.read_write_cb.cb) return; i2c->async.read_write_cb.cb((void *)i2c->async.cb_data, i2c, i2c->async.data, i2c->async.status); } #ifdef WORKER_THREAD static bool i2c_read_worker_thread_iterate(void *data) { struct sol_i2c *i2c = data; _i2c_read(i2c, i2c->async.data); return false; } #else static bool i2c_read_timeout_cb(void *data) { struct sol_i2c *i2c = data; _i2c_read(i2c, i2c->async.data); i2c->async.timeout = NULL; i2c->async.dispatch(i2c); return false; } #endif SOL_API struct sol_i2c_pending * sol_i2c_read(struct sol_i2c *i2c, uint8_t *values, size_t count, void (*read_cb)(void *cb_data, struct sol_i2c *i2c, uint8_t *data, ssize_t status), const void *cb_data) { #ifdef WORKER_THREAD struct sol_worker_thread_spec spec = { .api_version = SOL_WORKER_THREAD_SPEC_API_VERSION, .setup = NULL, .cleanup = NULL, .iterate = i2c_read_worker_thread_iterate, .finished = i2c_worker_thread_finished, .feedback = NULL, .data = i2c }; #endif SOL_NULL_CHECK(i2c, NULL); SOL_NULL_CHECK(values, NULL); SOL_INT_CHECK(count, == 0, NULL); SOL_INT_CHECK(i2c->dev, == 0, NULL); BUSY_CHECK(i2c, NULL); i2c->async.data = values; i2c->async.count = count; i2c->async.status = -1; i2c->async.read_write_cb.cb = read_cb; i2c->async.dispatch = _i2c_read_write_dispatch; i2c->async.cb_data = cb_data; #ifdef WORKER_THREAD i2c->async.worker = sol_worker_thread_new(&spec); SOL_NULL_CHECK(i2c->async.worker, NULL); return (struct sol_i2c_pending *)i2c->async.worker; #else i2c->async.timeout = sol_timeout_add(0, i2c_read_timeout_cb, i2c); SOL_NULL_CHECK(i2c->async.timeout, NULL); return (struct sol_i2c_pending *)i2c->async.timeout; #endif } static void _i2c_write(struct sol_i2c *i2c, uint8_t *values) { size_t i; for (i = 0; i < i2c->async.count; i++) { if (!write_byte(i2c, *values)) return; values++; } i2c->async.status = i2c->async.count; } #ifdef WORKER_THREAD static bool i2c_write_worker_thread_iterate(void *data) { struct sol_i2c *i2c = data; _i2c_write(i2c, i2c->async.data); return false; } #else static bool i2c_write_timeout_cb(void *data) { struct sol_i2c *i2c = data; _i2c_write(i2c, i2c->async.data); i2c->async.timeout = NULL; i2c->async.dispatch(i2c); return false; } #endif SOL_API struct sol_i2c_pending * sol_i2c_write(struct sol_i2c *i2c, uint8_t *values, size_t count, void (*write_cb)(void *cb_data, struct sol_i2c *i2c, uint8_t *data, ssize_t status), const void *cb_data) { #ifdef WORKER_THREAD struct sol_worker_thread_spec spec = { .api_version = SOL_WORKER_THREAD_SPEC_API_VERSION, .setup = NULL, .cleanup = NULL, .iterate = i2c_write_worker_thread_iterate, .finished = i2c_worker_thread_finished, .feedback = NULL, .data = i2c }; #endif SOL_NULL_CHECK(i2c, NULL); SOL_NULL_CHECK(values, NULL); SOL_INT_CHECK(count, == 0, NULL); SOL_INT_CHECK(i2c->dev, == 0, NULL); BUSY_CHECK(i2c, NULL); i2c->async.data = values; i2c->async.count = count; i2c->async.status = -1; i2c->async.read_write_cb.cb = write_cb; i2c->async.dispatch = _i2c_read_write_dispatch; i2c->async.cb_data = cb_data; #ifdef WORKER_THREAD i2c->async.worker = sol_worker_thread_new(&spec); SOL_NULL_CHECK(i2c->async.worker, NULL); return (struct sol_i2c_pending *)i2c->async.worker; #else i2c->async.timeout = sol_timeout_add(0, i2c_write_timeout_cb, i2c); SOL_NULL_CHECK(i2c->async.timeout, NULL); return (struct sol_i2c_pending *)i2c->async.timeout; #endif } static int sol_i2c_plain_read_register(const struct sol_i2c *i2c, uint8_t command, uint8_t *values, size_t count) { struct i2c_msg msgs[] = { { .addr = i2c->addr, .flags = 0, .len = 1, .buf = &command }, { .addr = i2c->addr, .flags = I2C_M_RD, .len = count, .buf = values, } };
#else SOL_EXP_CHECK(spi->transfer.timeout, false); #endif spi->transfer.tx = tx; spi->transfer.rx = rx; spi->transfer.count = size; spi->transfer.cb = transfer_cb; spi->transfer.cb_data = cb_data; spi->transfer.status = -1; #ifdef WORKER_THREAD spi->transfer.worker = sol_worker_thread_new(&spec); SOL_NULL_CHECK(spi->transfer.worker, false); #else spi->transfer.timeout = sol_timeout_add(0, spi_timeout_cb, spi); SOL_NULL_CHECK(spi->transfer.timeout, false); #endif return true; } SOL_API void sol_spi_close(struct sol_spi *spi) { SOL_NULL_CHECK(spi); #ifdef WORKER_THREAD if (spi->transfer.worker) { sol_worker_thread_cancel(spi->transfer.worker); }