├── 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 | 
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 | 
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