Advertisement
Guest User

Untitled

a guest
Mar 27th, 2024
67
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.84 KB | None | 0 0
  1. /* framehandler.cpp
  2.  *
  3.  * Arduino library to read from Victron devices using VE.Direct protocol.
  4.  * Derived from Victron framehandler reference implementation.
  5.  *
  6.  * The MIT License
  7.  *
  8.  * Copyright (c) 2019 Victron Energy BV
  9.  * Portions Copyright (C) 2020 Chris Terwilliger
  10.  *
  11.  * Permission is hereby granted, free of charge, to any person obtaining a copy
  12.  * of this software and associated documentation files (the "Software"), to deal
  13.  * in the Software without restriction, including without limitation the rights
  14.  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  15.  * copies of the Software, and to permit persons to whom the Software is
  16.  * furnished to do so, subject to the following conditions:
  17.  *
  18.  * The above copyright notice and this permission notice shall be included in
  19.  * all copies or substantial portions of the Software.
  20.  *
  21.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  22.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  23.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  24.  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  25.  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  26.  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  27.  * THE SOFTWARE.
  28.  *
  29.  * 2020.05.05 - 0.2 - initial release
  30.  * 2020.06.21 - 0.2 - add MIT license, no code changes
  31.  * 2020.08.20 - 0.3 - corrected #include reference
  32.  *
  33.  */
  34.  
  35. #include <Arduino.h>
  36. #include "VeDirectFrameHandler.h"
  37.  
  38. #define MODULE "VE.Frame" // Victron seems to use this to find out where logging messages were generated
  39.  
  40. // The name of the record that contains the checksum.
  41. static constexpr char checksumTagName[] = "CHECKSUM";
  42.  
  43. VeDirectFrameHandler::VeDirectFrameHandler() : // mStop(false), // don't know what Victron uses this for, not using
  44.                                                mState(IDLE),
  45.                                                mChecksum(0),
  46.                                                mTextPointer(0),
  47.                                                tempName(),
  48.                                                tempValue(),
  49.                                                frameIndex(0),
  50.                                                veName(),
  51.                                                veValue(),
  52.                                                veEnd(0)
  53. {
  54. }
  55.  
  56. /*
  57.  *  rxData
  58.  *  This function is called by the application which passes a byte of serial data
  59.  *  It is unchanged from Victron's example code
  60.  */
  61. void VeDirectFrameHandler::rxData(uint8_t inbyte)
  62. {
  63.      Serial.write(inbyte);
  64.     // if (mStop) return;
  65.     if ((inbyte == ':') && (mState != CHECKSUM))
  66.     {
  67.         mState = RECORD_HEX;
  68.     }
  69.     if (mState != RECORD_HEX)
  70.     {
  71.         mChecksum += inbyte;
  72.     }
  73.     inbyte = toupper(inbyte);
  74.  
  75.     switch (mState)
  76.     {
  77.     case IDLE:
  78.         /* wait for \n of the start of an record */
  79.         switch (inbyte)
  80.         {
  81.         case '\n':
  82.             mState = RECORD_BEGIN;
  83.             break;
  84.         case '\r': /* Skip */
  85.         default:
  86.             break;
  87.         }
  88.         break;
  89.     case RECORD_BEGIN:
  90.         mTextPointer = mName;
  91.         *mTextPointer++ = inbyte;
  92.         mState = RECORD_NAME;
  93.         break;
  94.     case RECORD_NAME:
  95.         // The record name is being received, terminated by a \t
  96.         switch (inbyte)
  97.         {
  98.         case '\t':
  99.             // the Checksum record indicates a EOR
  100.             if (mTextPointer < (mName + sizeof(mName)))
  101.             {
  102.                 *mTextPointer = 0; /* Zero terminate */
  103.                 if (strcmp(mName, checksumTagName) == 0)
  104.                 {
  105.                     mState = CHECKSUM;
  106.                     break;
  107.                 }
  108.             }
  109.             mTextPointer = mValue; /* Reset value pointer */
  110.             mState = RECORD_VALUE;
  111.             break;
  112.  
  113.  
  114.         default:
  115.             // add byte to name, but do no overflow
  116.             if (mTextPointer < (mName + sizeof(mName)))
  117.                 *mTextPointer++ = inbyte;
  118.             break;
  119.         }
  120.         break;
  121.     case RECORD_VALUE:
  122.         // The record value is being received.  The \r indicates a new record.
  123.         switch (inbyte)
  124.         {
  125.         case '\n':
  126.             // forward record, only if it could be stored completely
  127.             if (mTextPointer < (mValue + sizeof(mValue)))
  128.             {
  129.                 *mTextPointer = 0; // make zero ended
  130.                 textRxEvent(mName, mValue);
  131.             }
  132.             mState = RECORD_BEGIN;
  133.             break;
  134.         case '\r': /* Skip */
  135.             break;
  136.         default:
  137.             // add byte to value, but do no overflow
  138.             if (mTextPointer < (mValue + sizeof(mValue)))
  139.                 *mTextPointer++ = inbyte;
  140.             break;
  141.         }
  142.         break;
  143.     case CHECKSUM:
  144.     {
  145.         Serial.println();
  146.         Serial.print("Calcula CHK: ");
  147.         Serial.println(mChecksum, HEX);
  148.         Serial.print("Recived CHK: ");
  149.         Serial.println(inbyte, HEX);
  150.  
  151.         bool valid = mChecksum == 0;
  152.         // Serial.println(mChecksum);
  153.         if (!valid)
  154.         {
  155.             veError = 0;
  156.             logE((char *)MODULE, (char *)"[CHECKSUM] Invalid frame");
  157.         }
  158.         mChecksum = 0;
  159.         mState = IDLE;
  160.         frameEndEvent(valid);
  161.         break;
  162.     }
  163.     case RECORD_HEX:
  164.         if (hexRxEvent(inbyte))
  165.         {
  166.             mChecksum = 0;
  167.             mState = IDLE;
  168.             // here put in a callback later
  169.         }
  170.         break;
  171.     }
  172. }
  173.  
  174. /*
  175.  * textRxEvent
  176.  * This function is called every time a new name/value is successfully parsed.  It writes the values to the temporary buffer.
  177.  */
  178. void VeDirectFrameHandler::textRxEvent(char *mName, char *mValue)
  179. {
  180.     strcpy(tempName[frameIndex], mName);   // copy name to temporary buffer
  181.     strcpy(tempValue[frameIndex], mValue); // copy value to temporary buffer
  182.     frameIndex++;
  183. }
  184.  
  185. /*
  186.  *  frameEndEvent
  187.  *  This function is called at the end of the received frame.  If the checksum is valid, the temp buffer is read line by line.
  188.  *  If the name exists in the public buffer, the new value is copied to the public buffer.  If not, a new name/value entry
  189.  *  is created in the public buffer.
  190.  */
  191. void VeDirectFrameHandler::frameEndEvent(bool valid)
  192. {
  193.     if (valid)
  194.     {
  195.         for (int i = 0; i < frameIndex; i++)
  196.         { // read each name already in the temp buffer
  197.             bool nameExists = false;
  198.             for (int j = 0; j <= veEnd; j++)
  199.             { // compare to existing names in the public buffer
  200.                 if (strcmp(tempName[i], veName[j]) == 0)
  201.                 {
  202.                     strcpy(veValue[j], tempValue[i]); // overwrite tempValue in the public buffer
  203.                     nameExists = true;
  204.                     break;
  205.                 }
  206.             }
  207.             if (!nameExists)
  208.             {
  209.                 strcpy(veName[veEnd], tempName[i]);   // write new Name to public buffer
  210.                 strcpy(veValue[veEnd], tempValue[i]); // write new Value to public buffer
  211.                 veEnd++;                              // increment end of public buffer
  212.                 if (veEnd >= buffLen)
  213.                 { // stop any buffer overrun
  214.                     veEnd = buffLen - 1;
  215.                 }
  216.             }
  217.         }
  218.         veError = 0;
  219.         requestCallback(); // call the callback to do other things with the new data
  220.     }
  221.     else
  222.     {
  223.         veError = 1;
  224.     }
  225.     frameIndex = 0; // reset frame
  226. }
  227.  
  228. /*
  229.  *  logE
  230.  *  This function included for continuity and possible future use.
  231.  */
  232. void VeDirectFrameHandler::logE(char *module, char *error)
  233. {
  234.     Serial.print("MODULE: ");
  235.     Serial.println(module);
  236.     Serial.print("ERROR: ");
  237.     Serial.println(error);
  238.     return;
  239. }
  240.  
  241. /*
  242.  *  hexRxEvent
  243.  *  This function included for continuity and possible future use.
  244.  */
  245. bool VeDirectFrameHandler::hexRxEvent(uint8_t inbyte)
  246. {
  247.     return true; // stubbed out for future
  248. }
  249.  
  250. void VeDirectFrameHandler::callback(std::function<void()> func) // callback function when finnish request
  251. {
  252.     requestCallback = func;
  253. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement