4 次代码提交 edbe1f280f ... bdec962547

作者 SHA1 备注 提交日期
  Thomas Chef bdec962547 Added tsl2561 modules2 7 月之前
  Thomas Chef ce5b57346c DS18B20 works. Start with 2561 7 月之前
  Thomas Chef c18223a23e Added most of files needed 7 月之前
  Thomas Chef 9f4b9f3b50 Added transceiver files 7 月之前

+ 1 - 0
.gitignore

@@ -71,6 +71,7 @@ wifi_manager/doc/
 
 # Visual Studio Code
 .vscode/
+-.vscode/c_cpp_properties.json
 .DS_Store
 
 #Others ?

+ 6 - 0
.gitmodules

@@ -4,3 +4,9 @@
 [submodule "components/esp32-owb"]
 	path = components/esp32-owb
 	url = https://github.com/DavidAntliff/esp32-owb.git
+[submodule "components/esp32-smbus"]
+	path = components/esp32-smbus
+	url = https://github.com/DavidAntliff/esp32-smbus.git
+[submodule "components/esp32-tsl2561"]
+	path = components/esp32-tsl2561
+	url = https://github.com/DavidAntliff/esp32-tsl2561.git

+ 1 - 0
components/esp32-smbus

@@ -0,0 +1 @@
+Subproject commit 1bca026c4fe8d28f9cb76da30da05e8a70a8231f

+ 1 - 0
components/esp32-tsl2561

@@ -0,0 +1 @@
+Subproject commit 55185696cfbd9eb91da9cb262b277d4c29bd08ee

+ 7 - 2
main/CMakeLists.txt

@@ -1,5 +1,10 @@
 
-set(COMPONENT_SRCDIRS ".")
-set(COMPONENT_ADD_INCLUDEDIRS ".")
+set(COMPONENT_SRCDIRS "." "./Sensors")
+set(COMPONENT_ADD_INCLUDEDIRS "." "./Sensors")
+
+
+
+
+
 
 register_component()

+ 151 - 0
main/Sensors/ClasOSensor.c

@@ -0,0 +1,151 @@
+#include "ClasOSensor.h"
+#include <stdint.h>
+#include <stdio.h>
+#include "esp_log.h"
+#include "../rxTimer.h"
+#include "config.h"
+
+#ifdef TRANCEIVER_ENABLED
+
+enum
+{
+    UNKNOWN,
+    T0,
+    T1,
+    T2,
+    T3,
+    TEMP1_OK,
+    DONE
+};
+
+static uint8_t rx_state = UNKNOWN;
+
+static uint64_t sensor_data;
+static uint32_t rx_numBits;
+
+
+void ClasO_ResetDecoder()
+{
+    sensor_data = 0;
+    rx_numBits = 0;
+    rx_state = UNKNOWN;
+}
+
+static void addBit(uint8_t value)
+{
+
+    rx_numBits++;
+    sensor_data = (sensor_data << 1) + (value & 0x01);
+
+    rx_state = TEMP1_OK;
+}
+
+#define START_PULSE_MIN (3880-200)
+#define START_PULSE_MAX (4010+200)
+
+#define T0_PULSE_MIN (380-100)
+#define T0_PULSE_MAX (520+100)
+
+#define SHORT_PULSE_MIN (890-100)
+#define SHORT_PULSE_MAX (990+100)
+
+#define LONG_PULSE_MIN (1880-150)
+#define LONG_PULSE_MAX (1980+150)
+
+
+static int32_t rx_decode(uint32_t width)
+{
+    switch (rx_state) {
+        case UNKNOWN: // Start of frame
+            if ( START_PULSE_MIN <= width && width <= START_PULSE_MAX )
+            {
+                rx_state = T0;
+            }
+            else
+            {
+                return -1; // error, reset
+            }
+            break;
+
+        case T0: // First half of pulse : HIGH around 230us
+
+            if (rx_numBits == 32)
+            { // end of frame
+                rx_state = DONE;
+                sensor_data = (sensor_data >> 8); // Mask away some bits at the end
+                return 1;
+            }
+            else if( T0_PULSE_MIN <= width && width <= T0_PULSE_MAX )
+            {
+                rx_state = T1;
+            }
+            else
+            {
+                if (rx_numBits == 0 && START_PULSE_MIN <= width && width <= START_PULSE_MAX )
+                {
+                    rx_state = T0;
+                }
+                else
+                {
+                    return -1; // error, reset
+                }
+            }
+            break;
+
+        case T1:
+            if( SHORT_PULSE_MIN <= width && width <= SHORT_PULSE_MAX )
+            {
+                addBit(0);
+            }
+            else if( LONG_PULSE_MIN <= width && width <= LONG_PULSE_MAX )
+            {
+                addBit(1);
+            }
+            else
+            {
+                return -1; // error, reset
+            }
+            rx_state = T0;
+            break;
+    }
+    return 0;
+}
+
+int64_t nextPulseClasOSensor(uint32_t width)
+{
+    static int64_t previous_data = 0;
+    static uint32_t old_time=0;
+    static uint32_t now;
+    int64_t retVal = -1;
+
+    if (width > 0)
+    {
+        if (rx_state != DONE)
+        {
+            switch (rx_decode(width))
+            {
+            case -1:
+                ClasO_ResetDecoder();
+                break;
+            case 1:
+                rx_state = DONE;
+                break;
+            }
+        }
+    }
+    if (rx_state == DONE) {
+        now = millis();
+
+        if( sensor_data != previous_data || (now > (old_time+1000)) ) {
+            previous_data = sensor_data;
+            retVal = sensor_data;
+            
+        }
+        old_time = now;
+        ClasO_ResetDecoder();
+    }
+    
+    return retVal;
+}
+
+#endif

+ 11 - 0
main/Sensors/ClasOSensor.h

@@ -0,0 +1,11 @@
+#ifndef __CLASO__
+#define __CLASO__
+
+#include <stdbool.h>
+#include <stdint.h>
+
+void ClasO_ResetDecoder ();
+
+int64_t nextPulseClasOSensor(uint32_t width);
+
+#endif

+ 284 - 0
main/Sensors/esic.c

