From 01e9c1b98e4fb032c948ac427573ba2f9cde3e4f Mon Sep 17 00:00:00 2001 From: Felix5721 Date: Mon, 14 Jan 2019 14:53:15 +0100 Subject: [PATCH] add rf433mhz component to extras, for using antenna modules with esp --- examples/rf433mhz/Makefile | 4 + examples/rf433mhz/rf-send-recieve.c | 88 +++++++++++++++++++ extras/rf433mhz/README.md | 35 ++++++++ extras/rf433mhz/component.mk | 9 ++ extras/rf433mhz/rf_433mhz.c | 126 ++++++++++++++++++++++++++++ extras/rf433mhz/rf_433mhz.h | 66 +++++++++++++++ extras/rf433mhz/util.h | 31 +++++++ 7 files changed, 359 insertions(+) create mode 100644 examples/rf433mhz/Makefile create mode 100644 examples/rf433mhz/rf-send-recieve.c create mode 100644 extras/rf433mhz/README.md create mode 100644 extras/rf433mhz/component.mk create mode 100644 extras/rf433mhz/rf_433mhz.c create mode 100644 extras/rf433mhz/rf_433mhz.h create mode 100644 extras/rf433mhz/util.h diff --git a/examples/rf433mhz/Makefile b/examples/rf433mhz/Makefile new file mode 100644 index 0000000..86891e7 --- /dev/null +++ b/examples/rf433mhz/Makefile @@ -0,0 +1,4 @@ +PROGRAM = rf-send-recieve +EXTRA_COMPONENTS = extras/rf433mhz +include ../../common.mk + diff --git a/examples/rf433mhz/rf-send-recieve.c b/examples/rf433mhz/rf-send-recieve.c new file mode 100644 index 0000000..88641ed --- /dev/null +++ b/examples/rf433mhz/rf-send-recieve.c @@ -0,0 +1,88 @@ +//esp sdk +#include "espressif/esp_common.h" +#include "esp/uart.h" + +//rtos +#include "FreeRTOS.h" +#include "task.h" +#include "queue.h" + +//rf 433mhz +#include + +#define TRANSMITTER_PIN 5 +#define RECIEVER_PIN 4 + +reciever_433mhz* reciever; +QueueHandle_t decode_queue; + +void rf433mhz_transmit(void *pvParameters) { + gpio_enable(TRANSMITTER_PIN, GPIO_OUTPUT); + message_433mhz msg; + msg.code_lenght=24; + msg.repeat=2; + msg.pulse_length = 312; + protocol_433mhz proto = protocols_433mhz[PROTO1]; + msg.protocol = &proto; + + while(true) { + msg.data=1364; + send_message_433mhz(TRANSMITTER_PIN, &msg); + vTaskDelay(1000); + msg.data=1361; + send_message_433mhz(TRANSMITTER_PIN, &msg); + vTaskDelay(1000); + } +} + +void recieve_interrupt_handler(uint8_t gpio_num) { + BaseType_t xHigerPriorityTaskTriggerd = pdFALSE; + UBaseType_t uxSavedInterruptStatus; + uxSavedInterruptStatus = taskENTER_CRITICAL_FROM_ISR(); + recieve_on_interrupt(reciever); + if (reciever->repeatCount < 2) { + taskEXIT_CRITICAL_FROM_ISR(uxSavedInterruptStatus); + return; + } + //printf("Function recieve_interrupt_handler recieved going enter critical \n"); + reciever_433mhz* old_reciever = reciever; + reciever = create_reciever_buffer(); + taskEXIT_CRITICAL_FROM_ISR(uxSavedInterruptStatus); + xQueueSendFromISR(decode_queue, &old_reciever, &xHigerPriorityTaskTriggerd); +} + +void rf433mhz_recieve(void *pvParameters) { + //enable reception on recieve pin + gpio_enable(RECIEVER_PIN, GPIO_INPUT); + reciever = create_reciever_buffer(); + gpio_set_interrupt(RECIEVER_PIN, GPIO_INTTYPE_EDGE_ANY, recieve_interrupt_handler); + + reciever_433mhz* recv; + message_433mhz msg; + while(1) { + if(xQueueReceive(decode_queue, &recv, 0) == pdTRUE){ + //try to decode recieved data + bool recieved = false; + for(int i=0; i < PROTOCOL_COUNT ; i++) { + if(decode_recieved(recv, &protocols_433mhz[i], &msg)) { + recieved = true; + printf("Recieved message with data: %d\n", msg.data); + break; + } + //no protcol found to decode data + } + free(recv); + } + } +} + +void user_init(void) { + uart_set_baud(0, 115200); + + decode_queue = xQueueCreate(2, sizeof(reciever_433mhz*)); + + //start tasks + xTaskCreate(rf433mhz_transmit, "transmitter_rf", 256, NULL, 1, NULL); + xTaskCreate(rf433mhz_recieve, "reciever_rf", 256, NULL, 1, NULL); + +} diff --git a/extras/rf433mhz/README.md b/extras/rf433mhz/README.md new file mode 100644 index 0000000..d0b6e1b --- /dev/null +++ b/extras/rf433mhz/README.md @@ -0,0 +1,35 @@ +rf433hmz - A Copyright (c) 2018 Felix Richter + +# About + +This is a simple c library which implements encoding and decoding of various rf protocols for sending and recieving rf transmissions. +It is heavly based on the RC Switch library. It is designed to be used with the esp8266 using open rtos, but it should be very easy to port +to other platforms. + +# Issues + +If you find any bugs, please report them at: https://github.com/Felix5721/rf433mhz + +# License + +rf433hmz is published under the MIT license. + + Copyright © 2018 Felix Richter + + 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. diff --git a/extras/rf433mhz/component.mk b/extras/rf433mhz/component.mk new file mode 100644 index 0000000..aa58998 --- /dev/null +++ b/extras/rf433mhz/component.mk @@ -0,0 +1,9 @@ +# Component makefile for extras/rf433mhz + +# expected anyone using this driver includes it as 'rf433mhz/rf_433mhz.h' +INC_DIRS += $(rf433mhz_ROOT).. + +# args for passing into compile rule generation +rf433mhz_SRC_DIR = $(rf433mhz_ROOT) + +$(eval $(call component_compile_rules,rf433mhz)) diff --git a/extras/rf433mhz/rf_433mhz.c b/extras/rf433mhz/rf_433mhz.c new file mode 100644 index 0000000..903364d --- /dev/null +++ b/extras/rf433mhz/rf_433mhz.c @@ -0,0 +1,126 @@ +#include "rf_433mhz.h" +#include "util.h" + +protocol_433mhz protocols_433mhz[] = { + { { 1, 31 }, { 1, 3 }, { 3, 1 }, false }, // protocol 1 + { { 1, 10 }, { 1, 2 }, { 2, 1 }, false }, // protocol 2 + { { 30, 71 }, { 4, 11 }, { 9, 6 }, false }, // protocol 3 + { { 1, 6 }, { 1, 3 }, { 3, 1 }, false }, // protocol 4 + { { 6, 14 }, { 1, 2 }, { 2, 1 }, false }, // protocol 5 + { { 23, 1 }, { 1, 2 }, { 2, 1 }, true }, // protocol 6 (HT6P20B) + { { 2, 62 }, { 1, 6 }, { 6, 1 }, false } // protocol 7 (HS2303-PT, i. e. used in AUKEY Remote) +}; + +static inline unsigned int diff(int A, int B) { + return abs(A - B); +} + +//Transmit single pulse meaning 1 or 0 or sync +void transmit(uint8_t pin, protocol_433mhz* proto, pulse_t pulse_params, uint16_t pulse_length) { + bool firstLogicLevel = proto->inverted ? 0 : 1; + bool secondLogicLevel = proto->inverted ? 1 : 0; + + setPinDigital(pin, firstLogicLevel); + delayMicroSec(pulse_length * pulse_params.high_time); + setPinDigital(pin, secondLogicLevel); + delayMicroSec(pulse_length * pulse_params.low_time); +} + +void send_message_433mhz(uint8_t pin, message_433mhz* msg) { + disableInterrupts(); + for (uint8_t n_repeat=0; n_repeat < msg->repeat; n_repeat++) { + for(int i = msg->code_lenght-1; i>=0; i--) { + if ( msg->data & (1L << i) ) { + transmit(pin, msg->protocol, msg->protocol->one, msg->pulse_length); + } else { + transmit(pin, msg->protocol, msg->protocol->zero, msg->pulse_length); + } + } + transmit(pin, msg->protocol, msg->protocol->sync, msg->pulse_length); + } + //make sure antenna is powered off + setPinDigital(pin, 0); + enableInterrupts(); +} + +void recieve_on_interrupt(reciever_433mhz* reciever) { + long time = getMicroSec(); + unsigned int duration = time - reciever->last_time; + + if (duration > reciever->seperation_limit) { + //long stretch without change -> might be gap between transmittions + if ( diff(duration, reciever->timeings[0]) < 200 ) { + //this long singal is close in length to the previous recorded signals + reciever->repeatCount++; + return; + } else { + reciever->changeCount = 0; + } + } + + if ( reciever->changeCount >= RECIEVE_MAX_BUFFER_LEN ) { + reciever->changeCount = 0; + reciever->repeatCount = 0; + } + + reciever->timeings[reciever->changeCount++] = duration; + reciever->last_time = time; +} + +bool decode_recieved(reciever_433mhz* reciever, protocol_433mhz* proto, message_433mhz* msg) { + msg->data = 0; + unsigned int sync_len = (proto->sync.low_time > proto->sync.high_time) ? proto->sync.low_time : proto->sync.high_time; + unsigned int delay = reciever->timeings[0]/sync_len; + unsigned int delay_tolerance = delay * reciever->recieve_tolerance /100; + /* For protocols that start low, the sync period looks like + * _________ + * _____________| |XXXXXXXXXXXX| + * + * |--1st dur--|-2nd dur-|-Start data-| + * + * The 3rd saved duration starts the data. + * + * For protocols that start high, the sync period looks like + * + * ______________ + * | |____________|XXXXXXXXXXXXX| + * + * |-filtered out-|--1st dur--|--Start data--| + * + * The 2nd saved duration starts the data + */ + unsigned int firstdata = proto->inverted ? 2 : 1; + for (unsigned int i = firstdata; i < reciever->changeCount-1; i+=2) { + msg->data <<= 1; + if ( diff(reciever->timeings[i], delay*proto->zero.high_time) < delay_tolerance && + diff(reciever->timeings[i+1], delay*proto->zero.low_time) < delay_tolerance ){ + //recieved zero + } else if ( diff(reciever->timeings[i], delay*proto->one.high_time) < delay_tolerance && + diff(reciever->timeings[i+1], delay*proto->one.low_time) < delay_tolerance ) { + //recieved one + msg->data |= 1; + } else { + //Failed to decode data with given protocol + return false; + } + } + if (reciever->changeCount > 7) { + msg->code_lenght = (reciever->changeCount -1)/2; + msg->protocol = proto; + msg->pulse_length = delay; + return true; + } + return false; +} + +reciever_433mhz* create_reciever_buffer() { + reciever_433mhz* reciever = malloc(sizeof(reciever_433mhz)); + reciever->recieve_tolerance = RECIEVE_TOLERANCE_433MHZ; + reciever->seperation_limit = SEPERATION_LIMIT_433MHZ; + reciever->changeCount = 0; + reciever->repeatCount = 0; + reciever->last_time = getMicroSec(); + reciever->recieve_len = 0; + memset(&reciever->timeings, 0, RECIEVE_MAX_BUFFER_LEN); + return reciever; +} diff --git a/extras/rf433mhz/rf_433mhz.h b/extras/rf433mhz/rf_433mhz.h new file mode 100644 index 0000000..76ddd64 --- /dev/null +++ b/extras/rf433mhz/rf_433mhz.h @@ -0,0 +1,66 @@ +#ifndef rf_h_INCLUDED +#define rf_h_INCLUDED + +#include +#include + +#define RECIEVE_MAX_BUFFER_LEN 67 +#define SEPERATION_LIMIT_433MHZ 5000 +#define RECIEVE_TOLERANCE_433MHZ 60 + +/* + * This is a pure c reimplemnation of the rc swich library, it was build to be used with open rtos + * Copyright: Felix Richter 2018 + */ + + +typedef struct{ + uint8_t high_time; + uint8_t low_time; +} pulse_t; + +typedef struct{ + pulse_t sync; + pulse_t zero; + pulse_t one; + bool inverted; +} protocol_433mhz; + +typedef struct{ + uint32_t data; + unsigned int code_lenght; + protocol_433mhz* protocol; + uint16_t pulse_length; + uint8_t repeat; +} message_433mhz; + +typedef struct{ + uint16_t recieve_len; + unsigned long last_time; + unsigned int changeCount; + unsigned int repeatCount; + unsigned int seperation_limit; + unsigned int recieve_tolerance; + unsigned int timeings[RECIEVE_MAX_BUFFER_LEN]; +} reciever_433mhz; + +void send_message_433mhz(uint8_t pin, message_433mhz* msg); +void recieve_on_interrupt(reciever_433mhz* reciever); +bool decode_recieved(reciever_433mhz* reciever, protocol_433mhz* proto, message_433mhz* msg); +reciever_433mhz* create_reciever_buffer(); + +extern protocol_433mhz protocols_433mhz[]; + +typedef enum { + PROTO1, + PROTO2, + PROTO3, + PROTO4, + PROTO5, + PROTO6, + PROTO7, + PROTOCOL_COUNT +} protocol_name_433mhz; + +#endif // rf_h_INCLUDED + diff --git a/extras/rf433mhz/util.h b/extras/rf433mhz/util.h new file mode 100644 index 0000000..ef9d576 --- /dev/null +++ b/extras/rf433mhz/util.h @@ -0,0 +1,31 @@ +#ifndef util_h_INCLUDED +#define util_h_INCLUDED + +#include "espressif/esp_common.h" +#include "espressif/esp_misc.h" +#include "esp8266.h" +#include "FreeRTOS.h" +#include "task.h" + +void delayMicroSec(uint16_t us) { + sdk_os_delay_us(us); +} + +void setPinDigital(uint8_t pin, bool value) { + gpio_write(pin, value); +} + +unsigned long getMicroSec() { + return sdk_system_get_time(); +} + +void disableInterrupts() { + taskENTER_CRITICAL(); +} + +void enableInterrupts() { + taskEXIT_CRITICAL(); +} + +#endif // util_h_INCLUDED +