#include <cstdio>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <locale.h>

typedef struct {
    double u;
    double i;
    double p;
    double e_d; // energy day
    double e_t; // energy total
} ch_t;

typedef struct {
    ch_t ch_dc[4];
    ch_t ch_ac;
    double temp;
    double pct;
    double acFreq;
    bool acEn;

    double cmd01[3];
    double cmd02[2];
    double cmd03[3];
    double cmd84[1];
} data_t;


//-----------------------------------------------------------------------------
// GLOABAL
FILE *fpOut;
data_t dat;


//-----------------------------------------------------------------------------
// MACROS


//-----------------------------------------------------------------------------
// PROTOTYPES
bool parseFile(const char *path, const char *outPath);
void toByteArr(const char *stream, uint8_t arr[], uint8_t *len);
void parseData(uint8_t buf[], uint8_t len);
void parseCmd01(uint8_t buf[], uint8_t len);
void parseCmd02(uint8_t buf[], uint8_t len);
void parseCmd03(uint8_t buf[], uint8_t len);
void parseCmd84(uint8_t buf[], uint8_t len);
void dumpData(bool header = false, const char *path = NULL);
void dumpBuf(uint8_t buf[], uint8_t len, const char *info = NULL);


//-----------------------------------------------------------------------------
int main(int argc, char *argv[]) {
    setlocale(LC_NUMERIC, "de_DE.UTF-8");

    parseFile("220418_log.csv", "220418_log_out.csv");
    fclose(fpOut);


    return 0;
}


//-----------------------------------------------------------------------------
bool parseFile(const char *path, const char *outPath) {
    memset(&dat, 0, sizeof(data_t));
    dumpData(true, outPath);

    FILE *fp;
    char buf[1024] = {0};
    uint8_t arr[32];
    uint8_t len;

    fopen_s(&fp, path, "r");
    if(NULL != fp) {
        char *p = 0, *nxt = 0;
        while(!feof(fp)) {
            fgets(buf, 1024, fp);
            p = strtok_s(&buf[46], " ", &nxt);
            toByteArr(p, arr, &len);
            parseData(arr, len);
        }
        fclose(fp);
    }

    return true;
}


//-----------------------------------------------------------------------------
void toByteArr(const char *stream, uint8_t arr[], uint8_t *len) {
    char tmp[3] = {0};
    *len = strlen(stream)/2;

    for(uint8_t i = 0; i < *len; i ++) {
        tmp[0] = stream[i*2];
        tmp[1] = stream[i*2+1];
        arr[i] = strtol(tmp, NULL, 16);
    }
}


//-----------------------------------------------------------------------------
void parseData(uint8_t buf[], uint8_t len) {
    bool dump = true;
    //dumpBuf(buf, len);

    switch(buf[0]) {
        case 0x01: parseCmd01(buf, len); break;
        case 0x02: parseCmd02(buf, len); break;
        case 0x03: parseCmd03(buf, len); break;
        case 0x84: parseCmd84(buf, len); break;
        case 0x81:
            dump = false;
            break;
        default:
            dump = false;
            printf("unkown cmd: 0x%02X\n", buf[0]);
            break;
    }

    if(dump)
        dumpData();
}


//-----------------------------------------------------------------------------
void parseCmd01(uint8_t buf[], uint8_t len) {
    dat.ch_dc[0].u   = ((buf[ 3] << 8) | buf[ 4]) / 10.0f;
    dat.ch_dc[0].i   = ((buf[ 5] << 8) | buf[ 6]) / 100.0f;
    dat.ch_dc[1].i   = ((buf[ 7] << 8) | buf[ 8]) / 100.0f;
    dat.ch_dc[0].p   = ((buf[ 9] << 8) | buf[10]) / 10.0f;
    dat.ch_dc[1].p   = ((buf[11] << 8) | buf[12]) / 10.0f;
    dat.ch_dc[0].e_t = ((buf[15] << 8) | buf[16]) / 1000.0f; // energy total 0

    dat.cmd01[0]   = ((buf[ 1] << 8) | buf[ 2]) / 10.0f;
    dat.cmd01[1]   = ((buf[13] << 8) | buf[14]) / 10.0f;
    dat.cmd01[2]   = ((buf[17] << 8) | buf[18]) / 10.0f;
}


//-----------------------------------------------------------------------------
void parseCmd02(uint8_t buf[], uint8_t len) {
    dat.ch_dc[1].e_t = ((buf[ 3] << 8) | buf[ 4]) / 1000.0f; // energy total 1
    dat.ch_dc[0].e_d = ((buf[ 5] << 8) | buf[ 6]) / 1000.0f; // energy day 0
    dat.ch_dc[1].e_d = ((buf[ 7] << 8) | buf[ 8]) / 1000.0f; // energy day 1
    dat.ch_dc[1].u   = ((buf[ 9] << 8) | buf[10]) / 10.0f;
    dat.ch_dc[2].i   = ((buf[11] << 8) | buf[12]) / 100.0f;
    dat.ch_dc[3].i   = ((buf[13] << 8) | buf[14]) / 100.0f;
    dat.ch_dc[2].p   = ((buf[15] << 8) | buf[16]) / 10.0f;

    dat.cmd02[0]     = ((buf[ 1] << 8) | buf[ 2]) / 10.0f;
    dat.cmd02[1]     = ((buf[17] << 8) | buf[18]) / 10.0f;
}


