示例#1
0
int
main(int argc, char *argv[])
{
    int r = 0;

    if (sol_init() < 0)
        return EXIT_FAILURE;

    printf("Initial platform state: %d\n", sol_platform_get_state());
    sol_platform_add_state_monitor(on_state_change, NULL);

    if (argc > 2) {
        cmds = argv + 1;
        n_cmds = argc - 1;
        timeout_handle = sol_timeout_add(CMD_TICK, on_timeout_cmd, NULL);
    }

    sol_run();

    if (timeout_handle)
        sol_timeout_del(timeout_handle);

    sol_platform_del_state_monitor(on_state_change, NULL);

    sol_shutdown();

    return r;
}
static void
flow_node_close(struct sol_flow_node *node, void *data)
{
    struct flow_static_type *type = (struct flow_static_type *)node->type;
    struct flow_static_data *fsd = data;
    int i;

    if (fsd->delay_send)
        sol_timeout_del(fsd->delay_send);
    while (!sol_list_is_empty(&fsd->delayed_packets)) {
        struct delayed_packet *dp;
        struct sol_list *itr = fsd->delayed_packets.next;
        dp = SOL_LIST_GET_CONTAINER(itr, struct delayed_packet, list);
        sol_list_remove(itr);
        sol_flow_packet_del(dp->packet);
        free(dp);
    }

    teardown_connections(type, fsd);

    for (i = type->node_count - 1; i >= 0; i--)
        sol_flow_node_fini(fsd->nodes[i]);

    free(fsd->node_storage);
    free(fsd->nodes);

    if (type->owned_by_node)
        sol_flow_static_del_type(&type->base.base);
}
示例#3
0
/**
 * This destructor method is called when the node is finished.
 *
 * When this method returns the memory pointed by 'data' is released
 * and should stop being referenced.
 */
