SP8EBC-ParaTNC/system/src/ve_direct_protocol/parser.c

541 wiersze
15 KiB
C

/*
* parser.c
*
* Created on: 10.03.2019
* Author: mateusz
*/
#include "./ve_direct_protocol/parser.h"
#include "./ve_direct_protocol/average_struct.h"
#include <string.h>
#include <stdlib.h>
#define CHECKSUM_NAME_FIELD_LN_TO_DATA 10
#define LOWEST_PRINTABLE_CHARACTER 33
#define HIGHEST_PRINTABLE_CHARACTER 126
#define VE_DIRECT_MESSAGES_TO_SKIP 2
#define is_non_printable_character() (*(input + i) < LOWEST_PRINTABLE_CHARACTER || *(input + i) > HIGHEST_PRINTABLE_CHARACTER)
#define is_printable_character() (*(input + i) >= LOWEST_PRINTABLE_CHARACTER && *(input + i) <= HIGHEST_PRINTABLE_CHARACTER)
uint8_t key[9]; // the static array to store a key fetched from input file
uint8_t value[12];
uint8_t skip_counter = 0; // counter used to skip some of VE.Direct protocol messages to spread an average over longer
// period of time
//ve_direct_average_struct ve_avg;
static int copy_till_non_printable_char(uint8_t* input, uint16_t* input_offset, uint16_t input_ln, uint8_t* output, uint16_t output_ln) {
uint16_t j = 0;
uint16_t i = 0;
for (i = *input_offset; i < input_ln; i++) {
// if we reach any non-printable character
if (is_non_printable_character() || j > output_ln) {
// stop copying and rewind to first printable character
do {
i++;
} while (is_non_printable_character() && i < input_ln);
// updating an offset to input buffer
*input_offset = i;
if (i > input_ln) {
return VE_DIRECT_STRING_END_REACH_TO_EARLY;
}
else {
// end exit from function
return 0;
}
}
output[j++] = input[i];
}
*input_offset = i;
return 0;
}
static ve_direct_key_values get_key_value_from_str(uint8_t* input) {
const char *str = (const char*) input;
if (strcmp("PID", str) == 0) {
return VE_PID;
}
if (strcmp("FW", str) == 0) {
return VE_FW;
}
if (strcmp("SER#", str) == 0) {
return VE_SERIAL;
}
if (strcmp("V", str) == 0) {
return VE_V;
}
if (strcmp("I", str) == 0) {
return VE_I;
}
if (strcmp("VPV", str) == 0) {
return VE_VPV;
}
if (strcmp("PPV", str) == 0) {
return VE_PPV;
}
if (strcmp("CS", str) == 0) {
return VE_CS;
}
if (strcmp("ERR", str) == 0) {
return VE_ERR;
}
if (strcmp("LOAD", str) == 0) {
return VE_LOAD;
}
if (strcmp("IL", str) == 0) {
return VE_IL;
}
if (strcmp("H19", str) == 0) {
return VE_H19;
}
if (strcmp("H20", str) == 0) {
return VE_H20;
}
if (strcmp("H21", str) == 0) {
return VE_H21;
}
if (strcmp("H22", str) == 0) {
return VE_H22;
}
if (strcmp("H23", str) == 0) {
return VE_H23;
}
if (strcmp("HSDS", str) == 0) {
return VE_HSDS;
}
if (strcmp("Checksum", str) == 0) {
return VE_CHECKSUM;
}
return VE_UNKNOWN;
}
void ve_direct_parser_init(ve_direct_raw_struct* raw_struct, ve_direct_average_struct* avg_struct) {
//uint16_t size = sizeof(ve_avg);
memset(raw_struct, 0x00, sizeof(ve_direct_raw_struct));
memset(avg_struct, 0x00, sizeof(ve_direct_average_struct));
}
void ve_direct_cut_to_checksum(uint8_t* input, uint16_t input_ln,
uint16_t* target_ln) {
uint16_t i = 0;
uint16_t checksum_start = 0;
for (; i < input_ln - 1; i++) {
if (*(input + i) == 'C' && *(input + i + 1) == 'h') {
checksum_start = i;
break;
}
}
if (i >= input_ln - 1) {
*target_ln = 1;
return;
}
*target_ln = checksum_start + CHECKSUM_NAME_FIELD_LN_TO_DATA;
for (i = checksum_start + CHECKSUM_NAME_FIELD_LN_TO_DATA; i < input_ln; i++) {
*(input + i) = 0x00;
}
}
void ve_direct_validate_checksum(uint8_t* input, uint16_t input_ln, uint8_t* valid) {
uint8_t sum = 0;
int i = 0;
if (input_ln < 10) {
*valid = 0;
return;
}
// rewind to first printable chcaracter
while (is_non_printable_character()) {
i++;
// if we reach an end of the string but no printable character has been spotted
if (i >= input_ln) {
*valid = 0;
return;
}
}
// checksum need to be calculated including newline before first record
i -= 2;
for (; i < input_ln; i++) {
// workaround of the problem with loosing \n or \r characters
// don't ask why and what this crap is all about. i had no time
// to debug the connection between the controller and pv charging regulator
sum += *(input + i);
if (i > 0) {
// if \n is the current character check if the previous one was \r
if (*(input + i) == '\n' && *(input + i - 1) != '\r') {
// if not assume that it was received and add it to the checksum
sum += '\r';
// proceed to next character
continue;
}
// if \r is the current character but the next one isn't \n
if (*(input + i) == '\r' && *(input + i + 1) != '\n') {
// if not assume that it was received and add it to the checksum
sum += '\n';
// proceed to next character
continue;
}
}
}
sum %= 0xFF;
if (sum == 0)
*valid = 1;
else
*valid = 0;
return;
}
int ve_direct_parse_to_raw_struct(uint8_t* input, uint16_t input_ln, ve_direct_raw_struct* out) {
// local var to iterate throught
uint16_t i = 0;
// value used to store return value from
int32_t ret_val = 0;
// local variable for parsing a key value to something easly processed
ve_direct_key_values key_enum;
// the same but for values
char* pointer_val = (char*) value;
// rewind to first printable chcaracter
while (is_non_printable_character()) {
i++;
// if we reach an end of the string but no printable character has been spotted
if (i >= input_ln)
return VE_DIRECT_INVALID_INP_STR;
}
// loop from the first printable character till the end of input buffer
for (; i < input_ln;) {
memset(key, 0x00, 9);
memset(value, 0x00, 12);
// start copying a key of this entry
ret_val = copy_till_non_printable_char(input, &i, input_ln, key, sizeof(key));
// check if data were copied correctly
if (ret_val == VE_DIRECT_STRING_END_REACH_TO_EARLY)
return VE_DIRECT_INVALID_INP_STR;
key_enum = get_key_value_from_str(key);
if (key_enum == VE_CHECKSUM) {
// the checksum need to be treated separately, because it consist non-printable chracers
out->checksum = *(input + i - 1);
}
else {
// start copying a value of this entry
ret_val = copy_till_non_printable_char(input, &i, input_ln, value, sizeof(value));
// in case than value wasn't copiedo correctly
if (ret_val == VE_DIRECT_STRING_END_REACH_TO_EARLY)
return VE_DIRECT_INVALID_INP_STR;
}
switch (key_enum) {
case VE_CHECKSUM:
// the checksum is a little bit different because it can consist non-printable characters
break;
case VE_CS: {
switch (value[0]) {
case '0' : out->system_state = STATE_OFF; break;
case '1' : out->system_state = STATE_LOW_PWR; break;
case '2' : out->system_state = STATE_FAULT; break;
case '3' : out->system_state = STATE_BULK; break;
case '4' : out->system_state = STATE_ABSORPTION; break;
case '5' : out->system_state = STATE_FLOAT; break;
default: out->system_state = STATE_UNINITIALIZED; break;
}
break;
}
case VE_ERR:
if (strcmp(pointer_val, "0") == 0) out->error_reason = ERR_OK;
else if (strcmp(pointer_val, "2") == 0) out->error_reason = ERR_EXCESIVE_BAT_VOLTAGE;
else if (strcmp(pointer_val, "17") == 0) out->error_reason = ERR_CHGR_TEMP_TOO_HIGH;
else if (strcmp(pointer_val, "18") == 0) out->error_reason = ERR_CHGR_EXCESIVE_CURR;
else if (strcmp(pointer_val, "19") == 0) out->error_reason = ERR_CHGR_CURR_REVERSED;
else if (strcmp(pointer_val, "20") == 0) out->error_reason = ERR_BULK_TIME_EXCEED;
else if (strcmp(pointer_val, "21") == 0) out->error_reason = ERR_CURRENT_SENSE_FAIL;
else if (strcmp(pointer_val, "26") == 0) out->error_reason = ERR_EXCESIVE_TERMINAL_TEMP;
else if (strcmp(pointer_val, "33") == 0) out->error_reason = ERR_EXCESIVE_PV_VOLTAGE;
else if (strcmp(pointer_val, "34") == 0) out->error_reason = ERR_EXCESIVE_PV_CURRENT;
else if (strcmp(pointer_val, "38") == 0) out->error_reason = ERR_INPUT_SHUTDOWN;
else if (strcmp(pointer_val, "116") == 0) out->error_reason = ERR_TUNES_LOST;
else out->error_reason = ERR_UNINITIALIZED;
break;
case VE_FW:
strcpy(out->fw_version, pointer_val);
break;
case VE_H19:
out->energy_gathered_total = strtol(pointer_val, NULL, 10);
break;
case VE_H20:
out->energy_gathered_today = strtol(pointer_val, NULL, 10);
break;
case VE_H21:
out->maximum_power_today = strtol(pointer_val, NULL, 10);
break;
case VE_H22:
out->energy_gathered_yesterday = strtol(pointer_val, NULL, 10);
break;
case VE_H23:
out->maximum_power_yesterday = strtol(pointer_val, NULL, 10);
break;
case VE_HSDS:
out->day_seq_number = strtol(pointer_val, NULL, 10);
break;
case VE_I:
out->battery_current = strtol(pointer_val, NULL, 10);
break;
case VE_IL:
out->load_current = strtol(pointer_val, NULL, 10);
break;
case VE_LOAD:
if (strcmp(pointer_val, "ON") == 0) out->is_load_on = 1;
else out->is_load_on = 0;
break;
case VE_PID:
out->pid = strtol(pointer_val, NULL, 16);
break;
case VE_PPV:
out->pv_power = strtol(pointer_val, NULL, 10);
break;
case VE_SERIAL:
break;
case VE_V:
out->battery_voltage = strtol(pointer_val, NULL, 10);
break;
case VE_VPV:
out->pv_voltage = strtol(pointer_val, NULL, 10);
break;
default:
break;
}
}
return 0;
}
void ve_direct_add_to_average(ve_direct_raw_struct* in, ve_direct_average_struct* avg_struct) {
if (skip_counter++ < VE_DIRECT_MESSAGES_TO_SKIP) {
return;
}
else {
skip_counter = 0;
}
uint16_t it = avg_struct->current_pointer;
avg_struct->battery_current[it] = in->battery_current;
avg_struct->battery_voltage[it] = in->battery_voltage;
avg_struct->load_current[it] = in->load_current;
avg_struct->pv_voltage[it] = in->pv_voltage;
it++;
if (it > VE_DIRECT_AVERAGE_LEN - 1) {
it = 0;
avg_struct->full_buffer = 1;
}
else {
;
}
avg_struct->current_pointer = it;
if (in->battery_current < avg_struct->min_battery_current) {
avg_struct->min_battery_current = in->battery_current;
}
if (in->battery_current > avg_struct->max_battery_current) {
avg_struct->max_battery_current = in->battery_current;
}
return;
}
void ve_direct_get_averages(ve_direct_average_struct* avg_struct, int16_t* battery_current, uint16_t* battery_voltage,
uint16_t* pv_voltage, uint16_t* load_current) {
if (avg_struct->full_buffer != 1)
return;
int32_t battery_current_avg = 0;
uint32_t battery_voltage_avg = 0;
uint32_t pv_voltage_avg = 0;
uint32_t load_current_avg = 0;
for (int i = 0; i < VE_DIRECT_AVERAGE_LEN; i++) {
battery_current_avg += avg_struct->battery_current[i];
battery_voltage_avg += avg_struct->battery_voltage[i];
pv_voltage_avg += avg_struct->pv_voltage[i];
load_current_avg += avg_struct->load_current[i];
}
*battery_current = battery_current_avg / VE_DIRECT_AVERAGE_LEN;
*battery_voltage = battery_voltage_avg / VE_DIRECT_AVERAGE_LEN;
*pv_voltage = pv_voltage_avg / VE_DIRECT_AVERAGE_LEN;
*load_current = load_current_avg / VE_DIRECT_AVERAGE_LEN;
}
void ve_direct_set_sys_voltage(ve_direct_raw_struct* in, uint8_t* sys_voltage) {
}
void ve_direct_store_errors(ve_direct_raw_struct* input, ve_direct_error_reason* err_reason) {
if (input->error_reason != ERR_OK) {
*err_reason = input->error_reason;
}
else {
if (*err_reason == ERR_UNINITIALIZED || *err_reason == ERR_OK) {
*err_reason = ERR_OK;
}
}
}
void ve_direct_error_to_string(ve_direct_error_reason input, char* output, int8_t output_ln) {
memset(output, 0x00, output_ln);
switch(input) {
case ERR_UNINITIALIZED: snprintf(output, output_ln, "ERR_UNINITIALIZED"); break;
case ERR_OK: snprintf(output, output_ln, "ERR_OK"); break;
case ERR_EXCESIVE_BAT_VOLTAGE: snprintf(output, output_ln, "ERR_EXCESIVE_BAT_VOLTAGE"); break;
case ERR_CHGR_TEMP_TOO_HIGH: snprintf(output, output_ln, "ERR_CHGR_TEMP_TOO_HIGH"); break;
case ERR_CHGR_EXCESIVE_CURR: snprintf(output, output_ln, "ERR_CHGR_EXCESIVE_CURR"); break;
case ERR_CHGR_CURR_REVERSED: snprintf(output, output_ln, "ERR_CHGR_CURR_REVERSED"); break;
case ERR_BULK_TIME_EXCEED: snprintf(output, output_ln, "ERR_BULK_TIME_EXCEED"); break;
case ERR_CURRENT_SENSE_FAIL: snprintf(output, output_ln, "ERR_CURRENT_SENSE_FAIL"); break;
case ERR_EXCESIVE_TERMINAL_TEMP: snprintf(output, output_ln, "ERR_EXCESIVE_TERMINAL_TEMP"); break;
case ERR_EXCESIVE_PV_VOLTAGE: snprintf(output, output_ln, "ERR_EXCESIVE_PV_VOLTAGE"); break;
case ERR_EXCESIVE_PV_CURRENT: snprintf(output, output_ln, "ERR_EXCESIVE_PV_CURRENT"); break;
case ERR_INPUT_SHUTDOWN: snprintf(output, output_ln, "ERR_INPUT_SHUTDOWN"); break;
case ERR_TUNES_LOST: snprintf(output, output_ln, "ERR_TUNES_LOST"); break;
}
}
void ve_direct_state_to_string(ve_direct_system_state input, char* output, int8_t output_ln) {
memset(output, 0x00, output_ln);
switch(input) {
case STATE_UNINITIALIZED: snprintf(output, output_ln, "STATE_UNINITIALIZED"); break;
case STATE_OFF: snprintf(output, output_ln, "STATE_OFF"); break;
case STATE_LOW_PWR: snprintf(output, output_ln, "STATE_LOW_PWR"); break;
case STATE_FAULT: snprintf(output, output_ln, "STATE_FAULT"); break;
case STATE_BULK: snprintf(output, output_ln, "STATE_BULK"); break;
case STATE_ABSORPTION: snprintf(output, output_ln, "STATE_ABSORPTION"); break;
case STATE_FLOAT: snprintf(output, output_ln, "STATE_FLOAT"); break;
case STATE_INVERTING: snprintf(output, output_ln, "STATE_INVERTING"); break;
}
}
/**
*
*
*
*"\r\nPID\t0xA042\r\nFW\t127\r\nSER#\tHQ1723BQTPC\nV\t13780\nI\t190\r\nVPV\t17770\r\nPPV\t3\r\nCS\t5\r\nERR\t0\r\nLOAD\tON\nIL\t0\nH19\t593\r\nH20\t1\r\nH21\t12\r\nH22\t7\r\nH23\t93\r\nHSDS\t167\nChecksum\t8"
*
*
*\r\nPID\t0xA042
*\r\nFW\t127
*\r\nSER#\tHQ1723BQTPC
*\nV\t13780
*\nI\t190
*\r\nVPV\t17770
*\r\nPPV\t3
*\r\nCS\t5
*\r\nERR\t0
*\r\nLOAD\tON
*\nIL\t0
*\nH19\t593
*\r\nH20\t1
*\r\nH21\t12
*\r\nH22\t7
*\r\nH23\t93
*\r\nHSDS\t167
*\nChecksum\t8"
*
* Z:\home\mateusz\Documents\___STM32\VE_DIRECT_3.bin (3/22/2021 7:08:36 PM)
* StartOffset(h): 00000000, EndOffset(h): 0000009B, Length(h): 0000009C
*
*unsigned char rawData[156] = {
* 0x0D, 0x0A, 0x50, 0x49, 0x44, 0x09, 0x30, 0x78, 0x41, 0x30, 0x34, 0x32,
* 0x0D, 0x0A, 0x46, 0x57, 0x09, 0x31, 0x32, 0x37, 0x0D, 0x0A, 0x53, 0x45,
* 0x52, 0x23, 0x09, 0x48, 0x51, 0x31, 0x37, 0x32, 0x33, 0x42, 0x51, 0x54,
* 0x50, 0x43, 0x0A, 0x56, 0x09, 0x31, 0x33, 0x37, 0x38, 0x30, 0x0A, 0x49,
* 0x09, 0x31, 0x39, 0x30, 0x0D, 0x0A, 0x56, 0x50, 0x56, 0x09, 0x31, 0x37,
* 0x37, 0x37, 0x30, 0x0D, 0x0A, 0x50, 0x50, 0x56, 0x09, 0x33, 0x0D, 0x0A,
* 0x43, 0x53, 0x09, 0x35, 0x0D, 0x0A, 0x45, 0x52, 0x52, 0x09, 0x30, 0x0D,
* 0x0A, 0x4C, 0x4F, 0x41, 0x44, 0x09, 0x4F, 0x4E, 0x0A, 0x49, 0x4C, 0x09,
* 0x30, 0x0A, 0x48, 0x31, 0x39, 0x09, 0x35, 0x39, 0x33, 0x0D, 0x0A, 0x48,
* 0x32, 0x30, 0x09, 0x31, 0x0D, 0x0A, 0x48, 0x32, 0x31, 0x09, 0x31, 0x32,
* 0x0D, 0x0A, 0x48, 0x32, 0x32, 0x09, 0x37, 0x0D, 0x0A, 0x48, 0x32, 0x33,
* 0x09, 0x39, 0x33, 0x0D, 0x0A, 0x48, 0x53, 0x44, 0x53, 0x09, 0x31, 0x36,
* 0x37, 0x0A, 0x43, 0x68, 0x65, 0x63, 0x6B, 0x73, 0x75, 0x6D, 0x09, 0x38
*};
*
* 0D 0A 50 49 44 09 30 78 41 30 34 32 0D 0A 46 57 09 31 32 37 0D 0A 53 45 52 23 09 48 51 31 37 32 33 42 51 54 50 43 0A 56 09 31 33 37 38 30 0A 49 09 31 39 30 0D 0A 56 50 56 09 31 37 37 37 30 0D 0A 50 50 56 09 33 0D 0A 43 53 09 35 0D 0A 45 52 52 09 30 0D 0A 4C 4F 41 44 09 4F 4E 0A 49 4C 09 30 0A 48 31 39 09 35 39 33 0D 0A 48 32 30 09 31 0D 0A 48 32 31 09 31 32 0D 0A 48 32 32 09 37 0D 0A 48 32 33 09 39 33 0D 0A 48 53 44 53 09 31 36 37 0A 43 68 65 63 6B 73 75 6D 09 38
*
*
*
*
*
*
*
*
*/