//-----------------------------------------------------------------------------
void parseCmd03(uint8_t buf[], uint8_t len) {
    dat.ch_dc[3].p   = ((buf[ 1] << 8) | buf[ 2]) / 10.0f;
    dat.ch_dc[2].e_t = ((buf[ 5] << 8) | buf[ 6]) / 1000.0f; // energy total 2
    dat.ch_dc[3].e_t = ((buf[ 9] << 8) | buf[10]) / 1000.0f; // energy total 3
    dat.ch_dc[2].e_d = ((buf[11] << 8) | buf[12]) / 1000.0f; // energy day 2
    dat.ch_dc[3].e_d = ((buf[13] << 8) | buf[14]) / 1000.0f; // energy day 3
    dat.ch_ac.u      = ((buf[15] << 8) | buf[16]) / 10.0f;

    dat.cmd03[0]     = ((buf[ 3] << 8) | buf[ 4]) / 10.0f;
    dat.cmd03[1]     = ((buf[ 7] << 8) | buf[ 8]) / 10.0f;
    dat.cmd03[2]     = ((buf[17] << 8) | buf[18]) / 10.0f;

}


//-----------------------------------------------------------------------------
void parseCmd84(uint8_t buf[], uint8_t len) {
    dat.acFreq   = ((buf[ 1] << 8) | buf[ 2]) / 100.0f;
    dat.ch_ac.p  = ((buf[ 3] << 8) | buf[ 4]) / 10.0f;
    dat.ch_ac.i  = ((buf[ 7] << 8) | buf[ 8]) / 100.0f;
    dat.pct      = ((buf[ 9] << 8) | buf[10]) / 10.0f;
    dat.temp     = ((buf[11] << 8) | buf[12]) / 10.0f;

    dat.cmd84[0] = ((buf[ 5] << 8) | buf[ 6]) / 10.0f;
}


//-----------------------------------------------------------------------------
void dumpData(bool header, const char *path) {
    if(header) {
        fopen_s(&fpOut, path, "w");
        fprintf(fpOut, "DC_U0;DC_I0;DC_P0;DC_ED0;DC_ET0;;");
        fprintf(fpOut, "DC_U1;DC_I1;DC_P1;DC_ED1;DC_ET1;;");
        fprintf(fpOut, "DC_U2;DC_I2;DC_P2;DC_ED2;DC_ET2;;");
        fprintf(fpOut, "DC_U3;DC_I3;DC_P3;DC_ED3;DC_ET3;;");
        fprintf(fpOut, "AC_U;AC_I;AC_P;AC_F;;");
        fprintf(fpOut, "PCT;TEMP;;");
        fprintf(fpOut, "UK01_0;UK01_1;UK01_2;;");
        fprintf(fpOut, "UK02_0;UK02_1;;");
        fprintf(fpOut, "UK03_0;UK03_1;UK03_2;;");
        fprintf(fpOut, "UK84_0;");
        fprintf(fpOut, "\n");
    }
    else {
        for(uint8_t i = 0; i < 4; i++) {
            fprintf(fpOut, "%.1f;%.2f;%.1f;%.3f;%.3f;;", dat.ch_dc[i].u, dat.ch_dc[i].i, dat.ch_dc[i].p, dat.ch_dc[i].e_d, dat.ch_dc[i].e_t);
        }
        fprintf(fpOut, "%.1f;%.2f;%1.f;%.2f;;", dat.ch_ac.u, dat.ch_ac.i, dat.ch_ac.p, dat.acFreq);
        fprintf(fpOut, "%.1f;%.1f;;", dat.pct, dat.temp);

        // UNKNOWN VALUES
        for(uint8_t i = 0; i < 3; i++) {
            fprintf(fpOut, "%.1f;", dat.cmd01[i]);
        }
        fprintf(fpOut, ";");
        for(uint8_t i = 0; i < 2; i++) {
            fprintf(fpOut, "%.1f;", dat.cmd02[i]);
        }
        fprintf(fpOut, ";");
        for(uint8_t i = 0; i < 3; i++) {
            fprintf(fpOut, "%.1f;", dat.cmd03[i]);
        }
        fprintf(fpOut, ";");
        for(uint8_t i = 0; i < 1; i++) {
            fprintf(fpOut, "%.1f;", dat.cmd84[i]);
        }
        fprintf(fpOut, "\n");
    }
}


//-----------------------------------------------------------------------------
void dumpBuf(uint8_t buf[], uint8_t len, const char *info) {
    if(NULL != info)
        printf("%s\n", info);

    for(uint8_t i = 0; i < len; i++) {
        printf("%02X ", buf[i]);
    }
    printf("\n");
}