4 Commits

Author SHA1 Message Date
hg
13d19d4e15 meterbusclient is working, SND_NKE will be answered 2014-03-09 00:25:48 +01:00
hg
854d2f202a mbc seems to work partly now, finally 2014-03-08 20:57:17 +01:00
hg
b333be0cd9 meterbus integrated but not working 2014-03-08 19:24:27 +01:00
hg
d3d2c75541 start integrating MeterBus client 2014-03-08 13:23:09 +01:00
12 changed files with 538 additions and 184 deletions

View File

@ -8,6 +8,7 @@
#include <EEPROM.h>
#include "Config.h"
#include "Resources.h"
@ -83,29 +84,49 @@ void Config::setULong(int pos, unsigned long value) {
}
}
bool Config::isInitialized() {
unsigned int magic = getUInt(MAGIC);
return magic == MAGIC_TOKEN;
unsigned char Config::getUChar(int pos) {
u_uchar u;
for (unsigned int i = 0; i < sizeof(unsigned char); i++) {
u.e[i] = EEPROM.read(pos + i);
}
return u.c;
}
void Config::setUChar(int pos, unsigned char value) {
u_uchar u;
u.c = value;
for (unsigned int i = 0; i < sizeof(unsigned char); i++) {
EEPROM.write(pos + i, u.e[i]);
}
}
void Config::initialize() {
if (! isInitialized()) {
//Serial.println(getResource(CONFIG_INIT_KEY));
Serial.println(getResource(CONFIG_INIT_KEY));
setFloat(THERMOMETER_ALPHA, 1.0);
setULong(THERMOMETER_PERIOD, 1000);
for (int i = 0; i < 4; i++) {
setFloat(THERMOMETER_CAL[i], 1.0);
}
setBool(THERMOMETER_DEBUG, true);
setBool(THERMOMETER_INFO, true);
setBool(THERMOMETER_DEBUG, false);
setBool(THERMOMETER_INFO, false);
//Config::setUChar(Config::METERBUSCLIENT_ADDRESS, 0);
setUChar(METERBUSCLIENT_ADDRESS, 0);
setBool(METERBUSCLIENT_DEBUG, false);
setBool(METERBUSCLIENT_INFO, false);
setMagic();
}
}
bool Config::isInitialized() {
unsigned int magic = getUInt(MAGIC);
return magic == MAGIC_TOKEN;
}
void Config::setMagic() {
setUInt(MAGIC, MAGIC_TOKEN);
}

View File

@ -39,6 +39,11 @@ typedef union {
uint8_t e[sizeof(bool)];
} u_bool;
typedef union {
unsigned char c;
uint8_t e[sizeof(unsigned char)];
} u_uchar;
namespace Config {
const unsigned int MAGIC_TOKEN = 0xDEADBEEF;
@ -50,6 +55,10 @@ namespace Config {
const int THERMOMETER_DEBUG = 28; // 1
const int THERMOMETER_INFO = 29; // 1
const int METERBUSCLIENT_ADDRESS = 30; // 1
const int METERBUSCLIENT_DEBUG = 31; // 1
const int METERBUSCLIENT_INFO = 32; // 1
bool getBool(int pos);
void setBool(int pos, bool value);
@ -59,10 +68,11 @@ namespace Config {
void setUInt(int pos, unsigned int value);
unsigned long getULong(int pos);
void setULong(int pos, unsigned long value);
unsigned char getUChar(int pos);
void setUChar(int pos, unsigned char value);
void initialize();
bool isInitialized();
void setMagic();

View File

@ -1,97 +0,0 @@
/*
* MeterBusClient.cpp
*
* Created on: 08.03.2014
* Author: wn
*/
#include "MeterBusClient.h"
MeterBusClient::MeterBusClient() : m_address(0) {
}
void MeterBusClient::begin(CmdServer *cmdServer) {
Serial3.begin(1200);
//setAddress(Config::getUChar(Config::METERBUSCLIENT_ADDRESS));
}
void MeterBusClient::setAddress(unsigned char a) {
//Config::setUChar(Config::METERBUSCLIENT_ADDRESS, a);
m_address = a;
}
unsigned char MeterBusClient::getAddress() {
return m_address;
}
/*
* Single Character: E5h
*
* Short Frame:
* Start 10h
* C-Field
* A-Field
* Check-Sum
* Stop 16h
*
* Control Frame:
* Start 68h
* Length
* 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
*/
void MeterBusClient::exec() {
static uint8_t state = 0;
bool done = false;
if (Serial3.available()) {
int chi;
while ((chi = Serial3.read()) != -1) {
char ch = (char) chi;
switch (state) {
case 0:
break;
}
if (done) {
}
}
}
}

View File

@ -1,47 +0,0 @@
/*
* MeterBusClient.h
*
* Created on: 08.03.2014
* Author: wn
*/
#ifndef METERBUSCLIENT_H_
#define METERBUSCLIENT_H_
#include "cmd.h"
#include "Config.h"
#include "Resources.h"
class MeterBusClient;
class MeterBusClientConfig : public Cmd {
public:
MeterBusClientConfig(MeterBusClient *meterBusClient) : m_meterBusClient(meterBusClient) {};
virtual String getCmdName() { return "MBCC"; }
virtual String getHelp() { return getResource(MBC_CONFIG_HELP_KEY); }
virtual String exec(String params);
private:
MeterBusClient *m_meterBusClient;
};
class MeterBusClient {
public:
MeterBusClient();
void begin(CmdServer *cmdServer);
void exec();
friend class MeterBusClientConfig;
private:
unsigned char m_address;
void setAddress(unsigned char address);
unsigned char getAddress();
};
#endif /* METERBUSCLIENT_H_ */

View File

@ -63,12 +63,28 @@ const String TEXT_RESOURCES[] = {
"Thermometer calibration operations",
"No, no, we are in calibration zero mode, so directly switch to state 20",
"MeterBus Client Configuration",
"Invalid frame",
"No valid frame available",
"Invalid checksum",
"Not for me but for ",
"Unhandled frame",
"s: ",
"l: ",
"c: ",
"a: ",
"ci: ",
"u: ",
" ",
"frames: ",
"my frames: ",
"invalid frames: ",
"invalid checksum: ",
"mbus address: ",
};
const String& getResource(uint8_t key) {
//TEXT = String("T") + key + String(": ");
//return TEXT;

View File

@ -41,7 +41,7 @@ const uint8_t SET_TEMPERATURE_DEBUG_2_KEY = 25;
const uint8_t SET_TEMPERATURE_DEBUG_3_KEY = 26;
const uint8_t CONF_COLON_KEY = 27;
const uint8_t MODE_COLON_KEY = 28;
const uint8_t THERMOMETER_BEGIN_1_KEY = 29;
const uint8_t CONFIG_INIT_KEY = 29;
const uint8_t STATE_0_KEY = 30;
const uint8_t TO_STATE_1_KEY = 31;
const uint8_t TO_STATE_10_KEY = 32;
@ -62,8 +62,23 @@ const uint8_t THERMVALUES_HELP_KEY = 46;
const uint8_t THERMCALIBRATE_HELP_KEY = 47;
const uint8_t CALIBRATION_ZEOR_MODE_HINT_KEY = 48;
const uint8_t MBC_CONFIG_HELP_KEY = 49;
const uint8_t MBC_INVALID_FRAME_KEY = 50;
const uint8_t MBC_NO_VALID_FRAME_KEY = 51;
const uint8_t MBC_INVALID_CHECKSUM_KEY = 52;
const uint8_t MBC_NOT_FOR_ME_KEY = 53;
const uint8_t MBC_UNHANDLED_FRAME_KEY = 54;
const uint8_t MBC_START_DELIMITER_KEY = 55;
const uint8_t MBC_LENGTH_KEY = 56;
const uint8_t MBC_CFIELD_KEY = 57;
const uint8_t MBC_ADDRESS_KEY = 58;
const uint8_t MBC_CIFIELD_KEY = 59;
const uint8_t MBC_USERDATA_KEY = 60;
const uint8_t SPACE_KEY = 61;
const uint8_t MBC_FRAMES_KEY = 62;
const uint8_t MBC_MYFRAMES_KEY = 63;
const uint8_t MBC_INVALID_FRAMES_KEY = 64;
const uint8_t MBC_INVALID_CHECKSUM_CNT_KEY = 65;
const uint8_t MBC_ADDRESS_LONG_KEY = 66;
const String& getResource(uint8_t key);

View File

@ -5,34 +5,29 @@
#include "thermometer.h"
#include "Config.h"
#include "spi.h"
#include "meterBusClient.h"
// #define ENABLE_CONFIGURATION_INVALID_CMD 1
static CmdServer cmdServer(&Serial);
#ifdef ENABLE_CONFIGURATION_INVALID_CMD
static ConfigInvalidateCmd configInvalidateCmd;
#endif
static ConfigInvalidateCmd configInvalidateCmd;
static Uptime uptime;
static Thermometer thermometer;
static MeterBusClient meterBusClient;
void setup() {
Serial.begin(9600);
Config::initialize();
spiInit();
cmdServer.begin();
#ifdef ENABLE_CONFIGURATION_INVALID_CMD
configInvalidateCmd.registerYourself(&cmdServer);
#endif
uptime.begin(&cmdServer);
thermometer.begin(&cmdServer);
meterBusClient.begin(&cmdServer, &thermometer);
}
@ -40,4 +35,5 @@ void loop() {
cmdServer.exec();
uptime.exec();
thermometer.exec();
meterBusClient.exec();
}

View File

@ -1,10 +1,11 @@
#include <avr/interrupt.h>
#include"fatal.h"
#include <Arduino.h>
void fatal(uint8_t code) {
// cli();
// do something with the code and somehow show that there is a problem
Serial.print("Fatal: "); Serial.println(code);
while (1);
}

333
meterBusClient.cpp Normal file
View File

@ -0,0 +1,333 @@
/*
* meterBusClient.cpp
*
* Created on: 08.03.2014
* Author: wn
*/
#include "meterBusClient.h"
const bool MBC_COMPILE_TIME_DEBUG = false;
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);
} 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();
Serial.print(getResource(MBC_ADDRESS_LONG_KEY)); Serial.print(m_meterBusClient->getAddress()); Serial.println();
} else {
res = "subcommand not found";
}
return res;
}
MeterBusClient::MeterBusClient() : m_meterBusClientConfig(this), m_address(0),
m_frameCnt(0), m_myFrameCnt(0), m_invalidFrameCnt(0), m_invalidChecksum(0) {
}
void MeterBusClient::begin(CmdServer *cmdServer, Thermometer *thermometer) {
m_meterBusClientConfig.registerYourself(cmdServer);
m_thermometer = thermometer;
Serial3.begin(1200);
setAddress(Config::getUChar(Config::METERBUSCLIENT_ADDRESS));
}
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;
}
/*
* Single Character: E5h
*
* Short Frame:
* Start 10h
* C-Field
* A-Field
* Check-Sum
* Stop 16h
*
* Control Frame:
* Start 68h
* Length = 3
* 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
*/
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);
}
void MeterBusClient::handleFrame() {
m_frameCnt++;
if (! isChecksumValid(m_frame)) {
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();}
} else {
m_myFrameCnt++;
// 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();
} else if (m_frame.cField == 0x5b) {
REQ_UD2();
} else {
Serial.println(getResource(MBC_UNHANDLED_FRAME_KEY));
}
}
}
}
typedef enum {
STATE_START, STATE_IDLE, STATE_SHORT_FRAME, STATE_LONG_CTRL_FRAME, STATE_HANDLE, STATE_INVALID, STATE_DONE
} 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;
void MeterBusClient::exec() {
static e_meterBusClientState state = STATE_IDLE;
static e_meterBusClientSubState subState = SUBSTATE_LENGTH;
static unsigned char userDataCnt = 0;
int chi = Serial3.read();
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));
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;
}
}
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;
} 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)) {
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;
}
} else if (subState == SUBSTATE_USERDATA) {
m_frame.userData[userDataCnt] = ch;
userDataCnt++;
if (userDataCnt >= (m_frame.length - 3)) {
subState = SUBSTATE_CHECKSUM;
}
} 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;
}
}
}
break;
case STATE_INVALID:
m_invalidFrameCnt++;
state = STATE_START;
break;
case STATE_HANDLE:
if (m_frame.valid) {
handleFrame();
} else {
Serial.println(getResource(MBC_NO_VALID_FRAME_KEY));
}
state = STATE_DONE;
break;
case STATE_DONE:
// may be another useful message
state = STATE_START;
break;
}
}