static void
reader_close(struct sol_flow_node *node, void *data)
{
    struct reader_data *mdata = data;

    /* stop the timer */
    sol_timeout_del(mdata->timer);
}
示例#4
0
void
test_result_close(struct sol_flow_node *node, void *data)
{
    struct test_result_data *d = data;

    if (d->timer)
        sol_timeout_del(d->timer);
}
示例#5
0
static void
thingspeak_channel_update_queue(struct thingspeak_channel_update_data *mdata)
{
    if (mdata->timeout)
        sol_timeout_del(mdata->timeout);
    mdata->timeout = sol_timeout_add(500, thingspeak_channel_update_send,
        mdata);
    if (!mdata->timeout)
        SOL_WRN("Could not create timeout to update Thingspeak channel");
}
示例#6
0
void
int_generator_close(struct sol_flow_node *node, void *data)
{
    struct int_generator_data *mdata = data;

    if (mdata->values.len != mdata->next_index)
        sol_timeout_del(mdata->timer);

    sol_vector_clear(&mdata->values);
}
示例#7
0
void
boolean_generator_close(struct sol_flow_node *node, void *data)
{
    struct boolean_generator_data *mdata = data;

    if (*mdata->it != '\0')
        sol_timeout_del(mdata->timer);

    free(mdata->sequence);
}
示例#8
0
文件: timer.c 项目: Learn-iot/soletta
static int
stop_timer(struct timer_data *mdata)
{
    if (!mdata->timer)
        return 0;

    sol_timeout_del(mdata->timer);
    mdata->timer = NULL;
    return 0;
}
示例#9
0
static bool
on_timeout_del_and_new(void *data)
{
    struct sol_timeout *timeout_to_del = data;

    timeout_called++;
    ASSERT_INT_EQ(sol_timeout_del(timeout_to_del), 1);
    sol_timeout_add(250, on_timeout_quit, NULL);
    sol_timeout_add(200, on_timeout_chained, NULL);
    return false;
}
示例#10
0
static void
gyroscope_l3g4200d_close(struct sol_flow_node *node, void *data)
{
    struct gyroscope_l3g4200d_data *mdata = data;

    if (mdata->timer)
        sol_timeout_del(mdata->timer);

    if (mdata->i2c)
        sol_i2c_close(mdata->i2c);
}
示例#11
0
SOL_API void
sol_spi_close(struct sol_spi *spi)
{
    SOL_NULL_CHECK(spi);
    if (spi->transfer.timeout) {
        sol_timeout_del(spi->transfer.timeout);
        spi_transfer_dispatch(spi);
    }
    spi_poweroff(spi->bus);
    free(spi);
}
示例#12
0
static int
tune_stop(struct piezo_speaker_data *mdata)
{
    if (!mdata->timer)
        return 0;

    sol_timeout_del(mdata->timer);
    mdata->timer = NULL;

    return sol_pwm_set_enabled(mdata->pwm, false);
}
示例#13
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);
}
示例#14
0
static void
irange_buffer_close(struct sol_flow_node *node, void *data)
{
    struct irange_buffer_data *mdata = data;

    if (mdata->timer) {
        sol_timeout_del(mdata->timer);
        mdata->timer = NULL;
    }

    free(mdata->input_queue);
}
示例#15
0
static void
accelerometer_lsm303_close(struct sol_flow_node *node, void *data)
{
    struct accelerometer_lsm303_data *mdata = data;

    if (mdata->timer)
        sol_timeout_del(mdata->timer);

    if (mdata->i2c_pending)
        sol_i2c_pending_cancel(mdata->i2c, mdata->i2c_pending);
    if (mdata->i2c)
        sol_i2c_close(mdata->i2c);
}
示例#16
0
static void
shutdown(void)
{
    const char **itr;

    if (gpio)
        sol_gpio_close(gpio);
    sol_timeout_del(timeout);

    for (itr = services; *itr != NULL; itr++)
        sol_platform_del_service_monitor(on_service_change, *itr, NULL);
    sol_platform_del_state_monitor(on_platform_state_change, NULL);
}
示例#17
0
static void
temperature_stts751_close(struct sol_flow_node *node, void *data)
{
    struct stts751_data *mdata = data;

    if (mdata->i2c_pending)
        sol_i2c_pending_cancel(mdata->i2c, mdata->i2c_pending);
    if (mdata->i2c)
        sol_i2c_close(mdata->i2c);

    if (mdata->timer)
        sol_timeout_del(mdata->timer);
}
示例#18
0
static void
thingspeak_execute_close(struct sol_flow_node *node, void *data)
{
    struct thingspeak_execute_data *mdata = data;
    struct sol_http_client_connection *connection;
    uint16_t i;

    sol_timeout_del(mdata->timeout);
    free_talkback(&mdata->talkback);

    SOL_PTR_VECTOR_FOREACH_IDX (&mdata->pending_conns, connection, i)
        sol_http_client_connection_cancel(connection);
    sol_ptr_vector_clear(&mdata->pending_conns);
}
示例#19
0
文件: aio.c 项目: NilayNigam/soletta
static void
aio_close(struct sol_flow_node *node, void *data)
{
    struct aio_data *mdata = data;

    SOL_NULL_CHECK(mdata);

    free(mdata->pin);

    if (mdata->aio)
        sol_aio_close(mdata->aio);
    if (mdata->timer)
        sol_timeout_del(mdata->timer);
}
示例#20
0
文件: dbus.c 项目: nagineni/soletta
static void
on_fork_exit(void *data, uint64_t pid, int status)
{
    if (check_timeout) {
        sol_timeout_del(check_timeout);
        check_timeout = NULL;
    }

    SOL_DBG("dbus-daemon pid=%" PRIu64 " exited with status=%d", pid, status);

    if (status)
        sol_platform_linux_micro_inform_service_state(name, SOL_PLATFORM_SERVICE_STATE_FAILED);
    else
        sol_platform_linux_micro_inform_service_state(name, SOL_PLATFORM_SERVICE_STATE_INACTIVE);
}
示例#21
0
文件: timer.c 项目: Learn-iot/soletta
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;
}
示例#22
0
static int
watchdog_stop(const struct sol_platform_linux_micro_module *module, const char *service, bool force_immediate)
{
    if (watchdog_fd < 0)
        return 0;

    sol_timeout_del(watchdog_timeout);
    watchdog_timeout = NULL;

    close(watchdog_fd);
    watchdog_fd = -1;

    sol_platform_linux_micro_inform_service_state(service, SOL_PLATFORM_SERVICE_STATE_INACTIVE);
    service_name = NULL;
    return 0;
}
示例#23
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;
}
示例#24
0
SOL_API void
sol_spi_close(struct sol_spi *spi)
{
    SOL_NULL_CHECK(spi);

#ifdef PTHREAD
    if (spi->transfer.worker) {
        sol_worker_thread_cancel(spi->transfer.worker);
    }
#else
    if (spi->transfer.timeout) {
        sol_timeout_del(spi->transfer.timeout);
        spi_transfer_dispatch(spi);
    }
#endif
    close(spi->fd);

    free(spi);
}
示例#25
0
static void
thingspeak_channel_update_close(struct sol_flow_node *node, void *data)
{
    struct thingspeak_channel_update_data *mdata = data;
    struct sol_http_client_connection *connection;
    uint16_t i;

    for (i = 0; i < ARRAY_SIZE(mdata->fields); i++)
        free(mdata->fields[i]);
    free(mdata->status);

    free(mdata->api_key);
    free(mdata->endpoint);

    sol_timeout_del(mdata->timeout);

    SOL_PTR_VECTOR_FOREACH_IDX (&mdata->pending_conns, connection, i)
        sol_http_client_connection_cancel(connection);
    sol_ptr_vector_clear(&mdata->pending_conns);
}
示例#26
0
文件: dbus.c 项目: nagineni/soletta
static int
dbus_stop(const struct sol_platform_linux_micro_module *mod, const char *service, bool force_immediate)
{
    int err = 0;

    if (!fork_run)
        return 0;

    if (!force_immediate)
        err = sol_platform_linux_fork_run_send_signal(fork_run, SIGTERM);
    else {
        sol_platform_linux_fork_run_stop(fork_run);
        fork_run = NULL;
    }

    if (check_timeout) {
        sol_timeout_del(check_timeout);
        check_timeout = NULL;
    }

    return err;
}
示例#27
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;
}
示例#28
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;
}
示例#29
0
static void
i2c_read_data_cb(void *cb_data, struct sol_i2c *i2c, uint8_t reg, uint8_t *data, ssize_t status)
{
    struct gyroscope_l3g4200d_data *mdata = cb_data;
    double scale = mdata->use_rad ? GYRO_SCALE_R_S * DEG_TO_RAD : GYRO_SCALE_R_S;
    uint8_t num_samples_available;
    struct sol_direction_vector val =
    {
        .min = -GYRO_RANGE,
        .max = GYRO_RANGE,
        .x = mdata->reading[0],
        .y = mdata->reading[1],
        .z = mdata->reading[2]
    };

    mdata->i2c_pending = NULL;
    if (status < 0) {
        SOL_WRN("Failed to read L3G4200D gyro fifo status");
        return;
    }

    num_samples_available = status / (sizeof(int16_t) * 3);

    /* raw readings, with only the sensor-provided filtering */
    for (uint8_t i = 0; i < num_samples_available; i++) {
        mdata->reading[0] = mdata->gyro_data.buffer[i][0] * scale;
        mdata->reading[1] = -mdata->gyro_data.buffer[i][1] * scale;
        mdata->reading[2] = -mdata->gyro_data.buffer[i][2] * scale;
    }

    sol_flow_send_direction_vector_packet(mdata->node,
        SOL_FLOW_NODE_TYPE_GYROSCOPE_L3G4200D__OUT__OUT, &val);

    mdata->pending_ticks--;
    if (mdata->pending_ticks)
        gyro_tick_do(mdata);
}

static void
i2c_read_fifo_status_cb(void *cb_data, struct sol_i2c *i2c, uint8_t reg, uint8_t *data, ssize_t status)
{
    struct gyroscope_l3g4200d_data *mdata = cb_data;
    uint8_t num_samples_available;
    uint8_t fifo_status = mdata->common.buffer[0];

    mdata->i2c_pending = NULL;
    if (status < 0) {
        SOL_WRN("Failed to read L3G4200D gyro fifo status");
        return;
    }

    if (fifo_status & GYRO_REG_FIFO_SRC_OVERRUN) {
        num_samples_available = 32;
    } else if (fifo_status & GYRO_REG_FIFO_SRC_EMPTY) {
        num_samples_available = 0;
    } else {
        num_samples_available = fifo_status
            & GYRO_REG_FIFO_SRC_ENTRIES_MASK;
    }

    if (!num_samples_available) {
        SOL_INF("No samples available");
        return;
    }

    SOL_DBG("%d samples available", num_samples_available);

    /* Read *all* the entries in one go, using AUTO_INCREMENT */
    mdata->i2c_pending = sol_i2c_read_register(mdata->i2c,
        GYRO_REG_XL | GYRO_REG_AUTO_INCREMENT,
        (uint8_t *)&mdata->gyro_data.buffer[0][0],
        sizeof(mdata->gyro_data.buffer), i2c_read_data_cb, mdata);
    if (!mdata->i2c_pending)
        SOL_WRN("Failed to read L3G4200D gyro samples");
}