@@ -0,0 +1,284 @@
+#include "esic.h"
+#include <stdint.h>
+#include <stdio.h>
+#include "esp_log.h"
+#include "../rxTimer.h"
+#include "config.h"
+
+#ifdef TRANCEIVER_ENABLED
+
+/**
+**********************************************************************************
+* TEMP 3
+* ESIC WT450H
+
+    +---+   +---+   +-------+       +  high
+    |   |   |   |   |       |       |
+    |   |   |   |   |       |       |
+    +   +---+   +---+       +-------+  low
+    
+    ^       ^       ^       ^       ^  clock cycle
+    |   1   |   1   |   0   |   0   |  translates as
+    
+    Each transmission is 36 bits long (i.e. 72 ms)
+
+	.short_width = 976,  // half-bit width 976 us
+    .long_width  = 1952, // bit width 1952 us
+    
+    Data is transmitted in pure binary values, NOT BCD-coded.
+    
+    Example transmission (House 1, Channel 1, RH 59 %, Temperature 23.5 �C)
+    1100 00010011001110110100100110011000
+    
+    b00 - b03  (4 bits): Constant, 1100, probably preamble
+    b04 - b07  (4 bits): House code (here: 0001 = HC 1)
+    b08 - b09  (2 bits): Channel code - 1 (here 00 = CC 1)
+    b10 - b12  (3 bits): Constant, 110
+    b13 - b19  (7 bits): Relative humidity (here 0111011 = 59 %)
+    b20 - b34 (15 bits): Temperature (see below)
+    b35 - b35  (1 bit) : Parity (xor of all bits should give 0)
+    
+    The temperature is transmitted as (temp + 50.0) * 128,
+    which equals (temp * 128) + 6400. Adding 50.0 �C makes
+    all values positive, an unsigned 15 bit integer where the
+    first 8 bits correspond to the whole part of the temperature
+    (here 01001001, decimal 73, substract 50 = 23).
+    Remaining 7 bits correspond to the fractional part.
+    
+    To avoid floating point calculations I store the raw temperature value
+    as a signed integer in the variable esicTemp, then transform it to
+    actual temperature * 10 using "esicTemp = (esicTemp - 6400) * 10 / 128",
+    where 6400 is the added 50 times 128.
+    When reporting the temperature I simply print "esicTemp / 10" (integer division,
+    no fraction), followed by a decimal point and "esicTemp % 10" (remainder, which
+    equals first fractional decimal digit).
+      
+    Summary of bit fields:
+    1100 0001 00 110 0111011 010010011001100 0
+     c1   hc  cc  c2    rh          t        p
+     
+    c1, c2 = constant field 1 and 2
+    hc, cc = house code and channel code
+    rh, t  = relative humidity, temperature
+    p      = parity bit 1111111111111110
+
+
+	This interpretation is from: https://github.com/merbanan/rtl_433/blob/master/src/devices/wt450.c
+
+	   1100 0001 | 0011 0011 | 1000 0011 | 1011 0011 | 0001
+	   xxxx ssss | ccxx bhhh | hhhh tttt | tttt tttt | sseo
+
+	- x: constant
+	- s: House code
+	- c: Channel
+	- b: battery low indicator (0=>OK, 1=>LOW)
+	- h: Humidity
+	- t: Temperature, 12 bit, offset 50, scale 16
+	- s: sequence number of message repeat
+	- e: parity of all even bits
+	- o: parity of all odd bits
+
+**********************************************************************************
+*/
+
+
+
+volatile unsigned long long temp3_x_data;
+
+
+void ESIC_ResetDecoder() {
+	temp3_x_data = 0;
+}
+
+#define NO_OF_PULSES 60
+#define max(a,b) (((a)>(b))?(a):(b))
+#define isShortPulse(width)  (((long_pulse/2)-maxDiff) <= width && width <= ((long_pulse/2)+maxDiff))
+#define isLongPulse(width)  ((long_pulse-maxDiff) <= width && width <= (long_pulse+maxDiff))
+
+unsigned int temp3_pulses[NO_OF_PULSES];
+
+
+static int long_pulse = 1955;
+static int maxDiff = 300;
+
+static void storePulses(unsigned int inWidth) {
+
+	int i;
+
+	// Shift pulses down
+	for(i=1;i<NO_OF_PULSES;i++) {
+		temp3_pulses[i-1] = temp3_pulses[i];
+	}
+
+	temp3_pulses[NO_OF_PULSES-1] = inWidth;
+}
+
+static void sweepForNoise() {
+
+	// If we have a short pulse in position 2
+	// Then add together pos 1,2 and 3 if they are a valid pulse
+	// This way we can handle one single noise pulse in a real pulse
+	if( temp3_pulses[NO_OF_PULSES-2] < ((long_pulse/2)-maxDiff) ) {
+
+		int totPulse = temp3_pulses[NO_OF_PULSES-1]+temp3_pulses[NO_OF_PULSES-2]+temp3_pulses[NO_OF_PULSES-3];
+		
+		if( isShortPulse(totPulse) || isLongPulse(totPulse) ) {
+			
+			// Store new pulse in last position
+			temp3_pulses[NO_OF_PULSES-1] = totPulse;
+
+			// Move everything up again
+			for(int i=NO_OF_PULSES-2;i>1;i--) {
+				temp3_pulses[i] = temp3_pulses[i-2];
+			}
+			temp3_pulses[0] = 0;
+			temp3_pulses[1] = 0;
+		}
+	}
+}
+
+
+/*static void adjustTiming() {
+
+	int p1 = temp3_pulses[NO_OF_PULSES-8];
+	int p2 = temp3_pulses[NO_OF_PULSES-7];
+	int p3 = temp3_pulses[NO_OF_PULSES-6];
+	int p4 = temp3_pulses[NO_OF_PULSES-5];
+	int p5 = temp3_pulses[NO_OF_PULSES-4];
+	int p6 = temp3_pulses[NO_OF_PULSES-3];
+	int p7 = temp3_pulses[NO_OF_PULSES-2];
+	int p8 = temp3_pulses[NO_OF_PULSES-1];
+
+	// Check max differance between the short pulses
+	int sh_mean = (p1+p2+p3+p4) / 4;
+	int sh_max_diff = max(max(abs(p1-sh_mean),abs(p2-sh_mean)),max(abs(p3-sh_mean),abs(p4-sh_mean)));
+
+	// Check max differance between the long pulses
+	int long_mean = (p5+p6+p7+p8) / 4;
+	int long_max_diff = max(max(abs(p5-long_mean),abs(p6-long_mean)),max(abs(p7-long_mean),abs(p8-long_mean)));
+
+	if( sh_max_diff < maxDiff && long_max_diff < maxDiff ) {
+
+		int mean = (long_mean + sh_mean)/2;
+		if( long_mean > (mean+maxDiff) && sh_mean < (mean-maxDiff) ) {
+			if( abs(long_mean - (sh_mean*2)) < maxDiff ) {
+				long_pulse = (long_mean + sh_mean*2)/2;
+				maxDiff = long_mean / 15;
+			}
+		}
+	}
+}*/
+
+// The latest/newest pulse is at the end of the array [59]
+// This ([59]) is the latest bit in the bit-stream from the transmitter
+// This is way we input the bits at a high position and shift them towards lower values
+// So..start reading backwards and working towards the first/highest bits
+static int checkPulsePattern() {
+
+	int i = NO_OF_PULSES-1;	// Start reading from the last received (end of array)
+	int b = 0;
+
+	unsigned long long code = 0;
+
+	while( i >= 0 ) {
+
+		int combWidth = temp3_pulses[i] + temp3_pulses[i-1];
+
+		if( isLongPulse(temp3_pulses[i]) ) {
+			b++;
+			i-=1;
+			code = code >> 1;
+		}
+		else if( isShortPulse(temp3_pulses[i]) && isShortPulse(temp3_pulses[i-1]) ) {
+			b++;
+			i-=2;
+			code = ((code >> 1) | 0x200000000);
+		}
+		else if( isLongPulse( combWidth ) ) {
+			b++;
+			i-=2;
+			code = ((code >> 1) | 0x200000000);
+		}
+		else {
+			return -1;
+		}
+		if( b == 34 ) {
+/*
+		0000 0001 00 110 0101000 010010110101000 1
+AND:    0011 1111 00 111 0000000 000000000000000 0  = 001111110011100000000000000000000000 = 0x3F3800000
+RES:    0000 0001 00 110 0000000 000000000000000 0  = 000000010011000000000000000000000000 = 0x013000000
+
+		Summary of bit fields:
+		1100 0001 00 110 0111011 010010011001100 0
+		 c1   hc  cc  c2    rh          t        p
+		 */
+			if( (code & 0x3F3800000) == 0x013000000 ) {
+
+				temp3_x_data = (code&0xFFFFFFFF);
+				// Check parity
+				int even=0;
+				unsigned long long data = temp3_x_data;
+				for(int i=0;i<32;i++) {
+					if( data & 1 ) even++;
+					data >>= 1;
+				}
+				if( even % 2 != 0 ) {
+					temp3_x_data = 0;
+					printf("Wrong parity\n");
+					return -1;
+				}
+				// A correct code has been received
+				//printf("Code received: %llu on row:%d\n",(code&0xFFFFFFFF),row_no);
+				temp3_x_data &= 0xFFFFFFF0;	// Remove sequence and parity bits in lowest nibble
+				return 1;
+				
+			}
+			else {
+				return -1;
+			}
+		}
+	}
+	return 0;
+}
+
+static int temp3decode (unsigned int inWidth) {
+
+	int width = inWidth; //preProcessPulses(inWidth);
+
+	if( width == -1 ) return -1;
+	if( width == 0 ) return 0;
+
+	storePulses(inWidth);
+	sweepForNoise();
+	//adjustTiming();
+	return checkPulsePattern();
+}
+
+int64_t nextPulseESICSensor(uint32_t width) {
+  
+  	static int64_t previous_data = 0;
+	static uint32_t old_time=0;
+	static uint32_t now;
+	int64_t retVal = -1;
+  
+	if( width > 0 ) {
+		if( temp3_x_data == 0 ) {
+			temp3decode(width);
+		}
+	}
+  
+	if( temp3_x_data > 0 ) {
+		now = millis();
+
+		if( temp3_x_data != previous_data || (now > (old_time+1000)) ) {
+            previous_data = temp3_x_data;
+            retVal = temp3_x_data;
+		}
+		old_time = now;
+		ESIC_ResetDecoder();
+	}
+	
+	return retVal;
+}
+
+#endif

