#include "cmdio.h"
#include "serial.h"
#include <stdlib.h>
#include <string.h>

struct _cmdio_t {
    SERIAL *serial;
};

cmdio_t *cmdio_open(const char *devfile)
{
    /*
     * ハンドラ領域を確保する。
     */
    cmdio_t *p = (cmdio_t *)malloc(sizeof(cmdio_t));
    if (p == NULL) {
        return NULL;
    }

    /*
     * シリアルポートを開く。
     */
    p->serial = serial_open(devfile, SerialBaud115200);
    if (p->serial == NULL) {
        free(p);
        return NULL;
    }

    return p;
}

int cmdio_execute(
        cmdio_t *p,
        const char *send,
        char *recv,
        size_t recv_bufsiz)
{
    static const int TIMEOUT_MS = 10 * 1000;
    /*
     * コマンドを送信する。
     */
    const int len = strlen(send);
    serial_write(p->serial, (unsigned char *)send, len);
    if (strstr(send, "\r\n") == NULL) {
        serial_write(p->serial, (unsigned char *)"\r\n", 2);
    }

    /*
     * ターゲットから送信されてくるエコーバックを読み捨てる。
     */
    while (1) {
        unsigned char c;
        /*
         * １文字読む。
         */
        if (serial_read_with_timeout(p->serial, &c, 1, TIMEOUT_MS) != 0) {
            return -1;
        }
        /*
         * 改行ならばエコーバックの終端と見做す。
         */
        if (c == '\n') {
            break;
        }
    }

    /*
     * コマンドに対する応答を受信する。
     */
    size_t cnt = 0;
    while (1) {
        unsigned char c;
        /*
         * １文字読む。
         */
        if (serial_read_with_timeout(p->serial, &c, 1, TIMEOUT_MS) != 0) {
            return -2;
        }
        /*
         * プロンプトを見つけたらコマンドに対する応答の終端と見做す。
         */
        if (c == '>') {
            break;
        }
        /*
         * 受信文字を格納する。
         */
        recv[cnt] = c;
        cnt++;
    }
    recv[cnt] = '\0';

    /*
     * 応答の終端付近にある改行は無意味な物と見做し削除する。
     */
    {
        int i;
        for (i = cnt; 0 <= i; i--) {
            if ((recv[i] == '\r') ||
                    (recv[i] == '\n') ||
                    (recv[i] == '\0')) {
                recv[i] = '\0';
            } else {
                break;
            }
        }
    }

    return 0;
}

int cmdio_close(cmdio_t *p)
{
    serial_close(p->serial);
    free(p);
    p = NULL;
    return 0;
}