100
meterBusClient.h Normal file
View File

@ -0,0 +1,100 @@
/*
* meterBusClient.h
*
* Created on: 08.03.2014
* Author: wn
*/
#ifndef METERBUSCLIENT_H_
#define METERBUSCLIENT_H_
#include "cmd.h"
#include "Config.h"
#include "Resources.h"
#include "Thermometer.h"
class MeterBusClient;
class MeterBusClientConfig : public Cmd {
public:
MeterBusClientConfig(MeterBusClient *meterBusClient) : m_meterBusClient(meterBusClient) {};
virtual String getCmdName() { return "MBCC"; }
virtual String getHelp() { return getResource(MBC_CONFIG_HELP_KEY); }
virtual String exec(String params);
private:
MeterBusClient *m_meterBusClient;
};
struct MeterBusFrame {
/*
* Short Frame:
* Start 10h
* C-Field
* A-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
*
*/
unsigned char startDelimiter;
unsigned char length;
unsigned char cField;
unsigned char aField;
unsigned char ciField;
unsigned char userData[255];
unsigned char checksum;
bool valid;
};
class MeterBusClient {
public:
MeterBusClient();
void begin(CmdServer *cmdServer, Thermometer *thermometer);
void exec();
friend class MeterBusClientConfig;
private:
MeterBusClientConfig m_meterBusClientConfig;
Thermometer *m_thermometer;
unsigned char m_address;
void setAddress(unsigned char address);
unsigned char getAddress();
void handleFrame();
MeterBusFrame m_frame;
unsigned long m_frameCnt;
unsigned long m_myFrameCnt;
unsigned long m_invalidFrameCnt;
unsigned long m_invalidChecksum;
bool m_debug;
bool getDebug();
void setDebug(bool b);
bool m_info;
bool getInfo();
void setInfo(bool b);
void SND_NKE();
void REQ_UD2();
};
#endif /* METERBUSCLIENT_H_ */

