/* 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)); }