Ejemplo n.º 1
0
static void handle_write(const char *req, int *req_index)
{
    if (!uart_is_open(uart)) {
        send_error_response("ebadf");
        return;
    }

    int term_size;
    if (ei_decode_tuple_header(req, req_index, &term_size) < 0 ||
            term_size != 2)
        errx(EXIT_FAILURE, "expecting {data, timeout}");

    int term_type;
    if (ei_get_type(req, req_index, &term_type, &term_size) < 0 ||
            term_type != ERL_BINARY_EXT)
        errx(EXIT_FAILURE, "expecting data as a binary");

    uint8_t *to_write = malloc(term_size);
    long amount_to_write;
    if (ei_decode_binary(req, req_index, to_write, &amount_to_write) < 0)
        errx(EXIT_FAILURE, "decode binary error?");

    long timeout;
    if (ei_decode_long(req, req_index, &timeout) < 0)
        errx(EXIT_FAILURE, "expecting timeout");

    // uart_write always invokes a callback when it completes (error or no error).
    uart_write(uart, to_write, amount_to_write, timeout);
}
Ejemplo n.º 2
0
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());
}
Ejemplo n.º 3
0
static void handle_flush(const char *req, int *req_index)
{
    char dirstr[MAXATOMLEN];
    if (ei_decode_atom(req, req_index, dirstr) < 0) {
        send_error_response("einval");
        return;
    }

    enum uart_direction direction;
    if (strcmp(dirstr, "receive") == 0)
        direction = UART_DIRECTION_RECEIVE;
    else if (strcmp(dirstr, "transmit") == 0)
        direction = UART_DIRECTION_TRANSMIT;
    else if (strcmp(dirstr, "both") == 0)
        direction = UART_DIRECTION_BOTH;
    else {
        send_error_response("einval");
        return;
    }

    if (!uart_is_open(uart)) {
        send_error_response("ebadf");
        return;
    }

    if (uart_flush(uart, direction) >= 0)
        send_ok_response();
    else
        send_error_response(uart_last_error());
}
Ejemplo n.º 4
0
static void handle_close(const char *req, int *req_index)
{
    (void) req;
    (void) req_index;

    if (uart_is_open(uart))
        uart_close(uart);

    send_ok_response();
}
Ejemplo n.º 5
0
static void handle_drain(const char *req, int *req_index)
{
    (void) req;
    (void) req_index;
    if (!uart_is_open(uart)) {
        send_error_response("ebadf");
        return;
    }

    if (uart_drain(uart) >= 0)
        send_ok_response();
    else
        send_error_response(uart_last_error());
}
Ejemplo n.º 6
0
static void handle_read(const char *req, int *req_index)
{
    if (!uart_is_open(uart)) {
        send_error_response("ebadf");
        return;
    }

    long timeout;
    if (ei_decode_long(req, req_index, &timeout) < 0)
        errx(EXIT_FAILURE, "expecting timeout");

    uart_read(uart, timeout);

    // handle_read_completed is called when read completes, times out, or errors
}
Ejemplo n.º 7
0
void main_loop()
{
    uart_default_config(&current_config);
    if (uart_init(&uart,
                  handle_write_completed,
                  handle_read_completed,
                  handle_notify_read) < 0)
        errx(EXIT_FAILURE, "uart_init failed");

    struct erlcmd *handler = malloc(sizeof(struct erlcmd));
    erlcmd_init(handler, handle_elixir_request, NULL);

    for (;;) {
        struct pollfd fdset[3];

        fdset[0].fd = STDIN_FILENO;
        fdset[0].events = POLLIN;
        fdset[0].revents = 0;

        int timeout = -1; // Wait forever unless told by otherwise
        int count = uart_add_poll_events(uart, &fdset[1], &timeout);

        int rc = poll(fdset, count + 1, timeout);
        if (rc < 0) {
            // Retry if EINTR
            if (errno == EINTR)
                continue;

            err(EXIT_FAILURE, "poll");
        }

        if (fdset[0].revents & (POLLIN | POLLHUP)) {
            if (erlcmd_process(handler))
                break;
        }

        // Call uart_process if it added any events
        if (count)
            uart_process(uart, &fdset[1]);
    }

    // Exit due to Erlang trying to end the process.
    //
    if (uart_is_open(uart))
        uart_flush_all(uart);
}
Ejemplo n.º 8
0
static void handle_set_break(const char *req, int *req_index)
{
    int val;
    if (ei_decode_boolean(req, req_index, &val) < 0) {
        send_error_response("einval");
        return;
    }

    if (!uart_is_open(uart)) {
        send_error_response("ebadf");
        return;
    }

    if (uart_set_break(uart, !!val) >= 0)
        send_ok_response();
    else
        send_error_response(uart_last_error());
}
Ejemplo n.º 9
0
/*
 * Handle {name, kv_list}
 *
 *    name is the serial port name
 *    kv_list a list of configuration values (speed, parity, etc.)
 */