+ 11 - 0
main/Sensors/esic.h

@@ -0,0 +1,11 @@
+#ifndef __ESIC__
+#define __ESIC__
+
+#include <stdbool.h>
+#include <stdint.h>
+
+void ESIC_ResetDecoder();
+
+int64_t nextPulseESICSensor(uint32_t width);
+
+#endif

+ 179 - 0
main/Sensors/nexa.c

@@ -0,0 +1,179 @@
+#include "nexa.h"
+#include <stdint.h>
+#include <stdio.h>
+#include "../rxTimer.h"
+#include "config.h"
+
+#ifdef TRANCEIVER_ENABLED
+
+typedef struct {
+    uint32_t max;
+    uint32_t min;
+    uint32_t cnt;
+    uint32_t total;
+} debug_data_t;
+
+//static debug_data_t debug_data = { 0,99999,0,0 };
+//static debug_data_t debug_data_tot = { 0,99999,0,0 };
+
+#define DEBUG_WIDTH_FUNC() { \
+                    if( width > debug_data.max ) debug_data.max = width; \
+                    if( width < debug_data.min ) debug_data.min = width; \
+                    debug_data.total += width; \
+                    debug_data.cnt++; \
+                }
+
+
+#define FACTOR 9
+#define CONV(a) ((((a)*FACTOR) / 100) + (a))
+
+struct nexaData_t {
+  unsigned char bitNo;
+  unsigned short width;
+} ;
+
+enum { UNKNOWN, T0, T1, T2, T3, OK_Sensor, DONE };
+
+static uint8_t rx_state = UNKNOWN;
+
+static uint64_t sensor_data;
+static uint32_t rx_numBits;
+static uint8_t x_2ndbit;
+
+uint32_t startPulseWidth = 0;
+
+void NEXA_resetDecoder () {
+	sensor_data = 0;
+	rx_numBits = 0;
+	x_2ndbit = false;
+	rx_state = UNKNOWN;
+
+    //debug_data.max = 0;
+    //debug_data.min = 99999;
+}
+
+static void addBit (uint8_t value) {
+
+	// X
+	rx_numBits++;
+	sensor_data = (sensor_data << 1) + (value & 0x01);
+	if( x_2ndbit == false ) {
+		x_2ndbit = true;
+	}
+	else {
+		x_2ndbit = false;
+		unsigned int bits = (sensor_data & 0x03);
+		if( bits == 2 ) {
+			// Bit is 1
+			sensor_data = (sensor_data >> 1) | 0x00000001;
+		}
+		else {
+			// Bit is 0
+			sensor_data = (sensor_data >> 1) & 0xFFFFFFFE;
+		}
+	}
+
+	rx_state = OK_Sensor;
+}
+
+static int rx_decode(uint32_t width) {
+  
+    if( rx_numBits == 3 ) {	// end of frame
+          //state = DONE;
+          //return 1;
+	}
+        
+	switch (rx_state) {
+        case UNKNOWN: // Start of frame
+            if ( 2240 <= width && width <= 3540 ) { // Hallway-button: 2760
+                //DEBUG_WIDTH_FUNC();
+                startPulseWidth = width;
+
+                rx_state = T0;
+            }
+            else {
+                return -1;	// error, reset
+            }
+            break;
+
+        case T0: // First half of pulse
+
+            if ( 155 <= width && width <= 305 ) {   // Hallway-button: 230-250
+
+                rx_state = T1;
+
+            }
+            else {
+                if( rx_numBits == 0 && 2240 <= width && width <= 3540 ) {
+                    rx_state = T0;
+                }
+                else {
+                    return -1;	// error, reset
+                }
+            }
+            break;
+
+        case T1:
+            if ( 200 <= width && width <= 440 ) {   // Hallway-button: 250-270
+
+                addBit(0);
+            }
+            else if ( 950 <= width && width <= 1700 ) {  // Hallway-button: 1250-1270
+                
+
+                addBit(1);
+            } else if( rx_numBits == 64 ) {	// end of frame
+                rx_state = DONE;
+                return 1;
+            } else  {
+                return -1;	// error, reset
+            }
+            rx_state = T0;
+            break;
+	}
+	return 0;
+}
+
+#define TOO_SHORT 100
+
+int64_t nextPulseNEXA(uint32_t width)
+{
+    static int64_t previous_data = 0;
+    static uint32_t old_time=0;
+    static uint32_t now;
+    int64_t retVal = -1;
+
+    if (width > 0)
+    {
+        if (rx_state != DONE)
+        {
+            switch (rx_decode(width))
+            {
+            case -1:
+                NEXA_resetDecoder();
+                break;
+            case 1:
+                rx_state = DONE;
+                //printf("%d\n",debug_width);
+                break;
+            }
+        }
+    }
+    if (rx_state == DONE) {
+        now = millis();
+        //if( debug_data.max > debug_data_tot.max ) debug_data_tot.max = debug_data.max;
+        //if( debug_data.min < debug_data_tot.min ) debug_data_tot.min = debug_data.min;
+        //printf("NEXA Debug min,max:%u %u\n",debug_data_tot.min,debug_data_tot.max);
+
+        if( sensor_data != previous_data || (now > (old_time+1000)) ) {
+            previous_data = sensor_data;
+            retVal = sensor_data;
+        }
+        old_time = now;
+        NEXA_resetDecoder();
+    }
+    
+    return retVal;
+}
+
+#endif

+ 13 - 0
main/Sensors/nexa.h

