mirror of
https://github.com/lumapu/ahoy.git
synced 2025-05-03 12:15:54 +02:00
commit
2da9306cf9
9 changed files with 114 additions and 73 deletions
|
@ -13,7 +13,7 @@
|
|||
//-------------------------------------
|
||||
#define VERSION_MAJOR 0
|
||||
#define VERSION_MINOR 8
|
||||
#define VERSION_PATCH 7
|
||||
#define VERSION_PATCH 0707
|
||||
|
||||
//-------------------------------------
|
||||
typedef struct {
|
||||
|
|
|
@ -85,6 +85,10 @@ class CommQueue {
|
|||
mQueue[mRdPtr].attempts--;
|
||||
}
|
||||
|
||||
void incrAttempt(void) {
|
||||
mQueue[mRdPtr].attempts++;
|
||||
}
|
||||
|
||||
void inc(uint8_t *ptr) {
|
||||
if(++(*ptr) >= N)
|
||||
*ptr = 0;
|
||||
|
|
|
@ -11,9 +11,10 @@
|
|||
#include "../utils/crc.h"
|
||||
#include "Heuristic.h"
|
||||
|
||||
#define MI_TIMEOUT 250
|
||||
#define DEFAULT_TIMEOUT 500
|
||||
#define SINGLEFR_TIMEOUT 60
|
||||
#define MI_TIMEOUT 250 // timeout for MI type requests
|
||||
#define FRSTMSG_TIMEOUT 150 // how long to wait for first msg to be received
|
||||
#define DEFAULT_TIMEOUT 500 // timeout for regular requests
|
||||
#define SINGLEFR_TIMEOUT 60 // timeout for single frame requests
|
||||
#define MAX_BUFFER 250
|
||||
|
||||
typedef std::function<void(uint8_t, Inverter<> *)> payloadListenerType;
|
||||
|
@ -43,7 +44,8 @@ class Communication : public CommQueue<> {
|
|||
if(!valid)
|
||||
return; // empty
|
||||
|
||||
uint16_t timeout = q->iv->ivGen != IV_MI ? DEFAULT_TIMEOUT : MI_TIMEOUT;
|
||||
uint16_t timeout = q->iv->ivGen != IV_MI ? (mGotFragment && q->iv->mGotLastMsg) ? SINGLEFR_TIMEOUT : DEFAULT_TIMEOUT : MI_TIMEOUT;
|
||||
uint16_t timeout_min = q->iv->ivGen != IV_MI ? mGotFragment ? SINGLEFR_TIMEOUT : FRSTMSG_TIMEOUT : MI_TIMEOUT;
|
||||
bool testMode = false;
|
||||
|
||||
switch(mState) {
|
||||
|
@ -55,11 +57,13 @@ class Communication : public CommQueue<> {
|
|||
mLocalBuf[i].len = 0;
|
||||
}
|
||||
|
||||
mHeu.printStatus(q->iv);
|
||||
if(q->iv->radio->isSerialDebug())
|
||||
mHeu.printStatus(q->iv);
|
||||
mHeu.getTxCh(q->iv);
|
||||
testMode = mHeu.getTestModeEnabled();
|
||||
mGotFragment = false;
|
||||
mFirstTry = mFirstTry ? false : ( (IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen) ) && (q->iv->isAvailable()); //) || (millis() < 120000));}
|
||||
q->iv->mGotLastMsg = false;
|
||||
mFirstTry = mFirstTry ? false : ( ( (IV_HM == q->iv->ivGen) || (IV_MI == q->iv->ivGen) ) && (q->iv->isAvailable()) || (millis() < 120000) );
|
||||
if(NULL == q->iv->radio)
|
||||
cmdDone(true); // can't communicate while radio is not defined!
|
||||
mState = States::START;
|
||||
|
@ -83,12 +87,33 @@ class Communication : public CommQueue<> {
|
|||
q->iv->radio->prepareDevInformCmd(q->iv, q->cmd, q->ts, q->iv->alarmLastId, false);
|
||||
if(!testMode)
|
||||
q->iv->radioStatistics.txCnt++;
|
||||
mWaitTimeout = millis() + timeout;
|
||||
mWaitTimeout = millis() + timeout;
|
||||
mWaitTimeout_min = millis() + timeout_min;
|
||||
setAttempt();
|
||||
mState = States::WAIT;
|
||||
break;
|
||||
|
||||
case States::WAIT:
|
||||
if(millis() > mWaitTimeout_min) {
|
||||
if(!mGotFragment) { // nothing received yet?
|
||||
if(q->iv->radio->get()) { // radio received sth.?
|
||||
mGotFragment = true;
|
||||
if(q->iv->mGotLastMsg) {
|
||||
//mState = States::CHECK_FRAMES;
|
||||
mWaitTimeout = mWaitTimeout_min;
|
||||
}
|
||||
}
|
||||
} else if(mFirstTry) {
|
||||
DPRINT_IVID(DBG_INFO, q->iv->id);
|
||||
DBGPRINTLN(F("second try"));
|
||||
mFirstTry = false;
|
||||
if(!testMode)
|
||||
q->iv->radioStatistics.retransmits++; // got nothing
|
||||
mState = States::START;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
if(millis() < mWaitTimeout)
|
||||
return;
|
||||
mState = States::CHECK_FRAMES;
|
||||
|
@ -102,7 +127,7 @@ class Communication : public CommQueue<> {
|
|||
DBGPRINT(String(millis() - mWaitTimeout + timeout));
|
||||
DBGPRINTLN(F("ms"));
|
||||
|
||||
if(!mGotFragment && !mFirstTry) {
|
||||
if(!mGotFragment) { // && !mFirstTry) {
|
||||
if(!testMode)
|
||||
q->iv->radioStatistics.rxFailNoAnser++; // got nothing
|
||||
mHeu.setGotNothing(q->iv);
|
||||
|
@ -140,7 +165,7 @@ class Communication : public CommQueue<> {
|
|||
DBGPRINT(F(", "));
|
||||
DBGPRINT(String(p->rssi));
|
||||
DBGPRINT(F("dBm | "));
|
||||
ah::dumpBuf(p->packet, p->len);
|
||||
ah::dumpBuf(p->packet, p->len, 1, 8, "#"+String(q->iv->id));
|
||||
|
||||
if(checkIvSerial(&p->packet[1], q->iv)) {
|
||||
if(!testMode)
|
||||
|
@ -178,41 +203,39 @@ class Communication : public CommQueue<> {
|
|||
break;
|
||||
|
||||
case States::CHECK_PACKAGE:
|
||||
uint8_t framnr = 0;
|
||||
if(0 == mMaxFrameId) {
|
||||
setAttempt();
|
||||
|
||||
DPRINT_IVID(DBG_WARN, q->iv->id);
|
||||
DBGPRINT(F("frame missing: request retransmit ("));
|
||||
DBGPRINT(String(q->attempts));
|
||||
DBGPRINTLN(F(" attempts left)"));
|
||||
|
||||
uint8_t i = 0;
|
||||
while(i < MAX_PAYLOAD_ENTRIES) {
|
||||
if(mLocalBuf[i].len == 0)
|
||||
framnr = i+1;
|
||||
break;
|
||||
i++;
|
||||
}
|
||||
|
||||
sendRetransmit(q, i);
|
||||
return;
|
||||
}
|
||||
|
||||
for(uint8_t i = 0; i < mMaxFrameId; i++) {
|
||||
if(mLocalBuf[i].len == 0) {
|
||||
setAttempt();
|
||||
|
||||
DPRINT_IVID(DBG_WARN, q->iv->id);
|
||||
DBGPRINT(F("frame "));
|
||||
DBGPRINT(String(i + 1));
|
||||
DBGPRINT(F(" missing: request retransmit ("));
|
||||
DBGPRINT(String(q->attempts));
|
||||
DBGPRINTLN(F(" attempts left)"));
|
||||
|
||||
sendRetransmit(q, i);
|
||||
return;
|
||||
if(!framnr) {
|
||||
for(uint8_t i = 0; i < mMaxFrameId; i++) {
|
||||
if(mLocalBuf[i].len == 0) {
|
||||
framnr = i+1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(framnr) {
|
||||
setAttempt();
|
||||
|
||||
DPRINT_IVID(DBG_WARN, q->iv->id);
|
||||
DBGPRINT(F("frame "));
|
||||
DBGPRINT(String(framnr));
|
||||
DBGPRINT(F(" missing: request retransmit ("));
|
||||
DBGPRINT(String(q->attempts));
|
||||
DBGPRINTLN(F(" attempts left)"));
|
||||
sendRetransmit(q, framnr-1);
|
||||
return;
|
||||
}
|
||||
|
||||
mHeu.setGotAll(q->iv);
|
||||
compilePayload(q, testMode);
|
||||
|
||||
|
@ -257,8 +280,9 @@ class Communication : public CommQueue<> {
|
|||
return; // CRC8 is wrong, frame invalid
|
||||
}
|
||||
|
||||
if((*frameId & ALL_FRAMES) == ALL_FRAMES)
|
||||
if((*frameId & ALL_FRAMES) == ALL_FRAMES) {
|
||||
mMaxFrameId = (*frameId & 0x7f);
|
||||
}
|
||||
|
||||
frame_t *f = &mLocalBuf[(*frameId & 0x7f) - 1];
|
||||
memcpy(f->buf, &p->packet[10], p->len-11);
|
||||
|
@ -413,9 +437,6 @@ class Communication : public CommQueue<> {
|
|||
inline void miHwDecode(packet_t *p, const queue_s *q) {
|
||||
record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_All); // choose the record structure
|
||||
rec->ts = q->ts;
|
||||
//mPayload[iv->id].gotFragment = true;
|
||||
uint8_t multi_parts = 0;
|
||||
|
||||
/*
|
||||
Polling the device software and hardware version number command
|
||||
start byte Command word routing address target address User data check end byte
|
||||
|
@ -458,14 +479,13 @@ class Communication : public CommQueue<> {
|
|||
q->iv->isConnected = true;
|
||||
//if(mSerialDebug) {
|
||||
DPRINT_IVID(DBG_INFO, q->iv->id);
|
||||
DPRINT(DBG_INFO,F("HW_VER is "));
|
||||
DBGPRINT(F("HW_VER is "));
|
||||
DBGPRINTLN(String((p->packet[24] << 8) + p->packet[25]));
|
||||
//}
|
||||
record_t<> *rec = q->iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure
|
||||
rec->ts = q->ts;
|
||||
q->iv->setValue(1, rec, (uint32_t) ((p->packet[24] << 8) + p->packet[25])/1);
|
||||
//mPayload[iv->id].multi_parts +=4;
|
||||
multi_parts +=4;
|
||||
q->iv->miMultiParts +=4;
|
||||
} else if ( p->packet[9] == 0x01 || p->packet[9] == 0x10 ) {//second frame for MI, 3rd gen. answers in 0x10
|
||||
DPRINT_IVID(DBG_INFO, q->iv->id);
|
||||
if ( p->packet[9] == 0x01 ) {
|
||||
|
@ -486,19 +506,19 @@ class Communication : public CommQueue<> {
|
|||
//if(mSerialDebug) {
|
||||
DPRINT(DBG_INFO,F("HW_FB_TLmValue "));
|
||||
DBGPRINTLN(String((p->packet[14] << 8) + p->packet[15]));
|
||||
DPRINT(DBG_INFO,F("HW_FB_ReSPRT "));
|
||||
DBGPRINT(F("HW_FB_ReSPRT "));
|
||||
DBGPRINTLN(String((p->packet[16] << 8) + p->packet[17]));
|
||||
DPRINT(DBG_INFO,F("HW_GridSamp_ResValule "));
|
||||
DBGPRINT(F("HW_GridSamp_ResValule "));
|
||||
DBGPRINTLN(String((p->packet[18] << 8) + p->packet[19]));
|
||||
DPRINT(DBG_INFO,F("HW_ECapValue "));
|
||||
DBGPRINT(F("HW_ECapValue "));
|
||||
DBGPRINTLN(String((p->packet[20] << 8) + p->packet[21]));
|
||||
DPRINT(DBG_INFO,F("Matching_APPFW_PN "));
|
||||
DBGPRINT(F("Matching_APPFW_PN "));
|
||||
DBGPRINTLN(String((uint32_t) (((p->packet[22] << 8) | p->packet[23]) << 8 | p->packet[24]) << 8 | p->packet[25]));
|
||||
//}
|
||||
//notify(InverterDevInform_Simple, iv);
|
||||
//mPayload[iv->id].multi_parts +=2;
|
||||
multi_parts +=2;
|
||||
//notify(InverterDevInform_All, iv);
|
||||
if(NULL != mCbPayload)
|
||||
(mCbPayload)(InverterDevInform_All, q->iv);
|
||||
q->iv->miMultiParts +=2;
|
||||
|
||||
} else {
|
||||
DBGPRINTLN(F("3rd gen. inverter!"));
|
||||
}
|
||||
|
@ -515,21 +535,24 @@ class Communication : public CommQueue<> {
|
|||
//if(mSerialDebug) {
|
||||
DPRINT(DBG_INFO,F("APPFW_MINVER "));
|
||||
DBGPRINTLN(String((p->packet[10] << 8) + p->packet[11]));
|
||||
DPRINT(DBG_INFO,F("HWInfoAddr "));
|
||||
DBGPRINT(F("HWInfoAddr "));
|
||||
DBGPRINTLN(String((p->packet[12] << 8) + p->packet[13]));
|
||||
DPRINT(DBG_INFO,F("PNInfoCRC_gusv "));
|
||||
DBGPRINT(F("PNInfoCRC_gusv "));
|
||||
DBGPRINTLN(String((p->packet[14] << 8) + p->packet[15]));
|
||||
//}
|
||||
//mPayload[iv->id].multi_parts++;
|
||||
multi_parts++;
|
||||
if(NULL != mCbPayload)
|
||||
(mCbPayload)(InverterDevInform_Simple, q->iv);
|
||||
q->iv->miMultiParts++;
|
||||
}
|
||||
if(multi_parts > 5) {
|
||||
if(q->iv->miMultiParts > 5) {
|
||||
cmdDone(true);
|
||||
mState = States::RESET;
|
||||
q->iv->radioStatistics.rxSuccess++;
|
||||
mHeu.setGotAll(q->iv);
|
||||
q->iv->miMultiParts = 0;
|
||||
} else {
|
||||
mHeu.setGotFragment(q->iv);
|
||||
mState = States::WAIT;
|
||||
}
|
||||
|
||||
/*if (mPayload[iv->id].multi_parts > 5) {
|
||||
|
@ -568,9 +591,8 @@ class Communication : public CommQueue<> {
|
|||
|
||||
q->iv->setValue(q->iv->getPosByChFld(0, FLD_T, rec), rec, (float) ((int16_t)(p->packet[21] << 8) + p->packet[22])/10);
|
||||
q->iv->setValue(q->iv->getPosByChFld(0, FLD_IRR, rec), rec, (float) (calcIrradiation(q->iv, datachan)));
|
||||
//mPayload[q->iv->id].rssi[(datachan-1)] = p->rssi;
|
||||
|
||||
if (datachan == 1) //mPayload[q->iv->id].rssi[(datachan-1)] = p->rssi;
|
||||
if (datachan == 1)
|
||||
q->iv->rssi = p->rssi;
|
||||
else if(q->iv->rssi > p->rssi)
|
||||
q->iv->rssi = p->rssi;
|
||||
|
@ -597,6 +619,7 @@ class Communication : public CommQueue<> {
|
|||
} else if((p->packet[0] == (MI_REQ_CH1 + ALL_FRAMES)) && (q->iv->type == INV_TYPE_2CH)) {
|
||||
//addImportant(q->iv, MI_REQ_CH2);
|
||||
miNextRequest(MI_REQ_CH2, q);
|
||||
//use also miMultiParts here for better statistics?
|
||||
mHeu.setGotFragment(q->iv);
|
||||
} else { // first data msg for 1ch, 2nd for 2ch
|
||||
miComplete(q->iv);
|
||||
|
@ -604,25 +627,24 @@ class Communication : public CommQueue<> {
|
|||
}
|
||||
|
||||
inline void miNextRequest(uint8_t cmd, const queue_s *q) {
|
||||
//setAttempt();
|
||||
incrAttempt(); // if function is called, we got something, and we necessarily need more transmissions for MI types...
|
||||
DPRINT_IVID(DBG_WARN, q->iv->id);
|
||||
DBGPRINT(F("next request ("));
|
||||
DBGPRINT(String(q->attempts));
|
||||
DBGPRINT(F(" attempts left): 0x"));
|
||||
DBGHEXLN(cmd);
|
||||
|
||||
if(q->attempts) {
|
||||
//if(q->attempts) {
|
||||
q->iv->radio->sendCmdPacket(q->iv, cmd, 0x00, true);
|
||||
q->iv->radioStatistics.retransmits++;
|
||||
mWaitTimeout = millis() + MI_TIMEOUT;
|
||||
//chgCmd(Inverter<> *iv, uint8_t cmd, bool delOnPop = true)
|
||||
chgCmd(cmd);
|
||||
mState = States::WAIT;
|
||||
} else {
|
||||
/*} else {
|
||||
add(q, true);
|
||||
cmdDone();
|
||||
mState = States::RESET;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
inline void miStsConsolidate(const queue_s *q, uint8_t stschan, record_t<> *rec, uint8_t uState, uint8_t uEnum, uint8_t lState = 0, uint8_t lEnum = 0) {
|
||||
|
@ -699,13 +721,10 @@ class Communication : public CommQueue<> {
|
|||
|
||||
|
||||
inline void miComplete(Inverter<> *iv) {
|
||||
//if ( mPayload[iv->id].complete )
|
||||
// return; //if we got second message as well in repreated attempt
|
||||
//mPayload[iv->id].complete = true;
|
||||
//if (mSerialDebug) {
|
||||
if (iv->radio->isSerialDebug()) {
|
||||
DPRINT_IVID(DBG_INFO, iv->id);
|
||||
DBGPRINTLN(F("got all data msgs"));
|
||||
//}
|
||||
}
|
||||
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
||||
iv->setValue(iv->getPosByChFld(0, FLD_YD, rec), rec, calcYieldDayCh0(iv,0));
|
||||
|
||||
|
@ -751,7 +770,8 @@ class Communication : public CommQueue<> {
|
|||
private:
|
||||
States mState = States::RESET;
|
||||
uint32_t *mTimestamp;
|
||||
uint32_t mWaitTimeout = 0;
|
||||
uint32_t mWaitTimeout = 0;
|
||||
uint32_t mWaitTimeout_min = 0;
|
||||
std::array<frame_t, MAX_PAYLOAD_ENTRIES> mLocalBuf;
|
||||
bool mGotFragment = false;
|
||||
bool mFirstTry = false;
|
||||
|
|
|
@ -62,7 +62,7 @@ class Heuristic {
|
|||
|
||||
void printStatus(Inverter<> *iv) {
|
||||
DPRINT_IVID(DBG_INFO, iv->id);
|
||||
DBGPRINT(F("CH qualities:"));
|
||||
DBGPRINT(F("Radio infos:"));
|
||||
for(uint8_t i = 0; i < RF_MAX_CHANNEL_ID; i++) {
|
||||
DBGPRINT(F(" "));
|
||||
DBGPRINT(String(iv->txRfQuality[i]));
|
||||
|
@ -74,7 +74,9 @@ class Heuristic {
|
|||
DBGPRINT(F(", f: "));
|
||||
DBGPRINT(String(iv->radioStatistics.rxFail));
|
||||
DBGPRINT(F(", n: "));
|
||||
DBGPRINTLN(String(iv->radioStatistics.rxFailNoAnser));
|
||||
DBGPRINT(String(iv->radioStatistics.rxFailNoAnser));
|
||||
DBGPRINT(F(" | p: ")); // better debugging for helpers...
|
||||
DBGPRINTLN(String(iv->config->powerLevel));
|
||||
}
|
||||
|
||||
bool getTestModeEnabled(void) {
|
||||
|
|
|
@ -125,6 +125,8 @@ class Inverter {
|
|||
uint16_t alarmCnt; // counts the total number of occurred alarms
|
||||
uint16_t alarmLastId; // lastId which was received
|
||||
int8_t rssi; // RSSI
|
||||
uint8_t miMultiParts; // helper info for MI multiframe msgs
|
||||
bool mGotLastMsg; // shows if inverter has already finished transmission cycle
|
||||
Radio *radio; // pointer to associated radio class
|
||||
statistics_t radioStatistics; // information about transmitted, failed, ... packets
|
||||
int8_t txRfQuality[5]; // heuristics tx quality (check 'Heuristics.h')
|
||||
|
@ -150,8 +152,11 @@ class Inverter {
|
|||
alarmCnt = 0;
|
||||
alarmLastId = 0;
|
||||
rssi = -127;
|
||||
miMultiParts = 0;
|
||||
mGotLastMsg = false;
|
||||
radio = NULL;
|
||||
commEnabled = true;
|
||||
|
||||
memset(&radioStatistics, 0, sizeof(statistics_t));
|
||||
memset(txRfQuality, -6, 5);
|
||||
|
||||
|
|
|
@ -257,12 +257,14 @@ class HmRadio : public Radio {
|
|||
isLastPackage = (p.packet[9] > ALL_FRAMES); // > ALL_FRAMES indicates last packet received
|
||||
else if (p.packet[0] == ( 0x0f + ALL_FRAMES) ) // response from MI get information command
|
||||
isLastPackage = (p.packet[9] > 0x10); // > 0x10 indicates last packet received
|
||||
else if ((p.packet[0] != 0x88) && (p.packet[0] != 0x92)) // ignore fragment number zero and MI status messages //#0 was p.packet[0] != 0x00 &&
|
||||
else if ((p.packet[0] != 0x88) && (p.packet[0] != 0x92)) // ignore MI status messages //#0 was p.packet[0] != 0x00 &&
|
||||
isLastPackage = true; // response from dev control command
|
||||
}
|
||||
}
|
||||
yield();
|
||||
}
|
||||
if(isLastPackage)
|
||||
mLastIv->mGotLastMsg = true;
|
||||
return isLastPackage;
|
||||
}
|
||||
|
||||
|
@ -280,7 +282,7 @@ class HmRadio : public Radio {
|
|||
DBGPRINT(" CH");
|
||||
DBGPRINT(String(mTxChIdx));
|
||||
DBGPRINT(F(" | "));
|
||||
ah::dumpBuf(mTxBuf, len);
|
||||
ah::dumpBuf(mTxBuf, len, 1, 4, "#"+String(iv->id));
|
||||
}
|
||||
|
||||
mNrf24.stopListening();
|
||||
|
@ -304,6 +306,7 @@ class HmRadio : public Radio {
|
|||
uint8_t mRfChLst[RF_CHANNELS] = {03, 23, 40, 61, 75}; // channel List:2403, 2423, 2440, 2461, 2475MHz
|
||||
uint8_t mTxChIdx = 0;
|
||||
uint8_t mRxChIdx = 0;
|
||||
bool mGotLastMsg = false;
|
||||
uint32_t mMillis;
|
||||
|
||||
SPIClass* mSpi;
|
||||
|
|
|
@ -38,6 +38,10 @@ class Radio {
|
|||
mSerialDebug = true;
|
||||
}
|
||||
|
||||
bool isSerialDebug() {
|
||||
return mSerialDebug;
|
||||
}
|
||||
|
||||
void sendCmdPacket(Inverter<> *iv, uint8_t mid, uint8_t pid, bool isRetransmit, bool appendCrc16=true) {
|
||||
initPacket(getIvId(iv), mid, pid);
|
||||
sendPacket(iv, 10, isRetransmit, appendCrc16);
|
||||
|
|
|
@ -86,9 +86,12 @@ namespace ah {
|
|||
return ret;
|
||||
}
|
||||
|
||||
void dumpBuf(uint8_t buf[], uint8_t len) {
|
||||
void dumpBuf(uint8_t buf[], uint8_t len, uint8_t firstRepl, uint8_t lastRepl, String repl) {
|
||||
for(uint8_t i = 0; i < len; i++) {
|
||||
DHEX(buf[i]);
|
||||
if(i < firstRepl || i > lastRepl)
|
||||
DHEX(buf[i]);
|
||||
else
|
||||
DBGPRINT(repl);
|
||||
DBGPRINT(" ");
|
||||
}
|
||||
DBGPRINTLN("");
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace ah {
|
|||
String getDateTimeStrFile(time_t t);
|
||||
String getTimeStr(time_t t);
|
||||
uint64_t Serial2u64(const char *val);
|
||||
void dumpBuf(uint8_t buf[], uint8_t len);
|
||||
void dumpBuf(uint8_t buf[], uint8_t len, uint8_t firstRepl = 0, uint8_t lastRepl = 0, String repl = "");
|
||||
}
|
||||
|
||||
#endif /*__HELPER_H__*/
|
||||
|
|
Loading…
Add table
Reference in a new issue