static void handle_open(const char *req, int *req_index)
{
    int term_type;
    int term_size;

    if (ei_decode_tuple_header(req, req_index, &term_size) < 0 ||
            term_size != 2)
        errx(EXIT_FAILURE, ":open requires a 2-tuple");

    char name[32];
    long binary_len;
    if (ei_get_type(req, req_index, &term_type, &term_size) < 0 ||
            term_type != ERL_BINARY_EXT ||
            term_size >= (int) sizeof(name) ||
            ei_decode_binary(req, req_index, name, &binary_len) < 0) {
        // The name is almost certainly too long, so report that it
        // doesn't exist.
        send_error_response("enoent");
        return;
    }
    name[term_size] = '\0';

    struct uart_config config = current_config;
    if (parse_option_list(req, req_index, &config) < 0) {
        send_error_response("einval");
        return;
    }

    // If the uart was already open, close and open it again
    if (uart_is_open(uart))
        uart_close(uart);

    if (uart_open(uart, name, &config) >= 0) {
        current_config = config;
        send_ok_response();
    } else {
        send_error_response(uart_last_error());
    }
}
Ejemplo n.º 10
0
void main_loop()
{
    uart_default_config(&current_config);
    if (uart_init(&uart,
                  handle_write_completed,
                  handle_read_completed,
                  handle_notify_read) < 0)
        errx(EXIT_FAILURE, "uart_init failed");

    struct erlcmd *handler = malloc(sizeof(struct erlcmd));
    erlcmd_init(handler, handle_elixir_request, NULL);

    bool running = true;
    while (running) {
        HANDLE handles[3];
        handles[0] = erlcmd_wfmo_event(handler);

        DWORD timeout = INFINITE;
        DWORD count = 1 + uart_add_wfmo_handles(uart, &handles[1], &timeout);

        debug("Calling WFMO count=%d", (int) count);
        DWORD result = WaitForMultipleObjects(count,
                                              handles,
                                              FALSE,
                                              timeout);


        debug("WFMO returned %d", (int) result);

        switch(result) {
        case WAIT_OBJECT_0 + 0:
            if (erlcmd_process(handler))
                running = false;
            break;

        case WAIT_OBJECT_0 + 1:
            uart_process_handle(uart, handles[1]);
            break;

        case WAIT_OBJECT_0 + 2:
            uart_process_handle(uart, handles[2]);
            break;

        case WAIT_TIMEOUT:
            uart_process_timeout(uart);
            break;

        case WAIT_FAILED:
            debug("WFMO wait failed! %d", (int) GetLastError());
            // TODO: Is this ever a transient occurrence that we
            //       should ignore and retry?
            running = false;
            break;

        default:
            break;
        }

    }

    // Exit due to Erlang trying to end the process.
    if (uart_is_open(uart))
        uart_flush_all(uart);
}