@@ -0,0 +1,13 @@
+#ifndef __NEXA__
+#define __NEXA__
+
+#include <stdbool.h>
+#include <stdint.h>
+
+void NEXA_resetDecoder ();
+
+int64_t nextPulseNEXA(uint32_t width);
+
+extern uint32_t startPulseWidth;
+
+#endif

+ 113 - 0
main/Sensors/oregon.c

@@ -0,0 +1,113 @@
+#include "oregon.h"
+#include <stdint.h>
+#include <stdio.h>
+#include "../rxTimer.h"
+#include <string.h>
+#include "esp_log.h"
+#include "config.h"
+
+#ifdef TRANCEIVER_ENABLED
+
+static void done ();
+
+static unsigned char total_bits, bits, flip, state, pos, data[25];
+char result_str[25];
+
+enum { UNKNOWN, T0, T1, T2, T3, SENSOR_OK, DONE };
+
+void Oregon_ResetDecoder () {
+    total_bits = bits = pos = flip = 0;
+    state = UNKNOWN;
+    memset(result_str,'\0',sizeof(result_str));
+}
+
+
+// V3-Version of the gitBit-function
+static void gotBit (char value) {
+    data[pos] = (data[pos] >> 1) | (value ? 0x80 : 00);
+    total_bits++;
+    pos = total_bits >> 3;
+    if (pos >= sizeof data) {
+        Oregon_ResetDecoder();
+        return;
+    }
+    state = SENSOR_OK;
+}
+
+// store a bit using Manchester encoding
+static void manchester (char value) {
+    flip ^= value; // manchester code, long pulse flips the bit
+    gotBit(flip);
+}
+
+static void done () {
+    while (bits)
+        gotBit(0); // padding
+    state = DONE;
+}
+
+static int rx_decode( int width ) {
+    if( (480-200) < width && width < (980+200) ) {
+        char w = width >= 730;
+        switch (state) {
+            case UNKNOWN:
+                if (w == 0)
+                    ++flip;
+                else if (32 <= flip) {
+                    flip = 1;
+                    manchester(1);  // Width 950
+                } else
+                    return -1;
+                break;
+            case SENSOR_OK:
+                if (w == 0)
+                    state = T0;
+                else 
+                    manchester(1);  // Width 980
+
+                break;
+            case T0:
+                if (w == 0)
+                    manchester(0);  // Width 480
+                else
+                    return -1;
+                break;
+        }
+    } else {
+        return -1;
+    }
+    return  total_bits == 80 ? 1: 0;
+}
+
+ //10 bytes data: 2A 19 04 CE 00 00 60 12 00 30
+
+char * nextPulseOregonSensor(uint32_t width) {
+    if( state != DONE ) {
+    
+        switch (rx_decode(width)) {
+            case -1:
+                Oregon_ResetDecoder();
+                break;
+            case 1:
+                done();
+                break;
+        }
+    }
+    if( state == DONE ) {
+        if( pos == 10 ) {
+            for( int i=0; i<pos; i++ ) {
+                sprintf(result_str+(i*2),"%02X",data[i] );
+            }
+
+            return result_str;
+        }
+        else {
+            Oregon_ResetDecoder();
+            return  (char *)NULL;
+        }
+    }
+    else 
+        return (char *)NULL;
+}
+
+#endif

+ 11 - 0
main/Sensors/oregon.h

@@ -0,0 +1,11 @@
+#ifndef __OREGON__
+#define __OREGON__
+
+#include <stdbool.h>
+#include <stdint.h>
+
+void Oregon_ResetDecoder();
+
+char * nextPulseOregonSensor(uint32_t width);
+
+#endif

+ 163 - 0
main/Sensors/proovesmartSensor.c

@@ -0,0 +1,163 @@
+#include "proovesmartSensor.h"
+#include <stdint.h>
+#include <stdio.h>
+#include "../rxTimer.h"
+#include <string.h>
+#include "esp_log.h"
+#include "config.h"
+
+#ifdef TRANCEIVER_ENABLED
+
+typedef struct {
+    uint32_t max;
+    uint32_t min;
+    uint32_t cnt;
+    uint32_t total;
+} debug_data_t;
+
+static debug_data_t debug_data = { 0,99999,0,0 };
+static debug_data_t debug_data_tot = { 0,99999,0,0 };
+
+#define DEBUG_WIDTH_FUNC() { \
+                    if( width > debug_data.max ) debug_data.max = width; \
+                    if( width < debug_data.min ) debug_data.min = width; \
+                    debug_data.total += width; \
+                    debug_data.cnt++; \
+                }
+
+
+enum { UNKNOWN, T0, T1, T2, T3, OK_Sensor, DONE };
+
+static unsigned char rx_state = T0;
+
+static uint64_t sensor_data;
+static uint32_t rx_numBits;
+
+static unsigned char isTrigged = 0;
+static uint32_t trigDataBuff[4] = {0,0,0,0};
+
+void ProovesmartSensor_ResetDecoder () {
+	sensor_data = 0;
+	rx_numBits = 0;
+	rx_state = T0;
+    isTrigged = 0;
+    memset(trigDataBuff,0,sizeof(trigDataBuff));
+}
+
+static void addBit (uint8_t value) {
+
+	rx_numBits++;
+	sensor_data = (sensor_data << 1) + (value & 0x01);
+
+	rx_state = OK_Sensor;
+}
+
+static int rx_decode (uint32_t width) {
+        
+	switch (rx_state) {
+
+        uint32_t bitData;
+
+        case T0: // First ON-half of pulse : HIGH around 910
+
+            if ( (960-100) <= width && width <= (1080+100) ) {
+                rx_state = T1;
+            }
+            else {
+                return -1;	// error, reset
+            }
+            break;
+
+        case T1:
+            
+            if ( 200 <= width && width <= 2000 ) {
+                
+                if( width > 1000 ) {
+                    bitData = 0;
+                }
+                else {
+                    //DEBUG_WIDTH_FUNC();
+                    bitData = 1;
+                }
+
+            } else  {
+                return -1;	// error, reset
+            }
+
+            if( isTrigged == 0 ) {
+
+                trigDataBuff[3] = trigDataBuff[2];
+                trigDataBuff[2] = trigDataBuff[1];
+                trigDataBuff[1] = trigDataBuff[0];
+                trigDataBuff[0] = bitData;
+
+                if( trigDataBuff[3] == 0 &&
+                    trigDataBuff[2] == 1 &&
+                    trigDataBuff[1] == 0 &&
+                    trigDataBuff[0] == 0) {
+
+                        isTrigged = 1;
+                        // ESP_LOGI("PROOVE", "Trig %u",width);
+                }
+
+            }
+            else {
+                addBit(bitData);
+
+                if( rx_numBits == 36-8 ) {	// end of frame (We skip the last 8 bits)
+                    rx_state = DONE;
+                    return 1;
+                }
+            }
+              
+            rx_state = T0;
+
+            break;
+    }
+    return 0;
+}
+
+int64_t nextPulseProovesmartSensor(uint32_t width)
+{
+    static int64_t previous_data = 0;
+    static uint32_t old_time=0;
+    static uint32_t now;
+    int64_t retVal = -1;
+
+    if (width > 0)
+    {
+        if (rx_state != DONE)
+        {
+            switch (rx_decode(width))
+            {
+            case -1:
+                ProovesmartSensor_ResetDecoder();
+                break;
+            case 1:
+                rx_state = DONE;
+                break;
+            }
+        }
+    }
+    if (rx_state == DONE) {
+        now = millis();
+        sensor_data <<= 8;
+
+        /*
+        if( debug_data.max > debug_data_tot.max ) debug_data_tot.max = debug_data.max;
+        if( debug_data.min < debug_data_tot.min ) debug_data_tot.min = debug_data.min;
+        printf("OREGON DEbug min,max:%u %u\n",debug_data_tot.min,debug_data_tot.max);
+        */
+
+        if( sensor_data != previous_data || (now > (old_time+1000)) ) {
+            previous_data = sensor_data;
+            retVal = sensor_data;
+        }
+        old_time = now;
+        ProovesmartSensor_ResetDecoder();
+    }
+    
+    return retVal;
+}
+
+#endif