static bool
gyro_tick_do(void *data)
{
    struct gyroscope_l3g4200d_data *mdata = data;

    mdata->timer = NULL;
    if (sol_i2c_busy(mdata->i2c)) {
        gyro_timer_resched(mdata, GYRO_INIT_STEP_TIME, gyro_tick_do);
        return false;
    }

    if (!sol_i2c_set_slave_address(mdata->i2c, GYRO_ADDRESS)) {
        SOL_WRN("Failed to set slave at address 0x%02x\n", GYRO_ADDRESS);
        return false;
    }

    mdata->common.buffer[0] = 0;
    mdata->i2c_pending = sol_i2c_read_register(mdata->i2c, GYRO_REG_FIFO_SRC,
        mdata->common.buffer, 1, i2c_read_fifo_status_cb, mdata);
    if (!mdata->i2c_pending)
        SOL_WRN("Failed to read L3G4200D gyro fifo status");

    return false;
}

static bool
gyro_ready(void *data)
{
    struct gyroscope_l3g4200d_data *mdata = data;

    mdata->ready = true;
    SOL_DBG("gyro is ready for reading");

    if (mdata->pending_ticks)
        gyro_tick_do(mdata);

    return false;
}

static void
i2c_write_fifo_ctl_cb(void *cb_data, struct sol_i2c *i2c, uint8_t reg, uint8_t *data, ssize_t status)
{
    struct gyroscope_l3g4200d_data *mdata = cb_data;

    mdata->i2c_pending = NULL;
    if (status < 0) {
        SOL_WRN("could not set L3G4200D gyro sensor's stream mode");
        return;
    }

    if (gyro_timer_resched(mdata, GYRO_INIT_STEP_TIME, gyro_ready) < 0)
        SOL_WRN("error in scheduling a L3G4200D gyro's init command");
}

static bool
gyro_init_stream(void *data)
{
    struct gyroscope_l3g4200d_data *mdata = data;

    mdata->timer = NULL;
    if (sol_i2c_busy(mdata->i2c)) {
        gyro_timer_resched(mdata, GYRO_INIT_STEP_TIME, gyro_init_stream);
        return false;
    }

    if (!sol_i2c_set_slave_address(mdata->i2c, GYRO_ADDRESS)) {
        SOL_WRN("Failed to set slave at address 0x%02x\n", GYRO_ADDRESS);
        return false;
    }

    /* enable FIFO in stream mode */
    mdata->common.buffer[0] = GYRO_REG_FIFO_CTL_STREAM;
    mdata->i2c_pending = sol_i2c_write_register(mdata->i2c, GYRO_REG_FIFO_CTL,
        mdata->common.buffer, 1, i2c_write_fifo_ctl_cb, mdata);
    if (!mdata->i2c_pending)
        SOL_WRN("could not set L3G4200D gyro sensor's stream mode");

    return false;
}

