From a27d27a8274d36de193fb6ace36507f4e4a21b0b Mon Sep 17 00:00:00 2001 From: hg Date: Thu, 5 Jun 2014 21:17:41 +0200 Subject: [PATCH] all the prepared mini meterbus client stuff --- src/debug.cpp | 36 ++++ src/debug.h | 27 +++ src/main.cpp | 24 +-- src/meterBusClient.cpp | 315 +++++++++++++++++++++++++++++++++++ src/meterBusClient.h | 90 ++++++++++ src/meterBusClientFrames.cpp | 145 ++++++++++++++++ src/time.cpp | 49 ++++++ src/time.h | 17 ++ src/uart.cpp | 33 ++-- 9 files changed, 693 insertions(+), 43 deletions(-) create mode 100644 src/debug.cpp create mode 100644 src/debug.h create mode 100644 src/meterBusClient.cpp create mode 100644 src/meterBusClient.h create mode 100644 src/meterBusClientFrames.cpp create mode 100644 src/time.cpp create mode 100644 src/time.h diff --git a/src/debug.cpp b/src/debug.cpp new file mode 100644 index 0000000..612928e --- /dev/null +++ b/src/debug.cpp @@ -0,0 +1,36 @@ +/* + * debug.cpp + * + * Created on: 24.05.2014 + * Author: wn + */ + +#include "debug.h" +#include + + +void debugInit() { +#ifdef DEBUG + DEBUG_DIR_REG |= DEBUG_CS | DEBUG_CLK | DEBUG_OUT; + DEBUG_OUT_REG |= DEBUG_CS; + DEBUG_OUT_REG &= ~DEBUG_CLK; +#endif +} + +void debugWrite(uint8_t o) { +#ifdef DEBUG + DEBUG_OUT_REG &= ~DEBUG_CS; + + for (uint8_t i = 0; i < 8; i++) { + if (((o << i) & 0x80) == 0x80) { + DEBUG_OUT_REG |= DEBUG_OUT; + } else { + DEBUG_OUT_REG &= ~DEBUG_OUT; + } + DEBUG_OUT_REG |= DEBUG_CLK; + DEBUG_OUT_REG &= ~DEBUG_CLK; + } + + DEBUG_OUT_REG |= DEBUG_CS; +#endif +} diff --git a/src/debug.h b/src/debug.h new file mode 100644 index 0000000..3d71a3b --- /dev/null +++ b/src/debug.h @@ -0,0 +1,27 @@ +/* + * debug.h + * + * Created on: 24.05.2014 + * Author: wn + */ + +#ifndef DEBUG_H_ +#define DEBUG_H_ + +#include + +#define DEBUG 1 + + +#define DEBUG_CS BIT3 +#define DEBUG_CLK BIT4 +#define DEBUG_OUT BIT5 +#define DEBUG_DIR_REG P2DIR +#define DEBUG_OUT_REG P2OUT + + +void debugInit(); +void debugWrite(uint8_t o); + + +#endif /* DEBUG_H_ */ diff --git a/src/main.cpp b/src/main.cpp index 4608656..8153d51 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,35 +11,15 @@ #include #include "uart.h" +#include "time.h" -ISR(TIMER0_A0, TA0_ISR) { - static uint8_t state = 0; - - switch (state) { - case 0: - P1OUT = BIT0; - state = 1; - break; - case 1: - P1OUT = BIT6; - state = 0; - break; - default: - state = 0; - } -} int main() { WDTCTL = WDTPW | WDTHOLD; - P1DIR |= BIT6 | BIT0; - P1OUT = 0; - - TACCR0 = 1000; - TACCTL0 = CCIE; - TACTL = MC_1 | ID_0 | TASSEL_1 | TACLR; uartInit(); + timeInit(); __enable_interrupt(); diff --git a/src/meterBusClient.cpp b/src/meterBusClient.cpp new file mode 100644 index 0000000..9486c29 --- /dev/null +++ b/src/meterBusClient.cpp @@ -0,0 +1,315 @@ +/* + * meterBusClient.cpp + * + * Created on: 08.03.2014 + * Author: wn + */ + + + +#include "meterBusClient.h" +#include "uart.h" +#include "time.h" +#include "debug.h" + +const bool MBC_COMPILE_TIME_DEBUG = false; + + + +MeterBusClient::MeterBusClient() : m_address(0), + m_frameCnt(0), m_accessCnt(0), m_myFrameCnt(0), m_invalidFrameCnt(0), m_invalidChecksum(0), + m_collisionCnt(0) { +} + + + +void MeterBusClient::begin() { + // setAddress(Config::getUChar(Config::METERBUSCLIENT_ADDRESS)); + setAddress(0x22); +} + +void MeterBusClient::setAddress(unsigned char a) { + // Config::setUChar(Config::METERBUSCLIENT_ADDRESS, a); + m_address = a; +} + +unsigned char MeterBusClient::getAddress() { + return m_address; +} + + +unsigned char MeterBusClient::getStatus() { + return 0; +} + +unsigned char MeterBusClient::getAccessCnt() { + return m_accessCnt; +} + + +/* + * 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); +} + + + +bool MeterBusClient::handleFrame() { + bool res = false; + m_frameCnt++; + if (! isChecksumValid(m_frame)) { + m_invalidChecksum++; + } else if ((m_frame.aField == getAddress()) || (m_frame.aField == 0xfe)) { + m_myFrameCnt++; + // handle the frame + + if (m_frame.startDelimiter == 0x10) { + if (m_frame.cField == 0x40) { + m_accessCnt++; + SND_NKE(); + res = true; + } else if (m_frame.cField == 0x5b) { + m_accessCnt++; + REQ_UD2(); + res = true; + } + } else if (m_frame.startDelimiter == 0x68) { + if (m_frame.cField == 0x53) { + m_accessCnt++; + SND_UD(); + res = true; + } + } + } + return res; +} + + +typedef enum { + STATE_START, STATE_IDLE, STATE_SHORT_FRAME, STATE_LONG_CTRL_FRAME, STATE_HANDLE, STATE_INVALID, STATE_DONE, + STATE_DELAYED_RESPONSE, STATE_DELAY, STATE_RESPONSE, STATE_RECEIVE_ECHO +} 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; + static unsigned int echoReceiveCnt = 0; + static unsigned long receivedDoneTimestamp; + + + int chi = uartRead(); + char ch = (char) chi; + if (chi != -1) { + debugWrite(0x04); + debugWrite(ch); + debugWrite(state); + debugWrite(subState); + } + + 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; + 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: + state = STATE_DONE; + if (m_frame.valid) { + receivedDoneTimestamp = millis(); + if (handleFrame()) { + state = STATE_DELAY; + } + } + break; + + case STATE_DELAY: + if ((receivedDoneTimestamp + RESPONSE_DELAY) < millis()) { + state = STATE_DELAYED_RESPONSE; + } + break; + + case STATE_DELAYED_RESPONSE: + for (unsigned int i = 0; i < m_sendBufferLen; i++) { + uartWrite(m_sendBuffer[i]); + } + echoReceiveCnt = 0; + state = STATE_RECEIVE_ECHO; + break; + + case STATE_RECEIVE_ECHO: + if (chi != -1) { + if (ch == m_sendBuffer[echoReceiveCnt]) { + echoReceiveCnt++; + if (echoReceiveCnt == m_sendBufferLen) { + state = STATE_DONE; + } + } else { + m_collisionCnt++; + state = STATE_DONE; + } + } + break; + + case STATE_DONE: + // may be another useful message + state = STATE_START; + break; + } +} + + diff --git a/src/meterBusClient.h b/src/meterBusClient.h new file mode 100644 index 0000000..b6f4e4d --- /dev/null +++ b/src/meterBusClient.h @@ -0,0 +1,90 @@ +/* + * meterBusClient.h + * + * Created on: 08.03.2014 + * Author: wn + */ + +#ifndef METERBUSCLIENT_H_ +#define METERBUSCLIENT_H_ + + + + + +const unsigned long RESPONSE_DELAY = 50; + + + +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[64]; + unsigned char checksum; + bool valid; +}; + + +class MeterBusClient { +public: + MeterBusClient(); + void begin(); + void exec(); +private: + unsigned char m_address; + void setAddress(unsigned char address); + unsigned char getAddress(); + bool handleFrame(); + MeterBusFrame m_frame; + + unsigned char m_sendBuffer[64]; + unsigned int m_sendBufferLen; + void aSB(unsigned char v); // append to send buffer + void aSB(unsigned int v); + void aSB(unsigned long v); + void aSB(float v); + unsigned char calcSendChecksum(); + void calcAndSetFrameLength(); + + unsigned long m_frameCnt; + unsigned char m_accessCnt; + unsigned long m_myFrameCnt; + unsigned long m_invalidFrameCnt; + unsigned long m_invalidChecksum; + unsigned long m_collisionCnt; + + unsigned char getAccessCnt(); + unsigned char getStatus(); + + void SND_NKE(); + void REQ_UD2(); + void SND_UD(); +}; + + + +#endif /* METERBUSCLIENT_H_ */ diff --git a/src/meterBusClientFrames.cpp b/src/meterBusClientFrames.cpp new file mode 100644 index 0000000..9febcae --- /dev/null +++ b/src/meterBusClientFrames.cpp @@ -0,0 +1,145 @@ +/* + * meterBusClientFrames.cpp + * + * Created on: 09.03.2014 + * Author: wn + */ + +#include "meterBusClient.h" +#include "stdint.h" + +void MeterBusClient::aSB(unsigned char v) { + m_sendBuffer[m_sendBufferLen] = v; + m_sendBufferLen++; +} + +void MeterBusClient::aSB(unsigned int v) { + // 16 bit + union { + unsigned int i; + unsigned char c[2]; + } u; + u.i = v; + m_sendBuffer[m_sendBufferLen] = u.c[0]; + m_sendBufferLen++; + m_sendBuffer[m_sendBufferLen] = u.c[1]; + m_sendBufferLen++; +} + +void MeterBusClient::aSB(unsigned long v) { + // 32 bit + union{ + unsigned long l; + unsigned char c[4]; + } u; + u.l = v; + m_sendBuffer[m_sendBufferLen] = u.c[0]; + m_sendBufferLen++; + m_sendBuffer[m_sendBufferLen] = u.c[1]; + m_sendBufferLen++; + m_sendBuffer[m_sendBufferLen] = u.c[2]; + m_sendBufferLen++; + m_sendBuffer[m_sendBufferLen] = u.c[3]; + m_sendBufferLen++; +} + +void MeterBusClient::aSB(float v) { + // 32 bit + union{ + float f; + unsigned char c[4]; + } u; + u.f = v; + m_sendBuffer[m_sendBufferLen] = u.c[0]; + m_sendBufferLen++; + m_sendBuffer[m_sendBufferLen] = u.c[1]; + m_sendBufferLen++; + m_sendBuffer[m_sendBufferLen] = u.c[2]; + m_sendBufferLen++; + m_sendBuffer[m_sendBufferLen] = u.c[3]; + m_sendBufferLen++; +} + +unsigned char MeterBusClient::calcSendChecksum() { + unsigned char checksum = 0; + for (unsigned int i = 4; i < m_sendBufferLen; i++) { + checksum += m_sendBuffer[i]; + } + return checksum; +} + +void MeterBusClient::calcAndSetFrameLength() { + unsigned char frameLength = m_sendBufferLen - 6; + m_sendBuffer[1] = frameLength; + m_sendBuffer[2] = frameLength; +} + +void MeterBusClient::SND_NKE() { + m_sendBufferLen = 0; + aSB((unsigned char)0xE5); +} + +void MeterBusClient::REQ_UD2() { + m_sendBufferLen = 0; + // frame header + aSB((unsigned char)0x68); + aSB((unsigned char)0x00); + aSB((unsigned char)0x00); + aSB((unsigned char)0x68); + + // C + aSB((unsigned char)0x08); + + // A + aSB(getAddress()); + + // CI + aSB((unsigned char)0x72); + + // Header + aSB((unsigned long)0); // Ident + aSB((unsigned int)0); // Manu. + aSB((unsigned char)1); // Version + aSB((unsigned char)0); // Medium: other + aSB(getAccessCnt()); // Access + aSB(getStatus()); // Status + aSB((unsigned int)0); // Signatur + + + + aSB(calcSendChecksum()); + aSB((unsigned char)0x16); + calcAndSetFrameLength(); +} + +void MeterBusClient::SND_UD() { + m_sendBufferLen = 0; + // frame header + aSB((unsigned char)0x68); + aSB((unsigned char)0x00); + aSB((unsigned char)0x00); + aSB((unsigned char)0x68); + + + aSB(m_frame.cField); + aSB(m_frame.aField); + aSB(m_frame.ciField); + + aSB((unsigned char)0xff); + aSB((unsigned char)0xff); + aSB((unsigned char)0xff); + aSB((unsigned char)0xff); + + for (uint8_t i = 0; i < m_frame.length - 3; i++) { + aSB(m_frame.userData[i]); + } + + aSB(calcSendChecksum()); + aSB((unsigned char)0x16); + calcAndSetFrameLength(); +} + + + + + diff --git a/src/time.cpp b/src/time.cpp new file mode 100644 index 0000000..1bfb89e --- /dev/null +++ b/src/time.cpp @@ -0,0 +1,49 @@ +/* + * time.c + * + * Created on: 20.05.2014 + * Author: wn + */ +#include +#include +#include + + + +volatile unsigned long timestamp; + +ISR(TIMER0_A0, TA0_ISR) { + static uint8_t state = 0; + + timestamp++; + + switch (state) { + case 0: + P1OUT = BIT0; + state = 1; + break; + case 1: + P1OUT = BIT6; + state = 0; + break; + default: + state = 0; + } +} + + +void timeInit() { + timestamp = 0; + + P1DIR |= BIT6 | BIT0; + P1OUT = 0; + + TACCR0 = 1000; + TACCTL0 = CCIE; + TACTL = MC_1 | ID_0 | TASSEL_1 | TACLR; +} + + +unsigned long millis() { + return timestamp; +} diff --git a/src/time.h b/src/time.h new file mode 100644 index 0000000..10a66bc --- /dev/null +++ b/src/time.h @@ -0,0 +1,17 @@ +/* + * time.h + * + * Created on: 20.05.2014 + * Author: wn + */ + +#ifndef TIME_H_ +#define TIME_H_ + + + +void timeInit(); +unsigned long millis(); + + +#endif /* TIME_H_ */ diff --git a/src/uart.cpp b/src/uart.cpp index 7902061..d9dbf2d 100644 --- a/src/uart.cpp +++ b/src/uart.cpp @@ -40,30 +40,23 @@ void uartInit() { UCA0CTL1 &= ~UCSWRST; IE2 |= UCA0RXIE; - - -// FILE *mystdout = fdevopen(uartPutchar, NULL); -// stdout = mystdout; } inline void _realUartTx() { - if ((IFG2 | UCA0TXIE) != 0) { - if (txBufferReadIdx != txBufferWriteIdx) { - UCA0TXBUF = txBuffer[txBufferReadIdx]; - txBufferReadIdx++; - if (txBufferReadIdx > UART_TX_BUFFER_SIZE) { - txBufferReadIdx = 0; - } - } else { - disableDataRegisterEmptyInterrupt(); - } - } + if ((IFG2 | UCA0TXIE) != 0) { + if (txBufferReadIdx != txBufferWriteIdx) { + UCA0TXBUF = txBuffer[txBufferReadIdx]; + txBufferReadIdx++; + if (txBufferReadIdx > UART_TX_BUFFER_SIZE) { + txBufferReadIdx = 0; + } + } else { + disableDataRegisterEmptyInterrupt(); + } + } } void uartWrite(uint8_t o) { -#if 0 - UCA0TXBUF = o; -#else if (txBufferWriteIdx == (UART_TX_BUFFER_SIZE - 1)) { while (txBufferReadIdx == UART_TX_BUFFER_SIZE); } else { @@ -78,8 +71,6 @@ void uartWrite(uint8_t o) { } enableDataRegisterEmptyInterrupt(); - // _realUartTx(); -#endif } @@ -93,7 +84,7 @@ void uartWrite(uint8_t o) { ISR(USCIAB0TX, UART_TX_ISR) { - _realUartTx(); + _realUartTx(); } ISR(USCIAB0RX, UART_RX_ISR) {