Example #1
0
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);
}
Example #2
0
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;
}
Example #3
0
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);
}
Example #4
0
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;
}
Example #5
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;
}
Example #6
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;
}
Example #8
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;
}
Example #9
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;
}
Example #11
0
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;
}
Example #12
0
//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;
}
Example #13
0
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;
}
Example #14
0
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;
}
Example #15
0
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;
}
Example #16
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;
}
Example #17
0
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;
}
Example #18
0
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;
}
Example #19
0
static void
on_disconnect(void *data, struct sol_mqtt *mqtt)
{
    SOL_INF("Reconnecting...");
    sol_timeout_add(1000, try_reconnect, mqtt);
}
Example #20
0
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;
}
Example #21
0
#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)
Example #24
0
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,
        }
    };
Example #25
0
#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);
    }