initial
This commit is contained in:
232
meterBusMaster.cpp
Normal file
232
meterBusMaster.cpp
Normal file
@ -0,0 +1,232 @@
|
||||
#include <Arduino.h>
|
||||
#include <stdio.h>
|
||||
#include <WString.h>
|
||||
#include <Print.h>
|
||||
#include <HardwareSerial.h>
|
||||
#include "meterBusMaster.h"
|
||||
// #include "config.h"
|
||||
#include "fatal.h"
|
||||
|
||||
|
||||
|
||||
uint8_t charToNibble(char i) {
|
||||
uint8_t r = 99;
|
||||
if ((i >= '0') && (i <= '9')) {
|
||||
r = i - '0';
|
||||
} else if ((i >= 'a') && (i <= 'f')) {
|
||||
r = i - 'a' + 10;
|
||||
} else if ((i >= 'A') && (i <= 'F')) {
|
||||
r = i - 'A' + 10;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
uint16_t stringToUInt8(String i, uint8_t index) {
|
||||
uint16_t r = 999;
|
||||
char b0 = i[index];
|
||||
uint8_t c0 = charToNibble(b0);
|
||||
char b1 = i[index + 1];
|
||||
uint8_t c1 = charToNibble(b1);
|
||||
if ((c0 <= 15) && (c1 <= 15)) {
|
||||
r = (c0 << 4) | c1;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
// =====================================================================================================
|
||||
|
||||
|
||||
String SendOctets::exec(String params) {
|
||||
bool err = false;;
|
||||
uint16_t sendBufLen = 0;
|
||||
|
||||
uint8_t *sendBuffer = m_meterBusMaster->getSendBuffer();
|
||||
|
||||
if (sendBuffer == 0) {
|
||||
err = true;
|
||||
} else {
|
||||
uint16_t n;
|
||||
for (uint16_t j = 0; j < params.length(); j+=3) {
|
||||
n = stringToUInt8(params, j);
|
||||
if (n == 999) {
|
||||
err = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sendBufLen >= SEND_BUFFER_SIZE)
|
||||
fatal(FATAL_BUFFER_OVERFLOW + 2);
|
||||
|
||||
*(sendBuffer+sendBufLen) = n;
|
||||
sendBufLen++;
|
||||
}
|
||||
}
|
||||
|
||||
if (err) {
|
||||
return "error";
|
||||
} else {
|
||||
m_meterBusMaster->sendBufferReady(sendBufLen, this);
|
||||
return "success";
|
||||
}
|
||||
}
|
||||
|
||||
void SendOctets::sendResponse(uint8_t *responseBuffer, uint16_t responseBufferLength) {
|
||||
Print *out = m_stream;
|
||||
out->print("SO RESP: ");
|
||||
uint16_t i = 0;
|
||||
while (true) {
|
||||
if (responseBuffer[i] <= 0x0f) {
|
||||
out->print("0");
|
||||
}
|
||||
out->print(responseBuffer[i], HEX);
|
||||
out->print(" ");
|
||||
i++;
|
||||
if (i == responseBufferLength) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
out->println("");
|
||||
}
|
||||
|
||||
void SendOctets::sendError(uint8_t code) {
|
||||
switch (code) {
|
||||
case 1:
|
||||
m_stream->println("SO RESP: no resp.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// =====================================================================================================
|
||||
|
||||
|
||||
MeterBusMaster::MeterBusMaster() : m_sendOctets(this),
|
||||
m_cmdReadyToSend(false), m_cmdReadyFromRecv(false), m_expectResponse(false),
|
||||
m_sendBufLen(0), m_recvBufLen(0), m_retransmitCount(0), m_responseCallback(0) {
|
||||
pinMode(RX_EN_PIN, OUTPUT);
|
||||
digitalWrite(RX_EN_PIN, RX_DISABLE);
|
||||
Serial1.begin(2400, SERIAL_8E1);
|
||||
|
||||
}
|
||||
|
||||
uint8_t *MeterBusMaster::getSendBuffer() {
|
||||
return m_expectResponse ? 0 : m_sendBuffer;
|
||||
}
|
||||
|
||||
void MeterBusMaster::sendBufferReady(uint16_t sendBufLen, ResponseCallback *responseCallback) {
|
||||
m_cmdReadyToSend = true;
|
||||
m_retransmitCount = 0;
|
||||
m_sendBufLen = sendBufLen;
|
||||
m_responseCallback = responseCallback;
|
||||
}
|
||||
|
||||
void MeterBusMaster::prepareResponse(bool err, uint8_t in) {
|
||||
static int16_t expectedChars = -1;
|
||||
static uint8_t state = 0;
|
||||
|
||||
if (err) {
|
||||
if (m_responseCallback != 0) {
|
||||
m_responseCallback->sendError(1);
|
||||
}
|
||||
expectedChars = 0;
|
||||
state = 0;
|
||||
m_expectResponse = false;
|
||||
m_responseCallback = 0;
|
||||
} else {
|
||||
switch (state) {
|
||||
case 0:
|
||||
m_recvBufLen = 0;
|
||||
if (in == 0xe5) {
|
||||
state = 2;
|
||||
expectedChars = 0;
|
||||
} else if (in == 0x10) {
|
||||
state = 2;
|
||||
expectedChars = 4;
|
||||
} else if (in == 0x68) {
|
||||
state = 1;
|
||||
expectedChars = -1;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
expectedChars = (int16_t)in;
|
||||
expectedChars += 4;
|
||||
state = 2;
|
||||
break;
|
||||
case 2:
|
||||
expectedChars--;
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_recvBufLen >= RECEIVE_BUFFER_SIZE)
|
||||
fatal(FATAL_BUFFER_OVERFLOW + 1);
|
||||
|
||||
m_recvBuffer[m_recvBufLen] = in;
|
||||
m_recvBufLen++;
|
||||
|
||||
if (expectedChars == 0) {
|
||||
if (m_responseCallback != 0) {
|
||||
m_responseCallback->sendResponse(m_recvBuffer, m_recvBufLen);
|
||||
}
|
||||
m_expectResponse = false;
|
||||
state = 0;
|
||||
m_responseCallback = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MeterBusMaster::begin(CmdServer *cmdServer) {
|
||||
m_sendOctets.registerYourself(cmdServer);
|
||||
}
|
||||
|
||||
void MeterBusMaster::sample() {
|
||||
if (! m_sampling) {
|
||||
m_sampling = true;
|
||||
digitalWrite(RX_EN_PIN, RX_DISABLE);
|
||||
}
|
||||
}
|
||||
|
||||
void MeterBusMaster::hold() {
|
||||
if (m_sampling) {
|
||||
m_sampling = false;
|
||||
digitalWrite(RX_EN_PIN, RX_ENABLE);
|
||||
}
|
||||
}
|
||||
|
||||
void MeterBusMaster::exec() {
|
||||
static unsigned long cmdSendTime = 0;
|
||||
|
||||
if (m_cmdReadyToSend) {
|
||||
sample();
|
||||
Serial1.write(m_sendBuffer, m_sendBufLen);
|
||||
Serial1.flush();
|
||||
hold();
|
||||
m_cmdReadyToSend = false;
|
||||
m_expectResponse = true;
|
||||
cmdSendTime = millis();
|
||||
}
|
||||
|
||||
if (! m_expectResponse) {
|
||||
sample();
|
||||
}
|
||||
|
||||
// timeout
|
||||
if (m_expectResponse && ((millis() - cmdSendTime) > RESPONSE_TIMEOUT)) {
|
||||
m_retransmitCount++;
|
||||
if (m_retransmitCount > 2) {
|
||||
m_expectResponse = false;
|
||||
prepareResponse(true, 0);
|
||||
} else {
|
||||
m_cmdReadyToSend = true;
|
||||
}
|
||||
}
|
||||
|
||||
int serialInChar = Serial1.read();
|
||||
if ((serialInChar != -1) && m_expectResponse) {
|
||||
prepareResponse(false, (uint8_t)serialInChar);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// =====================================================================================================
|
Reference in New Issue
Block a user