SOL_API struct sol_update_handle * sol_update_install(void (*cb)(void *data, int status), const void *data) { SOL_NULL_CHECK_MSG(update_module, NULL, "No update module found"); SOL_NULL_CHECK_MSG(update_module->install, NULL, "No install function on update module"); return update_module->install(cb, data); }
SOL_API int sol_update_get_progress(struct sol_update_handle *handle) { SOL_NULL_CHECK_MSG(update_module, -EINVAL, "No update module found"); SOL_NULL_CHECK_MSG(update_module->get_progress, -ENOTSUP, "No progress function on update module"); return update_module->get_progress(handle); }
/* TODO should a cancel remove downloaded stuff? Shall we have a pause? * Shall we allow cancelling of 'install'? */ SOL_API bool sol_update_cancel(struct sol_update_handle *handle) { SOL_NULL_CHECK_MSG(update_module, false, "No update module found"); SOL_NULL_CHECK_MSG(update_module->cancel, false, "No cancel function on update module"); return update_module->cancel(handle); }
SOL_API struct sol_update_handle * sol_update_fetch(void (*cb)(void *data, int status), const void *data, bool resume) { SOL_NULL_CHECK_MSG(update_module, NULL, "No update module found"); SOL_NULL_CHECK_MSG(update_module->fetch, NULL, "No fetch function on update module"); return update_module->fetch(cb, data, resume); }
SOL_API struct sol_update_handle * sol_update_check( void (*cb)(void *data, int status, const struct sol_update_info *response), const void *data) { SOL_NULL_CHECK_MSG(update_module, NULL, "No update module found"); SOL_NULL_CHECK_MSG(update_module->check, NULL, "No check function on update module"); return update_module->check(cb, data); }
static int platform_service_open(struct sol_flow_node *node, void *data, const struct sol_flow_node_options *options) { struct platform_service_data *mdata = data; const struct sol_flow_node_type_platform_service_options *opts; SOL_NULL_CHECK_MSG(options, -1, "Platform Service Node: Options not found."); opts = (const struct sol_flow_node_type_platform_service_options *)options; SOL_FLOW_NODE_OPTIONS_SUB_API_CHECK(options, SOL_FLOW_NODE_TYPE_PLATFORM_SERVICE_OPTIONS_API_VERSION, -EINVAL); mdata->node = node; if (!opts->name) return 0; mdata->service_name = strdup(opts->name); SOL_NULL_CHECK(mdata->service_name, -ENOMEM); sol_platform_add_service_monitor(on_service_state_changed, mdata->service_name, mdata); mdata->state = sol_platform_get_service_state(mdata->service_name); return sol_flow_send_boolean_packet(node, SOL_FLOW_NODE_TYPE_PLATFORM_SERVICE__OUT__ACTIVE, (mdata->state == SOL_PLATFORM_SERVICE_STATE_ACTIVE)); }
static int temperature_stts751_open(struct sol_flow_node *node, void *data, const struct sol_flow_node_options *options) { struct stts751_data *mdata = data; const struct sol_flow_node_type_stts751_options *opts; SOL_FLOW_NODE_OPTIONS_SUB_API_CHECK(options, SOL_FLOW_NODE_TYPE_STTS751_OPTIONS_API_VERSION, -EINVAL); opts = (const struct sol_flow_node_type_stts751_options *)options; mdata->node = node; mdata->i2c = sol_i2c_open(opts->i2c_bus, SOL_I2C_SPEED_10KBIT); SOL_NULL_CHECK_MSG(mdata->i2c, -EINVAL, "Failed to open i2c bus"); mdata->slave = opts->i2c_slave; mdata->resolution = opts->temperature_resolution; if (mdata->resolution < 9 || mdata->resolution > 12) { SOL_WRN("Invalid temperature resolution bits for STTS751 %d. " "Must be between 9 and 12. Falling back to 10.", mdata->resolution); mdata->resolution = 10; } stts751_init(mdata); 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 hostname_start(const struct sol_platform_linux_micro_module *mod, const char *service) { struct sol_file_reader *reader; struct sol_str_slice str; const char *s, *p, *end; int err = 0; reader = sol_file_reader_open("/etc/hostname"); SOL_NULL_CHECK_MSG(reader, -errno, "could not read /etc/hostname"); str = sol_file_reader_get_all(reader); s = p = str.data; end = s + str.len; for (; s < end; s++) { if (!isblank(*s)) break; } for (p = end - 1; p > s; p--) { if (!isblank(*p)) break; } if (s >= p) { SOL_WRN("no hostname in /etc/hostname"); err = -ENOENT; } else if (sethostname(s, p - s) < 0) { SOL_WRN("could not set hostname: %s", sol_util_strerrora(errno)); err = -errno; } sol_file_reader_close(reader); 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 int accelerometer_lsm303_open(struct sol_flow_node *node, void *data, const struct sol_flow_node_options *options) { struct accelerometer_lsm303_data *mdata = data; const struct sol_flow_node_type_accelerometer_lsm303_options *opts; SOL_FLOW_NODE_OPTIONS_SUB_API_CHECK(options, SOL_FLOW_NODE_TYPE_ACCELEROMETER_LSM303_OPTIONS_API_VERSION, -EINVAL); opts = (const struct sol_flow_node_type_accelerometer_lsm303_options *)options; mdata->i2c = sol_i2c_open(opts->i2c_bus, SOL_I2C_SPEED_10KBIT); SOL_NULL_CHECK_MSG(mdata->i2c, -EINVAL, "Failed to open i2c bus"); mdata->node = node; mdata->scale = opts->scale; mdata->slave = opts->i2c_slave; lsm303_accel_init(mdata); return 0; }
SOL_API struct sol_flow_packet * sol_flow_packet_new(const struct sol_flow_packet_type *type, const void *value) { struct sol_flow_packet *packet; int r; if (SOL_UNLIKELY(type == SOL_FLOW_PACKET_TYPE_ANY)) { SOL_WRN("Couldn't create packet with type ANY. This type is used only on ports."); return NULL; } SOL_NULL_CHECK_MSG(type, NULL, "Couldn't create packet with NULL type"); #ifndef SOL_NO_API_VERSION if (SOL_UNLIKELY(type->api_version != SOL_FLOW_PACKET_TYPE_API_VERSION)) { SOL_WRN("Couldn't create packet with type '%s' that has unsupported version '%" PRIu16 "', expected version is '%" PRIu16 "'", type->name ? : "", type->api_version, SOL_FLOW_PACKET_TYPE_API_VERSION); return NULL; }
static bool check_module(const char *path, const char *symbol_name, void *symbol) { const struct sol_update **p_update; p_update = symbol; SOL_NULL_CHECK_MSG(*p_update, false, "Symbol [%s] in module [%s] is NULL", symbol_name, path); #ifndef SOL_NO_API_VERSION if ((*p_update)->api_version != SOL_UPDATE_API_VERSION) { SOL_WRN("Module [%s] has incorrect api_version: %u expected %u", path, (*p_update)->api_version, SOL_UPDATE_API_VERSION); return false; } #endif return true; }
static int string_concatenate_open(struct sol_flow_node *node, void *data, const struct sol_flow_node_options *options) { struct string_concatenate_data *mdata = data; const struct sol_flow_node_type_string_concatenate_options *opts; SOL_FLOW_NODE_OPTIONS_SUB_API_CHECK(options, SOL_FLOW_NODE_TYPE_STRING_CONCATENATE_OPTIONS_API_VERSION, -EINVAL); opts = (const struct sol_flow_node_type_string_concatenate_options *)options; if (opts->separator) { mdata->separator = strdup(opts->separator); SOL_NULL_CHECK_MSG(mdata->separator, -ENOMEM, "Failed to duplicate separator string"); } return 0; }
static bool check_metatype(const char *path, const char *symbol_name, void *symbol) { const struct sol_flow_metatype **p_metatype, *metatype; p_metatype = symbol; metatype = *p_metatype; SOL_NULL_CHECK_MSG(metatype, false, "Symbol '%s' in module '%s' is points to NULL instead of a valid metatype", symbol_name, path); #ifndef SOL_NO_API_VERSION if (metatype->api_version != SOL_FLOW_METATYPE_API_VERSION) { SOL_WRN("Module '%s' has incorrect api_version: %" PRIu16 " expected %" PRIu16, path, metatype->api_version, SOL_FLOW_METATYPE_API_VERSION); return false; } #endif return true; }
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_FLOW_NODE_OPTIONS_SUB_API_CHECK(options, SOL_FLOW_NODE_TYPE_GYROSCOPE_L3G4200D_OPTIONS_API_VERSION, -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 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; }