static void
i2c_write_ctrl_reg5_cb(void *cb_data, struct sol_i2c *i2c, uint8_t reg, uint8_t *data, ssize_t status)
{
    struct gyroscope_l3g4200d_data *mdata = cb_data;

    mdata->i2c_pending = NULL;
    if (status < 0) {
        SOL_WRN("could not set L3G4200D gyro sensor's fifo mode");
        return;
    }

    if (gyro_timer_resched(mdata, GYRO_INIT_STEP_TIME,
        gyro_init_stream) < 0)
        SOL_WRN("error in scheduling a L3G4200D gyro's init command");
}

static bool
gyro_init_fifo(void *data)
{
    struct gyroscope_l3g4200d_data *mdata = data;

    mdata->timer = NULL;
    if (sol_i2c_busy(mdata->i2c)) {
        gyro_timer_resched(mdata, GYRO_INIT_STEP_TIME, gyro_init_fifo);
        return false;
    }

    if (!sol_i2c_set_slave_address(mdata->i2c, GYRO_ADDRESS)) {
        SOL_WRN("Failed to set slave at address 0x%02x\n", GYRO_ADDRESS);
        return false;
    }

    mdata->common.buffer[0] = GYRO_REG_CTRL_REG5_FIFO_EN;
    mdata->i2c_pending = sol_i2c_write_register(mdata->i2c, GYRO_REG_CTRL_REG5,
        mdata->common.buffer, 1, i2c_write_ctrl_reg5_cb, mdata);
    if (!mdata->i2c_pending)
        SOL_WRN("could not set L3G4200D gyro sensor's fifo mode");

    return false;
}

static void
i2c_write_ctrl_reg4_cb(void *cb_data, struct sol_i2c *i2c, uint8_t reg, uint8_t *data, ssize_t status)
{
    struct gyroscope_l3g4200d_data *mdata = cb_data;

    mdata->i2c_pending = NULL;
    if (status < 0) {
        SOL_WRN("could not set L3G4200D gyro sensor's resolution");
        return;
    }

    if (gyro_timer_resched(mdata, GYRO_INIT_STEP_TIME,
        gyro_init_fifo) < 0)
        SOL_WRN("error in scheduling a L3G4200D gyro's init command");
}

static bool
gyro_init_range(void *data)
{
    struct gyroscope_l3g4200d_data *mdata = data;

    mdata->timer = NULL;
    if (sol_i2c_busy(mdata->i2c)) {
        gyro_timer_resched(mdata, GYRO_INIT_STEP_TIME, gyro_init_range);
        return false;
    }

    if (!sol_i2c_set_slave_address(mdata->i2c, GYRO_ADDRESS)) {
        SOL_WRN("Failed to set slave at address 0x%02x\n", GYRO_ADDRESS);
        return false;
    }

    /* setup for 2000 degrees/sec */
    mdata->common.buffer[0] = GYRO_REG_CTRL_REG4_FS_2000;
    mdata->i2c_pending = sol_i2c_write_register(mdata->i2c, GYRO_REG_CTRL_REG4,
        mdata->common.buffer, 1, i2c_write_ctrl_reg4_cb, mdata);
    if (!mdata->i2c_pending)
        SOL_WRN("could not set L3G4200D gyro sensor's resolution");

    return false;
}

static bool gyro_init_sampling(void *data);

static void
i2c_write_ctrl_reg1_cb(void *cb_data, struct sol_i2c *i2c, uint8_t reg, uint8_t *data, ssize_t status)
{
    struct gyroscope_l3g4200d_data *mdata = cb_data;

    mdata->i2c_pending = NULL;
    if (status < 0) {
        SOL_WRN("could not set L3G4200D gyro sensor's sampling rate");
        return;
    }

    mdata->init_sampling_cnt--;

    if (gyro_timer_resched(mdata, GYRO_INIT_STEP_TIME,
        mdata->init_sampling_cnt ?
        gyro_init_sampling : gyro_init_range) < 0) {
        SOL_WRN("error in scheduling a L3G4200D gyro's init command");
    }
}

