Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 84 additions & 15 deletions VeDirectFrameHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,24 +36,34 @@
#include "VeDirectFrameHandler.h"

#define MODULE "VE.Frame" // Victron seems to use this to find out where logging messages were generated
#define MAX_HEX_CALLBACK 10 // initial number - buffer is dynamically increased if necessary

// The name of the record that contains the checksum.
static constexpr char checksumTagName[] = "CHECKSUM";

VeDirectFrameHandler::VeDirectFrameHandler() :
veName(),
veValue(),
frameIndex(0),
veEnd(0),
veHEnd(0),
//mStop(false), // don't know what Victron uses this for, not using
logEF(0),
mState(IDLE),
mChecksum(0),
mTextPointer(0),
tempName(),
tempValue(),
frameIndex(0),
veName(),
veValue(),
veEnd(0)
tempName(),
tempValue(),
veHexCBList(0),
veCBEnd(0),
maxCB(MAX_HEX_CALLBACK)
{
}

VeDirectFrameHandler::~VeDirectFrameHandler() {
if (veHexCBList) delete veHexCBList;
}

/*
* rxData
* This function is called by the application which passes a byte of serial data
Expand All @@ -63,7 +73,9 @@ void VeDirectFrameHandler::rxData(uint8_t inbyte)
{
//if (mStop) return;
if ( (inbyte == ':') && (mState != CHECKSUM) ) {
vePushedState = mState; //hex frame can interrupt TEXT
mState = RECORD_HEX;
veHEnd = 0;
}
if (mState != RECORD_HEX) {
mChecksum += inbyte;
Expand Down Expand Up @@ -140,10 +152,7 @@ void VeDirectFrameHandler::rxData(uint8_t inbyte)
break;
}
case RECORD_HEX:
if (hexRxEvent(inbyte)) {
mChecksum = 0;
mState = IDLE;
}
mState = hexRxEvent(inbyte);
break;
}
}
Expand Down Expand Up @@ -192,18 +201,78 @@ void VeDirectFrameHandler::frameEndEvent(bool valid) {
* logE
* This function included for continuity and possible future use.
*/
void VeDirectFrameHandler::logE(char * module, char * error) {
void VeDirectFrameHandler::logE(const char * module, const char * error) {
//Serial.print("MODULE: ");
//Serial.println(module);
//Serial.print("ERROR: ");
//Serial.println(error);
return;
if (logEF)
(*logEF)(module,error);
}

/*
* addHexCallback
* This function record a new callback for hex frames
*/
void VeDirectFrameHandler::addHexCallback(hexCallback cb, void* data) {
if (veHexCBList==0) { // first time, allocate callbacks buffer
veHexCBList=new VeHexCB[maxCB];
veCBEnd=0;
}
else if (veCBEnd==maxCB) { // we need to resize the callbacks buffer, we double the max size
int newMax=maxCB*2;
VeHexCB* tmpb=new VeHexCB[newMax];
memcpy(tmpb, veHexCBList, maxCB*sizeof(VeHexCB));
maxCB=newMax;
delete veHexCBList;
veHexCBList=tmpb;
}
veHexCBList[veCBEnd].cb=cb;
veHexCBList[veCBEnd].data=data;
veCBEnd++;
}

/*
* hexIsValid
* This function compute checksum and validate hex frame
*/
#define ascii2hex(v) (v-48-(v>='A'?7:0))
#define hex2byte(b) (ascii2hex(*(b)))*16+((ascii2hex(*(b+1))))
static bool hexIsValid(const char* buffer, int size) {
uint8_t checksum=0x55-ascii2hex(buffer[1]);
for (int i=2; i<size; i+=2) checksum -= hex2byte(buffer+i);
return (checksum==0);
}

/*
* hexRxEvent
* This function included for continuity and possible future use.
* This function records hex answers or async messages
*/
bool VeDirectFrameHandler::hexRxEvent(uint8_t inbyte) {
return true; // stubbed out for future
int VeDirectFrameHandler::hexRxEvent(uint8_t inbyte) {
int ret=RECORD_HEX; // default - continue recording until end of frame

switch (inbyte) {
case '\n':
// message ready - call all callbacks
if (hexIsValid(veHexBuffer,veHEnd)) {
for(int i=0; i<veCBEnd; i++) {
(*(veHexCBList[i].cb))(veHexBuffer, veHEnd, veHexCBList[i].data);
}
}
else {
logE(MODULE,"[CHECKSUM] Invalid hex frame");
}
// restore previous state
ret=vePushedState;

default:
veHexBuffer[veHEnd++]=inbyte;
if (veHEnd>=hexBuffLen) { // oops -buffer overflow - something went wrong, we abort
logE(MODULE,"hexRx buffer overflow - aborting read");
veHEnd=0;
ret=IDLE;
}
}

return ret;
}
27 changes: 24 additions & 3 deletions VeDirectFrameHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,38 @@ const byte frameLen = 18; // VE.Direct Protocol: max frame
const byte nameLen = 9; // VE.Direct Protocol: max name size is 9 including /0
const byte valueLen = 33; // VE.Direct Protocol: max value size is 33 including /0
const byte buffLen = 40; // Maximum number of lines possible from the device. Current protocol shows this to be the BMV700 at 33 lines.
const byte hexBuffLen = 100; // Maximum size of hex frame - max payload 34 byte (=68 char) + safe buffer

typedef void (*hexCallback)(const char*, int, void*);

struct VeHexCB {
hexCallback cb;
void* data;
};

typedef void (*logFunction)(const char *, const char *);


class VeDirectFrameHandler {

public:
VeDirectFrameHandler();
~VeDirectFrameHandler();
void setErrorHandler(logFunction f) { logEF=f;} // error handler
void rxData(uint8_t inbyte); // byte of serial data to be passed by the application
void addHexCallback(hexCallback, void*); // add function called back when hex frame is ready (sync or async)

char veName[buffLen][nameLen] = { }; // public buffer for received names
char veValue[buffLen][valueLen] = { }; // public buffer for received values
char veHexBuffer[hexBuffLen] = { }; // public buffer for received hex frames

int frameIndex; // which line of the frame are we on
int veEnd; // current size (end) of the public buffer
int veHEnd; // size of hex buffer

private:
//bool mStop; // not sure what Victron uses this for, not using
logFunction logEF;

enum States { // state machine
IDLE,
Expand All @@ -42,7 +58,7 @@ class VeDirectFrameHandler {

int mState; // current state

uint8_t mChecksum; // checksum value
uint8_t mChecksum; // checksum value

char * mTextPointer; // pointer to the private buffer we're writing to, name or value

Expand All @@ -53,8 +69,13 @@ class VeDirectFrameHandler {

void textRxEvent(char *, char *);
void frameEndEvent(bool);
void logE(char *, char *);
bool hexRxEvent(uint8_t);
void logE(const char *, const char *);
int hexRxEvent(uint8_t);

VeHexCB* veHexCBList;
int veCBEnd;
int maxCB;
int vePushedState;
};

#endif // FRAMEHANDLER_H_
23 changes: 22 additions & 1 deletion example/ReadVEDirectFramehandler.ino
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,34 @@ VeDirectFrameHandler myve;
// SoftwareSerial
#define rxPin D7 // RX using Software Serial so we can use the hardware UART to check the ouput
#define txPin D8 // TX Not used
SoftwareSerial veSerial(rxPin, txPin);
SoftwareSerial veSerial(rxPin, txPin);

// hex frame callback function
void HexCallback(const char* buffer, int size, void* data) {
char tmp[100];
memcpy(tmp, buffer, size*sizeof(char));
tmp[size]=0;
Serial.print("received hex frame: ");
Serial.println(tmp);
}

// log helper
void LogHelper(const char* module, const char* error) {
Serial.print(module);
Serial.print(":");
Serial.println(error);
}


void setup() {
Serial.begin(115200); // output serial port
veSerial.begin(19200); // input serial port (VE device)
veSerial.flush();
Serial.println("DEBUG-setup");
// log helper
myve.setErrorHandler(&LogHelper);
// hex protocol callback
myve.addHexCallback(&HexCallback, (void*)42);
}

void loop() {
Expand Down