├── board.jpg ├── meter_label.png ├── Makefile ├── wiringPiSPI.h ├── everblu_meters.h ├── README.md ├── everblu_meters.c ├── utils.c ├── wiringPi.h └── cc1101.c /board.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neutrinus/everblu-meters/HEAD/board.jpg -------------------------------------------------------------------------------- /meter_label.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neutrinus/everblu-meters/HEAD/meter_label.png -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile 2 | 3 | main: 4 | gcc everblu_meters.c -o everblu_meters -lwiringPi -lmosquitto -lpthread -Wall 5 | -------------------------------------------------------------------------------- /wiringPiSPI.h: -------------------------------------------------------------------------------- 1 | /* 2 | * wiringPiSPI.h: 3 | * Simplified SPI access routines 4 | * Copyright (c) 2012-2015 Gordon Henderson 5 | *********************************************************************** 6 | * This file is part of wiringPi: 7 | * https://projects.drogon.net/raspberry-pi/wiringpi/ 8 | * 9 | * wiringPi is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU Lesser General Public License as 11 | * published by the Free Software Foundation, either version 3 of the 12 | * License, or (at your option) any later version. 13 | * 14 | * wiringPi is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with wiringPi. 21 | * If not, see . 22 | *********************************************************************** 23 | */ 24 | 25 | #ifdef __cplusplus 26 | extern "C" { 27 | #endif 28 | 29 | int wiringPiSPIGetFd (int channel) ; 30 | int wiringPiSPIDataRW (int channel, unsigned char *data, int len) ; 31 | int wiringPiSPISetupMode (int channel, int speed, int mode) ; 32 | int wiringPiSPISetup (int channel, int speed) ; 33 | 34 | #ifdef __cplusplus 35 | } 36 | #endif 37 | -------------------------------------------------------------------------------- /everblu_meters.h: -------------------------------------------------------------------------------- 1 | /* the radian_trx SW shall not be distributed nor used for commercial product*/ 2 | /* it is exposed just to demonstrate CC1101 capability to reader water meter indexes */ 3 | /* there is no Warranty on radian_trx SW */ 4 | 5 | #include "time.h" 6 | #include "stdio.h" 7 | #include "stdarg.h" 8 | #include "stdlib.h" 9 | #include "pthread.h" 10 | #include "stdint.h" 11 | #include "string.h" 12 | 13 | #include "wiringPi.h" 14 | 15 | #ifdef __unix__ 16 | # include 17 | # include // pour sleep 18 | # include 19 | //# include // pour getch mais fonctionne bizarement 20 | char getch(){ 21 | /*#include //_getch*/ 22 | /*#include //_getch*/ 23 | char buf=0; 24 | struct termios old={0}; 25 | fflush(stdout); 26 | if(tcgetattr(0, &old)<0) 27 | perror("tcsetattr()"); 28 | old.c_lflag&=~ICANON; 29 | old.c_lflag&=~ECHO; 30 | old.c_cc[VMIN]=1; 31 | old.c_cc[VTIME]=0; 32 | if(tcsetattr(0, TCSANOW, &old)<0) 33 | perror("tcsetattr ICANON"); 34 | if(read(0,&buf,1)<0) 35 | perror("read()"); 36 | old.c_lflag|=ICANON; 37 | old.c_lflag|=ECHO; 38 | if(tcsetattr(0, TCSADRAIN, &old)<0) 39 | perror ("tcsetattr ~ICANON"); 40 | printf("%c",buf); 41 | return buf; 42 | } 43 | 44 | #elif defined _WIN32 45 | # include 46 | # include // pour getch 47 | #define sleep(x) Sleep(1000 * x) 48 | #endif 49 | 50 | typedef unsigned char T_BOOL; //1 octets 51 | 52 | #define GDO2 2 //header 13 53 | #define GDO1_MISO 13 54 | #define GDO0 0 //header 11 55 | #define MOSI 12 56 | #define cc1101_CSn 10 ////header 24 57 | 58 | 59 | #include "utils.c" 60 | #include "wiringPi.h" 61 | #include "wiringPiSPI.h" 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # No longer maintained 2 | As I have new water meter (lora enabled), this project is no longer maintained by me. Feel free to fork it and develop further. 3 | 4 | # everblu-meters - Water usage data for Home Assistant 5 | Fetch water/gas usage data from Cyble EverBlu meters using RADIAN protocol on 433Mhz. Integrated with Home Assistant via MQTT. 6 | 7 | Note: HASS autodiscovery is still missing, during development. 8 | 9 | Meters supported: 10 | - Itron EverBlu Cyble Enhanced 11 | 12 | 13 | ## Hardware 14 | ![Raspberry Pi Zero with CC1101](board.jpg) 15 | The project runs on Raspberry Pi with an RF transreciver (CC1101). 16 | 17 | ### Connections (rpi to CC1101): 18 | - pin 1 (3V3) to pin 2 (VCC) 19 | - pin 6 (GND) to pin 1 (GND) 20 | - pin 11 (GPIO0 ) to pin 3 (GDO0) 21 | - pin 24 (CE0) to pin 4 (CSN) 22 | - pin 23 (SCLK) to pin 5 (SCK) 23 | - pin 19 (MOSI) to pin 6 (MOSI) 24 | - pin 21 (MISO) to pin 7 (MISO) 25 | - pin 13 (GPIO27) to pin 8 (GD02) 26 | 27 | 28 | ## Configuration 29 | 1. Enable SPI in raspi-config. 30 | 2. Install WiringPi from https://github.com/WiringPi/WiringPi/ 31 | 3. Install libmosquitto-dev: `apt install libmosquitto-dev` 32 | 4. Set meter serial number and production date in `everblu_meters.c`, it can be found on the meter label itself: 33 | ![Cyble Meter Label](meter_label.png) 34 | 5. Configure MQTT connection details in `everblu_meters.c`: `MQTT_HOST`, `MQTT_USER`, 'MQTT_PASS` 35 | 5. Compile the code with `make` 36 | 6. Run `everblu_meters`, after ~2s your meter data should be on the screen and data should be pushed to MQTT. 37 | 7. Setup crontab to run it twice a day 38 | 39 | ## Troubleshooting 40 | 41 | ### Frequency adjustment 42 | Your transreciver module may be not calibrated correctly, please modify frequency a bit lower or higher and try again. You may use RTL-SDR to measure the offset needed. 43 | 44 | 45 | ### Business hours 46 | Your meter may be configured in such a way that is listens for request only during hours when data collectors work - to conserve energy. If you are unable to communicate with the meter, please try again during business hours (8-16). 47 | 48 | ### Serial number starting with 0 49 | Please ignore the leading 0, provide serial in configuration without it. 50 | 51 | 52 | ### Save power 53 | The meter has internal battery, which should last for 10 years when queried once a day. 54 | 55 | ## Origin and license 56 | 57 | This code is based on code from http://www.lamaisonsimon.fr/wiki/doku.php?id=maison2:compteur_d_eau:compteur_d_eau 58 | 59 | 60 | The license is unknown, citing one of the authors (fred): 61 | 62 | > I didn't put a license on this code maybe I should, I didn't know much about it in terms of licensing. 63 | > this code was made by "looking" at the radian protocol which is said to be open source earlier in the page, I don't know if that helps? 64 | 65 | # Links 66 | 67 | There is a very nice port to ESP8266/ESP32: https://github.com/psykokwak-com/everblu-meters-esp8266 68 | 69 | -------------------------------------------------------------------------------- /everblu_meters.c: -------------------------------------------------------------------------------- 1 | /* the radian_trx SW shall not be distributed nor used for commercial product*/ 2 | /* it is exposed just to demonstrate CC1101 capability to reader water meter indexes */ 3 | 4 | #define METER_YEAR 16 5 | #define METER_SERIAL 123456 6 | 7 | #define MQTT_HOST "localhost" 8 | #define MQTT_PORT 1883 9 | #define MQTT_USER "homeassistant" 10 | #define MQTT_PASS "PASS" 11 | 12 | 13 | #define MQTT_KEEP_ALIVE 60 14 | #define MQTT_MSG_MAX_SIZE 512 15 | 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include "everblu_meters.h" 23 | #include "cc1101.c" 24 | 25 | void my_message_callback(struct mosquitto *mosq, void *userdata, const struct mosquitto_message *message) 26 | { 27 | 28 | if(message->payloadlen){ 29 | printf("%s %s", message->topic, (char *)message->payload); 30 | }else{ 31 | //printf("%s (null)\n", message->topic); 32 | } 33 | fflush(stdout); 34 | } 35 | 36 | void my_connect_callback(struct mosquitto *mosq, void *userdata, int result) 37 | { 38 | if(!result){ 39 | /* Subscribe to broker information topics on successful connect. */ 40 | mosquitto_subscribe(mosq, NULL, "WaterUsage ", 2); 41 | }else{ 42 | fprintf(stderr, "Connect failed\n"); 43 | } 44 | } 45 | 46 | void my_subscribe_callback(struct mosquitto *mosq, void *userdata, int mid, int qos_count, const int *granted_qos) 47 | { 48 | int i; 49 | printf("Subscribed (mid: %d): %d", mid, granted_qos[0]); 50 | for(i=1; i>= 1 ) 50 | { 51 | (mask & *ptr) > 0 ? printf("1") : printf("0"); 52 | } 53 | printf(" "); 54 | } 55 | printf("\n"); 56 | } 57 | 58 | void echo_debug(T_BOOL l_flag,char *fmt, ...) 59 | { 60 | if (l_flag) 61 | { 62 | va_list args; 63 | va_start (args, fmt); 64 | vprintf (fmt, args); 65 | fflush(stdout); 66 | } 67 | 68 | } 69 | 70 | void print_time(void) 71 | {/* 72 | time_t mytime; 73 | mytime = time(NULL); 74 | printf(ctime(&mytime));*/ 75 | 76 | 77 | time_t rawtime; 78 | struct tm * timeinfo; 79 | char buffer [80]; 80 | 81 | time (&rawtime); 82 | timeinfo = localtime (&rawtime); 83 | 84 | strftime (buffer,80,"%d/%m/%Y %X",timeinfo); 85 | printf("%s",buffer); 86 | 87 | } 88 | 89 | 90 | 91 | /*----------------------------------------------------------------------------*/ 92 | #define CRC_START_KERMIT 0x0000 93 | #define CRC_POLY_KERMIT 0x8408 94 | static uint8_t crc_tab_init = 0; 95 | static uint16_t crc_tab[256]; 96 | /*----------------------------------------------------------------------------*/ 97 | /* https://www.libcrc.org/ 98 | * static void init_crc_tab( void ); 99 | * 100 | * For optimal performance, the CRC Kermit routine uses a lookup table with 101 | * values that can be used directly in the XOR arithmetic in the algorithm. 102 | * This lookup table is calculated by the init_crc_tab() routine, the first 103 | * time the CRC function is called. 104 | */ 105 | 106 | static void init_crc_tab( void ) { 107 | 108 | uint16_t i; 109 | uint16_t j; 110 | uint16_t crc; 111 | uint16_t c; 112 | 113 | for (i=0; i<256; i++) { 114 | 115 | crc = 0; 116 | c = i; 117 | 118 | for (j=0; j<8; j++) { 119 | 120 | if ( (crc ^ c) & 0x0001 ) crc = ( crc >> 1 ) ^ CRC_POLY_KERMIT; 121 | else crc = crc >> 1; 122 | 123 | c = c >> 1; 124 | } 125 | 126 | crc_tab[i] = crc; 127 | } 128 | 129 | crc_tab_init = 1; 130 | 131 | } /* init_crc_tab */ 132 | 133 | 134 | /* https://www.libcrc.org/ 135 | * uint16_t crc_kermit( const unsigned char *input_str, size_t num_bytes ); 136 | * 137 | * The function crc_kermit() calculates the 16 bits Kermit CRC in one pass for 138 | * a byte string of which the beginning has been passed to the function. The 139 | * number of bytes to check is also a parameter. 140 | */ 141 | 142 | uint16_t crc_kermit( const unsigned char *input_ptr, size_t num_bytes ) { 143 | 144 | uint16_t crc; 145 | uint16_t tmp; 146 | uint16_t short_c; 147 | uint16_t low_byte; 148 | uint16_t high_byte; 149 | const unsigned char *ptr; 150 | size_t a; 151 | 152 | if ( ! crc_tab_init ) init_crc_tab(); 153 | 154 | crc = CRC_START_KERMIT; 155 | ptr = input_ptr; 156 | 157 | for (a=0; a> 8) ^ crc_tab[ tmp & 0xff ]; 162 | 163 | ptr++; 164 | } 165 | 166 | low_byte = (crc & 0xff00) >> 8; 167 | high_byte = (crc & 0x00ff) << 8; 168 | crc = low_byte | high_byte; 169 | 170 | return crc; 171 | 172 | } /* crc_kermit */ 173 | 174 | /*----------------------------------------------------------------------------*/ 175 | /** 176 | * Reverses the bit order of the input data and adds a start bit before and a stop bit 177 | * after each byte. 178 | * 179 | * @param inputBuffer Points to the unencoded data. 180 | * @param inputBufferLen Number of bytes of unencoded data. 181 | * @param outputBuffer Points to the encoded data. 182 | * @param outputBufferLen Number of bytes of encoded data. 183 | */ 184 | int encode2serial_1_3(uint8_t *inputBuffer, int inputBufferLen, uint8_t *outputBuffer) { 185 | 186 | // Adds a start and stop bit and reverses the bit order. 187 | // 76543210 76543210 76543210 76543210 188 | // is encoded to: 189 | // #0123456 7###0123 4567###0 1234567# ##012345 6s7# (# -> Start/Stop bit) 190 | 191 | int bytepos; 192 | int bitpos; 193 | int i; 194 | int j = 0; 195 | 196 | for (i=0 ; i < (inputBufferLen * 8) ; i++) { 197 | //printf("\r\ni=%u",i); 198 | if (i % 8 == 0) { 199 | if (i > 0) { 200 | //printf(" j=%u stopBIT",j); 201 | // Insert stop bit (3) 202 | bytepos = j / 8; 203 | bitpos = j % 8; 204 | outputBuffer[bytepos] |= 1 << (7 - bitpos); 205 | j++; 206 | 207 | bytepos = j / 8; 208 | bitpos = j % 8; 209 | outputBuffer[bytepos] |= 1 << (7 - bitpos); 210 | j++; 211 | 212 | bytepos = j / 8; 213 | bitpos = j % 8; 214 | outputBuffer[bytepos] |= 1 << (7 - bitpos); 215 | j++; 216 | } //stop bit 217 | 218 | // Insert start bit (0) 219 | bytepos = j / 8; 220 | bitpos = j % 8; 221 | //printf(" j=%u startBIT",j); 222 | outputBuffer[bytepos] &= ~(1 << (7 - bitpos)); 223 | j++; 224 | }// start stop bit 225 | 226 | bytepos = i / 8; 227 | bitpos = i % 8; 228 | uint8_t mask = 1 << bitpos; 229 | if ((inputBuffer[bytepos] & mask) > 0) { 230 | bytepos = j / 8; 231 | bitpos = 7 - (j % 8); 232 | outputBuffer[bytepos] |= 1 << bitpos; 233 | 234 | } else { 235 | bytepos = j / 8; 236 | bitpos = 7 - (j % 8); 237 | outputBuffer[bytepos] &= ~(1 << bitpos); 238 | } 239 | 240 | j++; 241 | }//for 242 | 243 | //insert additional stop bit until end of byte 244 | while (j%8 > 0) 245 | { 246 | bytepos = j / 8; 247 | bitpos = 7 - (j % 8); 248 | outputBuffer[bytepos] |= 1 << bitpos; 249 | j++; 250 | } 251 | outputBuffer[bytepos+1] = 0xFF; 252 | return bytepos+2; 253 | } 254 | 255 | int Make_Radian_Master_req(uint8_t *outputBuffer,uint8_t year,uint32_t serial) 256 | { 257 | uint16_t crc; 258 | uint8_t to_encode[] ={0x13,0x10,0x00,0x45,0xFF,0xFF,0xFF,0xFF,0x00,0x45,0x20,0x0A,0x50,0x14,0x00,0x0A,0x40,0xFF,0xFF}; //les 2 derniers octet sont en reserve pour le CKS ainsi que le serial number 259 | uint8_t synch_pattern[] ={0x50,0x00,0x00,0x00,0x03,0xFF,0xFF,0xFF,0xFF}; 260 | uint8_t TS_len_u8; 261 | 262 | to_encode[4] = year; 263 | to_encode[5] = (uint8_t)((serial&0x00FF0000)>>16); 264 | to_encode[6] = (uint8_t)((serial&0x0000FF00)>>8); 265 | to_encode[7] = (uint8_t) (serial&0x000000FF); 266 | crc = crc_kermit(to_encode,sizeof(to_encode)-2); 267 | //printf("crc:%x\r\n",crc); 268 | to_encode[sizeof(to_encode)-2]=(uint8_t)((crc&0xFF00)>>8); 269 | to_encode[sizeof(to_encode)-1]=(uint8_t)(crc&0x00FF); 270 | //show_in_hex_one_line(to_encode,sizeof(to_encode)); 271 | memcpy(outputBuffer,synch_pattern,sizeof(synch_pattern)); 272 | TS_len_u8=encode2serial_1_3(to_encode,sizeof(to_encode),&outputBuffer[sizeof(synch_pattern)]); 273 | return TS_len_u8+sizeof(synch_pattern); 274 | } 275 | -------------------------------------------------------------------------------- /wiringPi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * wiringPi.h: 3 | * Arduino like Wiring library for the Raspberry Pi. 4 | * Copyright (c) 2012-2016 Gordon Henderson 5 | *********************************************************************** 6 | * This file is part of wiringPi: 7 | * https://projects.drogon.net/raspberry-pi/wiringpi/ 8 | * 9 | * wiringPi is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU Lesser General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * wiringPi is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public License 20 | * along with wiringPi. If not, see . 21 | *********************************************************************** 22 | */ 23 | 24 | #ifndef __WIRING_PI_H__ 25 | #define __WIRING_PI_H__ 26 | 27 | // C doesn't have true/false by default and I can never remember which 28 | // way round they are, so ... 29 | 30 | #ifndef TRUE 31 | # define TRUE (1==1) 32 | # define FALSE (!TRUE) 33 | #endif 34 | 35 | // Handy defines 36 | 37 | // wiringPi modes 38 | 39 | #define WPI_MODE_PINS 0 40 | #define WPI_MODE_GPIO 1 41 | #define WPI_MODE_GPIO_SYS 2 42 | #define WPI_MODE_PHYS 3 43 | #define WPI_MODE_PIFACE 4 44 | #define WPI_MODE_UNINITIALISED -1 45 | 46 | // Pin modes 47 | 48 | #define INPUT 0 49 | #define OUTPUT 1 50 | #define PWM_OUTPUT 2 51 | #define GPIO_CLOCK 3 52 | #define SOFT_PWM_OUTPUT 4 53 | #define SOFT_TONE_OUTPUT 5 54 | #define PWM_TONE_OUTPUT 6 55 | 56 | #define LOW 0 57 | #define HIGH 1 58 | 59 | // Pull up/down/none 60 | 61 | #define PUD_OFF 0 62 | #define PUD_DOWN 1 63 | #define PUD_UP 2 64 | 65 | // PWM 66 | 67 | #define PWM_MODE_MS 0 68 | #define PWM_MODE_BAL 1 69 | 70 | // Interrupt levels 71 | 72 | #define INT_EDGE_SETUP 0 73 | #define INT_EDGE_FALLING 1 74 | #define INT_EDGE_RISING 2 75 | #define INT_EDGE_BOTH 3 76 | 77 | // Pi model types and version numbers 78 | // Intended for the GPIO program Use at your own risk. 79 | 80 | #define PI_MODEL_A 0 81 | #define PI_MODEL_B 1 82 | #define PI_MODEL_AP 2 83 | #define PI_MODEL_BP 3 84 | #define PI_MODEL_2 4 85 | #define PI_ALPHA 5 86 | #define PI_MODEL_CM 6 87 | #define PI_MODEL_07 7 88 | #define PI_MODEL_3 8 89 | #define PI_MODEL_ZERO 9 90 | 91 | #define PI_VERSION_1 0 92 | #define PI_VERSION_1_1 1 93 | #define PI_VERSION_1_2 2 94 | #define PI_VERSION_2 3 95 | 96 | #define PI_MAKER_SONY 0 97 | #define PI_MAKER_EGOMAN 1 98 | #define PI_MAKER_MBEST 2 99 | #define PI_MAKER_UNKNOWN 3 100 | 101 | extern const char *piModelNames [16] ; 102 | extern const char *piRevisionNames [16] ; 103 | extern const char *piMakerNames [16] ; 104 | extern const int piMemorySize [ 8] ; 105 | 106 | 107 | // Intended for the GPIO program Use at your own risk. 108 | 109 | // Threads 110 | 111 | #define PI_THREAD(X) void *X (void *dummy) 112 | 113 | // Failure modes 114 | 115 | #define WPI_FATAL (1==1) 116 | #define WPI_ALMOST (1==2) 117 | 118 | 119 | // wiringPiNodeStruct: 120 | // This describes additional device nodes in the extended wiringPi 121 | // 2.0 scheme of things. 122 | // It's a simple linked list for now, but will hopefully migrate to 123 | // a binary tree for efficiency reasons - but then again, the chances 124 | // of more than 1 or 2 devices being added are fairly slim, so who 125 | // knows.... 126 | 127 | struct wiringPiNodeStruct 128 | { 129 | int pinBase ; 130 | int pinMax ; 131 | 132 | int fd ; // Node specific 133 | unsigned int data0 ; // ditto 134 | unsigned int data1 ; // ditto 135 | unsigned int data2 ; // ditto 136 | unsigned int data3 ; // ditto 137 | 138 | void (*pinMode) (struct wiringPiNodeStruct *node, int pin, int mode) ; 139 | void (*pullUpDnControl) (struct wiringPiNodeStruct *node, int pin, int mode) ; 140 | int (*digitalRead) (struct wiringPiNodeStruct *node, int pin) ; 141 | void (*digitalWrite) (struct wiringPiNodeStruct *node, int pin, int value) ; 142 | void (*pwmWrite) (struct wiringPiNodeStruct *node, int pin, int value) ; 143 | int (*analogRead) (struct wiringPiNodeStruct *node, int pin) ; 144 | void (*analogWrite) (struct wiringPiNodeStruct *node, int pin, int value) ; 145 | 146 | struct wiringPiNodeStruct *next ; 147 | } ; 148 | 149 | extern struct wiringPiNodeStruct *wiringPiNodes ; 150 | 151 | 152 | // Function prototypes 153 | // c++ wrappers thanks to a comment by Nick Lott 154 | // (and others on the Raspberry Pi forums) 155 | 156 | #ifdef __cplusplus 157 | extern "C" { 158 | #endif 159 | 160 | // Data 161 | 162 | // Internal 163 | 164 | extern int wiringPiFailure (int fatal, const char *message, ...) ; 165 | 166 | // Core wiringPi functions 167 | 168 | extern struct wiringPiNodeStruct *wiringPiFindNode (int pin) ; 169 | extern struct wiringPiNodeStruct *wiringPiNewNode (int pinBase, int numPins) ; 170 | 171 | extern int wiringPiSetup (void) ; 172 | extern int wiringPiSetupSys (void) ; 173 | extern int wiringPiSetupGpio (void) ; 174 | extern int wiringPiSetupPhys (void) ; 175 | 176 | extern void pinModeAlt (int pin, int mode) ; 177 | extern void pinMode (int pin, int mode) ; 178 | extern void pullUpDnControl (int pin, int pud) ; 179 | extern int digitalRead (int pin) ; 180 | extern void digitalWrite (int pin, int value) ; 181 | extern void pwmWrite (int pin, int value) ; 182 | extern int analogRead (int pin) ; 183 | extern void analogWrite (int pin, int value) ; 184 | 185 | // PiFace specifics 186 | // (Deprecated) 187 | 188 | extern int wiringPiSetupPiFace (void) ; 189 | extern int wiringPiSetupPiFaceForGpioProg (void) ; // Don't use this - for gpio program only 190 | 191 | // On-Board Raspberry Pi hardware specific stuff 192 | 193 | extern int piBoardRev (void) ; 194 | extern void piBoardId (int *model, int *rev, int *mem, int *maker, int *overVolted) ; 195 | extern int wpiPinToGpio (int wpiPin) ; 196 | extern int physPinToGpio (int physPin) ; 197 | extern void setPadDrive (int group, int value) ; 198 | extern int getAlt (int pin) ; 199 | extern void pwmToneWrite (int pin, int freq) ; 200 | extern void digitalWriteByte (int value) ; 201 | extern unsigned int digitalReadByte (void) ; 202 | extern void pwmSetMode (int mode) ; 203 | extern void pwmSetRange (unsigned int range) ; 204 | extern void pwmSetClock (int divisor) ; 205 | extern void gpioClockSet (int pin, int freq) ; 206 | 207 | // Interrupts 208 | // (Also Pi hardware specific) 209 | 210 | extern int waitForInterrupt (int pin, int mS) ; 211 | extern int wiringPiISR (int pin, int mode, void (*function)(void)) ; 212 | 213 | // Threads 214 | 215 | extern int piThreadCreate (void *(*fn)(void *)) ; 216 | extern void piLock (int key) ; 217 | extern void piUnlock (int key) ; 218 | 219 | // Schedulling priority 220 | 221 | extern int piHiPri (const int pri) ; 222 | 223 | // Extras from arduino land 224 | 225 | extern void delay (unsigned int howLong) ; 226 | extern void delayMicroseconds (unsigned int howLong) ; 227 | extern unsigned int millis (void) ; 228 | extern unsigned int micros (void) ; 229 | 230 | #ifdef __cplusplus 231 | } 232 | #endif 233 | 234 | #endif 235 | -------------------------------------------------------------------------------- /cc1101.c: -------------------------------------------------------------------------------- 1 | /* the radian_trx SW shall not be distributed nor used for commercial product*/ 2 | /* it is exposed just to demonstrate CC1101 capability to reader water meter indexes */ 3 | /* there is no Warranty on radian_trx SW */ 4 | 5 | uint8_t RF_config_u8=0xFF; 6 | uint8_t RF_Test_u8=0; 7 | // +10, +7, 5, 0, -10, -15, -20, -30 8 | uint8_t PA_Test[] = {0xC0,0xC8,0x85,0x60,0x34,0x1D,0x0E,0x12,}; 9 | 10 | uint8_t PA[] = {0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,}; 11 | 12 | uint8_t CC1101_status_state=0; 13 | uint8_t CC1101_status_FIFO_FreeByte=0; 14 | uint8_t CC1101_status_FIFO_ReadByte=0; 15 | uint8_t debug_out=0; 16 | 17 | struct tmeter_data { 18 | int liters; 19 | int reads_counter; // how many times the meter has been readed 20 | int battery_left; //in months 21 | int time_start; // like 8am 22 | int time_end; // like 4pm 23 | }; 24 | 25 | 26 | 27 | 28 | #define TX_LOOP_OUT 300 29 | /*---------------------------[CC1100 - R/W offsets]------------------------------*/ 30 | #define WRITE_SINGLE_BYTE 0x00 31 | #define WRITE_BURST 0x40 32 | #define READ_SINGLE_BYTE 0x80 33 | #define READ_BURST 0xC0 34 | 35 | /*-------------------------[CC1100 - config register]----------------------------*/ 36 | #define IOCFG2 0x00 // GDO2 output pin configuration 37 | #define IOCFG1 0x01 // GDO1 output pin configuration 38 | #define IOCFG0 0x02 // GDO0 output pin configuration 39 | #define FIFOTHR 0x03 // RX FIFO and TX FIFO thresholds 40 | #define SYNC1 0x04 // Sync word, high byte 41 | #define SYNC0 0x05 // Sync word, low byte 42 | #define PKTLEN 0x06 // Packet length 43 | #define PKTCTRL1 0x07 // Packet automation control 44 | #define PKTCTRL0 0x08 // Packet automation control 45 | #define ADDRR 0x09 // Device address 46 | #define CHANNR 0x0A // Channel number 47 | #define FSCTRL1 0x0B // Frequency synthesizer control 48 | #define FSCTRL0 0x0C // Frequency synthesizer control 49 | #define FREQ2 0x0D // Frequency control word, high byte 50 | #define FREQ1 0x0E // Frequency control word, middle byte 51 | #define FREQ0 0x0F // Frequency control word, low byte 52 | 53 | #define MDMCFG4 0x10 // Modem configuration 54 | #define MDMCFG3 0x11 // Modem configuration 55 | #define MDMCFG2 0x12 // Modem configuration 56 | #define MDMCFG1 0x13 // Modem configuration 57 | #define MDMCFG0 0x14 // Modem configuration 58 | #define DEVIATN 0x15 // Modem deviation setting 59 | #define MCSM2 0x16 // Main Radio Cntrl State Machine config 60 | #define MCSM1 0x17 // Main Radio Cntrl State Machine config 61 | #define MCSM0 0x18 // Main Radio Cntrl State Machine config 62 | #define FOCCFG 0x19 // Frequency Offset Compensation config 63 | #define BSCFG 0x1A // Bit Synchronization configuration 64 | #define AGCCTRL2 0x1B // AGC control 65 | #define AGCCTRL1 0x1C // AGC control 66 | #define AGCCTRL0 0x1D // AGC control 67 | #define WOREVT1 0x1E // High byte Event 0 timeout 68 | #define WOREVT0 0x1F // Low byte Event 0 timeout 69 | 70 | #define WORCTRL 0x20 // Wake On Radio control 71 | #define FREND1 0x21 // Front end RX configuration 72 | #define FREND0 0x22 // Front end TX configuration 73 | #define FSCAL3 0x23 // Frequency synthesizer calibration 74 | #define FSCAL2 0x24 // Frequency synthesizer calibration 75 | #define FSCAL1 0x25 // Frequency synthesizer calibration 76 | #define FSCAL0 0x26 // Frequency synthesizer calibration 77 | #define RCCTRL1 0x27 // RC oscillator configuration 78 | #define RCCTRL0 0x28 // RC oscillator configuration 79 | #define FSTEST 0x29 // Frequency synthesizer cal control 80 | #define PTEST 0x2A // Production test 81 | #define AGCTEST 0x2B // AGC test 82 | #define TEST2 0x2C // Various test settings 83 | #define TEST1 0x2D // Various test settings 84 | #define TEST0 0x2E // Various test settings 85 | /*----------------------------[END config register]------------------------------*/ 86 | //------------------[write register]-------------------------------- 87 | uint8_t halRfWriteReg(uint8_t reg_addr, uint8_t value) 88 | { 89 | uint8_t tbuf[2] = {0}; 90 | tbuf[0] = reg_addr | WRITE_SINGLE_BYTE; 91 | tbuf[1] = value; 92 | uint8_t len = 2; 93 | wiringPiSPIDataRW (0, tbuf, len) ; 94 | CC1101_status_FIFO_FreeByte=tbuf[1]&0x0F; 95 | CC1101_status_state=(tbuf[0]>>4)&0x0F; 96 | 97 | return TRUE; 98 | } 99 | 100 | /*-------------------------[CC1100 - status register]----------------------------*/ 101 | /* 0x3? is replace by 0xF? because for status register burst bit shall be set */ 102 | #define PARTNUM_ADDR 0xF0 // Part number 103 | #define VERSION_ADDR 0xF1 // Current version number 104 | #define FREQEST_ADDR 0xF2 // Frequency offset estimate 105 | #define LQI_ADDR 0xF3 // Demodulator estimate for link quality 106 | #define RSSI_ADDR 0xF4 // Received signal strength indication 107 | #define MARCSTATE_ADDR 0xF5 // Control state machine state 108 | #define WORTIME1_ADDR 0xF6 // High byte of WOR timer 109 | #define WORTIME0_ADDR 0xF7 // Low byte of WOR timer 110 | #define PKTSTATUS_ADDR 0xF8 // Current GDOx status and packet status 111 | #define VCO_VC_DAC_ADDR 0xF9 // Current setting from PLL cal module 112 | #define TXBYTES_ADDR 0xFA // Underflow and # of bytes in TXFIFO 113 | #define RXBYTES_ADDR 0xFB // Overflow and # of bytes in RXFIFO 114 | //----------------------------[END status register]------------------------------- 115 | #define RXBYTES_MASK 0x7F // Mask "# of bytes" field in _RXBYTES 116 | 117 | uint8_t halRfReadReg(uint8_t spi_instr) 118 | { 119 | uint8_t value; 120 | uint8_t rbuf[2] = {0}; 121 | uint8_t len = 2; 122 | 123 | //rbuf[0] = spi_instr | READ_SINGLE_BYTE; 124 | //rbuf[1] = 0; 125 | //wiringPiSPIDataRW (0, rbuf, len) ; 126 | //errata Section 3. You have to make sure that you read the same value of the register twice in a row before you evaluate it otherwise you might read a value that is a mix of 2 state values. 127 | rbuf[0] = spi_instr | READ_SINGLE_BYTE; 128 | rbuf[1] = 0; 129 | wiringPiSPIDataRW (0, rbuf, len) ; 130 | CC1101_status_FIFO_ReadByte=rbuf[0]&0x0F; 131 | CC1101_status_state=(rbuf[0]>>4)&0x0F; 132 | value = rbuf[1]; 133 | return value; 134 | } 135 | 136 | #define PATABLE_ADDR 0x3E // Pa Table Adress 137 | #define TX_FIFO_ADDR 0x3F 138 | #define RX_FIFO_ADDR 0xBF 139 | void SPIReadBurstReg(uint8_t spi_instr, uint8_t *pArr, uint8_t len) 140 | { 141 | uint8_t rbuf[len + 1]; 142 | uint8_t i=0; 143 | memset(rbuf, 0, len + 1); 144 | rbuf[0] = spi_instr | READ_BURST; 145 | wiringPiSPIDataRW (0, rbuf, len + 1) ; 146 | for (i=0; i>4)&0x0F; 153 | } 154 | 155 | void SPIWriteBurstReg(uint8_t spi_instr, uint8_t *pArr, uint8_t len) 156 | { 157 | uint8_t tbuf[len + 1]; 158 | uint8_t i=0; 159 | tbuf[0] = spi_instr | WRITE_BURST; 160 | for (i=0; i>4)&0x0F; 168 | } 169 | 170 | /*---------------------------[CC1100-command strobes]----------------------------*/ 171 | #define SRES 0x30 // Reset chip 172 | #define SFSTXON 0x31 // Enable/calibrate freq synthesizer 173 | #define SXOFF 0x32 // Turn off crystal oscillator. 174 | #define SCAL 0x33 // Calibrate freq synthesizer & disable 175 | #define SRX 0x34 // Enable RX. 176 | #define STX 0x35 // Enable TX. 177 | #define SIDLE 0x36 // Exit RX / TX 178 | #define SAFC 0x37 // AFC adjustment of freq synthesizer 179 | #define SWOR 0x38 // Start automatic RX polling sequence 180 | #define SPWD 0x39 // Enter pwr down mode when CSn goes hi 181 | #define SFRX 0x3A // Flush the RX FIFO buffer. 182 | #define SFTX 0x3B // Flush the TX FIFO buffer. 183 | #define SWORRST 0x3C // Reset real time clock. 184 | #define SNOP 0x3D // No operation. 185 | /*----------------------------[END command strobes]------------------------------*/ 186 | void CC1101_CMD(uint8_t spi_instr) 187 | { 188 | uint8_t tbuf[1] = {0}; 189 | tbuf[0] = spi_instr | WRITE_SINGLE_BYTE; 190 | //echo_debug(debug_out,"SPI_data: 0x%02X\n", tbuf[0]); 191 | wiringPiSPIDataRW (0, tbuf, 1) ; 192 | CC1101_status_state=(tbuf[0]>>4)&0x0F; 193 | } 194 | 195 | 196 | 197 | 198 | void echo_cc1101_version(void); 199 | 200 | //---------------[CC1100 reset functions "200us"]----------------------- 201 | void cc1101_reset(void) // reset defined in cc1100 datasheet §19.1 202 | {// CS should be high from gpio load spi command 203 | /* commented car ne fonctionne pas avec wiringPi a voir avec BCM2835 .. 204 | digitalWrite(cc1101_CSn, 0); // CS low 205 | pinMode (cc1101_CSn, OUTPUT); 206 | delayMicroseconds(30); 207 | digitalWrite(cc1101_CSn, 1); // CS high 208 | delayMicroseconds(100); // min 40us 209 | //Pull CSn low and wait for SO to go low 210 | digitalWrite(cc1101_CSn, 0); // CS low 211 | delayMicroseconds(30); 212 | */ 213 | 214 | CC1101_CMD(SRES); //GDO0 pin should output a clock signal with a frequency of CLK_XOSC/192. 215 | //periode 1/7.417us= 134.8254k * 192 --> 25.886477M 216 | //10 periode 73.83 = 135.4463k *192 --> 26Mhz 217 | delay(1); //1ms for getting chip to reset properly 218 | 219 | CC1101_CMD(SFTX); //flush the TX_fifo content -> a must for interrupt handling 220 | CC1101_CMD(SFRX); //flush the RX_fifo content -> a must for interrupt handling 221 | 222 | } 223 | 224 | void cc1101_configureRF_0(void) 225 | { 226 | RF_config_u8=0; 227 | // 228 | // Rf settings for CC1101 229 | // 230 | halRfWriteReg(IOCFG2,0x0D); //GDO2 Output Pin Configuration : Serial Data Output 231 | halRfWriteReg(IOCFG0,0x06); //GDO0 Output Pin Configuration : Asserts when sync word has been sent / received, and de-asserts at the end of the packet. 232 | halRfWriteReg(FIFOTHR,0x47); //0x4? adc with bandwith< 325khz 233 | halRfWriteReg(SYNC1,0x55); //01010101 234 | halRfWriteReg(SYNC0,0x00); //00000000 235 | 236 | //halRfWriteReg(PKTCTRL1,0x80);//Preamble quality estimator threshold=16 ; APPEND_STATUS=0; no addr check 237 | halRfWriteReg(PKTCTRL1,0x00);//Preamble quality estimator threshold=0 ; APPEND_STATUS=0; no addr check 238 | halRfWriteReg(PKTCTRL0,0x00);//fix length , no CRC 239 | halRfWriteReg(FSCTRL1,0x08); //Frequency Synthesizer Control 240 | 241 | halRfWriteReg(FREQ2,0x10); //Frequency Control Word, High Byte Base frequency = 433.82 242 | halRfWriteReg(FREQ1,0xAF); //Frequency Control Word, Middle Byte 243 | halRfWriteReg(FREQ0,0x75); //Frequency Control Word, Low Byte la fréquence reel etait 433.790 (centre) 244 | //halRfWriteReg(FREQ0,0xC1); //Frequency Control Word, Low Byte rasmobo 814 824 (KO) ; minepi 810 820 (OK) 245 | //halRfWriteReg(FREQ0,0x9B); //rasmobo 808.5 -16 pour -38 246 | //halRfWriteReg(FREQ0,0xB7); //rasmobo 810 819.5 OK 247 | //mon compteur F1 : 433809500 F2 : 433820000 deviation +-5.25khz depuis 433.81475M 248 | 249 | halRfWriteReg(MDMCFG4,0xF6); //Modem Configuration RX filter BW = 58Khz 250 | halRfWriteReg(MDMCFG3,0x83); //Modem Configuration 26M*((256+83h)*2^6)/2^28 = 2.4kbps 251 | halRfWriteReg(MDMCFG2,0x02); //Modem Configuration 2-FSK; no Manchester ; 16/16 sync word bits detected 252 | halRfWriteReg(MDMCFG1,0x00); //Modem Configuration num preamble 2=>0 , Channel spacing_exp 253 | halRfWriteReg(MDMCFG0,0x00); /*# MDMCFG0 Channel spacing = 25Khz*/ 254 | halRfWriteReg(DEVIATN,0x15); //5.157471khz 255 | //halRfWriteReg(MCSM1,0x0F); //CCA always ; default mode RX 256 | halRfWriteReg(MCSM1,0x00); //CCA always ; default mode IDLE 257 | halRfWriteReg(MCSM0,0x18); //Main Radio Control State Machine Configuration 258 | halRfWriteReg(FOCCFG,0x1D); //Frequency Offset Compensation Configuration 259 | halRfWriteReg(BSCFG,0x1C); //Bit Synchronization Configuration 260 | halRfWriteReg(AGCCTRL2,0xC7);//AGC Control 261 | halRfWriteReg(AGCCTRL1,0x00);//AGC Control 262 | halRfWriteReg(AGCCTRL0,0xB2);//AGC Control 263 | halRfWriteReg(WORCTRL,0xFB); //Wake On Radio Control 264 | halRfWriteReg(FREND1,0xB6); //Front End RX Configuration 265 | halRfWriteReg(FSCAL3,0xE9); //Frequency Synthesizer Calibration 266 | halRfWriteReg(FSCAL2,0x2A); //Frequency Synthesizer Calibration 267 | halRfWriteReg(FSCAL1,0x00); //Frequency Synthesizer Calibration 268 | halRfWriteReg(FSCAL0,0x1F); //Frequency Synthesizer Calibration 269 | halRfWriteReg(TEST2,0x81); //Various Test Settings link to adc retention 270 | halRfWriteReg(TEST1,0x35); //Various Test Settings link to adc retention 271 | halRfWriteReg(TEST0,0x09); //Various Test Settings link to adc retention 272 | 273 | SPIWriteBurstReg(PATABLE_ADDR, PA, 8); 274 | } 275 | 276 | void cc1101_init(void) 277 | { 278 | // to use SPI pi@MinePi ~ $ gpio unload spi then gpio load spi 279 | // sinon pas de MOSI ni pas de CSn , buffer de 4kB 280 | if ((wiringPiSPISetup (0, 100000)) < 0) // channel 0 100khz min 500khz ds la doc ? 281 | { 282 | //fprintf (stderr, "Can't open the SPI bus: %s\n", strerror (errno)) ; 283 | printf ("Can't open the SPI bus"); 284 | exit (EXIT_FAILURE) ; 285 | } 286 | cc1101_reset(); 287 | delay(1); //1ms 288 | cc1101_configureRF_0(); 289 | } 290 | 291 | int8_t cc1100_rssi_convert2dbm(uint8_t Rssi_dec) 292 | { 293 | int8_t rssi_dbm; 294 | if(Rssi_dec >= 128) 295 | { 296 | rssi_dbm=((Rssi_dec-256)/2)-74; //rssi_offset via datasheet 297 | } 298 | else 299 | { 300 | rssi_dbm=((Rssi_dec)/2)-74; 301 | } 302 | return rssi_dbm; 303 | } 304 | 305 | 306 | /* configure cc1101 in receive mode */ 307 | void cc1101_rec_mode(void) 308 | { 309 | uint8_t marcstate; 310 | CC1101_CMD(SIDLE); //sets to idle first. must be in 311 | CC1101_CMD(SRX); //writes receive strobe (receive mode) 312 | marcstate = 0xFF; //set unknown/dummy state value 313 | while((marcstate != 0x0D) && (marcstate != 0x0E) && (marcstate != 0x0F)) //0x0D = RX 314 | { 315 | marcstate = halRfReadReg(MARCSTATE_ADDR); //read out state of cc1100 to be sure in RX 316 | } 317 | } 318 | 319 | void echo_cc1101_version(void) 320 | { 321 | echo_debug(debug_out,"CC1101 Partnumber: 0x%02X\r\n", halRfReadReg(PARTNUM_ADDR)); 322 | echo_debug(debug_out,"CC1101 Version != 00 or 0xFF : 0x%02X\r\n", halRfReadReg(VERSION_ADDR)); // != 00 or 0xFF 323 | } 324 | 325 | 326 | #define CFG_REGISTER 0x2F //47 registers 327 | void show_cc1101_registers_settings(void) 328 | { 329 | uint8_t config_reg_verify[CFG_REGISTER],Patable_verify[8]; 330 | uint8_t i ; 331 | 332 | SPIReadBurstReg(0,config_reg_verify,CFG_REGISTER); //reads all 47 config register from cc1100 "359.63us" 333 | SPIReadBurstReg(PATABLE_ADDR,Patable_verify,8); //reads output power settings from cc1100 "104us" 334 | 335 | echo_debug(debug_out,"Config Register in hex:\r\n"); 336 | echo_debug(debug_out," 0 1 2 3 4 5 6 7 8 9 A B C D E F\r\n"); 337 | for(i = 0 ; i < CFG_REGISTER; i++) //showes rx_buffer for debug 338 | { 339 | echo_debug(debug_out,"%02X ", config_reg_verify[i]); 340 | 341 | if(i==15 || i==31 || i==47 || i==63) //just for beautiful output style 342 | { 343 | echo_debug(debug_out,"\r\n"); 344 | } 345 | } 346 | echo_debug(debug_out,"\r\n"); 347 | echo_debug(debug_out,"PaTable:\r\n"); 348 | 349 | for(i = 0 ; i < 8; i++) //showes rx_buffer for debug 350 | { 351 | echo_debug(debug_out,"%02X ", Patable_verify[i]); 352 | } 353 | echo_debug(debug_out,"\r\n"); 354 | 355 | } 356 | 357 | uint8_t is_look_like_radian_frame(uint8_t* buffer, size_t len) 358 | { 359 | int i,ret; 360 | ret=FALSE; 361 | for (i=0 ; i= 30) 437 | { 438 | //echo_debug(1,"\r\n%u/%u/20%u %u:%u:%u ",decoded_buffer[24],decoded_buffer[25],decoded_buffer[26],decoded_buffer[28],decoded_buffer[29],decoded_buffer[30]); 439 | //echo_debug(1,"%u litres ",decoded_buffer[18]+decoded_buffer[19]*256 + decoded_buffer[20]*65536 + decoded_buffer[21]*16777216); 440 | 441 | data.liters = decoded_buffer[18]+decoded_buffer[19]*256 + decoded_buffer[20]*65536 + decoded_buffer[21]*16777216; 442 | } 443 | if (size >= 48) 444 | { 445 | //echo_debug(1,"Num %u %u Mois %uh-%uh ",decoded_buffer[48], decoded_buffer[31],decoded_buffer[44],decoded_buffer[45]); 446 | data.reads_counter = decoded_buffer[48]; 447 | data.battery_left = decoded_buffer[31]; 448 | data.time_start = decoded_buffer[44]; 449 | data.time_end = decoded_buffer[45]; 450 | } 451 | 452 | return data; 453 | } 454 | 455 | // Remove the start- and stop-bits in the bitstream , also decode oversampled bit 0xF0 => 1,0 456 | // 01234567 ###01234 567###01 234567## #0123456 (# -> Start/Stop bit) 457 | // is decoded to: 458 | // 76543210 76543210 76543210 76543210 459 | uint8_t decode_4bitpbit_serial(uint8_t *rxBuffer, int l_total_byte, uint8_t* decoded_buffer ) 460 | { 461 | uint16_t i,j,k; 462 | uint8_t bit_cnt=0; 463 | int8_t bit_cnt_flush_S8=0; 464 | uint8_t bit_pol=0; 465 | uint8_t dest_bit_cnt=0; 466 | uint8_t dest_byte_cnt=0; 467 | uint8_t current_Rx_Byte; 468 | //show_in_hex(rxBuffer,l_total_byte); 469 | /*set 1st bit polarity*/ 470 | bit_pol=(rxBuffer[0]&0x80); //initialize with 1st bit state 471 | 472 | for (i=0;i> 1; 495 | decoded_buffer[dest_byte_cnt] |= bit_pol; 496 | } 497 | dest_bit_cnt ++; 498 | //if ((dest_bit_cnt ==9) && (!bit_pol)){ echo_debug(debug_out,"stop bit error9"); return dest_byte_cnt;} 499 | if ((dest_bit_cnt ==10) && (!bit_pol)){ echo_debug(debug_out,"stop bit error10"); return dest_byte_cnt;} 500 | if ((dest_bit_cnt >= 11) && (!bit_pol)) //start bit 501 | { 502 | dest_bit_cnt=0; 503 | echo_debug(debug_out," dec[%i]=0x%02X \r\n",dest_byte_cnt,decoded_buffer[dest_byte_cnt]); 504 | dest_byte_cnt++; 505 | } 506 | } 507 | bit_pol = current_Rx_Byte&0x80; 508 | bit_cnt = 1; 509 | } 510 | current_Rx_Byte=current_Rx_Byte<<1; 511 | }//scan TX_bit 512 | }//scan TX_byte 513 | return dest_byte_cnt; 514 | } 515 | 516 | 517 | /* 518 | search for 0101010101010000b sync pattern then change data rate in order to get 4bit per bit 519 | search for end of sync pattern with start bit 1111111111110000b 520 | */ 521 | int receive_radian_frame(int size_byte,int rx_tmo_ms ,uint8_t*rxBuffer,int rxBuffer_size) 522 | { 523 | uint8_t l_byte_in_rx=0; 524 | uint16_t l_total_byte=0; 525 | uint16_t l_radian_frame_size_byte = ((size_byte*(8+3))/8)+1; 526 | int l_tmo=0; 527 | uint8_t l_Rssi_dbm,l_lqi,l_freq_est; 528 | 529 | if (l_radian_frame_size_byte*4 > rxBuffer_size) {echo_debug(debug_out,"buffer too small\r\n");return 0;} 530 | CC1101_CMD(SFRX); 531 | halRfWriteReg(MCSM1,0x0F); //CCA always ; default mode RX 532 | halRfWriteReg(MDMCFG2,0x02); //Modem Configuration 2-FSK; no Manchester ; 16/16 sync word bits detected 533 | /* configure to receive beginning of sync pattern */ 534 | halRfWriteReg(SYNC1,0x55); //01010101 535 | halRfWriteReg(SYNC0,0x50); //01010000 536 | halRfWriteReg(MDMCFG4,0xF6); //Modem Configuration RX filter BW = 58Khz 537 | halRfWriteReg(MDMCFG3,0x83); //Modem Configuration 26M*((256+83h)*2^6)/2^28 = 2.4kbps 538 | halRfWriteReg(PKTLEN,1); // just one byte of synch pattern 539 | cc1101_rec_mode(); 540 | l_byte_in_rx =0; 541 | while ((digitalRead(GDO0) == FALSE)&&(l_tmo 0)&&(l_total_byte < (l_radian_frame_size_byte*4))&&(l_tmo682b , 7ms pour 18b->99byte 590 | /*restore default reg */ 591 | halRfWriteReg(MDMCFG4,0xF6); //Modem Configuration RX filter BW = 58Khz 592 | halRfWriteReg(MDMCFG3,0x83); //Modem Configuration 26M*((256+83h)*2^6)/2^28 = 2.4kbps 593 | halRfWriteReg(PKTCTRL0,0x00); //fix packet len 594 | halRfWriteReg(PKTLEN,38); 595 | halRfWriteReg(SYNC1,0x55); //01010101 596 | halRfWriteReg(SYNC0,0x00); //00000000 597 | return l_total_byte; 598 | } 599 | 600 | /* 601 | scenario_releve 602 | 2s de WUP 603 | 130ms : trame interrogation de l'outils de reléve ______------|...............----- 604 | 43ms de bruit 605 | 34ms 0101...01 606 | 14.25ms 000...000 607 | 14ms 1111...11111 608 | 83.5ms de data acquitement 609 | 50ms de 111111 610 | 34ms 0101...01 611 | 14.25ms 000...000 612 | 14ms 1111...11111 613 | 582ms de data avec l'index 614 | 615 | l'outils de reléve doit normalement acquité 616 | */ 617 | struct tmeter_data get_meter_data(void) 618 | { 619 | struct tmeter_data sdata; 620 | uint8_t marcstate = 0xFF; 621 | uint8_t wupbuffer[] ={0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55}; 622 | uint8_t wup2send =77; 623 | uint16_t tmo=0; 624 | uint8_t rxBuffer[1000]; 625 | int rxBuffer_size; 626 | uint8_t meter_data[200]; 627 | uint8_t meter_data_size=0; 628 | 629 | uint8_t txbuffer[100]; 630 | Make_Radian_Master_req(txbuffer, METER_YEAR , METER_SERIAL ); 631 | 632 | halRfWriteReg(MDMCFG2,0x00); //clear MDMCFG2 to do not send preamble and sync 633 | halRfWriteReg(PKTCTRL0,0x02); //infinite packet len 634 | SPIWriteBurstReg(TX_FIFO_ADDR,wupbuffer,8); wup2send--; 635 | CC1101_CMD(STX); //sends the data store into transmit buffer over the air 636 | delay(10); //to give time for calibration 637 | marcstate = halRfReadReg(MARCSTATE_ADDR); //to update CC1101_status_state 638 | echo_debug(debug_out,"MARCSTATE : raw:0x%02X 0x%02X free_byte:0x%02X sts:0x%02X sending 2s WUP...\r\n",marcstate,marcstate&0x1F ,CC1101_status_FIFO_FreeByte,CC1101_status_state); 639 | while((CC1101_status_state == 0x02) && (tmo