/* * meterBusClient.cpp * * Created on: 08.03.2014 * Author: wn */ #include "meterBusClient.h" 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 { res = "subcommand not found"; } return res; } MeterBusClient::MeterBusClient() : m_meterBusClientConfig(this), m_address(0) { } void MeterBusClient::begin(CmdServer *cmdServer) { m_meterBusClientConfig.registerYourself(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 = 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() { if (m_frame.aField != getAddress()) { Serial.print(getResource(MBC_NOT_FOR_ME_KEY)); Serial.print((int)m_frame.aField, 16); Serial.println(); } else if (! isChecksumValid(m_frame)) { Serial.println(getResource(MBC_INVALID_CHECKSUM_KEY)); } else { // handle the frame Serial.print("s: "); Serial.println(m_frame.startDelimiter, 16); Serial.print("l: "); Serial.println(m_frame.length, 16); Serial.print("c: "); Serial.println(m_frame.cField, 16); Serial.print("a: "); Serial.println(m_frame.ciField, 16); } } typedef enum { STATE_START, STATE_IDLE, STATE_SHORT_FRAME, STATE_LONG_CTRL_FRAME, STATE_HANDLE, STATE_INVALID, STATE_FOREIGN, 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; bool done = false; 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) { Serial.println("switching to short frame, c field"); m_frame.startDelimiter = 0x10; state = STATE_SHORT_FRAME; subState = SUBSTATE_C_FIELD; } else if (ch == 0x68) { Serial.println("switching to long frame, length"); m_frame.startDelimiter = 0x68; state = STATE_LONG_CTRL_FRAME; subState = SUBSTATE_LENGTH; } else { Serial.println("switching to invalid"); 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_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) { 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; } } else if (subState == SUBSTATE_USERDATA) { // count and collect // then: 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: Serial.println(getResource(MBC_INVALID_FRAME_KEY)); state = STATE_START; break; case STATE_HANDLE: Serial.println("handle frame"); if (m_frame.valid) { handleFrame(); } else { Serial.println(getResource(MBC_NO_VALID_FRAME_KEY)); } state = STATE_DONE; break; case STATE_FOREIGN: // not for me message state = STATE_START; break; case STATE_DONE: // may be another useful message state = STATE_START; break; } }