static void handle_signals(const char *req, int *req_index) { // No arguments (void) req; (void) req_index; if (!uart_is_open(uart)) { send_error_response("ebadf"); return; } struct uart_signals sig; if (uart_get_signals(uart, &sig) >= 0) { char resp[128]; int resp_index = sizeof(uint16_t); resp[resp_index++] = response_id; ei_encode_version(resp, &resp_index); ei_encode_tuple_header(resp, &resp_index, 2); ei_encode_atom(resp, &resp_index, "ok"); ei_encode_map_header(resp, &resp_index, 8); encode_kv_bool(resp, &resp_index, "dsr", sig.dsr); encode_kv_bool(resp, &resp_index, "dtr", sig.dtr); encode_kv_bool(resp, &resp_index, "rts", sig.rts); encode_kv_bool(resp, &resp_index, "st", sig.st); encode_kv_bool(resp, &resp_index, "sr", sig.sr); encode_kv_bool(resp, &resp_index, "cts", sig.cts); encode_kv_bool(resp, &resp_index, "cd", sig.cd); encode_kv_bool(resp, &resp_index, "rng", sig.rng); erlcmd_send(resp, resp_index); } else send_error_response(uart_last_error()); }
/** * @brief Send :ok back to Elixir */ static void send_ok_response() { char resp[256]; int resp_index = sizeof(uint16_t); // Space for payload size ei_encode_version(resp, &resp_index); ei_encode_atom(resp, &resp_index, "ok"); erlcmd_send(resp, resp_index); }
/** * @brief Send a response of the form {:error, reason} * * @param reason a reason (sent back as an atom) */ static void send_error_response(const char *reason) { char resp[256]; int resp_index = sizeof(uint16_t); // Space for payload size ei_encode_version(resp, &resp_index); ei_encode_tuple_header(resp, &resp_index, 2); ei_encode_atom(resp, &resp_index, "error"); ei_encode_atom(resp, &resp_index, reason); erlcmd_send(resp, resp_index); }
static void enumerate_ports() { struct serial_info *port_list = find_serialports(); int port_list_len = 0; for (struct serial_info *port = port_list; port != NULL; port = port->next) port_list_len++; debug("Found %d ports", port_list_len); char resp[4096]; int resp_index = sizeof(uint16_t); // Space for payload size resp[resp_index++] = response_id; ei_encode_version(resp, &resp_index); ei_encode_map_header(resp, &resp_index, port_list_len); for (struct serial_info *port = port_list; port != NULL; port = port->next) { ei_encode_binary(resp, &resp_index, port->name, strlen(port->name)); int info_count = (port->description ? 1 : 0) + (port->manufacturer ? 1 : 0) + (port->serial_number ? 1 : 0) + (port->vid > 0 ? 1 : 0) + (port->pid > 0 ? 1 : 0); ei_encode_map_header(resp, &resp_index, info_count); if (port->description) { ei_encode_atom(resp, &resp_index, "description"); ei_encode_binary(resp, &resp_index, port->description, strlen(port->description)); } if (port->manufacturer) { ei_encode_atom(resp, &resp_index, "manufacturer"); ei_encode_binary(resp, &resp_index, port->manufacturer, strlen(port->manufacturer)); } if (port->serial_number) { ei_encode_atom(resp, &resp_index, "serial_number"); ei_encode_binary(resp, &resp_index, port->serial_number, strlen(port->serial_number)); } if (port->vid > 0) { ei_encode_atom(resp, &resp_index, "vendor_id"); ei_encode_ulong(resp, &resp_index, port->vid); } if (port->pid > 0) { ei_encode_atom(resp, &resp_index, "product_id"); ei_encode_ulong(resp, &resp_index, port->pid); } } erlcmd_send(resp, resp_index); serial_info_free_list(port_list); }
/* Called when uart_read completes or fails */ static void handle_read_completed(int rc, const uint8_t *data, size_t len) { if (rc >= 0) { char *resp = malloc(32 + len); int resp_index = sizeof(uint16_t); ei_encode_version(resp, &resp_index); ei_encode_tuple_header(resp, &resp_index, 2); ei_encode_atom(resp, &resp_index, "ok"); ei_encode_binary(resp, &resp_index, data, len); erlcmd_send(resp, resp_index); free(resp); } else send_error_response(uart_last_error()); }
static void handle_configuration(const char *req, int *req_index) { char resp[256]; int resp_index = sizeof(uint16_t); // Space for payload size resp[resp_index++] = response_id; ei_encode_version(resp, &resp_index); ei_encode_list_header(resp, &resp_index, 5); ei_encode_tuple_header(resp, &resp_index, 2); ei_encode_atom(resp, &resp_index, "speed"); ei_encode_long(resp, &resp_index, current_config.speed); ei_encode_tuple_header(resp, &resp_index, 2); ei_encode_atom(resp, &resp_index, "data_bits"); ei_encode_long(resp, &resp_index, current_config.data_bits); ei_encode_tuple_header(resp, &resp_index, 2); ei_encode_atom(resp, &resp_index, "stop_bits"); ei_encode_long(resp, &resp_index, current_config.stop_bits); ei_encode_tuple_header(resp, &resp_index, 2); ei_encode_atom(resp, &resp_index, "parity"); switch (current_config.parity) { default: case UART_PARITY_NONE: ei_encode_atom(resp, &resp_index, "none"); break; case UART_PARITY_EVEN: ei_encode_atom(resp, &resp_index, "even"); break; case UART_PARITY_ODD: ei_encode_atom(resp, &resp_index, "odd"); break; case UART_PARITY_SPACE: ei_encode_atom(resp, &resp_index, "space"); break; case UART_PARITY_MARK: ei_encode_atom(resp, &resp_index, "mark"); break; case UART_PARITY_IGNORE: ei_encode_atom(resp, &resp_index, "ignore"); break; } ei_encode_tuple_header(resp, &resp_index, 2); ei_encode_atom(resp, &resp_index, "flow_control"); switch (current_config.parity) { default: case UART_FLOWCONTROL_NONE: ei_encode_atom(resp, &resp_index, "none"); break; case UART_FLOWCONTROL_HARDWARE: ei_encode_atom(resp, &resp_index, "hardware"); break; case UART_FLOWCONTROL_SOFTWARE: ei_encode_atom(resp, &resp_index, "software"); break; } ei_encode_empty_list(resp, &resp_index); erlcmd_send(resp, resp_index); }
/* Called in active mode when there's a read or an error */ static void handle_notify_read(int error_reason, const uint8_t *data, size_t len) { char *resp = malloc(64 + len); int resp_index = sizeof(uint16_t); ei_encode_version(resp, &resp_index); ei_encode_tuple_header(resp, &resp_index, 2); ei_encode_atom(resp, &resp_index, "notif"); if (error_reason == 0) { // Normal receive ei_encode_binary(resp, &resp_index, data, len); } else { // Error notification ei_encode_tuple_header(resp, &resp_index, 2); ei_encode_atom(resp, &resp_index, "error"); ei_encode_atom(resp, &resp_index, uart_last_error()); } erlcmd_send(resp, resp_index); free(resp); }
static void i2c_handle_request(const char *req, void *cookie) { struct i2c_info *i2c = (struct i2c_info *) cookie; // Commands are of the form {Command, Arguments}: // { atom(), term() } int req_index = sizeof(uint16_t); if (ei_decode_version(req, &req_index, NULL) < 0) errx(EXIT_FAILURE, "Message version issue?"); int arity; if (ei_decode_tuple_header(req, &req_index, &arity) < 0 || arity != 2) errx(EXIT_FAILURE, "expecting {cmd, args} tuple"); char cmd[MAXATOMLEN]; if (ei_decode_atom(req, &req_index, cmd) < 0) errx(EXIT_FAILURE, "expecting command atom"); char resp[256]; int resp_index = sizeof(uint16_t); // Space for payload size ei_encode_version(resp, &resp_index); if (strcmp(cmd, "read") == 0) { long int len; if (ei_decode_long(req, &req_index, &len) < 0 || len < 1 || len > I2C_SMBUS_BLOCK_MAX) errx(EXIT_FAILURE, "read amount: min=1, max=%d", I2C_SMBUS_BLOCK_MAX); char data[I2C_SMBUS_BLOCK_MAX]; if (i2c_transfer(i2c, 0, 0, data, len)) ei_encode_binary(resp, &resp_index, data,len); else { ei_encode_tuple_header(resp, &resp_index, 2); ei_encode_atom(resp, &resp_index, "error"); ei_encode_atom(resp, &resp_index, "i2c_read_failed"); } } else if (strcmp(cmd, "write") == 0) { char data[I2C_SMBUS_BLOCK_MAX]; int len; int type; long llen; if (ei_get_type(req, &req_index, &type, &len) < 0 || type != ERL_BINARY_EXT || len < 1 || len > I2C_SMBUS_BLOCK_MAX || ei_decode_binary(req, &req_index, &data, &llen) < 0) errx(EXIT_FAILURE, "write: need a binary between 1 and %d bytes", I2C_SMBUS_BLOCK_MAX); if (i2c_transfer(i2c, data, len, 0, 0)) ei_encode_atom(resp, &resp_index, "ok"); else { ei_encode_tuple_header(resp, &resp_index, 2); ei_encode_atom(resp, &resp_index, "error"); ei_encode_atom(resp, &resp_index, "i2c_write_failed"); } } else if (strcmp(cmd, "wrrd") == 0) { char write_data[I2C_SMBUS_BLOCK_MAX]; char read_data[I2C_SMBUS_BLOCK_MAX]; int write_len; long int read_len; int type; long llen; if (ei_decode_tuple_header(req, &req_index, &arity) < 0 || arity != 2) errx(EXIT_FAILURE, "wrrd: expecting {write_data, read_count} tuple"); if (ei_get_type(req, &req_index, &type, &write_len) < 0 || type != ERL_BINARY_EXT || write_len < 1 || write_len > I2C_SMBUS_BLOCK_MAX || ei_decode_binary(req, &req_index, &write_data, &llen) < 0) errx(EXIT_FAILURE, "wrrd: need a binary between 1 and %d bytes", I2C_SMBUS_BLOCK_MAX); if (ei_decode_long(req, &req_index, &read_len) < 0 || read_len < 1 || read_len > I2C_SMBUS_BLOCK_MAX) errx(EXIT_FAILURE, "wrrd: read amount: min=1, max=%d", I2C_SMBUS_BLOCK_MAX); if (i2c_transfer(i2c, write_data, write_len, read_data, read_len)) ei_encode_binary(resp, &resp_index, read_data, read_len); else { ei_encode_tuple_header(resp, &resp_index, 2); ei_encode_atom(resp, &resp_index, "error"); ei_encode_atom(resp, &resp_index, "i2c_wrrd_failed"); } } else errx(EXIT_FAILURE, "unknown command: %s", cmd); debug("sending response: %d bytes", resp_index); erlcmd_send(resp, resp_index); }