/*
 * Software License Agreement (BSD License)
 *
 * Copyright (c) 2017, DUKELEC, Inc.
 * All rights reserved.
 *
 * Author: Duke Fong <d@d-l.io>
 */

#include "app_main.h"
#define LOOPBACK_TEST
#define DUMP_HW_STATUS

static gpio_t led_g = { .group = LED_G_GPIO_Port, .num = LED_G_Pin };

static gpio_t r_cs = { .group = CD_CS_GPIO_Port, .num = CD_CS_Pin };
static spi_t r_spi = { .hspi = &hspi1, .ns_pin = &r_cs };

static cd_frame_t frame_alloc[FRAME_MAX];
list_head_t frame_free_head = {0};

static cdctl_dev_t r_dev = {0}; // CDCTL01A
static cdctl_cfg_t cdctl_cfg = CDCTL_CFG_DFT(0x01); // local mac: 0x01


static void check_reply(void)
{
    cd_frame_t *frm = cdctl_recv_frame(&r_dev);
    if (!frm)
        return;
    printf("received, src_mac: %02x, dst_mac: %02x, len: %d\n", frm->dat[0], frm->dat[1], frm->dat[2]);
    printf("  data: %02x %02x %02x %02x ...\n", frm->dat[3], frm->dat[4], frm->dat[5], frm->dat[6]);
    cd_list_put(&frame_free_head, frm);
}

static int sent_cmd(uint8_t *d, uint8_t d_len)
{
    cd_frame_t *frm = cd_list_get(&frame_free_head);
    if (!frm)
        return -1;
#ifdef LOOPBACK_TEST
    // 00 -> 01 (send a packet spoofed as 00)
    frm->dat[0] = 0x00;
    frm->dat[1] = 0x01;
#else
    // 01 -> 00
    frm->dat[0] = 0x01;
    frm->dat[1] = 0x00;
#endif
    frm->dat[2] = d_len;
    memcpy(frm->dat + 3, d, d_len);
    cdctl_send_frame(&r_dev, frm);
    return 0;
}


#ifdef DUMP_HW_STATUS
static void dump_hw_status(void)
{
    static int t_l = 0;
    if (get_systick() - t_l > 5000) {
        t_l = get_systick();

        d_debug("ctl: t_len %d, r_len %d\n",
                r_dev.tx_head.len, r_dev.rx_head.len);
        d_debug("  r_cnt %d (lost %d, err %d, no-free %d), t_cnt %d (cd %d, err %d)\n",
                r_dev.rx_cnt, r_dev.rx_lost_cnt, r_dev.rx_error_cnt,
                r_dev.rx_no_free_node_cnt,
                r_dev.tx_cnt, r_dev.tx_cd_cnt, r_dev.tx_error_cnt);
    }
}
#endif


void app_main(void)
{
    printf("\nstart app_main (pio)...\n");
    delay_systick(50);

    for (int i = 0; i < FRAME_MAX; i++)
        cd_list_put(&frame_free_head, &frame_alloc[i]);

    cdctl_cfg.baud_l = 1000000;  //  1Mbps
    cdctl_cfg.baud_h = 10000000; // 10Mbps
    cdctl_dev_init(&r_dev, &frame_free_head, &cdctl_cfg, &r_spi);

    gpio_set_val(&led_g, 1);
    uint32_t t_last = 0;

    sent_cmd((uint8_t []){0x12, 0x34, 0xab, 0xcd}, 4);

    while (true) {
        if (get_systick() - t_last > 200) {
            t_last = get_systick();
            gpio_set_val(&led_g, !gpio_get_val(&led_g));
        }

        cdctl_poll(&r_dev);
#ifdef DUMP_HW_STATUS
        dump_hw_status();
#endif
        check_reply();
    }
}

// for printf
int fputc(int ch, FILE *p)
{
    arch_dbg_tx((uint8_t *)&ch, 1);
    return ch;
}