+ 11 - 0
main/Sensors/proovesmartSensor.h

@@ -0,0 +1,11 @@
+#ifndef __PROOVE__
+#define __PROOVE__
+
+#include <stdbool.h>
+#include <stdint.h>
+
+void ProovesmartSensor_ResetDecoder ();
+
+int64_t nextPulseProovesmartSensor(uint32_t width);
+
+#endif

+ 15 - 5
main/config.h

@@ -6,15 +6,25 @@
 #define SW_VERSION "1.0"
 
 // These defines configures which code to generate (to save download time during development)
-#define WIFI_ENABLED
-#define MQTT_ENABLED
-#define ENABLE_DS18B20
 
-//#define MQTT_DEBUG              // Add an extra debug string to the beginning of the topic-string
+//#define RX_TIMER_ENABLED
+//#define TRANCEIVER_ENABLED
+
+//#define WIFI_ENABLED
+//#define MQTT_ENABLED
+#define ENABLE_DS18B20
 
-#define KWH_COUNTER_INPUT_IO      GPIO_NUM_16   // Input
+#define MQTT_DEBUG              // Add an extra debug string to the beginning of the topic-string
 
 #define ONE_WIRE_BUS_IO           GPIO_NUM_26   // Temp sensors
 
 
+#define ENABLE_LUX_SENSOR
+#define I2C_MASTER_SCL  4   // GPIO number for I2C Master clock line.
+#define I2C_MASTER_SDA  5   // GPIO number for I2C Master data line.
+#define I2C_MASTER_FREQUENCY 400000  // I2C master clock frequency
+#define CONFIG_TSL2561_I2C_ADDRESS 0x39
+
+
+
 #endif

+ 115 - 0
main/lux.c

@@ -0,0 +1,115 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2017 David Antliff
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/**
+ * @file app_main.c
+ * @brief Example application for the TSL2561 Light-to-Digital Converter.
+ */
+
+
+#include <stdio.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "esp_system.h"
+#include "driver/gpio.h"
+#include "driver/i2c.h"
+#include "esp_log.h"
+#include "sdkconfig.h"
+
+#include "smbus.h"
+#include "tsl2561.h"
+#include "config.h"
+
+#ifdef ENABLE_LUX_SENSOR
+
+#define TAG "app"
+
+#define I2C_MASTER_NUM           I2C_NUM_0
+#define I2C_MASTER_TX_BUF_LEN    0                     // disabled
+#define I2C_MASTER_RX_BUF_LEN    0                     // disabled
+#define I2C_MASTER_FREQ_HZ       100000
+#define I2C_MASTER_SDA_IO        I2C_MASTER_SDA
+#define I2C_MASTER_SCL_IO        I2C_MASTER_SCL
+
+static void i2c_master_init(void)
+{
+    int i2c_master_port = I2C_MASTER_NUM;
+    i2c_config_t conf;
+    conf.mode = I2C_MODE_MASTER;
+    conf.sda_io_num = I2C_MASTER_SDA_IO;
+    conf.sda_pullup_en = GPIO_PULLUP_DISABLE;  // GY-2561 provides 10kΩ pullups
+    conf.scl_io_num = I2C_MASTER_SCL_IO;
+    conf.scl_pullup_en = GPIO_PULLUP_DISABLE;  // GY-2561 provides 10kΩ pullups
+    conf.master.clk_speed = I2C_MASTER_FREQ_HZ;
+    i2c_param_config(i2c_master_port, &conf);
+    i2c_driver_install(i2c_master_port, conf.mode,
+                       I2C_MASTER_RX_BUF_LEN,
+                       I2C_MASTER_TX_BUF_LEN, 0);
+}
+
+static void tsl2561_task(void * pvParameter)
+{
+    // Set up I2C
+    i2c_master_init();
+    i2c_port_t i2c_num = I2C_MASTER_NUM;
+    uint8_t address = CONFIG_TSL2561_I2C_ADDRESS;
+
+    // Set up the SMBus
+    smbus_info_t * smbus_info = smbus_malloc();
+    smbus_init(smbus_info, i2c_num, address);
+    smbus_set_timeout(smbus_info, 1000 / portTICK_RATE_MS);
+
+    // Set up the TSL2561 device
+    tsl2561_info_t * tsl2561_info = tsl2561_malloc();
+    tsl2561_init(tsl2561_info, smbus_info);
+
+    // Set sensor integration time and gain
+    tsl2561_set_integration_time_and_gain(tsl2561_info, TSL2561_INTEGRATION_TIME_402MS, TSL2561_GAIN_1X);
+    //tsl2561_set_integration_time_and_gain(tsl2561_info, TSL2561_INTEGRATION_TIME_402MS, TSL2561_GAIN_16X);
+
+    while (1)
+    {
+        tsl2561_visible_t visible = 0;
+        tsl2561_infrared_t infrared = 0;
+        tsl2561_read(tsl2561_info, &visible, &infrared);
+
+        printf("\nFull spectrum: %d\n", visible + infrared);
+        printf("Infrared:      %d\n", infrared);
+        printf("Visible:       %d\n", visible);
+        printf("Lux:           %d\n", tsl2561_compute_lux(tsl2561_info, visible, infrared));
+
+        vTaskDelay(2000 / portTICK_RATE_MS);
+    }
+}
+
+void init_tsl2561()
+{
+    xTaskCreate(&tsl2561_task, "tsl2561_task", 2048, NULL, 5, NULL);
+
+    // I2C/SMBus Test application
+    //extern void test_smbus_task(void * pvParameter);
+    //xTaskCreate(&test_smbus_task, "test_smbus_task", 2048, NULL, 5, NULL);
+}
+
+#endif

+ 12 - 0
main/lux.h

@@ -0,0 +1,12 @@
+#ifndef __TSL_2561__
+#define __TSL_2561__
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/queue.h"
+#include <stdint.h>
+
+void init_tsl2561();
+
+
+
+#endif

+ 30 - 4
main/main.c

@@ -5,25 +5,47 @@
 #include "wifi.h"
 #include "mqtt.h"
 #include "readTemps.h"
+#include "rxTimer.h"
+#include "transceiver.h"
+#include "receiver.h"
+#include "lux.h"
 
 
 // Chip info:
 // This is esp32 chip with 2 CPU cores, WiFi/BT/BLE, silicon revision 1, 4MB external flash
 
