ThermometerPro/meterBusClient.cpp

394 lines
10 KiB
C++
Raw Permalink Normal View History

2014-03-08 13:23:09 +01:00
/*
* meterBusClient.cpp
*
* Created on: 08.03.2014
* Author: wn
*/
2014-03-08 19:24:27 +01:00
2014-03-08 13:23:09 +01:00
#include "meterBusClient.h"
const bool MBC_COMPILE_TIME_DEBUG = false;
2014-03-08 20:57:17 +01:00
String MeterBusClientConfig::exec(String params) {
String res = "done";
int space = params.indexOf(' ');
String p1 = "";
char pb1[128];
if (space != -1) {
params.toCharArray(pb1, 128, space+1);
}
if (params.startsWith("a ") && (space != -1)) {
unsigned int a = atoi(pb1);
m_meterBusClient->setAddress(a);
2014-04-04 20:38:11 +02:00
Serial.print("Address is now "); Serial.println(a);
Serial.print("MBC is at "); Serial.println((long) m_meterBusClient, 16);
} else if (params.startsWith("debug ") && (space != -1)) {
bool b = (strcmp(pb1, "on") == 0);
m_meterBusClient->setDebug(b);
} else if (params.startsWith("info ") && (space != -1)) {
bool b = (strcmp(pb1, "on") == 0);
m_meterBusClient->setInfo(b);
} else if (params.startsWith("show")) {
Serial.print(getResource(MBC_FRAMES_KEY)); Serial.print(m_meterBusClient->m_frameCnt); Serial.println();
Serial.print(getResource(MBC_MYFRAMES_KEY)); Serial.print(m_meterBusClient->m_myFrameCnt); Serial.println();
Serial.print(getResource(MBC_INVALID_FRAMES_KEY)); Serial.print(m_meterBusClient->m_invalidFrameCnt); Serial.println();
Serial.print(getResource(MBC_INVALID_CHECKSUM_CNT_KEY)); Serial.print(m_meterBusClient->m_invalidChecksum); Serial.println();
2014-04-02 22:50:17 +02:00
Serial.print(getResource(MBC_COLLISION_CNT_KEY)); Serial.print(m_meterBusClient->m_collisionCnt); Serial.println();
Serial.print(getResource(MBC_ADDRESS_LONG_KEY)); Serial.print(m_meterBusClient->getAddress()); Serial.println();
2014-03-08 20:57:17 +01:00
} else {
res = "subcommand not found";
}
return res;
}
MeterBusClient::MeterBusClient() : m_meterBusClientConfig(this), m_address(0),
2014-05-04 20:56:03 +02:00
m_frameCnt(0), m_accessCnt(0), m_myFrameCnt(0), m_invalidFrameCnt(0), m_invalidChecksum(0),
2014-04-02 22:50:17 +02:00
m_collisionCnt(0) {
2014-03-08 13:23:09 +01:00
}
2014-05-04 20:56:03 +02:00
void MeterBusClient::begin(CmdServer *cmdServer, Thermometer *thermometer, Uptime *uptime) {
2014-04-04 20:38:11 +02:00
Serial.print("I'm at "); Serial.println((long)this, 16);
2014-03-08 20:57:17 +01:00
m_meterBusClientConfig.registerYourself(cmdServer);
m_thermometer = thermometer;
2014-05-04 20:56:03 +02:00
m_uptime = uptime;
2014-03-08 20:57:17 +01:00
2014-04-02 22:50:17 +02:00
//Serial3.begin(1200);
//Serial3.begin(2400, SERIAL_8E1);
Serial3.begin(2400);
UART2_C1 |= UART_C1_PE | UART_C1_M;
2014-03-08 13:23:09 +01:00
setAddress(Config::getUChar(Config::METERBUSCLIENT_ADDRESS));
2014-03-08 19:24:27 +01:00
2014-03-08 13:23:09 +01:00
}
void MeterBusClient::setAddress(unsigned char a) {
Config::setUChar(Config::METERBUSCLIENT_ADDRESS, a);
m_address = a;
}
unsigned char MeterBusClient::getAddress() {
return m_address;
}
void MeterBusClient::setDebug(bool b) {
Config::setBool(Config::METERBUSCLIENT_DEBUG, b);
m_debug = b;
}
bool MeterBusClient::getDebug() {
return m_debug;
}
void MeterBusClient::setInfo(bool b) {
Config::setBool(Config::METERBUSCLIENT_INFO, b);
m_info = b;
}
bool MeterBusClient::getInfo() {
return m_info;
}
2014-05-04 20:56:03 +02:00
unsigned char MeterBusClient::getStatus() {
return 0;
}
unsigned char MeterBusClient::getAccessCnt() {
return m_accessCnt;
}
2014-03-08 13:23:09 +01:00
/*
* Single Character: E5h
*
* Short Frame:
* Start 10h
* C-Field
* A-Field
* Check-Sum
* Stop 16h
*
* Control Frame:
* Start 68h
2014-03-08 19:24:27 +01:00
* Length = 3
2014-03-08 13:23:09 +01:00
* Length
* Start 68h
* C-Field
* A-Field
* CI-Field
* Check-Sum
* Stop 16h
*
* Long Frame:
* Start 68h
* Length
* Length
* Start 68h
* C-Field
* A-Field
* CI-Field
* User-Data
* Check-Sum
* Stop 16h
*
* Frames:
* SND_NKE
* Short Frame, C: 40h
*
* REQ_UD2
* Short Frame, C: 5Bh
*/
2014-03-08 19:24:27 +01:00
bool isChecksumValid(MeterBusFrame frame) {
unsigned char ctrlsum = frame.aField + frame.cField + frame.ciField;
for (int i = 0; i < (frame.length - 3); i++) {
ctrlsum += frame.userData[i];
}
return (ctrlsum == frame.checksum);
}
2014-04-02 22:50:17 +02:00
bool MeterBusClient::handleFrame() {
bool res = false;
m_frameCnt++;
if (! isChecksumValid(m_frame)) {
2014-03-08 19:24:27 +01:00
Serial.println(getResource(MBC_INVALID_CHECKSUM_KEY));
m_invalidChecksum++;
} else if (m_frame.aField != getAddress()) {
if (MBC_COMPILE_TIME_DEBUG && getDebug()) { Serial.print(getResource(MBC_NOT_FOR_ME_KEY)); Serial.print((int)m_frame.aField, 16); Serial.println();}
2014-03-08 19:24:27 +01:00
} else {
m_myFrameCnt++;
2014-03-08 19:24:27 +01:00
// handle the frame
if (MBC_COMPILE_TIME_DEBUG && getDebug()) { Serial.print(getResource(MBC_START_DELIMITER_KEY)); Serial.println(m_frame.startDelimiter, 16);}
if (MBC_COMPILE_TIME_DEBUG && getDebug()) { Serial.print(getResource(MBC_LENGTH_KEY)); Serial.println(m_frame.length, 16);}
if (MBC_COMPILE_TIME_DEBUG && getDebug()) { Serial.print(getResource(MBC_CFIELD_KEY)); Serial.println(m_frame.cField, 16);}
if (MBC_COMPILE_TIME_DEBUG && getDebug()) { Serial.print(getResource(MBC_ADDRESS_KEY)); Serial.println(m_frame.aField, 16);}
if (MBC_COMPILE_TIME_DEBUG && getDebug()) { Serial.print(getResource(MBC_CIFIELD_KEY)); Serial.println(m_frame.ciField, 16);}
if (m_frame.length > 3) {
if (MBC_COMPILE_TIME_DEBUG && getDebug()) { Serial.print(getResource(MBC_USERDATA_KEY));}
for (unsigned char i = 0; i < (m_frame.length - 3); i++) {
if (MBC_COMPILE_TIME_DEBUG && getDebug()) { Serial.print(m_frame.userData[i], 16);}
if (MBC_COMPILE_TIME_DEBUG && getDebug()) { Serial.print(getResource(SPACE_KEY));}
}
if (MBC_COMPILE_TIME_DEBUG && getDebug()) { Serial.println();}
}
if (m_frame.startDelimiter == 0x10) {
if (m_frame.cField == 0x40) {
SND_NKE();
2014-04-02 22:50:17 +02:00
res = true;
} else if (m_frame.cField == 0x5b) {
2014-05-04 20:56:03 +02:00
m_accessCnt++;
REQ_UD2();
2014-04-02 22:50:17 +02:00
res = true;
} else {
Serial.println(getResource(MBC_UNHANDLED_FRAME_KEY));
}
}
2014-03-08 19:24:27 +01:00
}
2014-04-02 22:50:17 +02:00
return res;
2014-03-08 19:24:27 +01:00
}
typedef enum {
2014-03-09 21:12:17 +01:00
STATE_START, STATE_IDLE, STATE_SHORT_FRAME, STATE_LONG_CTRL_FRAME, STATE_HANDLE, STATE_INVALID, STATE_DONE,
2014-04-02 22:50:17 +02:00
STATE_DELAYED_RESPONSE, STATE_DELAY, STATE_RESPONSE, STATE_RECEIVE_ECHO
2014-03-08 19:24:27 +01:00
} e_meterBusClientState;
typedef enum {
SUBSTATE_LENGTH, SUBSTATE_LENGTH_REPEAT, SUBSTATE_START_REPEAT, SUBSTATE_C_FIELD, SUBSTATE_A_FIELD, SUBSTATE_CI_FIELD,
SUBSTATE_USERDATA, SUBSTATE_CHECKSUM, SUBSTATE_STOP
} e_meterBusClientSubState;
2014-03-08 13:23:09 +01:00
void MeterBusClient::exec() {
2014-03-08 19:24:27 +01:00
static e_meterBusClientState state = STATE_IDLE;
static e_meterBusClientSubState subState = SUBSTATE_LENGTH;
static unsigned char userDataCnt = 0;
2014-04-02 22:50:17 +02:00
static unsigned int echoReceiveCnt = 0;
2014-03-09 21:12:17 +01:00
static unsigned long receivedDoneTimestamp;
2014-03-08 13:23:09 +01:00
2014-03-08 19:24:27 +01:00
int chi = Serial3.read();
2014-05-04 20:56:03 +02:00
//if (chi != -1) {
// Serial.print("Received: "); Serial.println(chi, 16);
//}
2014-03-08 19:24:27 +01:00
char ch = (char) chi;
switch (state) {
case STATE_START:
m_frame.startDelimiter = 0;
m_frame.length = 0;
m_frame.cField = 0;
m_frame.aField = 0;
m_frame.ciField = 0;
//memset(m_frame.userData, 0, sizeof(m_frame.userData));
2014-03-08 19:24:27 +01:00
m_frame.valid = false;
state = STATE_IDLE;
break;
case STATE_IDLE:
if (chi != -1) {
if (ch == 0x10) {
m_frame.startDelimiter = 0x10;
state = STATE_SHORT_FRAME;
subState = SUBSTATE_C_FIELD;
} else if (ch == 0x68) {
m_frame.startDelimiter = 0x68;
state = STATE_LONG_CTRL_FRAME;
subState = SUBSTATE_LENGTH;
} else {
state = STATE_INVALID;
2014-03-08 13:23:09 +01:00
}
2014-03-08 19:24:27 +01:00
}
break;
case STATE_SHORT_FRAME:
if (chi != -1) {
if (subState == SUBSTATE_C_FIELD) {
m_frame.cField = ch;
subState = SUBSTATE_A_FIELD;
} else if (subState == SUBSTATE_A_FIELD) {
m_frame.aField = ch;
subState = SUBSTATE_CHECKSUM;
} else if (subState == SUBSTATE_CHECKSUM) {
m_frame.checksum = ch;
subState = SUBSTATE_STOP;
2014-03-08 19:24:27 +01:00
} else if (subState == SUBSTATE_STOP) {
if (ch == 0x16) {
m_frame.valid = true;
state = STATE_HANDLE;
} else {
state = STATE_INVALID;
}
}
}
break;
case STATE_LONG_CTRL_FRAME:
if (chi != -1) {
if (subState == SUBSTATE_LENGTH) {
m_frame.length = ch;
if ((m_frame.length < 3) || (m_frame.length > 252)) {
2014-03-08 19:24:27 +01:00
state = STATE_INVALID;
} else {
subState = SUBSTATE_LENGTH_REPEAT;
}
} else if (subState == SUBSTATE_LENGTH_REPEAT) {
if (ch == m_frame.length) {
subState = SUBSTATE_START_REPEAT;
} else {
state = STATE_INVALID;
}
} else if (subState == SUBSTATE_START_REPEAT) {
if (ch == 0x68) {
subState = SUBSTATE_C_FIELD;
} else {
state = STATE_INVALID;
}
} else if (subState == SUBSTATE_C_FIELD) {
m_frame.cField = ch;
subState = SUBSTATE_A_FIELD;
} else if (subState == SUBSTATE_A_FIELD) {
m_frame.aField = ch;
subState = SUBSTATE_CI_FIELD;
} else if (subState == SUBSTATE_CI_FIELD) {
m_frame.ciField = ch;
if (m_frame.length == 3) {
subState = SUBSTATE_CHECKSUM;
} else {
subState = SUBSTATE_USERDATA;
userDataCnt = 0;
2014-03-08 19:24:27 +01:00
}
} else if (subState == SUBSTATE_USERDATA) {
m_frame.userData[userDataCnt] = ch;
userDataCnt++;
if (userDataCnt >= (m_frame.length - 3)) {
subState = SUBSTATE_CHECKSUM;
}
2014-03-08 19:24:27 +01:00
} else if (subState == SUBSTATE_CHECKSUM) {
m_frame.checksum = ch;
subState = SUBSTATE_STOP;
} else if (subState == SUBSTATE_STOP) {
if (ch == 0x16) {
m_frame.valid = true;
state = STATE_HANDLE;
} else {
state = STATE_INVALID;
}
2014-03-08 13:23:09 +01:00
}
}
2014-03-08 19:24:27 +01:00
break;
case STATE_INVALID:
2014-04-02 22:50:17 +02:00
Serial.println("INVALID FRAME");
m_invalidFrameCnt++;
2014-03-08 19:24:27 +01:00
state = STATE_START;
break;
case STATE_HANDLE:
2014-04-02 22:50:17 +02:00
state = STATE_DONE;
if (m_frame.valid) {
receivedDoneTimestamp = millis();
if (handleFrame()) {
state = STATE_DELAY;
}
}
2014-03-09 21:12:17 +01:00
break;
case STATE_DELAY:
if ((receivedDoneTimestamp + RESPONSE_DELAY) < millis()) {
2014-04-02 22:50:17 +02:00
state = STATE_DELAYED_RESPONSE;
2014-03-09 21:12:17 +01:00
}
break;
2014-04-02 22:50:17 +02:00
case STATE_DELAYED_RESPONSE:
2014-05-04 20:56:03 +02:00
for (unsigned int i = 0; i < m_sendBufferLen; i++) {
Serial3.write(m_sendBuffer[i]);
2014-04-02 22:50:17 +02:00
}
echoReceiveCnt = 0;
state = STATE_RECEIVE_ECHO;
break;
case STATE_RECEIVE_ECHO:
if (chi != -1) {
2014-05-04 20:56:03 +02:00
//Serial.println("echo character");
if (ch == m_sendBuffer[echoReceiveCnt]) {
2014-04-02 22:50:17 +02:00
echoReceiveCnt++;
2014-05-04 20:56:03 +02:00
if (echoReceiveCnt == m_sendBufferLen) {
2014-04-02 22:50:17 +02:00
state = STATE_DONE;
}
} else {
m_collisionCnt++;
state = STATE_DONE;
}
2014-03-08 19:24:27 +01:00
}
break;
case STATE_DONE:
// may be another useful message
state = STATE_START;
break;
2014-03-08 13:23:09 +01:00
}
}