/*
Copyright (C) 2020 chester4444@wolke7.net
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include "WaterMeter.h"
WaterMeter::WaterMeter()
{
}
// ChipSelect assert
inline void WaterMeter::selectCC1101(void)
{
digitalWrite(SS, LOW);
}
// ChipSelect deassert
inline void WaterMeter::deselectCC1101(void)
{
digitalWrite(SS, HIGH);
}
// wait for MISO pulling down
inline void WaterMeter::waitMiso(void)
{
while(digitalRead(MISO) == HIGH);
}
// write a single register of CC1101
void WaterMeter::writeReg(uint8 regAddr, uint8 value)
{
selectCC1101(); // Select CC1101
waitMiso(); // Wait until MISO goes low
SPI.transfer(regAddr); // Send register address
SPI.transfer(value); // Send value
deselectCC1101(); // Deselect CC1101
}
// send a strobe command to CC1101
void WaterMeter::cmdStrobe(uint8 cmd)
{
selectCC1101(); // Select CC1101
delayMicroseconds(5);
waitMiso(); // Wait until MISO goes low
SPI.transfer(cmd); // Send strobe command
delayMicroseconds(5);
deselectCC1101(); // Deselect CC1101
}
// read CC1101 register (status or configuration)
uint8 WaterMeter::readReg(uint8 regAddr, uint8 regType)
{
uint8 addr, val;
addr = regAddr | regType;
selectCC1101(); // Select CC1101
waitMiso(); // Wait until MISO goes low
SPI.transfer(addr); // Send register address
val = SPI.transfer(0x00); // Read result
deselectCC1101(); // Deselect CC1101
return val;
}
//
void WaterMeter::readBurstReg(uint8 * buffer, uint8 regAddr, uint8 len)
{
uint8 addr, i;
addr = regAddr | READ_BURST;
selectCC1101(); // Select CC1101
delayMicroseconds(5);
waitMiso(); // Wait until MISO goes low
SPI.transfer(addr); // Send register address
for(i=0 ; i Output
SPI.begin(); // Initialize SPI interface
pinMode(CC1101_GDO0, INPUT); // Config GDO0 as input
reset(); // power on CC1101
//Serial.println("Setting CC1101 registers");
initializeRegisters(); // init CC1101 registers
cmdStrobe(CC1101_SCAL);
delay(1);
attachInterrupt(digitalPinToInterrupt(CC1101_GDO0), GD0_ISR, FALLING);
startReceiver();
}
// reads a single byte from the RX fifo
uint8_t WaterMeter::readByteFromFifo(void)
{
return readReg(CC1101_RXFIFO, CC1101_CONFIG_REGISTER);
}
// handles a received frame and restart the CC1101 receiver
void WaterMeter::receive(WMBusFrame * frame)
{
// read preamble, should be 0x543D
uint8_t p1 = readByteFromFifo();
uint8_t p2 = readByteFromFifo();
//Serial.printf("%02x%02x", p1, p2);
uint8_t payloadLength = readByteFromFifo();
// is it Mode C1, frame B and does it fit in the buffer
if ( (payloadLength < WMBusFrame::MAX_LENGTH )
&& (p1 == 0x54) && (p2 == 0x3D) )
{
// 3rd byte is payload length
frame->length = payloadLength;
//Serial.printf("%02X", lfield);
// starting with 1! index 0 is lfield
for (int i = 0; i < payloadLength; i++)
{
frame->payload[i] = readByteFromFifo();
}
// do some checks: my meterId, crc ok
frame->decode();
}
// flush RX fifo and restart receiver
startReceiver();
//Serial.printf("rxStatus: 0x%02x\n\r", readStatusReg(CC1101_RXBYTES));
}