all the prepared mini meterbus client stuff

This commit is contained in:
hg 2014-06-05 21:17:41 +02:00
parent 7802282906
commit a27d27a827
9 changed files with 693 additions and 43 deletions

36
src/debug.cpp Normal file
View File

@ -0,0 +1,36 @@
/*
* debug.cpp
*
* Created on: 24.05.2014
* Author: wn
*/
#include "debug.h"
#include <msp430g2553.h>
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
}

27
src/debug.h Normal file
View File

@ -0,0 +1,27 @@
/*
* debug.h
*
* Created on: 24.05.2014
* Author: wn
*/
#ifndef DEBUG_H_
#define DEBUG_H_
#include <stdint.h>
#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_ */

View File

@ -11,35 +11,15 @@
#include <isr_compat.h> #include <isr_compat.h>
#include "uart.h" #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() { int main() {
WDTCTL = WDTPW | WDTHOLD; WDTCTL = WDTPW | WDTHOLD;
P1DIR |= BIT6 | BIT0;
P1OUT = 0;
TACCR0 = 1000;
TACCTL0 = CCIE;
TACTL = MC_1 | ID_0 | TASSEL_1 | TACLR;
uartInit(); uartInit();
timeInit();
__enable_interrupt(); __enable_interrupt();

315
src/meterBusClient.cpp Normal file
View File

@ -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;
}
}

90
src/meterBusClient.h Normal file
View File

@ -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_ */

View File

@ -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();
}

49
src/time.cpp Normal file
View File

@ -0,0 +1,49 @@
/*
* time.c
*
* Created on: 20.05.2014
* Author: wn
*/
#include <msp430g2553.h>
#include <isr_compat.h>
#include <stdint.h>
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;
}

17
src/time.h Normal file
View File

@ -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_ */

View File

@ -40,30 +40,23 @@ void uartInit() {
UCA0CTL1 &= ~UCSWRST; UCA0CTL1 &= ~UCSWRST;
IE2 |= UCA0RXIE; IE2 |= UCA0RXIE;
// FILE *mystdout = fdevopen(uartPutchar, NULL);
// stdout = mystdout;
} }
inline void _realUartTx() { inline void _realUartTx() {
if ((IFG2 | UCA0TXIE) != 0) { if ((IFG2 | UCA0TXIE) != 0) {
if (txBufferReadIdx != txBufferWriteIdx) { if (txBufferReadIdx != txBufferWriteIdx) {
UCA0TXBUF = txBuffer[txBufferReadIdx]; UCA0TXBUF = txBuffer[txBufferReadIdx];
txBufferReadIdx++; txBufferReadIdx++;
if (txBufferReadIdx > UART_TX_BUFFER_SIZE) { if (txBufferReadIdx > UART_TX_BUFFER_SIZE) {
txBufferReadIdx = 0; txBufferReadIdx = 0;
} }
} else { } else {
disableDataRegisterEmptyInterrupt(); disableDataRegisterEmptyInterrupt();
} }
} }
} }
void uartWrite(uint8_t o) { void uartWrite(uint8_t o) {
#if 0
UCA0TXBUF = o;
#else
if (txBufferWriteIdx == (UART_TX_BUFFER_SIZE - 1)) { if (txBufferWriteIdx == (UART_TX_BUFFER_SIZE - 1)) {
while (txBufferReadIdx == UART_TX_BUFFER_SIZE); while (txBufferReadIdx == UART_TX_BUFFER_SIZE);
} else { } else {
@ -78,8 +71,6 @@ void uartWrite(uint8_t o) {
} }
enableDataRegisterEmptyInterrupt(); enableDataRegisterEmptyInterrupt();
// _realUartTx();
#endif
} }
@ -93,7 +84,7 @@ void uartWrite(uint8_t o) {
ISR(USCIAB0TX, UART_TX_ISR) { ISR(USCIAB0TX, UART_TX_ISR) {
_realUartTx(); _realUartTx();
} }
ISR(USCIAB0RX, UART_RX_ISR) { ISR(USCIAB0RX, UART_RX_ISR) {