23
meterBusClientFrames.cpp Normal file
View File

@ -0,0 +1,23 @@
/*
* meterBusClientFrames.cpp
*
* Created on: 09.03.2014
* Author: wn
*/
#include "meterBusClient.h"
void MeterBusClient::SND_NKE() {
Serial3.write(0xE5);
}
void MeterBusClient::REQ_UD2() {
}

View File

@ -252,19 +252,7 @@ void Thermometer::begin(CmdServer *cmdServer) {
AD7190_Calibrate(AD7190_MODE_CAL_INT_ZERO, AD7190_CH_AIN1P_AINCOM);
AD7190_Calibrate(AD7190_MODE_CAL_INT_FULL, AD7190_CH_AIN1P_AINCOM);
/*
if (! Config::isInitialized()) {
Serial.println(getResource(THERMOMETER_BEGIN_1_KEY));
Config::setFloat(Config::THERMOMETER_ALPHA, 1.0);
Config::setULong(Config::THERMOMETER_PERIOD, 1000);
for (int i = 0; i < 4; i++) {
Config::setFloat(Config::THERMOMETER_CAL[i], 1.0);
}
Config::setBool(Config::THERMOMETER_DEBUG, true);
Config::setBool(Config::THERMOMETER_INFO, true);
Config::setMagic();
}
*/
setAlpha(Config::getFloat(Config::THERMOMETER_ALPHA));
setPeriodMeasure(Config::getULong(Config::THERMOMETER_PERIOD));
@ -274,12 +262,7 @@ void Thermometer::begin(CmdServer *cmdServer) {
setDebug(Config::getBool(Config::THERMOMETER_DEBUG));
setInfo(Config::getBool(Config::THERMOMETER_INFO));
//setCalibrateFactor(0, 1.002999);
//setCalibrateFactor(1, 1.001804);
//setCalibrateFactor(2, 1.000794);
//setCalibrateFactor(3, 1.001071);
// prepare
prepareAdc();
}