/********************************** (C) COPYRIGHT *******************************
 * File Name          : main.c
 * Author             : WCH
 * Version            : V1.0.0
 * Date               : 2021/06/06
 * Description        : Main program body.
 *********************************************************************************
 * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd.
 * Attention: This software (modified or not) and binary are used for
 * microcontroller manufactured by Nanjing Qinheng Microelectronics.
 *******************************************************************************/

/*
 *@Note
 *task1 and task2 alternate printing
 */

#include "ch32v30x_rng.h"
#include "meshcore/meshframing.h"
#include "meshcore/packets/advert.h"
#include "meshcore/packets/control.h"
#include "meshcore/packets/encrypted.h"
#include "meshcore/packets/group.h"

#include "meshcore/packetstructs.h"
#include "sx1262.h"
#include "util/hexdump.h"
#include "util/log.h"
#include "string.h"
#include "meshcore/meshcore.h"
#include "lib/config.h"
#include "lib/rtc/rtc.h"
#include "lib/monocypher/monocypher-ed25519.h"
#include "meshcore/stats.h"
#include "lib/adc/temperature.h"

#define TAG "MeshCore"


static TIM_TypeDef *runtimeTIM = TIM2;  // use TIM2 for example

void vConfigureTimerForRunTimeStats (void) {
    TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

    // Reset the timer
    TIM_DeInit (runtimeTIM);

    // Set timer for max period, upcounting
    TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1;  // Assuming 72 MHz clock -> 1 MHz timer tick (1 ?s)
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_TimeBaseStructure.TIM_Period = 0xFFFF;     // Max 16-bit value
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;

    TIM_TimeBaseInit (runtimeTIM, &TIM_TimeBaseStructure);
    TIM_Cmd (runtimeTIM, ENABLE);
}

uint32_t ulGetRunTimeCounterValue (void) {
    return TIM_GetCounter (runtimeTIM);
}

/*********************************************************************
 * @fn      task1_task
 *
 * @brief   task1 program.
 *
 * @param  *pvParameters - Parameters point of task1
 *
 * @return  none
 */

// uint8_t bufIn[260];

uint8_t bootedUp = 0;

/*********************************************************************
 * @fn      main
 *
 * @brief   ; program.
 *
 * @return  none
 */

int main (void) {

    NVIC_PriorityGroupConfig (NVIC_PriorityGroup_2);
    SystemCoreClockUpdate();
    Delay_Init();


    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;

    RCC_APB2PeriphClockCmd (RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init (GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init (GPIOA, &GPIO_InitStructure);

    USART_InitStructure.USART_BaudRate = 115200;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;

    USART_Init (USART1, &USART_InitStructure);
    USART_Cmd (USART1, ENABLE);

	printf("hello there");



    MESH_LOGD (TAG, "SystemClk:%d\r\n", SystemCoreClock);
    MESH_LOGD (TAG, "ChipID:%08x\r\n", DBGMCU_GetCHIPID());

    while (1) {
        // loadConfig();
        populateDefaults();

        LoraApply();

        ADC_Function_Init();
        RTC_Init();
        startupTime = RTC_GetCounter();
        memset (&stats, 0, sizeof (stats));


        /*
            DiscoverRequestPayload discReq;
            discReq.prefixOnly = 0;
            discReq.since = 0;
            discReq.tag = RTC_GetCounter();
            discReq.typeFilter = 0xFF;
            sendDiscoverRequest (&discReq);

        */
        sendAdvert (0);
        bootedUp = 1;
		uint64_t ticker = 0;

        while (1) {
            if (USART_GetFlagStatus (USART1, USART_FLAG_RXNE) == SET) {
                char x;
                x = USART_ReceiveData (USART1);
                if (x == 'M') {
                    MESH_LOGI (TAG, "Sending message\n");
                    char tempBuf[180];
                    sniprintf (tempBuf, 180, "SySTick is %llu", ticker);
                    makeSendGroupMessage (tempBuf, 1);
                }
                if (x == '0') {
                    MESH_LOGI (TAG, "Sending zero hop advert\n");
                    sendAdvert (0);
                }
                if (x == 'F') {
                    MESH_LOGI (TAG, "Sending flood advert\n");
                    sendAdvert (1);
                }
                if (x == 'N') {
                    printNodeDB();
                }
                if (x == 'D') {
                    PlainTextMessagePayload plainTextMessage;
                    plainTextMessage.timestamp = RTC_GetCounter();
                    plainTextMessage.textType = 0;
                    plainTextMessage.attempt = 0;
                    snprintf (plainTextMessage.message, sizeof (plainTextMessage.message), "Sending message at SySTick is %llu", ticker);
                    iprintf ("Sending a direct message to the first node\n");
                    sendEncryptedTextMessage (&(persistent.contacts[0]), &plainTextMessage);
                }
                if (x == 'C') {
                    for (uint8_t i = 0; i < ChannelCount; i++) {
                        Channel *channel = &(persistent.channels[i]);
                        if (strlen (channel->name) == 0) {
                            continue;
                        }
                        if (channel->timestamp == 0) {
                            continue;
                        }
                        iprintf ("Channel index %d, named %s, timestamp is %d, hash is %d\n", i, channel->name, channel->timestamp, channel->hash);
                        hexdump ("Pubkey", channel->key, sizeof (channel->key));
                    }
                }
            }

            int8_t rssi, snr, rawsnr;
            FrameStruct frame;
            if (ReadFrame (&frame, &rssi, &snr, &rawsnr)) {
                hexdump ("Whole frame", frame.payload, frame.payloadLen);
                stats.lastSNR = rawsnr;
                // stats.lastSNR = snr; //TODO figure out which to use
                stats.lastRSSI = rssi;
                MESH_LOGI (TAG, "rssi=%d[dBm] snr=%d[dB] rawsnr=%d[quarter dB]", rssi, snr, rawsnr);
                // frame = decodeFrame (bufIn, rxLen);
                processFrame (&frame);
                if (persistent.doRepeat) {
                    retransmitFrame (&frame);
                }
                memset (&frame, 0, sizeof (FrameStruct));  // prepare for the next round
            }

            int lost = GetPacketLost();
            if (lost != 0) {
                MESH_LOGW (TAG, "%d packets lost", lost);
            }
			ticker++;
        }
    }
}