+void getChipInfo(void) {
+    esp_chip_info_t chip_info;
+    esp_chip_info(&chip_info);
+
+    ESP_LOGI("MAIN", "Model: %s", chip_info.model == CHIP_ESP32 ? "ESP32" : "Unknown");
+    ESP_LOGI("MAIN", "Features: WiFi%s%s, %d cores",
+             (chip_info.features & CHIP_FEATURE_BT) ? "/BT" : "",
+             (chip_info.features & CHIP_FEATURE_BLE) ? "/BLE" : "",
+             chip_info.cores);
+    ESP_LOGI("MAIN", "Revision: %d", chip_info.revision);
+}
+
 
 void app_main(void)
 {
     ESP_LOGI("MAIN", "GarageTransceiver ESP32. Core:%d",xPortGetCoreID());
+    getChipInfo();
 
     // Wait for stable environment
     vTaskDelay(2000.0 / portTICK_PERIOD_MS);
 
-#ifdef ENABLE_DS18B20
-    initTempReadings();
+#ifdef RX_TIMER_ENABLED
+    rxTimerInit();          // First we start the Timer (which samples Rx and handles uS-delays)
 #endif
 
-#ifdef ENABLE_KWH_COUNTER
-    kWhCounter_init();
+#ifdef TRANCEIVER_ENABLED
+    initTransceiver();      // Init the transceiver
+    initReceiver();         // Init the receiver
+#endif
+
+#ifdef ENABLE_DS18B20
+    initTempReadings();
 #endif
 
 #ifdef WIFI_ENABLED
@@ -34,6 +56,10 @@ void app_main(void)
     mqtt_init();
 #endif
 
+#ifdef ENABLE_LUX_SENSOR
+    init_tsl2561();
+#endif
+
     TickType_t vLastWakeTime = xTaskGetTickCount();
 
     // Do an initial delay to make the different tasks to work out of sync to each other (not send all data at same time)

+ 47 - 34
main/readTemps.c

@@ -60,58 +60,71 @@ void initTempReadings() {
         ds18b20_use_crc(ds18b20_info, true);           // enable CRC check on all reads
         ds18b20_set_resolution(ds18b20_info, DS18B20_RESOLUTION);
     }
+
+    // Start the TEMPS task
+    xTaskCreatePinnedToCore(readAndSendTemps, "TEMPS-Task", 1024*10, NULL, 2, NULL,0);
 }
 
 void readAndSendTemps(void *pvParameters) {
 
     ESP_LOGI("TEMPS", "Read temperature task. Core:%d",xPortGetCoreID());
 
-    // Read temperatures more efficiently by starting conversions on all devices at the same time
-    int errors_count[MAX_DEVICES] = {0};
-    if (num_devices > 0)
+    while(true)
     {
-        ds18b20_convert_all(owb);
+   
 
-        // In this application all devices use the same resolution,
-        // so use the first device to determine the delay
-        const float sampleTime = ds18b20_wait_for_conversion(devices[0]);
+        // Read temperatures more efficiently by starting conversions on all devices at the same time
+        int errors_count[MAX_DEVICES] = {0};
+        if (num_devices > 0)
+        {
+            ds18b20_convert_all(owb);
 
-        // Read the results immediately after conversion otherwise it may fail
-        // (using printf before reading may take too long)
-        float readings[MAX_DEVICES] = { 0 };
-        DS18B20_ERROR errors[MAX_DEVICES] = { 0 };
+            // In this application all devices use the same resolution,
+            // so use the first device to determine the delay
+            const float sampleTime = ds18b20_wait_for_conversion(devices[0]);
 
-        for (int i = 0; i < num_devices; ++i)
-        {
-            errors[i] = ds18b20_read_temp(devices[i], &readings[i]);
-        }
+            vTaskDelay(500 / portTICK_PERIOD_MS);
 
-        ESP_LOGI("TEMPS","Sample time:%.0fms",sampleTime);
+            // Read the results immediately after conversion otherwise it may fail
+            // (using printf before reading may take too long)
+            float readings[MAX_DEVICES] = { 0 };
+            DS18B20_ERROR errors[MAX_DEVICES] = { 0 };
 
-        // Print results in a separate loop, after all have been read
-        for (int i = 0; i < num_devices; ++i)
-        {
-            if (errors[i] != DS18B20_OK)
+            for (int i = 0; i < num_devices; ++i)
             {
-                ++errors_count[i];
+                errors[i] = ds18b20_read_temp(devices[i], &readings[i]);
             }
-            
-            char rom_code_s[25];
-            char mqtt_s[50];
-            char value_s[10];
-            owb_string_from_rom_code(devices[i]->rom_code, rom_code_s, sizeof(rom_code_s));
 
-            sprintf(mqtt_s,"basement/boiler/temps/%s", rom_code_s);
-            sprintf(value_s,"%.1f",readings[i]);
-            ESP_LOGI("TEMPS","%s %s", mqtt_s, value_s);
+            ESP_LOGI("TEMPS","Sample time:%.0fms",sampleTime);
 
-            sendMQTTMessage(mqtt_s, value_s);
+            // Print results in a separate loop, after all have been read
+            for (int i = 0; i < num_devices; ++i)
+            {
+                if (errors[i] != DS18B20_OK)
+                {
+                    ++errors_count[i];
+                }
+                
+                char rom_code_s[25];
+                char mqtt_s[50];
+                char value_s[10];
+                owb_string_from_rom_code(devices[i]->rom_code, rom_code_s, sizeof(rom_code_s));
+
+                sprintf(mqtt_s,"garage/temps/%s", rom_code_s);
+                sprintf(value_s,"%.1f",readings[i]);
+                ESP_LOGI("TEMPS","%s %s", mqtt_s, value_s);
+
+                sendMQTTMessage(mqtt_s, value_s);
+            }
+
+        }
+        else
+        {
+            ESP_LOGE("TEMPS", "No DS18B20 devices detected!");
         }
 
-    }
-    else
-    {
-        ESP_LOGE("TEMPS", "No DS18B20 devices detected!");
+        vTaskDelay(10000 / portTICK_PERIOD_MS);
+    
     }
     vTaskDelete(NULL);
 }

+ 173 - 0
main/receiver.c

@@ -0,0 +1,173 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/time.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "esp_sleep.h"
+#include "esp_log.h"
+#include "driver/uart.h"
+#include "driver/rtc_io.h"
+#include "esp_intr_alloc.h"
+#include "esp_attr.h"
+#include "driver/timer.h"
+#include <stddef.h>
+#include "esp_intr_alloc.h"
+
+#include "receiver.h"
+#include "transceiver.h"
+#include "rxTimer.h"
+#include "Sensors/ClasOSensor.h"
+#include "Sensors/proovesmartSensor.h"
+#include "Sensors/nexa.h"
+#include "Sensors/oregon.h"
+#include "Sensors/esic.h"
+#include "config.h"
+
+uint32_t dataArr[1000];
+uint32_t dataArrIdx = 0;
+
+#ifdef TRANCEIVER_ENABLED
+
+static int convertToSignedTemp(unsigned int value)
+{
+
+	//int signValue;
+
+	return ( (value >> 11) == 0 )? value : ((-1 ^ 0xFFF) | value);
+}
+
+#define UDP_QUEUE_OBJ_LENGTH 40
+
+void receiverTask(void *pvParameter)
+{
+    ESP_LOGI("RX", "Receiver task starting.");
+    uint32_t width;
+    
+    char dataStr[UDP_QUEUE_OBJ_LENGTH];
+
+    while (1) {
+
+        while( xQueueReceive( rxQueue, &width, portMAX_DELAY ) == pdTRUE ) {
+
+            dataArr[dataArrIdx++] = width;
+            if( dataArrIdx == 1000 ) dataArrIdx=0;
+
+            // Receive the Clas Ohlsson Sensors
+            int64_t data = nextPulseClasOSensor(width);
+            if( data != -1 ) {
+
+                int value      = convertToSignedTemp( data & 0xFFF );
+                unsigned char id         = (data>>12) & 0x007;
+
+                ESP_LOGI("RX", "ClasO:  <TR%08llX> %u               %4.1f",data,id, (float)value/10);
+
+                sprintf(dataStr,"<TR%08llX>",data);
+#ifdef MQTT_ENABLED
+                //sendUDPMessage(dataStr, true);
+#endif
+            }
+
+            // Receive the Telldus / Proovesmart Sensors
+            data = nextPulseProovesmartSensor(width);
+            if( data != -1 ) {
+
+                const int value = (data & 0x00FFF0000) >> 16;
+                const int id = (data & 0xFF0000000) >> 28;
+
+                ESP_LOGI("RX", "Proove: <Tr%016llX> ID:%d  %4.1f",data,id,(float)value/10);
+
+                sprintf(dataStr,"<Tr%016llX>",data);
+#ifdef MQTT_ENABLED
+                //sendUDPMessage(dataStr, true);
+#endif
+            }
+
+            // Receive the NEXA Sensors
+            data = nextPulseNEXA(width);
+            if( data != -1 ) {
+
+                ESP_LOGI("RX", "NEXA: <NR%08llX>",data);
+
+                sprintf(dataStr,"<NR%08llX>%u",data,startPulseWidth);
+
+#ifdef MQTT_ENABLED
+                //sendUDPMessage(dataStr, false);
+#endif
+            }
+
+            // Receive the Oregon (Rain) Sensor
+            char *ch_data_p = nextPulseOregonSensor(width);
+            if( ch_data_p != NULL ) {
+
+                // Nibbles 17..12 = Total Rain = LSD is 0.001 inch (0,0254 mm)
+                
+                //   0 1 2 3  4 5  6 7 8  9                     Rate    Total
+                // RR2A1904CE 0000 601600 70 = 001.660          0000    001660
+                // RR2A1904CE 2001 702000 60 = 002.070 = 0,41   0120    002070
+                // RR2A1904CE 0001 902400 A0 = 002.490 = 0,42           002490
+                // RR2A1904CE 0000 906600 F0 = 006.690 = 6.69 = 109,62903 cm2
+                // Sequence:       563412  
+                // 1 cubic mm of water = 0,001 gram
+                // 7 grams of water = 7000 mm2
+                // Area of the rain sensor is 7697.69 sq.mm. It flips every ~7grams of water
+                // Every flip is therefore 0.90936402542048 mm or rain
+                // The value that is reported is in 1/1000 cubic inches of water.
+                // Multiply with 16387 / 1000 to get cm2
+
+                double total = 100 * (ch_data_p[4+12]-'0') + 
+                                10 * (ch_data_p[5+12]-'0') +
+                                     (ch_data_p[2+12]-'0') +
+                               0.1 * (ch_data_p[3+12]-'0') +
+                              0.01 * (ch_data_p[0+12]-'0') +
+                             0.001 * (ch_data_p[1+12]-'0');
+
+                total = (total * 16387) / 1000; // Convert to cubic centimeters
+
+                char ch_data[21];
+                strncpy(ch_data,ch_data_p, sizeof(ch_data));
+                ESP_LOGI("RX", "OREGON: <RR%s> %6.4f cm2", ch_data, total );
+
+#ifdef MQTT_ENABLED
+                //sprintf(dataStr,"<RR%s>",ch_data);
+                //sendUDPMessage(dataStr, true);
+#endif
+
+                Oregon_ResetDecoder();
+            }
+
+            // ESIC (Fridge / Freezer Sensors)
+            data = nextPulseESICSensor(width);
+            if( data != -1 ) {
+
+                int32_t value	   = (data & 0xFFFE) >> 1;
+		                value	   = (value - 6400) * 10 / 128;
+
+                int32_t id         = (data>>12) & 0x007;
+
+                ESP_LOGI("RX", "ESIC:   <TE%08llX> %u               %4.1f",data,id, (float)value/10);
+
+                sprintf(dataStr,"<TE%08llX>",data);
+#ifdef MQTT_ENABLED
+                //sendUDPMessage(dataStr, true);
+#endif
+            }
+        }
+    }
+    vTaskDelete(NULL);
+}
+
+void initReceiver() {
+
+    Oregon_ResetDecoder();
+    ClasO_ResetDecoder();
+    ProovesmartSensor_ResetDecoder();
+    ESIC_ResetDecoder();
+            
+    ESP_LOGI("RX", "Receiver has been initialized.");
+
+    xTaskCreatePinnedToCore(&receiverTask, "receiverTask", 8192, NULL, tskIDLE_PRIORITY + 5, NULL, 0);
+}
+
+#endif

+ 13 - 0
main/receiver.h

@@ -0,0 +1,13 @@
+#ifndef __RECEIVER__
+#define __RECEIVER__
+
+
+
+void initReceiver();
+
+extern uint32_t dataArr[1000];
+extern uint32_t dataArrIdx;
+
+
+
+#endif

+ 124 - 0
main/rxTimer.c

@@ -0,0 +1,124 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/time.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "esp_sleep.h"
+#include "esp_log.h"
+#include "driver/uart.h"
+#include "driver/rtc_io.h"
+#include "esp_intr_alloc.h"
+#include "esp_attr.h"
+#include "driver/timer.h"
+#include <stddef.h>
+#include "esp_intr_alloc.h"
+#include "transceiver.h"
+
+#ifdef RX_TIMER_ENABLED
+
+static intr_handle_t s_timer_handle;
+
+static bool timerTaskIsDone = false;
+
+static volatile uint32_t tenUsCounter = 0;  
+
+QueueHandle_t rxQueue = NULL;
+
+static uint32_t millisCnt=0;
+
+uint32_t millis() { return millisCnt; }
+
+
+static void timer_tg0_isr(void* arg)
+{
+    static uint32_t subMillisCounter=100;
+
+    if( subMillisCounter-- == 0 ) {
+        millisCnt++;
+        subMillisCounter=100;
+    }
+
+    tenUsCounter++;
+
+    static uint8_t currValue = 0;
+  
+    static uint16_t samples = 0;
+    static uint16_t newSamples = 0;
+    
+    // Sample the pin value
+    uint8_t value = (uint8_t)gpio_get_level(GPIO_RX_DATA);
+
+    if( value == currValue ) {
+        samples++;
+        samples+=newSamples;
+        newSamples=0;
+    }
+    else {
+        newSamples++;
+    }
+    
+    if( newSamples == 6 ) {
+
+        const uint32_t dataToSend = samples * 10;
+
+        if( disableRx == false ) {
+            xQueueSend( rxQueue, &dataToSend, 0 );
+        }
+        
+        samples = newSamples;
+        newSamples = 0;
+        currValue = value;    
+    }
+
+    //Reset irq and set for next time
+    TIMERG1.int_clr_timers.t1 = 1;
+    TIMERG1.hw_timer[1].config.alarm_en = 1;
+}
+
+static void timerSetupTask(void *pvParameter)
+{
+    rxQueue = xQueueCreate( 1000, sizeof( uint32_t ) );
+
+    timer_config_t config = {
+        .alarm_en = true,				//Alarm Enable
+        .counter_en = false,			//If the counter is enabled it will start incrementing / decrementing immediately after calling timer_init()
+        .intr_type = TIMER_INTR_LEVEL,	//Is interrupt is triggered on timer’s alarm (timer_intr_mode_t)
+        .counter_dir = TIMER_COUNT_UP,	//Does counter increment or decrement (timer_count_dir_t)
+        .auto_reload = true,			//If counter should auto_reload a specific initial value on the timer’s alarm, or continue incrementing or decrementing.
+        .divider = 8   				//Divisor of the incoming 160 MHz (12.5nS) APB_CLK clock. E.g. 800 = 10uS per timer tick
+    };
+
+    timer_init(TIMER_GROUP_1, TIMER_1, &config);
+    timer_set_counter_value(TIMER_GROUP_1, TIMER_1, 0);
+    timer_set_alarm_value(TIMER_GROUP_1, TIMER_1, 100);     // Here we set the ISR-Value
+    timer_enable_intr(TIMER_GROUP_1, TIMER_1);
+    timer_isr_register(TIMER_GROUP_1, TIMER_1, &timer_tg0_isr, NULL, 0, &s_timer_handle);
+
+    timer_start(TIMER_GROUP_1, TIMER_1);
+
+    
+
+    timerTaskIsDone = true;
+    vTaskDelete(NULL);
+}
+
+void rxTimerInit()
+{
+    xTaskCreatePinnedToCore(&timerSetupTask, "timerSetupTask", 8192, NULL, tskIDLE_PRIORITY + 2, NULL, 1);
+
+    // Wait until task has finished
+    while(timerTaskIsDone == false) vTaskDelay( 50 / portTICK_PERIOD_MS );
+
+    ESP_LOGI("rxTimer", "10uS Timer has been started.");
+}
+
+void delayMicroseconds(uint32_t delay)
+{
+	volatile uint32_t endtime = tenUsCounter + ((uint32_t)delay / 10);
+
+	while( tenUsCounter < endtime ) ;
+}
+
+#endif

+ 18 - 0
main/rxTimer.h

@@ -0,0 +1,18 @@
+#ifndef __RX_TIMER__
+#define __RX_TIMER__
+
+#include "freertos/FreeRTOS.h"
+#include "freertos/queue.h"
+#include <stdint.h>
+
+void rxTimerInit();
+
+void delayMicroseconds(uint32_t delay);
+
+extern QueueHandle_t rxQueue;
+
+uint32_t millis();
+
+
+
+#endif

+ 92 - 0
main/transceiver.c

@@ -0,0 +1,92 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <sys/time.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include "esp_sleep.h"
+#include "esp_log.h"
+#include "driver/uart.h"
+#include "driver/rtc_io.h"
+#include "esp_intr_alloc.h"
+#include "esp_attr.h"
+#include "driver/timer.h"
+#include <stddef.h>
+#include "esp_intr_alloc.h"
+
+#include "transceiver.h"
+#include "rxTimer.h"
+#include "config.h"
+
+
+bool disableRx = true; // Controls if trcv is in RX or TX-mode
+
+#ifdef TRANCEIVER_ENABLED
+
+void trcvSendHighLowPulse(uint32_t high, uint32_t low) {
+
+  if( disableRx == false ) return;
+  
+  gpio_set_level(GPIO_TX_DATA, 1);
+  delayMicroseconds( high ); 
+  gpio_set_level(GPIO_TX_DATA, 0);
+  delayMicroseconds( low );  
+}
+
+void initTransceiver() {
+
+    gpio_set_level(GPIO_ENABLE, 0);
+    gpio_set_level(GPIO_TX_ENABLE, 0);
+    gpio_set_level(GPIO_TX_DATA, 0);
+
+    gpio_pad_select_gpio(GPIO_ENABLE);
+    gpio_pad_select_gpio(GPIO_TX_ENABLE);
+    gpio_pad_select_gpio(GPIO_TX_DATA);
+    gpio_pad_select_gpio(GPIO_RX_DATA);
+
+    gpio_set_direction(GPIO_ENABLE, GPIO_MODE_OUTPUT);
+    gpio_set_direction(GPIO_TX_ENABLE, GPIO_MODE_OUTPUT);
+    gpio_set_direction(GPIO_TX_DATA, GPIO_MODE_OUTPUT);
+    gpio_set_direction(GPIO_RX_DATA, GPIO_MODE_INPUT);
+
+    // ------------------ INIT THE TRANCEIVER -------------------------
+    // From powerdown mode (pin 4-5-6 low), 
+    // 1. Drive high pin 6 (ENABLE)
+    // 2. After 20us drive high pin 5 (RX/TX)200us, hold on 40us 
+    // 3. Drive down 20us pin 6 (ENABLE).  
+    gpio_set_level(GPIO_ENABLE, 1); delayMicroseconds( 20 ); 
+    gpio_set_level(GPIO_TX_ENABLE, 1); delayMicroseconds( 200 ); gpio_set_level(GPIO_TX_ENABLE, 0);
+    delayMicroseconds( 40 ); 
+    gpio_set_level(GPIO_ENABLE, 0); delayMicroseconds( 20 ); gpio_set_level(GPIO_ENABLE, 1);  
+    delayMicroseconds( 200 );
+    // ------------------ INIT THE TRANCEIVER -------------------------  
+            
+    ESP_LOGI("TRCV", "Transceiver has been initialized.");
+}
+
+void trcvSwitch2transmit() {
+
+  disableRx = true;
+  // ------------------ GO TO TRANSMIT STATE -------------------------
+  gpio_set_level(GPIO_TX_ENABLE, 1);
+  delayMicroseconds( 400 );
+  // ------------------ GO TO TRANSMIT STATE -------------------------
+}
+
+void trcvSwitch2receive() {
+  // ------------------ GO TO RECEIVE STATE -------------------------
+  // From Transmission Mode to Receiver Mode follow the procedure:
+  // Drive down pin 5 (RX/TX), after 40us drive down pin 6 (ENABLE) 20us long.
+  //After 200 us the device is ready for reception.
+  gpio_set_level(GPIO_TX_ENABLE, 0); 
+  delayMicroseconds( 40 ); 
+  gpio_set_level(GPIO_ENABLE, 0); 
+  delayMicroseconds( 20 ); 
+  gpio_set_level(GPIO_ENABLE, 1);  
+  delayMicroseconds( 200 );
+  // ------------------ GO TO RECEIVE STATE -------------------------
+  disableRx = false;
+}
+
+#endif

+ 30 - 0
main/transceiver.h

@@ -0,0 +1,30 @@
+#ifndef __TRANSCEIVER__
+#define __TRANSCEIVER__
+
+/****************************************************************************************************
+ * The following I/O-Pins are used in the transceiver app:
+ * 
+ * 19	Output ENABLE
+ * 18	Output TX_ENABLE
+ * 17	Output TX_DATA
+ * 16	Input  RX_DATA
+ ****************************************************************************************************/
+
+ #define GPIO_ENABLE        19
+ #define GPIO_TX_ENABLE     18
+ #define GPIO_TX_DATA       17
+ #define GPIO_RX_DATA       16
+
+
+ extern bool disableRx;
+
+
+void initTransceiver();
+
+void trcvSwitch2transmit();
+void trcvSwitch2receive();
+
+void trcvSendHighLowPulse(uint32_t high, uint32_t low);
+
+
+#endif