/* meant to run 3 times */
static bool
gyro_init_sampling(void *data)
{
    struct gyroscope_l3g4200d_data *mdata = data;

    mdata->timer = NULL;
    if (sol_i2c_busy(mdata->i2c)) {
        gyro_timer_resched(mdata, GYRO_INIT_STEP_TIME, gyro_init_sampling);
        return false;
    }

    if (!sol_i2c_set_slave_address(mdata->i2c, GYRO_ADDRESS)) {
        SOL_WRN("Failed to set slave at address 0x%02x\n", GYRO_ADDRESS);
        return false;
    }

    /* setup for 800Hz sampling with 110Hz filter */
    mdata->common.buffer[0] = GYRO_REG_CTRL_REG1_DRBW_800_110 |
        GYRO_REG_CTRL_REG1_PD | GYRO_REG_CTRL_REG1_XYZ_ENABLE;
    mdata->i2c_pending = sol_i2c_write_register(mdata->i2c, GYRO_REG_CTRL_REG1,
        mdata->common.buffer, 1, i2c_write_ctrl_reg1_cb, mdata);
    if (!mdata->i2c_pending)
        SOL_WRN("could not set L3G4200D gyro sensor's sampling rate");

    return false;
}

static void
i2c_read_who_am_i_cb(void *cb_data, struct sol_i2c *i2c, uint8_t reg, uint8_t *data, ssize_t status)
{
    struct gyroscope_l3g4200d_data *mdata = cb_data;

    mdata->i2c_pending = NULL;
    if (status < 0) {
        SOL_WRN("Failed to read i2c register");
        return;
    }

    if (mdata->common.buffer[0] != GYRO_REG_WHO_AM_I_VALUE) {
        SOL_WRN("could not find L3G4200D gyro sensor");
        return;
    }

    gyro_timer_resched(mdata, GYRO_INIT_STEP_TIME, gyro_init_sampling);
}

static bool
gyro_init(void *data)
{
    struct gyroscope_l3g4200d_data *mdata = data;

    mdata->timer = NULL;
    if (sol_i2c_busy(mdata->i2c)) {
        gyro_timer_resched(mdata, GYRO_INIT_STEP_TIME, gyro_init);
        return false;
    }

    if (!sol_i2c_set_slave_address(mdata->i2c, GYRO_ADDRESS)) {
        SOL_WRN("Failed to set slave at address 0x%02x\n",
            GYRO_ADDRESS);
        return false;
    }

    mdata->i2c_pending = sol_i2c_read_register(mdata->i2c, GYRO_REG_WHO_AM_I,
        mdata->common.buffer, 1, i2c_read_who_am_i_cb, mdata);
    if (!mdata->i2c_pending)
        SOL_WRN("Failed to read i2c register");

    return false;
}

static int
gyroscope_l3g4200d_open(struct sol_flow_node *node,
    void *data,
    const struct sol_flow_node_options *options)
{
    struct gyroscope_l3g4200d_data *mdata = data;
    const struct sol_flow_node_type_gyroscope_l3g4200d_options *opts =
        (const struct sol_flow_node_type_gyroscope_l3g4200d_options *)options;

    SOL_NULL_CHECK(options, -EINVAL);

    mdata->i2c = sol_i2c_open(opts->i2c_bus, I2C_SPEED);
    SOL_NULL_CHECK_MSG(mdata->i2c, -EIO, "Failed to open i2c bus");

    mdata->use_rad = opts->output_radians;
    mdata->init_sampling_cnt = 3;
    mdata->node = node;

    gyro_init(mdata);

    return 0;
}

static void
gyroscope_l3g4200d_close(struct sol_flow_node *node, void *data)
{
    struct gyroscope_l3g4200d_data *mdata = data;

    if (mdata->i2c_pending)
        sol_i2c_pending_cancel(mdata->i2c, mdata->i2c_pending);
    if (mdata->i2c)
        sol_i2c_close(mdata->i2c);

    if (mdata->timer)
        sol_timeout_del(mdata->timer);
}

static int
gyroscope_l3g4200d_tick(struct sol_flow_node *node,
    void *data,
    uint16_t port,
    uint16_t conn_id,
    const struct sol_flow_packet *packet)
{
    struct gyroscope_l3g4200d_data *mdata = data;

    if (!mdata->ready || mdata->pending_ticks) {
        mdata->pending_ticks++;
        return 0;
    }

    gyro_tick_do(mdata);
    return 0;
}