This commit is contained in:
Alexey Zholtikov 2024-05-14 16:11:08 +03:00
parent dfe2a84bb3
commit f996a6c86f
86 changed files with 5235 additions and 0 deletions

View File

@ -0,0 +1 @@
idf_component_register(SRCS "zh_rf24.c" INCLUDE_DIRS "include" REQUIRES driver)

View File

@ -0,0 +1,59 @@
//Receiver program
#include "Mirf.h"
#include "printf.h"
Nrf24l Mirf = Nrf24l(10, 9); // CE,CSN
union MYDATA_t {
byte value[32];
char now_time[32];
};
MYDATA_t mydata;
void setup()
{
Serial.begin(115200);
Mirf.spi = &MirfHardwareSpi;
Mirf.init();
Mirf.payload = sizeof(mydata.value); // Set the payload size
Mirf.channel = 90; // Set the used channel
Mirf.config();
// Set my own address to RX_ADDR_P1
Mirf.setRADDR((byte *)"1RECV");
// Add my own address to RX_ADDR_P2
Mirf.addRADDR(2, '2'); // 2RECV
// Add my own address to RX_ADDR_P3
Mirf.addRADDR(3, '3'); // 3RECV
// Add my own address to RX_ADDR_P4
Mirf.addRADDR(4, '4'); // 4RECV
// Add my own address to RX_ADDR_P5
Mirf.addRADDR(5, '5'); // 5RECV
// Clear RX FiFo
while(1) {
if (Mirf.dataReady() == false) break;
Mirf.getData(mydata.value);
}
// Print current settings
printf_begin();
Mirf.printDetails();
Serial.println("Listening...");
}
void loop()
{
// Wait for received data
if (Mirf.dataReady()) {
uint8_t pipe = Mirf.getDataPipe();
Mirf.getData(mydata.value);
Serial.print("Got data pipe(");
Serial.print(pipe);
Serial.print(") is: ");
Serial.println(mydata.now_time);
}
delay(1);
}

View File

@ -0,0 +1,37 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* @file printf.h
*
* Setup necessary to direct stdout to the Arduino Serial library, which
* enables 'printf'
*/
#ifndef __PRINTF_H__
#define __PRINTF_H__
#ifdef ARDUINO
int serial_putc( char c, FILE * )
{
Serial.write( c );
return c;
}
void printf_begin(void)
{
fdevopen( &serial_putc, 0 );
}
#else
#error This example is only for use on Arduino.
#endif // ARDUINO
#endif // __PRINTF_H__

View File

@ -0,0 +1,41 @@
//Transmitter program
#include "Mirf.h"
Nrf24l Mirf = Nrf24l(10, 9); // CE,CSN
union MYDATA_t {
byte value[32];
char now_time[32];
};
MYDATA_t mydata;
void setup()
{
Serial.begin(115200);
Mirf.spi = &MirfHardwareSpi;
Mirf.init();
Mirf.payload = sizeof(mydata.value); // Set the payload size
Mirf.channel = 90; // Set the channel used
Mirf.config();
// Set destination address to TX_ADDR
// Set ACK waiting address to RX_ADDR_P0
Mirf.setTADDR((byte *)"1RECV");
}
void loop()
{
sprintf(mydata.now_time,"now is %lu", micros());
Mirf.send(mydata.value);
Serial.print("Wait for sending.....");
// Verify send was successful
if (Mirf.isSend()) {
Serial.print("Send success:");
Serial.println(mydata.now_time);
} else {
Serial.println("Send fail:");
}
delay(1000);
}

View File

@ -0,0 +1,41 @@
//Transmitter program
#include "Mirf.h"
Nrf24l Mirf = Nrf24l(10, 9); // CE,CSN
union MYDATA_t {
byte value[32];
char now_time[32];
};
MYDATA_t mydata;
void setup()
{
Serial.begin(115200);
Mirf.spi = &MirfHardwareSpi;
Mirf.init();
Mirf.payload = sizeof(mydata.value); // Set the payload size
Mirf.channel = 90; // Set the channel used
Mirf.config();
// Set destination address to TX_ADDR
// Set ACK waiting address to RX_ADDR_P0
Mirf.setTADDR((byte *)"2RECV");
}
void loop()
{
sprintf(mydata.now_time,"now is %lu",micros());
Mirf.send(mydata.value);
Serial.print("Wait for sending.....");
// Verify send was successful
if (Mirf.isSend()) {
Serial.print("Send success:");
Serial.println(mydata.now_time);
} else {
Serial.println("Send fail:");
}
delay(1000);
}

View File

@ -0,0 +1,41 @@
//Transmitter program
#include "Mirf.h"
Nrf24l Mirf = Nrf24l(10, 9); // CE,CSN
union MYDATA_t {
byte value[32];
char now_time[32];
};
MYDATA_t mydata;
void setup()
{
Serial.begin(115200);
Mirf.spi = &MirfHardwareSpi;
Mirf.init();
Mirf.payload = sizeof(mydata.value); // Set the payload size
Mirf.channel = 90; // Set the channel used
Mirf.config();
// Set destination address to TX_ADDR
// Set ACK waiting address to RX_ADDR_P0
Mirf.setTADDR((byte *)"3RECV");
}
void loop()
{
sprintf(mydata.now_time,"now is %lu",micros());
Mirf.send(mydata.value);
Serial.print("Wait for sending.....");
// Verify send was successful
if (Mirf.isSend()) {
Serial.print("Send success:");
Serial.println(mydata.now_time);
} else {
Serial.println("Send fail:");
}
delay(1000);
}

View File

@ -0,0 +1,41 @@
//Transmitter program
#include "Mirf.h"
Nrf24l Mirf = Nrf24l(10, 9); // CE,CSN
union MYDATA_t {
byte value[32];
char now_time[32];
};
MYDATA_t mydata;
void setup()
{
Serial.begin(115200);
Mirf.spi = &MirfHardwareSpi;
Mirf.init();
Mirf.payload = sizeof(mydata.value); // Set the payload size
Mirf.channel = 90; // Set the channel used
Mirf.config();
// Set destination address to TX_ADDR
// Set ACK waiting address to RX_ADDR_P0
Mirf.setTADDR((byte *)"4RECV");
}
void loop()
{
sprintf(mydata.now_time,"now is %lu",micros());
Mirf.send(mydata.value);
Serial.print("Wait for sending.....");
// Verify send was successful
if (Mirf.isSend()) {
Serial.print("Send success:");
Serial.println(mydata.now_time);
} else {
Serial.println("Send fail:");
}
delay(1000);
}

View File

@ -0,0 +1,41 @@
//Transmitter program
#include "Mirf.h"
Nrf24l Mirf = Nrf24l(10, 9); // CE,CSN
union MYDATA_t {
byte value[32];
char now_time[32];
};
MYDATA_t mydata;
void setup()
{
Serial.begin(115200);
Mirf.spi = &MirfHardwareSpi;
Mirf.init();
Mirf.payload = sizeof(mydata.value); // Set the payload size
Mirf.channel = 90; // Set the channel used
Mirf.config();
// Set destination address to TX_ADDR
// Set ACK waiting address to RX_ADDR_P0
Mirf.setTADDR((byte *)"5RECV");
}
void loop()
{
sprintf(mydata.now_time,"now is %lu",micros());
Mirf.send(mydata.value);
Serial.print("Wait for sending.....");
// Verify send was successful
if (Mirf.isSend()) {
Serial.print("Send success:");
Serial.println(mydata.now_time);
} else {
Serial.println("Send fail:");
}
delay(1000);
}

View File

@ -0,0 +1,57 @@
//Transmitter program
#include "Mirf.h"
Nrf24l Mirf = Nrf24l(10, 9); // CE,CSN
struct Pack {
byte index;
char payload[31];
};
#define PackSize sizeof(Pack)
union MYDATA_t {
byte value[PackSize];
struct Pack pack;
};
MYDATA_t mydata;
void setup()
{
Serial.begin(115200);
Mirf.spi = &MirfHardwareSpi;
Mirf.init();
Mirf.payload = sizeof(mydata.value); // Set the payload size
Mirf.channel = 90; // Set the channel used
Mirf.config();
// Set destination address to TX_ADDR
// Set ACK waiting address to RX_ADDR_P0
Mirf.setTADDR((byte *)"FGHIJ");
}
void loop()
{
static int payload = 0x41; // 'A'
mydata.pack.index = payload - 0x41; // 0
for (int i=0;i<30;i++) {
mydata.pack.payload[i] = payload;
}
mydata.pack.payload[30] = 0;
Mirf.send(mydata.value);
Serial.print("Wait for sending.....");
// Verify send was successfuly
if (Mirf.isSend()) {
Serial.print("Send success:");
Serial.println(mydata.pack.index);
payload++;
if(payload == 0x7e) {
payload = 0x41;
}
} else {
Serial.println("Send fail:");
}
delay(1000);
}

View File

@ -0,0 +1,19 @@
# Peer-to-peer Communication
nRF24L01 can send and receive up to 32 characters, but by adding an index to the sent data, it can send and receive 256 types of data.
```
Listening...
Got index=7 payload=HHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
Got index=8 payload=IIIIIIIIIIIIIIIIIIIIIIIIIIIIII
Got index=9 payload=JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ
Got index=10 payload=KKKKKKKKKKKKKKKKKKKKKKKKKKKKKK
Got index=11 payload=LLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
Got index=12 payload=MMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
Got index=13 payload=NNNNNNNNNNNNNNNNNNNNNNNNNNNNNN
Got index=14 payload=OOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
Got index=15 payload=PPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
Got index=16 payload=QQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ
Got index=17 payload=RRRRRRRRRRRRRRRRRRRRRRRRRRRRRR
```

View File

@ -0,0 +1,51 @@
//Receiver program
#include "Mirf.h"
Nrf24l Mirf = Nrf24l(10, 9); // CE,CSN
struct Pack {
byte index;
char payload[31];
};
#define PackSize sizeof(Pack)
union MYDATA_t {
byte value[PackSize];
struct Pack pack;
};
MYDATA_t mydata;
void setup()
{
Serial.begin(115200);
Mirf.spi = &MirfHardwareSpi;
Mirf.init();
Mirf.payload = sizeof(mydata.value); // Set the payload size
Mirf.channel = 90; // Set the used channel
Mirf.config();
// Set my own address to RX_ADDR_P1
Mirf.setRADDR((byte *)"FGHIJ");
// Clear RX FiFo
while(1) {
if (Mirf.dataReady() == false) break;
Mirf.getData(mydata.value);
}
Serial.println("Listening...");
}
void loop()
{
// Wait for received data
if (Mirf.dataReady()) {
Mirf.getData(mydata.value);
Serial.print("Got index=");
Serial.print(mydata.pack.index);
Serial.print(" payload=");
Serial.println(mydata.pack.payload);
}
}

View File

@ -0,0 +1,41 @@
//Transmitter program
#include "Mirf.h"
Nrf24l Mirf = Nrf24l(10, 9); // CE,CSN
union MYDATA_t {
byte value[32];
char now_time[32];
};
MYDATA_t mydata;
void setup()
{
Serial.begin(115200);
Mirf.spi = &MirfHardwareSpi;
Mirf.init();
Mirf.payload = sizeof(mydata.value); // Set the payload size
Mirf.channel = 90; // Set the channel used
Mirf.config();
// Set destination address to TX_ADDR
// Set ACK waiting address to RX_ADDR_P0
Mirf.setTADDR((byte *)"FGHIJ");
}
void loop()
{
sprintf(mydata.now_time,"now is %lu",micros());
Mirf.send(mydata.value);
Serial.print("Wait for sending.....");
// Verify send was successfuly
if (Mirf.isSend()) {
Serial.print("Send success:");
Serial.println(mydata.now_time);
} else {
Serial.println("Send fail:");
}
delay(1000);
}

View File

@ -0,0 +1,42 @@
//Receiver program
#include "Mirf.h"
Nrf24l Mirf = Nrf24l(10, 9); // CE,CSN
union MYDATA_t {
byte value[32];
char now_time[32];
};
MYDATA_t mydata;
void setup()
{
Serial.begin(115200);
Mirf.spi = &MirfHardwareSpi;
Mirf.init();
Mirf.payload = sizeof(mydata.value); // Set the payload size
Mirf.channel = 90; // Set the used channel
Mirf.config();
// Set my own address to RX_ADDR_P1
Mirf.setRADDR((byte *)"FGHIJ");
// Clear RX FiFo
while(1) {
if (Mirf.dataReady() == false) break;
Mirf.getData(mydata.value);
}
Serial.println("Listening...");
}
void loop()
{
// Wait for received data
if (Mirf.dataReady()) {
Mirf.getData(mydata.value);
Serial.print("Got string: ");
Serial.println(mydata.now_time);
}
}

View File

@ -0,0 +1,71 @@
//primary program
#include "Mirf.h"
#include "printf.h"
Nrf24l Mirf = Nrf24l(10, 9); // CE,CSN
union MYDATA_t {
byte value[32];
char now_time[32];
};
MYDATA_t mydata;
void setup()
{
Serial.begin(115200);
Mirf.spi = &MirfHardwareSpi;
Mirf.init();
Mirf.payload = sizeof(mydata.value); // Set the payload size
Mirf.channel = 90; //Set the channel used
Mirf.config();
// Set my own address to RX_ADDR_P1
Mirf.setRADDR((byte *)"ABCDE");
// Set destination address to TX_ADDR
// Set ACK waiting address to RX_ADDR_P0
Mirf.setTADDR((byte *)"FGHIJ");
// Print current settings
printf_begin();
Mirf.printDetails();
// Clear RX FiFo
while(1) {
if (Mirf.dataReady() == false) break;
Mirf.getData(mydata.value);
}
}
void loop()
{
sprintf(mydata.now_time,"now is %lu",micros());
unsigned long startMillis = millis();
Mirf.send(mydata.value);
Serial.print("Wait for sending.....");
// Verify send was successful
if (Mirf.isSend()) {
Serial.print("Send success:");
Serial.println(mydata.now_time);
// Wait for received data
Serial.print("Wait for response.....");
while(1) {
if (Mirf.dataReady()) break;
}
Mirf.getData(mydata.value);
unsigned long diffMillis = millis() - startMillis;
Serial.print("Got response:");
Serial.print(mydata.now_time);
Serial.print(" Elapsed:");
Serial.print(diffMillis);
Serial.println(" mSec");
} else {
Serial.println("Send fail:");
}
delay(1000);
}

View File

@ -0,0 +1,37 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* @file printf.h
*
* Setup necessary to direct stdout to the Arduino Serial library, which
* enables 'printf'
*/
#ifndef __PRINTF_H__
#define __PRINTF_H__
#ifdef ARDUINO
int serial_putc( char c, FILE * )
{
Serial.write( c );
return c;
}
void printf_begin(void)
{
fdevopen( &serial_putc, 0 );
}
#else
#error This example is only for use on Arduino.
#endif // ARDUINO
#endif // __PRINTF_H__

View File

@ -0,0 +1,9 @@
# PingPong
```
Primary -----> Secondary
Primary <----- Secondary
```
![PingPong](https://user-images.githubusercontent.com/6020549/149616366-3e2cbce7-6a60-4ac8-8ce3-5f2ecdc2726a.jpg)

View File

@ -0,0 +1,63 @@
//secondary program
#include "Mirf.h"
#include "printf.h"
Nrf24l Mirf = Nrf24l(10, 9); // CE,CSN
union MYDATA_t {
byte value[32];
char now_time[32];
};
MYDATA_t mydata;
void setup()
{
Serial.begin(115200);
Mirf.spi = &MirfHardwareSpi;
Mirf.init();
Mirf.payload = sizeof(mydata.value); // Set the payload size
Mirf.channel = 90; // Set the used channel
Mirf.config();
// Set my own address to RX_ADDR_P1
Mirf.setRADDR((byte *)"FGHIJ");
// Set destination address to TX_ADDR
// Set ACK waiting address to RX_ADDR_P0
Mirf.setTADDR((byte *)"ABCDE");
// Print current settings
printf_begin();
Mirf.printDetails();
Serial.println("Listening...");
// Clear RX FiFo
while(1) {
if (Mirf.dataReady() == false) break;
Mirf.getData(mydata.value);
}
}
void loop()
{
// Wait for received data
if (Mirf.dataReady()) {
Mirf.getData(mydata.value);
Serial.print("Got string: ");
Serial.println(mydata.now_time);
delay(10);
Mirf.send(mydata.value);
Serial.print("Wait for sending.....");
// Verify send was successful
if (Mirf.isSend()) {
Serial.println("Send success:");
} else {
Serial.println("Send fail:");
}
}
}

View File

@ -0,0 +1,37 @@
/*
Copyright (C) 2011 J. Coliz <maniacbug@ymail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
version 2 as published by the Free Software Foundation.
*/
/**
* @file printf.h
*
* Setup necessary to direct stdout to the Arduino Serial library, which
* enables 'printf'
*/
#ifndef __PRINTF_H__
#define __PRINTF_H__
#ifdef ARDUINO
int serial_putc( char c, FILE * )
{
Serial.write( c );
return c;
}
void printf_begin(void)
{
fdevopen( &serial_putc, 0 );
}
#else
#error This example is only for use on Arduino.
#endif // ARDUINO
#endif // __PRINTF_H__

View File

@ -0,0 +1,28 @@
# Arduino code for nRF24L01
### Wirering
|nRF24L01||ATMega328|ATMega2560|ESP8266||
|:-:|:-:|:-:|:-:|:-:|:-:|
|VCC|--|3.3V|3.3V|3.3V|(*1)|
|GND|--|GND|GND|GND||
|MISO|--|D12|IO50|IO12||
|MOSI(*2)|--|D11|IO51|IO13||
|SCK(*2)|--|D13|IO52|IO14||
|CE(*2)|--|D10|IO10|IO15|(*3)|
|CSN(*2)|--|D9|IO9|IO16|(*3)|
(*1)
UNO's 3.3V output can only supply 50mA.
In addition, the output current capacity of UNO-compatible devices is smaller than that of official products.
__So nRF24L01 may not work normally when supplied from the on-board 3v3__.
nRF24L01+PA+LNA(nRF24L01+RFX24C01) needs 115mA.
You will need to power it from the 5V pin using a regulator.
(*2)
These pins are 5V Tolerant and can accept up to 5.25V.
(*3)
These pins can be changed in the sketch.

View File

@ -0,0 +1,8 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS ../components/mirf)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(mirf)

View File

@ -0,0 +1,53 @@
# IRQ Detection Example
Use IRQ to detect transmission completion and reception completion.
# About the nrf24l01 assertion
nrf24l01 has three assertions.
- MAX_RT
- RX_DR
- TX_DS
![Enhanced-Shokburst-1](https://user-images.githubusercontent.com/6020549/216748353-9028e1c9-0ec3-45fa-a13e-bfeabb42db86.jpg)
After the packet is transmitted by the PTX and received by the PRX the ACK packet with payload is transmitted from the PRX to the PTX.
The RX_DR IRQ is asserted after the packet is received by the PRX, whereas on the PTX side the TX_DS IRQ is asserted when the ACK packet is received by the PTX.
On the PRX side, the TX_DS IRQ for the ACK packet payload is asserted after a new packet from PTX is received.
![Enhanced-Shokburst-2](https://user-images.githubusercontent.com/6020549/216748358-5264affc-6f7c-4f44-b8b8-23e0e30ddef1.jpg)
the ACK packet is lost and a retransmission is needed before the TX_DS IRQ is asserted, but the RX_DR IRQ is asserted immediately.
MAX_RT IRQ is asserted if the auto retransmit counter(ARC_CNT) exceeds the programmed maximum limit(ARC).
See the nrf24l01 datasheet for more details.
This project treats RX_DR as received completion.
This project treats MAX_RT as transmission failure.
Therefore, if there is no assertion after the transmission, the transmission succeeds, and if there is an assertion, the transmission fails.
This project does not deal with TX_DS.
# Configuration
![config-top](https://github.com/nopnop2002/esp-idf-mirf/assets/6020549/3aabd6f8-7477-4b71-b6c4-950d18402a87)
![config-app](https://github.com/nopnop2002/esp-idf-mirf/assets/6020549/01c6e755-05b1-43e7-90d5-c0eb063f5b82)
# Wirering
__For this project we need one more connection for IRQ detection.__
|nRF24L01||ESP32|ESP32-S2/S3|ESP32-C2/C3/C6||
|:-:|:-:|:-:|:-:|:-:|:-:|
|MISO|--|GPIO19|GPIO37|GPIO4|(*1)|
|MOSI|--|GPIO23|GPIO35|GPIO3|(*1)|
|SCK|--|GPIO18|GPIO36|GPIO2|(*1)|
|CE|--|GPIO16|GPIO34|GPIO1|(*1)|
|CSN|--|GPIO17|GPIO33|GPIO0|(*1)|
|IRQ|--|GPIO15|GPIO38|GPIO5|(*1)|
|GND|--|GND|GND|GND||
|VCC|--|3.3V|3.3V|3.3V||
(*1)You can change it to any pin using menuconfig.
__IRQ needs to be able to use interrupts.__
__Some GPIOs cannot use interrupts.__
# Communicat with Arduino Environment
Run this sketch.
ArduinoCode\Peer-to-peer\StringTest

View File

@ -0,0 +1,4 @@
set(component_srcs "main.c")
idf_component_register(SRCS "${component_srcs}"
INCLUDE_DIRS ".")

View File

@ -0,0 +1,39 @@
menu "Application Configuration"
config GPIO_RANGE_MAX
int
default 33 if IDF_TARGET_ESP32
default 46 if IDF_TARGET_ESP32S2
default 48 if IDF_TARGET_ESP32S3
default 18 if IDF_TARGET_ESP32C2
default 19 if IDF_TARGET_ESP32C3
default 30 if IDF_TARGET_ESP32C6
choice DIRECTION
prompt "Communication polarity"
default SENDER
help
Select Communication polarity.
config SENDER
bool "As the sender"
help
As the sender.
config RECEIVER
bool "As the receiver"
help
As the receiver.
endchoice
config IRQ_GPIO
int "IRQ GPIO number"
range 0 GPIO_RANGE_MAX
default 15 if IDF_TARGET_ESP32
default 38 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
default 5 # C3 and others
help
GPIO number (IOxx) to IRQ.
Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to MISO.
On the ESP32, GPIOs 35-39 are input-only so cannot be used as outputs.
On the ESP32-S2, GPIO 46 is input-only so cannot be used as outputs.
endmenu

View File

@ -0,0 +1,5 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

View File

@ -0,0 +1,181 @@
/* Mirf Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_log.h"
#include "driver/gpio.h"
#include "mirf.h"
static QueueHandle_t gpio_evt_queue = NULL;
#define GPIO_INPUT_PIN_SEL (1ULL<<CONFIG_IRQ_GPIO)
#define ESP_INTR_FLAG_DEFAULT 0
#if CONFIG_ADVANCED
void AdvancedSettings(NRF24_t * dev)
{
#if CONFIG_RF_RATIO_2M
ESP_LOGW(pcTaskGetName(0), "Set RF Data Ratio to 2MBps");
Nrf24_SetSpeedDataRates(dev, 1);
#endif // CONFIG_RF_RATIO_2M
#if CONFIG_RF_RATIO_1M
ESP_LOGW(pcTaskGetName(0), "Set RF Data Ratio to 1MBps");
Nrf24_SetSpeedDataRates(dev, 0);
#endif // CONFIG_RF_RATIO_2M
#if CONFIG_RF_RATIO_250K
ESP_LOGW(pcTaskGetName(0), "Set RF Data Ratio to 250KBps");
Nrf24_SetSpeedDataRates(dev, 2);
#endif // CONFIG_RF_RATIO_2M
ESP_LOGW(pcTaskGetName(0), "CONFIG_RETRANSMIT_DELAY=%d", CONFIG_RETRANSMIT_DELAY);
Nrf24_setRetransmitDelay(dev, CONFIG_RETRANSMIT_DELAY);
}
#endif // CONFIG_ADVANCED
// GPIO interrupt handler
static void IRAM_ATTR gpio_isr_handler(void* arg)
{
uint32_t gpio_num = (uint32_t) arg;
xQueueSendFromISR(gpio_evt_queue, &gpio_num, NULL);
}
#if CONFIG_RECEIVER
void receiver(void *pvParameters)
{
ESP_LOGI(pcTaskGetName(0), "Start");
NRF24_t dev;
Nrf24_init(&dev);
uint8_t payload = 32;
uint8_t channel = CONFIG_RADIO_CHANNEL;
Nrf24_config(&dev, channel, payload);
// Set my own address using 5 characters
esp_err_t ret = Nrf24_setRADDR(&dev, (uint8_t *)"FGHIJ");
if (ret != ESP_OK) {
ESP_LOGE(pcTaskGetName(0), "nrf24l01 not installed");
while(1) { vTaskDelay(1); }
}
#if CONFIG_ADVANCED
AdvancedSettings(&dev);
#endif // CONFIG_ADVANCED
// Print settings
Nrf24_printDetails(&dev);
ESP_LOGI(pcTaskGetName(0), "Listening...");
uint8_t buf[32];
// Clear RX FiFo
while(1) {
if (Nrf24_dataReady(&dev) == false) break;
Nrf24_getData(&dev, buf);
}
uint32_t io_num;
while(1) {
// Wait for assertion of RX receive complete(RX_DR)
if(xQueueReceive(gpio_evt_queue, &io_num, portMAX_DELAY)) {
ESP_LOGD(pcTaskGetName(0), "GPIO[%"PRIu32"] intr, val: %d", io_num, gpio_get_level(io_num));
Nrf24_getData(&dev, buf);
ESP_LOGI(pcTaskGetName(0), "Got data:%s", buf);
}
}
}
#endif // CONFIG_RECEIVER
#if CONFIG_SENDER
void sender(void *pvParameters)
{
ESP_LOGI(pcTaskGetName(0), "Start");
NRF24_t dev;
Nrf24_init(&dev);
uint8_t payload = 32;
uint8_t channel = CONFIG_RADIO_CHANNEL;
Nrf24_config(&dev, channel, payload);
// Set destination address using 5 characters
esp_err_t ret = Nrf24_setTADDR(&dev, (uint8_t *)"FGHIJ");
if (ret != ESP_OK) {
ESP_LOGE(pcTaskGetName(0), "nrf24l01 not installed");
while(1) { vTaskDelay(1); }
}
#if CONFIG_ADVANCED
AdvancedSettings(&dev);
#endif // CONFIG_ADVANCED
//Print settings
Nrf24_printDetails(&dev);
uint8_t buf[32];
uint32_t io_num;
while(1) {
TickType_t nowTick = xTaskGetTickCount();
sprintf((char *)buf, "Hello World %"PRIu32, nowTick);
Nrf24_send(&dev, buf);
ESP_LOGI(pcTaskGetName(0), "Wait for sending.....");
// Wait for assertion of TX transmit retry over(MAX_RT)
if(xQueueReceive(gpio_evt_queue, &io_num, 1000/portTICK_PERIOD_MS)) {
ESP_LOGW(pcTaskGetName(0),"Send fail:");
// Assert does not occur after successful transmission
} else {
ESP_LOGD(pcTaskGetName(0), "GPIO[%"PRIu32"] intr, val: %d", io_num, gpio_get_level(io_num));
ESP_LOGI(pcTaskGetName(0),"Send success:%s", buf);
}
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
#endif // CONFIG_SENDER
void app_main(void)
{
// Initialize gpio
//zero-initialize the config structure.
gpio_config_t io_conf = {};
//interrupt of falling edge
io_conf.intr_type = GPIO_INTR_NEGEDGE;
//bit mask of the pins, use GPIO4/5 here
io_conf.pin_bit_mask = GPIO_INPUT_PIN_SEL;
//set as input mode
io_conf.mode = GPIO_MODE_INPUT;
//enable pull-up mode
io_conf.pull_up_en = 1;
gpio_config(&io_conf);
//install gpio isr service
gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT);
//hook isr handler for specific gpio pin
gpio_isr_handler_add(CONFIG_IRQ_GPIO, gpio_isr_handler, (void*) CONFIG_IRQ_GPIO);
//create a queue to handle gpio event from isr
gpio_evt_queue = xQueueCreate(10, sizeof(uint32_t));
#if CONFIG_RECEIVER
xTaskCreate(&receiver, "RECEIVER", 1024*3, NULL, 2, NULL);
#endif
#if CONFIG_SENDER
xTaskCreate(&sender, "SENDER", 1024*3, NULL, 2, NULL);
#endif
}

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 nopnop2002
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.

View File

@ -0,0 +1,8 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS ../components/mirf)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(mirf)

View File

@ -0,0 +1,42 @@
# Multiple Receive Example
The nRF24L01 has 6 receive data pipes (RX_ADDR_P0-P6).
In this library, the first data pipe(RX_ADDR_P0) is used for automatic ACK reception on transmission.
The second(RX_ADDR_P1) to sixth(RX_ADDR_P5) data pipes are used for data reception.
Therefore, it is possible to receive from a maximum of five transmitting sides.
This example receive from ```1RECV/2RECV/3RECV/4RECV/5RECV```.
# nRF24L01 Address Register Setting
|Sender|||||Receiver||||||
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|#1|TX_ADDR<br>"1RECV"|RX_ADDR_P0<br>"1RECV"|RX_ADDR_P1<br>NONE||TX_ADDR<br>NONE|RX_ADDR_P0<br>NONE|RX_ADDR_P1<br>"1RECV"|RX_ADDR_P2<br>"2RECV"|RX_ADDR_P5<br>"5RECV"||
||(Send Data)|->|->|->|->|->|(Get Data)|||Data to Receiver|
|||(Get Ack)|<-|<-|<-|<-|(Send Ack)|||Ack to Sender|
|#2|TX_ADDR<br>"2RECV"|RX_ADDR_P0<br>"2RECV"|RX_ADDR_P1<br>NONE||TX_ADDR<br>NONE|RX_ADDR_P0<br>NONE|RX_ADDR_P1<br>"1RECV"|RX_ADDR_P2<br>"2RECV"|RX_ADDR_P5<br>"5RECV"||
||(Send Data)|->|->|->|->|->|->|(Get Data)||Data to Receiver|
|||(Get Ack)|<-|<-|<-|<-|<-|(Send Ack)||Ack to Sender|
|#5|TX_ADDR<br>"5RECV"|RX_ADDR_P0<br>"5RECV"|RX_ADDR_P1<br>NONE||TX_ADDR<br>NONE|RX_ADDR_P0<br>NONE|RX_ADDR_P1<br>"1RECV"|RX_ADDR_P2<br>"2RECV"|RX_ADDR_P5<br>"5RECV"||
||(Send Data)|->|->|->|->|->|->|->|(Get Data)|Data to Receiver|
|||(Get Ack)|<-|<-|<-|<-|<-|<-|(Send Ack)|Ack to Sender|
# Configuration
![config-top](https://github.com/nopnop2002/esp-idf-mirf/assets/6020549/cd5392c4-a6d5-4e55-bc8b-372050573a2b)
![config-app](https://github.com/nopnop2002/esp-idf-mirf/assets/6020549/e289c28c-72e5-4490-9db1-40163c9db5a0)
# Receiver Register
RX_ADDR_P1 is 0x3152454356.
RX_ADDR_P2 will be 0x3252454356. The same value is used for the last 4 bytes.
![Register-Receiver](https://github.com/nopnop2002/esp-idf-mirf/assets/6020549/e8e0812a-8fa2-43ae-a2be-fd346c2e6da2)
# Communicat with Arduino Environment
Run this sketch.
ArduinoCode\Multiple-Receive/EmitterX
# Receiver screenshot
This is received from 5 units at the same time.
![ScreenShot](https://github.com/nopnop2002/esp-idf-mirf/assets/6020549/d763f44f-9ca2-4ed8-a841-90272aa18032)

View File

@ -0,0 +1,4 @@
set(component_srcs "main.c")
idf_component_register(SRCS "${component_srcs}"
INCLUDE_DIRS ".")

View File

@ -0,0 +1,47 @@
menu "Application Configuration"
choice DIRECTION
prompt "Communication polarity"
default RECEIVER
help
Select Communication polarity.
config SENDER
bool "As the sender"
help
As the sender.
config RECEIVER
bool "As the receiver"
help
As the receiver.
endchoice
choice TADDR
prompt "Sender's address"
depends on SENDER
default TADDR1
help
Select sender's address.
config TADDR1
bool "Use 1 as sender's address"
help
Use 1 as sender's address
config TADDR2
bool "Use 2 as sender's address"
help
Use 2 as sender's address
config TADDR3
bool "Use 3 as sender's address"
help
Use 3 as sender's address
config TADDR4
bool "Use 4 as sender's address"
help
Use 4 as sender's address
config TADDR5
bool "Use 5 as sender's address"
help
Use 5 as sender's address
endchoice
endmenu

View File

@ -0,0 +1,5 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

View File

@ -0,0 +1,161 @@
/* Mirf Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "mirf.h"
#if CONFIG_ADVANCED
void AdvancedSettings(NRF24_t * dev)
{
#if CONFIG_RF_RATIO_2M
ESP_LOGW(pcTaskGetName(0), "Set RF Data Ratio to 2MBps");
Nrf24_SetSpeedDataRates(dev, 1);
#endif // CONFIG_RF_RATIO_2M
#if CONFIG_RF_RATIO_1M
ESP_LOGW(pcTaskGetName(0), "Set RF Data Ratio to 1MBps");
Nrf24_SetSpeedDataRates(dev, 0);
#endif // CONFIG_RF_RATIO_2M
#if CONFIG_RF_RATIO_250K
ESP_LOGW(pcTaskGetName(0), "Set RF Data Ratio to 250KBps");
Nrf24_SetSpeedDataRates(dev, 2);
#endif // CONFIG_RF_RATIO_2M
ESP_LOGW(pcTaskGetName(0), "CONFIG_RETRANSMIT_DELAY=%d", CONFIG_RETRANSMIT_DELAY);
Nrf24_setRetransmitDelay(dev, CONFIG_RETRANSMIT_DELAY);
}
#endif // CONFIG_ADVANCED
#if CONFIG_RECEIVER
void receiver(void *pvParameters)
{
ESP_LOGI(pcTaskGetName(0), "Start");
NRF24_t dev;
Nrf24_init(&dev);
uint8_t payload = 32;
uint8_t channel = CONFIG_RADIO_CHANNEL;
Nrf24_config(&dev, channel, payload);
// Set my own address using 5 characters
esp_err_t ret = Nrf24_setRADDR(&dev, (uint8_t *)"1RECV");
if (ret != ESP_OK) {
ESP_LOGE(pcTaskGetName(0), "nrf24l01 not installed");
while(1) { vTaskDelay(1); }
}
// Add my own address using 1 characters
Nrf24_addRADDR(&dev, 2, '2'); // 2RECV
Nrf24_addRADDR(&dev, 3, '3'); // 3RECV
Nrf24_addRADDR(&dev, 4, '4'); // 4RECV
Nrf24_addRADDR(&dev, 5, '5'); // 5RECV
#if CONFIG_ADVANCED
AdvancedSettings(&dev);
#endif // CONFIG_ADVANCED
// Print settings
Nrf24_printDetails(&dev);
ESP_LOGI(pcTaskGetName(0), "Listening...");
uint8_t buf[32];
// Clear RX FiFo
while(1) {
if (Nrf24_dataReady(&dev) == false) break;
Nrf24_getData(&dev, buf);
}
while(1) {
// Wait for received data
if (Nrf24_dataReady(&dev)) {
uint8_t pipe = Nrf24_getDataPipe(&dev);
Nrf24_getData(&dev, buf);
ESP_LOGI(pcTaskGetName(0), "Got data pipe(%d):%s", pipe, buf);
}
vTaskDelay(1);
}
}
#endif // CONFIG_RECEIVER
#if CONFIG_SENDER
void sender(void *pvParameters)
{
ESP_LOGI(pcTaskGetName(0), "Start");
NRF24_t dev;
Nrf24_init(&dev);
uint8_t payload = 32;
uint8_t channel = CONFIG_RADIO_CHANNEL;
Nrf24_config(&dev, channel, payload);
// Set destination address using 5 characters
int sender_id;
#if CONFIG_TADDR1
esp_err_t ret = Nrf24_setTADDR(&dev, (uint8_t *)"1RECV");
sender_id = 1;
#elif CONFIG_TADDR2
esp_err_t ret = Nrf24_setTADDR(&dev, (uint8_t *)"2RECV");
sender_id = 2;
#elif CONFIG_TADDR3
esp_err_t ret = Nrf24_setTADDR(&dev, (uint8_t *)"3RECV");
sender_id = 3;
#elif CONFIG_TADDR4
esp_err_t ret = Nrf24_setTADDR(&dev, (uint8_t *)"4RECV");
sender_id = 4;
#elif CONFIG_TADDR5
esp_err_t ret = Nrf24_setTADDR(&dev, (uint8_t *)"5RECV");
sender_id = 5;
#endif
if (ret != ESP_OK) {
ESP_LOGE(pcTaskGetName(0), "nrf24l01 not installed");
while(1) { vTaskDelay(1); }
}
#if CONFIG_ADVANCED
AdvancedSettings(&dev);
#endif // CONFIG_ADVANCED
// Print settings
Nrf24_printDetails(&dev);
uint8_t buf[32];
while(1) {
TickType_t nowTick = xTaskGetTickCount();
sprintf((char *)buf, "Hello World %"PRIu32" from %d", nowTick, sender_id);
Nrf24_send(&dev, buf);
vTaskDelay(1);
ESP_LOGI(pcTaskGetName(0), "Wait for sending.....");
if (Nrf24_isSend(&dev, 1000)) {
ESP_LOGI(pcTaskGetName(0),"Send success:%s", buf);
} else {
ESP_LOGW(pcTaskGetName(0),"Send fail:");
}
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
#endif // CONFIG_SENDER
void app_main(void)
{
#if CONFIG_RECEIVER
xTaskCreate(&receiver, "RECEIVER", 1024*3, NULL, 2, NULL);
#endif
#if CONFIG_SENDER
xTaskCreate(&sender, "SENDER", 1024*3, NULL, 2, NULL);
#endif
}

View File

@ -0,0 +1,8 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS ../components/mirf)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(mirf)

View File

@ -0,0 +1,17 @@
# Peer-to-peer
One-way communication for transmission or reception with index.
nRF24L01 can send and receive up to 32 characters, but by adding an index to the sent data, it can send and receive 256 types of data.
# Configuration
![config-top](https://user-images.githubusercontent.com/6020549/154790249-b1f28d18-7c60-4a55-b262-5d821adbbfc3.jpg)
![config-app](https://github.com/nopnop2002/esp-idf-mirf/assets/6020549/73e39ee3-9f25-44de-93d4-b46f70ce4c14)
# Screen Shot
![Peer-to-peer-indexed](https://github.com/nopnop2002/esp-idf-mirf/assets/6020549/69657915-df86-4a50-816b-0001a199ca03)
# Communicat with Arduino Environment
Run this sketch.
ArduinoCode\Peer-to-peer\IndexedStringTest

View File

@ -0,0 +1,4 @@
set(component_srcs "main.c")
idf_component_register(SRCS "${component_srcs}"
INCLUDE_DIRS ".")

View File

@ -0,0 +1,18 @@
menu "Application Configuration"
choice DIRECTION
prompt "Communication polarity"
default SENDER
help
Select Communication polarity.
config SENDER
bool "As the sender"
help
As the sender.
config RECEIVER
bool "As the receiver"
help
As the receiver.
endchoice
endmenu

View File

@ -0,0 +1,5 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

View File

@ -0,0 +1,144 @@
/* Mirf Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "mirf.h"
#if CONFIG_ADVANCED
void AdvancedSettings(NRF24_t * dev)
{
#if CONFIG_RF_RATIO_2M
ESP_LOGW(pcTaskGetName(0), "Set RF Data Ratio to 2MBps");
Nrf24_SetSpeedDataRates(dev, 1);
#endif // CONFIG_RF_RATIO_2M
#if CONFIG_RF_RATIO_1M
ESP_LOGW(pcTaskGetName(0), "Set RF Data Ratio to 1MBps");
Nrf24_SetSpeedDataRates(dev, 0);
#endif // CONFIG_RF_RATIO_2M
#if CONFIG_RF_RATIO_250K
ESP_LOGW(pcTaskGetName(0), "Set RF Data Ratio to 250KBps");
Nrf24_SetSpeedDataRates(dev, 2);
#endif // CONFIG_RF_RATIO_2M
ESP_LOGW(pcTaskGetName(0), "CONFIG_RETRANSMIT_DELAY=%d", CONFIG_RETRANSMIT_DELAY);
Nrf24_setRetransmitDelay(dev, CONFIG_RETRANSMIT_DELAY);
}
#endif // CONFIG_ADVANCED
#if CONFIG_RECEIVER
void receiver(void *pvParameters)
{
ESP_LOGI(pcTaskGetName(0), "Start");
NRF24_t dev;
Nrf24_init(&dev);
uint8_t payload = 32;
uint8_t channel = CONFIG_RADIO_CHANNEL;
Nrf24_config(&dev, channel, payload);
// Set my own address using 5 characters
esp_err_t ret = Nrf24_setRADDR(&dev, (uint8_t *)"FGHIJ");
if (ret != ESP_OK) {
ESP_LOGE(pcTaskGetName(0), "nrf24l01 not installed");
while(1) { vTaskDelay(1); }
}
#if CONFIG_ADVANCED
AdvancedSettings(&dev);
#endif // CONFIG_ADVANCED
// Print settings
Nrf24_printDetails(&dev);
ESP_LOGI(pcTaskGetName(0), "Listening...");
uint8_t buf[32];
// Clear RX FiFo
while(1) {
if (Nrf24_dataReady(&dev) == false) break;
Nrf24_getData(&dev, buf);
}
while(1) {
// Wait for received data
if (Nrf24_dataReady(&dev)) {
Nrf24_getData(&dev, buf);
ESP_LOGI(pcTaskGetName(0), "Got data:%d [%s]", buf[0], &buf[1]);
//ESP_LOG_BUFFER_HEXDUMP(pcTaskGetName(0), buf, payload, ESP_LOG_INFO);
}
vTaskDelay(1);
}
}
#endif // CONFIG_RECEIVER
#if CONFIG_SENDER
void sender(void *pvParameters)
{
ESP_LOGI(pcTaskGetName(0), "Start");
NRF24_t dev;
Nrf24_init(&dev);
uint8_t payload = 32;
uint8_t channel = CONFIG_RADIO_CHANNEL;
Nrf24_config(&dev, channel, payload);
// Set destination address using 5 characters
esp_err_t ret = Nrf24_setTADDR(&dev, (uint8_t *)"FGHIJ");
if (ret != ESP_OK) {
ESP_LOGE(pcTaskGetName(0), "nrf24l01 not installed");
while(1) { vTaskDelay(1); }
}
#if CONFIG_ADVANCED
AdvancedSettings(&dev);
#endif // CONFIG_ADVANCED
// Print settings
Nrf24_printDetails(&dev);
uint8_t buf[32];
uint8_t index = 0;
while(1) {
TickType_t nowTick = xTaskGetTickCount();
buf[0] = index;
sprintf((char *)&buf[1], "Hello World %"PRIu32, nowTick);
Nrf24_send(&dev, buf);
vTaskDelay(1);
ESP_LOGI(pcTaskGetName(0), "Wait for sending.....");
if (Nrf24_isSend(&dev, 1000)) {
ESP_LOGI(pcTaskGetName(0),"Send success:%d [%s]", buf[0], &buf[1]);
index++;
} else {
ESP_LOGW(pcTaskGetName(0),"Send fail:");
}
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
#endif // CONFIG_SENDER
void app_main(void)
{
#if CONFIG_RECEIVER
xTaskCreate(&receiver, "RECEIVER", 1024*3, NULL, 2, NULL);
#endif
#if CONFIG_SENDER
xTaskCreate(&sender, "SENDER", 1024*3, NULL, 2, NULL);
#endif
}

View File

@ -0,0 +1,8 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS ../components/mirf)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(mirf)

View File

@ -0,0 +1,55 @@
# Peer-to-peer Example
One-way communication for transmission or reception.
# Configuration
![config-top](https://user-images.githubusercontent.com/6020549/154790249-b1f28d18-7c60-4a55-b262-5d821adbbfc3.jpg)
![config-app](https://github.com/nopnop2002/esp-idf-mirf/assets/6020549/73e39ee3-9f25-44de-93d4-b46f70ce4c14)
# Parameter Setting
The following parameters must match on the sender and receiver.
## Payload size & channel
```
uint8_t payload = 32;
uint8_t channel = CONFIG_RADIO_CHANNEL;
```
## Sender side
```
// Set destination address using 5 characters
esp_err_t ret = Nrf24_setTADDR(&dev, (uint8_t *)"FGHIJ");
```
## Receiver side
```
// Set my own address using 5 characters
esp_err_t ret = Nrf24_setRADDR(&dev, (uint8_t *)"FGHIJ");
```
# nRF24L01 Address Register Setting
|Sender||||Receiver||||
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|TX_ADDR<br>"FGHIJ"|RX_ADDR_P0<br>"FGHIJ"|RX_ADDR_P1<br>NONE||TX_ADDR<br>NONE|RX_ADDR_P0<br>NONE|RX_ADDR_P1<br>"FGHIJ"||
|(Send Data)|->|->|->|->|->|(Get Data)|Data to Receiver|
||(Get Ack)|<-|<-|<-|<-|(Send Ack)|Ack to Sender|
# Setting Register
The underlined address match on the sending and receiving sides.
No other addresses are used.
### Sender Register
![Register-Sender](https://github.com/nopnop2002/esp-idf-mirf/assets/6020549/b534f7b9-f3b5-4bb3-a065-716dc81f5888)
### Receiver Register
![Register-Receiver](https://github.com/nopnop2002/esp-idf-mirf/assets/6020549/4025b2c5-24fe-4fc2-8e9c-8ab38d301149)
# Screen Shot
![Peer-to-peer](https://github.com/nopnop2002/esp-idf-mirf/assets/6020549/f0a7a3f8-692b-4890-a0eb-97244c4e64db)
# Communicat with Arduino Environment
Run this sketch.
ArduinoCode\Peer-to-peer\StringTest

View File

@ -0,0 +1,4 @@
set(component_srcs "main.c")
idf_component_register(SRCS "${component_srcs}"
INCLUDE_DIRS ".")

View File

@ -0,0 +1,18 @@
menu "Application Configuration"
choice DIRECTION
prompt "Communication polarity"
default SENDER
help
Select Communication polarity.
config SENDER
bool "As the sender"
help
As the sender.
config RECEIVER
bool "As the receiver"
help
As the receiver.
endchoice
endmenu

View File

@ -0,0 +1,5 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

View File

@ -0,0 +1,141 @@
/* Mirf Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "mirf.h"
#if CONFIG_ADVANCED
void AdvancedSettings(NRF24_t * dev)
{
#if CONFIG_RF_RATIO_2M
ESP_LOGW(pcTaskGetName(0), "Set RF Data Ratio to 2MBps");
Nrf24_SetSpeedDataRates(dev, 1);
#endif // CONFIG_RF_RATIO_2M
#if CONFIG_RF_RATIO_1M
ESP_LOGW(pcTaskGetName(0), "Set RF Data Ratio to 1MBps");
Nrf24_SetSpeedDataRates(dev, 0);
#endif // CONFIG_RF_RATIO_2M
#if CONFIG_RF_RATIO_250K
ESP_LOGW(pcTaskGetName(0), "Set RF Data Ratio to 250KBps");
Nrf24_SetSpeedDataRates(dev, 2);
#endif // CONFIG_RF_RATIO_2M
ESP_LOGW(pcTaskGetName(0), "CONFIG_RETRANSMIT_DELAY=%d", CONFIG_RETRANSMIT_DELAY);
Nrf24_setRetransmitDelay(dev, CONFIG_RETRANSMIT_DELAY);
}
#endif // CONFIG_ADVANCED
#if CONFIG_RECEIVER
void receiver(void *pvParameters)
{
ESP_LOGI(pcTaskGetName(0), "Start");
NRF24_t dev;
Nrf24_init(&dev);
uint8_t payload = 32;
uint8_t channel = CONFIG_RADIO_CHANNEL;
Nrf24_config(&dev, channel, payload);
// Set my own address using 5 characters
esp_err_t ret = Nrf24_setRADDR(&dev, (uint8_t *)"FGHIJ");
if (ret != ESP_OK) {
ESP_LOGE(pcTaskGetName(0), "nrf24l01 not installed");
while(1) { vTaskDelay(1); }
}
#if CONFIG_ADVANCED
AdvancedSettings(&dev);
#endif // CONFIG_ADVANCED
// Print settings
Nrf24_printDetails(&dev);
ESP_LOGI(pcTaskGetName(0), "Listening...");
uint8_t buf[32];
// Clear RX FiFo
while(1) {
if (Nrf24_dataReady(&dev) == false) break;
Nrf24_getData(&dev, buf);
}
while(1) {
// Wait for received data
if (Nrf24_dataReady(&dev)) {
Nrf24_getData(&dev, buf);
ESP_LOGI(pcTaskGetName(0), "Got data:%s", buf);
//ESP_LOG_BUFFER_HEXDUMP(pcTaskGetName(0), buf, payload, ESP_LOG_INFO);
}
vTaskDelay(1);
}
}
#endif // CONFIG_RECEIVER
#if CONFIG_SENDER
void sender(void *pvParameters)
{
ESP_LOGI(pcTaskGetName(0), "Start");
NRF24_t dev;
Nrf24_init(&dev);
uint8_t payload = 32;
uint8_t channel = CONFIG_RADIO_CHANNEL;
Nrf24_config(&dev, channel, payload);
// Set destination address using 5 characters
esp_err_t ret = Nrf24_setTADDR(&dev, (uint8_t *)"FGHIJ");
if (ret != ESP_OK) {
ESP_LOGE(pcTaskGetName(0), "nrf24l01 not installed");
while(1) { vTaskDelay(1); }
}
#if CONFIG_ADVANCED
AdvancedSettings(&dev);
#endif // CONFIG_ADVANCED
// Print settings
Nrf24_printDetails(&dev);
uint8_t buf[32];
while(1) {
TickType_t nowTick = xTaskGetTickCount();
sprintf((char *)buf, "Hello World %"PRIu32, nowTick);
Nrf24_send(&dev, buf);
vTaskDelay(1);
ESP_LOGI(pcTaskGetName(0), "Wait for sending.....");
if (Nrf24_isSend(&dev, 1000)) {
ESP_LOGI(pcTaskGetName(0),"Send success:%s", buf);
} else {
ESP_LOGW(pcTaskGetName(0),"Send fail:");
}
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
#endif // CONFIG_SENDER
void app_main(void)
{
#if CONFIG_RECEIVER
xTaskCreate(&receiver, "RECEIVER", 1024*3, NULL, 2, NULL);
#endif
#if CONFIG_SENDER
xTaskCreate(&sender, "SENDER", 1024*3, NULL, 2, NULL);
#endif
}

View File

@ -0,0 +1,8 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS ../components/mirf)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(mirf)

View File

@ -0,0 +1,35 @@
# Ping-Pong Example
Send data from primary to secondary.
In the secondary, sent back received data.
# Configuration
![config-top](https://user-images.githubusercontent.com/6020549/154790653-277f0f2f-0b51-4a2c-aead-6aeea0ac232f.jpg)
![config-app](https://github.com/nopnop2002/esp-idf-mirf/assets/6020549/29b81f36-dde7-4e36-bb99-0eb9efe6e1f2)
# nRF24L01 Address Register Setting
|Primary||||Secondary||||
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|TX_ADDR<br>"FGHIJ"|RX_ADDR_P0<br>"FGHIJ"|RX_ADDR_P1<br>"ABCDE"||TX_ADDR<br>"ABCDE"|RX_ADDR_P0<br>"ABCDE"|RX_ADDR_P1<br>"FGHIJ"||
|(Send Data)|->|->|->|->|->|(Get Data)|Data to Secondary|
||(Get Ack)|<-|<-|<-|<-|(Send Ack)|Ack to Primary|
|||||||||
|||(Get Data)|<-|(Send Data)|||Data to Primary|
|||(Send Ack)|->|->|(Get Ack)||Ack to Secondary|
# Setting Register
The underlined address match on the sending and receiving sides.
### Primary Register
![Register-Primary](https://github.com/nopnop2002/esp-idf-mirf/assets/6020549/fa2929cb-13cd-4aea-8022-db92d427bf18)
### Secondary Register
![Register-Secondary](https://github.com/nopnop2002/esp-idf-mirf/assets/6020549/b30bc789-0802-4c67-8586-67ca52a2051c)
# Communicat with Arduino Environment
Run this sketch.
ArduinoCode/Ping-Pong

View File

@ -0,0 +1,4 @@
set(component_srcs "main.c")
idf_component_register(SRCS "${component_srcs}"
INCLUDE_DIRS ".")

View File

@ -0,0 +1,18 @@
menu "Application Configuration"
choice POLARITY
prompt "Communication Polarity"
default PRIMARY
help
Select Communication Polarity.
config PRIMARY
bool "Primary"
help
As Echo Client.
config SECONDARY
bool "Secondary"
help
As Echo Server.
endchoice
endmenu

View File

@ -0,0 +1,5 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

View File

@ -0,0 +1,178 @@
/* Mirf Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "mirf.h"
#if CONFIG_ADVANCED
void AdvancedSettings(NRF24_t * dev)
{
#if CONFIG_RF_RATIO_2M
ESP_LOGW(pcTaskGetName(0), "Set RF Data Ratio to 2MBps");
Nrf24_SetSpeedDataRates(dev, 1);
#endif // CONFIG_RF_RATIO_2M
#if CONFIG_RF_RATIO_1M
ESP_LOGW(pcTaskGetName(0), "Set RF Data Ratio to 1MBps");
Nrf24_SetSpeedDataRates(dev, 0);
#endif // CONFIG_RF_RATIO_2M
#if CONFIG_RF_RATIO_250K
ESP_LOGW(pcTaskGetName(0), "Set RF Data Ratio to 250KBps");
Nrf24_SetSpeedDataRates(dev, 2);
#endif // CONFIG_RF_RATIO_2M
ESP_LOGW(pcTaskGetName(0), "CONFIG_RETRANSMIT_DELAY=%d", CONFIG_RETRANSMIT_DELAY);
Nrf24_setRetransmitDelay(dev, CONFIG_RETRANSMIT_DELAY);
}
#endif // CONFIG_ADVANCED
#if CONFIG_PRIMARY
void primary(void *pvParameters)
{
ESP_LOGI(pcTaskGetName(0), "Start");
NRF24_t dev;
Nrf24_init(&dev);
uint8_t payload = 32;
uint8_t channel = CONFIG_RADIO_CHANNEL;
Nrf24_config(&dev, channel, payload);
// Set my own address using 5 characters
esp_err_t ret = Nrf24_setRADDR(&dev, (uint8_t *)"ABCDE");
if (ret != ESP_OK) {
ESP_LOGE(pcTaskGetName(0), "nrf24l01 not installed");
while(1) { vTaskDelay(1); }
}
// Set destination address using 5 characters
ret = Nrf24_setTADDR(&dev, (uint8_t *)"FGHIJ");
if (ret != ESP_OK) {
ESP_LOGE(pcTaskGetName(0), "nrf24l01 not installed");
while(1) { vTaskDelay(1); }
}
#if CONFIG_ADVANCED
AdvancedSettings(&dev);
#endif // CONFIG_ADVANCED
// Print settings
Nrf24_printDetails(&dev);
uint8_t buf[32];
while(1) {
TickType_t nowTick = xTaskGetTickCount();
sprintf((char *)buf, "Hello World %"PRIu32, nowTick);
Nrf24_send(&dev, buf);
memset(buf, 0, sizeof(buf));
ESP_LOGI(pcTaskGetName(0), "Wait for sending.....");
if (Nrf24_isSend(&dev, 1000)) {
ESP_LOGI(pcTaskGetName(0),"Send success:%s", buf);
// Wait for response
//ESP_LOGI(pcTaskGetName(0), "Wait for response.....");
bool received = false;
for(int i=0;i<100;i++) {
if (Nrf24_dataReady(&dev)) {
received = true;
break;
}
vTaskDelay(1);
}
if (received) {
Nrf24_getData(&dev, buf);
TickType_t diffTick = xTaskGetTickCount() - nowTick;
ESP_LOGI(pcTaskGetName(0), "Got response:[%s] Elapsed:%"PRIu32" ticks", buf, diffTick);
} else {
ESP_LOGW(pcTaskGetName(0), "No response");
}
} else {
ESP_LOGW(pcTaskGetName(0),"Send fail:");
}
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
#endif // CONFIG_PRIMARY
#if CONFIG_SECONDARY
void secondary(void *pvParameters)
{
ESP_LOGI(pcTaskGetName(0), "Start");
NRF24_t dev;
Nrf24_init(&dev);
uint8_t payload = 32;
uint8_t channel = CONFIG_RADIO_CHANNEL;
Nrf24_config(&dev, channel, payload);
// Set my own address using 5 characters
esp_err_t ret = Nrf24_setRADDR(&dev, (uint8_t *)"FGHIJ");
if (ret != ESP_OK) {
ESP_LOGE(pcTaskGetName(0), "nrf24l01 not installed");
while(1) { vTaskDelay(1); }
}
// Set destination address using 5 characters
ret = Nrf24_setTADDR(&dev, (uint8_t *)"ABCDE");
if (ret != ESP_OK) {
ESP_LOGE(pcTaskGetName(0), "nrf24l01 not installed");
while(1) { vTaskDelay(1); }
}
#if CONFIG_ADVANCED
AdvancedSettings(&dev);
#endif // CONFIG_ADVANCED
// Print settings
Nrf24_printDetails(&dev);
ESP_LOGI(pcTaskGetName(0), "Listening...");
uint8_t buf[32];
// Clear RX FiFo
while(1) {
if (Nrf24_dataReady(&dev) == false) break;
Nrf24_getData(&dev, buf);
}
while(1) {
// Wait for received data
if (Nrf24_dataReady(&dev)) {
Nrf24_getData(&dev, buf);
ESP_LOGI(pcTaskGetName(0), "Got data:%s", buf);
Nrf24_send(&dev, buf);
ESP_LOGI(pcTaskGetName(0), "Wait for sending.....");
if (Nrf24_isSend(&dev, 1000)) {
ESP_LOGI(pcTaskGetName(0),"Send success:%s", buf);
} else {
ESP_LOGW(pcTaskGetName(0),"Send fail:");
}
}
vTaskDelay(1);
}
}
#endif // CONFIG_SECONDARY
void app_main(void)
{
#if CONFIG_PRIMARY
xTaskCreate(&primary, "PRIMARY", 1024*3, NULL, 2, NULL);
#endif
#if CONFIG_SECONDARY
xTaskCreate(&secondary, "SECONDARY", 1024*3, NULL, 2, NULL);
#endif
}

View File

@ -0,0 +1,177 @@
# esp-idf-mirf
A port of the Mirf library for ESP-IDF.
The library provides basic control of the Nordic nRF24L01/nRF24L01+ RF modules.
I ported from [here](https://github.com/nopnop2002/Arduino-STM32-nRF24L01).
![Standard](https://user-images.githubusercontent.com/6020549/154830046-77f034cf-ce30-4cbc-838c-66734656cd8e.JPG)
![SMD-3](https://user-images.githubusercontent.com/6020549/154830127-366ee996-751d-48c0-879f-b201b1bb31f7.JPG)
![SMD-Pinout](https://github.com/nopnop2002/esp-idf-mirf/assets/6020549/4566928d-7fb8-4569-b780-4a502b77cc34)
# Software requirements
ESP-IDF V4.4/V5.x.
ESP-IDF V5.0 is required when using ESP32-C2.
ESP-IDF V5.1 is required when using ESP32-C6.
# Installation
```Shell
git clone https://github.com/nopnop2002/esp-idf-mirf
cd esp-idf-mirf/Peer-to-peer
idf.py set-target {esp32/esp32s2/esp32s3/esp32c2/esp32c3/esp32c6}
idf.py menuconfig
idf.py flash
```
__Note for ESP32C3__
For some reason, there are development boards that cannot use GPIO06, GPIO08, GPIO09, GPIO19 for SPI clock pins.
According to the ESP32C3 specifications, these pins can also be used as SPI clocks.
I used a raw ESP-C3-13 to verify that these pins could be used as SPI clocks.
# Configuration for Transceiver
![config-nrf24l01-1](https://user-images.githubusercontent.com/6020549/168019514-93c377c9-2823-4840-bce4-168f0c2b7338.jpg)
![config-nrf24l01-2](https://github.com/nopnop2002/esp-idf-mirf/assets/6020549/4898836a-b614-4d30-8ef4-c653706ba7f3)
__Note for Channel__
Channels range from 0 to 127.
The channel number of the sender and receiver must be the same.
Channel = 0 uses the frequency of 2.4000GHz, channel = 127 uses the frequency of 2.4127GHz.
The width of one channel is only 0.01GHz.
Using multiple radio node at the same time will almost always cause interference, even if you change channels.
# SPI BUS selection
![config-nrf24l01-3](https://github.com/nopnop2002/esp-idf-mirf/assets/6020549/377bbcc5-2ca9-4e74-a54d-3ca87c5ac241)
The ESP32 series has three SPI BUSs.
SPI1_HOST is used for communication with Flash memory.
You can use SPI2_HOST and SPI3_HOST freely.
When you use SDSPI(SD Card via SPI), SDSPI uses SPI2_HOST BUS.
When using this module at the same time as SDSPI or other SPI device using SPI2_HOST, it needs to be changed to SPI3_HOST.
When you don't use SDSPI, both SPI2_HOST and SPI3_HOST will work.
Previously it was called HSPI_HOST / VSPI_HOST, but now it is called SPI2_HOST / SPI3_HOST.
# Using Advanced Settings
When used at long distances, lowering the RF data rate stabilizes it.
When changing the RF data rate, the sender and receiver must have the same value.
When using 250KBps, it takes time to PAYLOAD sending and ACK PACKET receiving, so it is necessary to increase the automatic retransmission delay.
I tested it with [this](https://github.com/nopnop2002/Arduino-STM32-nRF24L01/tree/master/example/AdvancedSetting).
![config-nrf24l01-4](https://github.com/nopnop2002/esp-idf-mirf/assets/6020549/a18be916-7716-4e22-bdc0-6813883c64a5)
![config-nrf24l01-5](https://github.com/nopnop2002/esp-idf-mirf/assets/6020549/ba577705-c2b7-494c-bcd7-969d96cf859a)
__If you want to initialize the nRF24L01 settings after using the Advanced Settings, you need to power cycle the nRF24L01 before executing.__
Because nRF24L01 remembers the previous setting.
nRF24L01 does not have Software Reset function.
# Wirering
|nRF24L01||ESP32|ESP32-S2/S3|ESP32-C2/C3/C6||
|:-:|:-:|:-:|:-:|:-:|:-:|
|MISO|--|GPIO19|GPIO37|GPIO4|(*1)|
|SCK|--|GPIO18|GPIO36|GPIO3|(*1)|
|MOSI|--|GPIO23|GPIO35|GPIO2|(*1)|
|CE|--|GPIO16|GPIO34|GPIO1|(*1)|
|CSN|--|GPIO17|GPIO33|GPIO0|(*1)|
|GND|--|GND|GND|GND||
|VCC|--|3.3V|3.3V|3.3V||
(*1)You can change it to any pin using menuconfig.
# Communicat with Arduino Environment
I used [this](https://github.com/nopnop2002/Arduino-STM32-nRF24L01) library on Arduino environment.
__You need to match the payload size and channel with Arduino and esp-idf.__
- Arduino environment
```C++
Mirf.payload = sizeof(mydata.value);
Mirf.channel = 90;
Mirf.config();
```
- esp-idf
```C
uint8_t payload = sizeof(value);
uint8_t channel = 90;
Nrf24_config(&dev, channel, payload);
```
# Communicat with Raspberry Pi
I used [this](https://github.com/nopnop2002/Raspberry-Mirf) library on Raspberry Pi.
# Using binary data
nRF24L01 is not interested in the contents of the payload.
Therefore, nRF24L01 can send and receive binary data.
But the internal format of the binary data depends on the MCU architecture, so communication between different architectures is not possible.
If you want to send or receive binary data between different architectures, you need to encode it into a CSV format string like this.
```123,-123,1234.5,-1234.5```
nRF24L01 can send and receive up to 32 characters, but by adding an index to the sent data, it can send and receive 256 types of data.
# Important
When changing the settings of the nRF24L01, it is necessary to power cycle the nRF24L01 before executing.
Because nRF24L01 remembers the previous setting.
nRF24L01 does not have Software Reset function.
# Enhanced ShockBurst features
nRF24L01 has "Enhanced ShockBurst" features.
"Enhanced ShockBurst" automatically sets the PTX(=Transmitter) in receive mode to wait for the ACK packet from PRX(=Receiver).
## Transmission Successful
|ESP32||nRF24L01[PTX]||nRF24L01[PRX]||ESP32|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|ESP32|-->|nRF24L01|||||
|||nRF24L01|--(Payload Packet)-->|nRF24L01|||||
||||wait 250uS||||||
|||nRF24L01|<--(Ack Packet)--|nRF24L01|||||
|ESP32|<--|nRF24L01|||||||
|||||nRF24L01|-->|ESP32|
## Transmission Failure
PTX waits for an ACK packet for 250uS and retransmits 3 times.
|ESP32||nRF24L01[PTX]||nRF24L01[PRX]||ESP32|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|ESP32|-->|nRF24L01|||||
|||nRF24L01|--(Payload Packet)-->|nRF24L01|||||
||||wait 250uS||||||
|||nRF24L01|--(Payload Packet)-->|nRF24L01|||||
||||wait 250uS||||||
|||nRF24L01|--(Payload Packet)-->|nRF24L01|||||
||||wait 250uS||||||
|ESP32|<--|nRF24L01|||||||
Using a data rate of 250KBps extends the range of radio waves.
However, it takes time to send PAYLOAD and receive ACK PACKET.
Therefore, the delay time for automatic retransmission should be longer than 250uS.
If the delay of automatic retransmission is not increased, it is considered as a transmission failure.
|ESP32||nRF24L01[PTX]||nRF24L01[PRX]||ESP32|
|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
|ESP32|-->|nRF24L01|||||
|||nRF24L01|--(Payload Packet)-->|nRF24L01|||||
||||Over 250uS||||||
|||nRF24L01|<--(Ack Packet)--|nRF24L01|||||
|ESP32|<--|nRF24L01|||||||
|||||nRF24L01|-->|ESP32|
See the data sheet for details on Enhanced ShockBurst.
# Throughput
spi_device_transmit is executed by the SPI driver and consumes 1tick of CPU time.
When DMA is enabled, SPI max_transfer_sz defaults to 4092(4K).
This indicates that 4092 bytes of data can be sent in 1tick(10 millsec).
Therefore, the SPI transmission potential of ESP-IDF is 400Kbytes/Sec.
This has a significant impact on the nRF24L01, which has a small maximum payload size.
Unfortunately, nRF24L01's maximum payload size is 32 bytes.
1 tick (10 millsec) is required to send payload and receive ack packet.
This has nothing to do with SPI bus speed.
The throughput of nRF24L01 is 32 bytes/10 millsec(=3,200 bytes/sec).
RF data rate of nRF24L01 affects the radio range, but not the throughput.
# About Si24R1 clone
Si24R1 is marketed as a nRF24L01 compatible.
__Si24R1 clone cannot send and receive correctly.__
After purchasing the nRF24L01, be sure to check the markings on the chip.
Many suppliers sell Si24R1 as nRF24L01.

View File

@ -0,0 +1,5 @@
set(component_srcs "mirf.c")
idf_component_register(SRCS "${component_srcs}"
PRIV_REQUIRES driver
INCLUDE_DIRS ".")

View File

@ -0,0 +1,130 @@
menu "nRF24L01 Configuration"
config GPIO_RANGE_MAX
int
default 33 if IDF_TARGET_ESP32
default 46 if IDF_TARGET_ESP32S2
default 48 if IDF_TARGET_ESP32S3
default 18 if IDF_TARGET_ESP32C2
default 19 if IDF_TARGET_ESP32C3
default 30 if IDF_TARGET_ESP32C6
config RADIO_CHANNEL
int "Channel number"
range 0 127
default 90
help
Channel number.
config MISO_GPIO
int "MISO GPIO number"
range 0 GPIO_RANGE_MAX
default 19 if IDF_TARGET_ESP32
default 37 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
default 4 # C3 and others
help
GPIO number (IOxx) to SPI MISO.
Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to MISO.
On the ESP32, GPIOs 35-39 are input-only so cannot be used as outputs.
On the ESP32-S2, GPIO 46 is input-only so cannot be used as outputs.
config SCLK_GPIO
int "SCLK GPIO number"
range 0 GPIO_RANGE_MAX
default 18 if IDF_TARGET_ESP32
default 36 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
default 3 # C3 and others
help
GPIO number (IOxx) to SPI SCLK.
Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to SCLK.
On the ESP32, GPIOs 35-39 are input-only so cannot be used as outputs.
On the ESP32-S2, GPIO 46 is input-only so cannot be used as outputs.
config MOSI_GPIO
int "MOSI GPIO number"
range 0 GPIO_RANGE_MAX
default 23 if IDF_TARGET_ESP32
default 35 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
default 2 # C3 and others
help
GPIO number (IOxx) to SPI MOSI.
Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to MOSI.
On the ESP32, GPIOs 35-39 are input-only so cannot be used as outputs.
On the ESP32-S2, GPIO 46 is input-only so cannot be used as outputs.
config CE_GPIO
int "CE GPIO number"
range 0 GPIO_RANGE_MAX
default 16 if IDF_TARGET_ESP32
default 34 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
default 1 # C3 and others
help
GPIO number (IOxx) to CE.
Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to CE.
On the ESP32, GPIOs 35-39 are input-only so cannot be used as outputs.
On the ESP32-S2, GPIO 46 is input-only so cannot be used as outputs.
config CSN_GPIO
int "CSN GPIO number"
range 0 GPIO_RANGE_MAX
default 17 if IDF_TARGET_ESP32
default 33 if IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
default 0 # C3 and others
help
GPIO number (IOxx) to CSN.
Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to CSN.
On the ESP32, GPIOs 35-39 are input-only so cannot be used as outputs.
On the ESP32-S2, GPIO 46 is input-only so cannot be used as outputs.
choice SPI_HOST
prompt "SPI peripheral that controls this bus"
default SPI2_HOST
help
Select SPI peripheral that controls this bus.
config SPI2_HOST
bool "SPI2_HOST"
help
Use SPI2_HOST. This is also called HSPI_HOST.
config SPI3_HOST
depends on IDF_TARGET_ESP32 || IDF_TARGET_ESP32S2 || IDF_TARGET_ESP32S3
bool "SPI3_HOST"
help
USE SPI3_HOST. This is also called VSPI_HOST
endchoice
config ADVANCED
bool "Enable Advanced Setting"
default false
help
Enable Advanced Setting.
choice RF_RATIO
depends on ADVANCED
prompt "RF Data Ratio"
default RF_RATIO_2M
help
Select RF Data Ratio.
config RF_RATIO_2M
bool "2Mbps"
help
RF Data Ratio is 2Mbps.
config RF_RATIO_1M
bool "1Mbps"
help
RF Data Ratio is 1Mbps.
config RF_RATIO_250K
bool "250Kbps"
help
RF Data Ratio is 250Kbps.
endchoice
config RETRANSMIT_DELAY
depends on ADVANCED
int "Auto Retransmit Delay"
range 0 15
default 0
help
Set Auto Retransmit Delay.
Delay = value * 250us.
endmenu

View File

@ -0,0 +1,613 @@
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <driver/spi_master.h>
#include <driver/gpio.h>
#include "esp_log.h"
#include "mirf.h"
#define TAG "NRF24"
// SPI Stuff
#if CONFIG_SPI2_HOST
#define HOST_ID SPI2_HOST
#elif CONFIG_SPI3_HOST
#define HOST_ID SPI3_HOST
#endif
static const int SPI_Frequency = 4000000; // Stable even with a long jumper cable
//static const int SPI_Frequency = 6000000;
//static const int SPI_Frequency = 8000000; // Requires a short jumper cable
//static const int SPI_Frequency = 10000000; // Unstable even with a short jumper cable
//const char rf24_datarates[][8] = {"1Mbps", "2Mbps", "250Kbps"};
char rf24_datarates[][8] = {"1Mbps", "2Mbps", "250Kbps"};
const char rf24_crclength[][10] = {"Disabled", "8 bits", "16 bits"};
//const char rf24_pa_dbm[][8] = {"PA_MIN", "PA_LOW", "PA_HIGH", "PA_MAX"};
char rf24_pa_dbm[][8] = {"PA_MIN", "PA_LOW", "PA_HIGH", "PA_MAX"};
void Nrf24_init(NRF24_t * dev)
{
esp_err_t ret;
ESP_LOGI(TAG, "CONFIG_MISO_GPIO=%d", CONFIG_MISO_GPIO);
ESP_LOGI(TAG, "CONFIG_MOSI_GPIO=%d", CONFIG_MOSI_GPIO);
ESP_LOGI(TAG, "CONFIG_SCLK_GPIO=%d", CONFIG_SCLK_GPIO);
ESP_LOGI(TAG, "CONFIG_CE_GPIO=%d", CONFIG_CE_GPIO);
ESP_LOGI(TAG, "CONFIG_CSN_GPIO=%d", CONFIG_CSN_GPIO);
//gpio_pad_select_gpio(CONFIG_CE_GPIO);
gpio_reset_pin(CONFIG_CE_GPIO);
gpio_set_direction(CONFIG_CE_GPIO, GPIO_MODE_OUTPUT);
gpio_set_level(CONFIG_CE_GPIO, 0);
//gpio_pad_select_gpio(CONFIG_CSN_GPIO);
gpio_reset_pin(CONFIG_CSN_GPIO);
gpio_set_direction(CONFIG_CSN_GPIO, GPIO_MODE_OUTPUT);
gpio_set_level(CONFIG_CSN_GPIO, 1);
spi_bus_config_t spi_bus_config = {
.sclk_io_num = CONFIG_SCLK_GPIO,
.mosi_io_num = CONFIG_MOSI_GPIO,
.miso_io_num = CONFIG_MISO_GPIO,
.quadwp_io_num = -1,
.quadhd_io_num = -1
};
ret = spi_bus_initialize( HOST_ID, &spi_bus_config, SPI_DMA_CH_AUTO );
ESP_LOGI(TAG, "spi_bus_initialize=%d",ret);
assert(ret==ESP_OK);
spi_device_interface_config_t devcfg;
memset( &devcfg, 0, sizeof( spi_device_interface_config_t ) );
devcfg.clock_speed_hz = SPI_Frequency;
// It does not work with hardware CS control.
//devcfg.spics_io_num = csn_pin;
// It does work with software CS control.
devcfg.spics_io_num = -1;
devcfg.queue_size = 7;
devcfg.mode = 0;
devcfg.flags = SPI_DEVICE_NO_DUMMY;
spi_device_handle_t handle;
ret = spi_bus_add_device( HOST_ID, &devcfg, &handle);
ESP_LOGI(TAG, "spi_bus_add_device=%d",ret);
assert(ret==ESP_OK);
dev->cePin = CONFIG_CE_GPIO;
dev->csnPin = CONFIG_CSN_GPIO;
dev->channel = 1;
dev->payload = 16;
dev->_SPIHandle = handle;
}
bool spi_write_byte(NRF24_t * dev, uint8_t* Dataout, size_t DataLength )
{
spi_transaction_t SPITransaction;
if ( DataLength > 0 ) {
memset( &SPITransaction, 0, sizeof( spi_transaction_t ) );
SPITransaction.length = DataLength * 8;
SPITransaction.tx_buffer = Dataout;
SPITransaction.rx_buffer = NULL;
spi_device_transmit( dev->_SPIHandle, &SPITransaction );
}
return true;
}
bool spi_read_byte(NRF24_t * dev, uint8_t* Datain, uint8_t* Dataout, size_t DataLength )
{
spi_transaction_t SPITransaction;
if ( DataLength > 0 ) {
memset( &SPITransaction, 0, sizeof( spi_transaction_t ) );
SPITransaction.length = DataLength * 8;
SPITransaction.tx_buffer = Dataout;
SPITransaction.rx_buffer = Datain;
spi_device_transmit( dev->_SPIHandle, &SPITransaction );
}
return true;
}
uint8_t spi_transfer(NRF24_t * dev, uint8_t address) {
uint8_t datain[1];
uint8_t dataout[1];
dataout[0] = address;
//spi_write_byte(dev, dataout, 1 );
spi_read_byte(dev, datain, dataout, 1 );
return datain[0];
}
void spi_csnHi(NRF24_t * dev) {
gpio_set_level( dev->csnPin, 1 );
}
void spi_csnLow(NRF24_t * dev) {
gpio_set_level( dev->csnPin, 0 );
}
// Sets the important registers in the MiRF module and powers the module
// in receiving mode
// NB: channel and payload must be set now.
void Nrf24_config(NRF24_t * dev, uint8_t channel, uint8_t payload)
{
dev->channel = channel;
dev->payload = payload;
Nrf24_configRegister(dev, RF_CH, dev->channel); // Set RF channel
Nrf24_configRegister(dev, RX_PW_P0, dev->payload); // Set length of incoming payload
Nrf24_configRegister(dev, RX_PW_P1, dev->payload);
Nrf24_powerUpRx(dev); // Start receiver
Nrf24_flushRx(dev);
}
// Sets the receiving device address
//void Nrf24_setRADDR(NRF24_t * dev, uint8_t * adr)
esp_err_t Nrf24_setRADDR(NRF24_t * dev, uint8_t * adr)
{
esp_err_t ret = ESP_OK;
Nrf24_writeRegister(dev, RX_ADDR_P1, adr, mirf_ADDR_LEN);
uint8_t buffer[5];
Nrf24_readRegister(dev, RX_ADDR_P1, buffer, sizeof(buffer));
for (int i=0;i<5;i++) {
ESP_LOGD(TAG, "adr[%d]=0x%x buffer[%d]=0x%x", i, adr[i], i, buffer[i]);
if (adr[i] != buffer[i]) ret = ESP_FAIL;
}
return ret;
}
// Sets the transmitting device address
//void Nrf24_setTADDR(NRF24_t * dev, uint8_t * adr)
esp_err_t Nrf24_setTADDR(NRF24_t * dev, uint8_t * adr)
{
esp_err_t ret = ESP_OK;
Nrf24_writeRegister(dev, RX_ADDR_P0, adr, mirf_ADDR_LEN); //RX_ADDR_P0 must be set to the sending addr for auto ack to work.
Nrf24_writeRegister(dev, TX_ADDR, adr, mirf_ADDR_LEN);
uint8_t buffer[5];
Nrf24_readRegister(dev, RX_ADDR_P0, buffer, sizeof(buffer));
for (int i=0;i<5;i++) {
ESP_LOGD(TAG, "adr[%d]=0x%x buffer[%d]=0x%x", i, adr[i], i, buffer[i]);
if (adr[i] != buffer[i]) ret = ESP_FAIL;
}
return ret;
}
// Add the receiving device address
void Nrf24_addRADDR(NRF24_t * dev, uint8_t pipe, uint8_t adr)
{
uint8_t value;
Nrf24_readRegister(dev, EN_RXADDR, &value, 1);
if (pipe == 2) {
Nrf24_configRegister(dev, RX_PW_P2, dev->payload);
Nrf24_configRegister(dev, RX_ADDR_P2, adr);
value = value | 0x04;
Nrf24_configRegister(dev, EN_RXADDR, value);
} else if (pipe == 3) {
Nrf24_configRegister(dev, RX_PW_P3, dev->payload);
Nrf24_configRegister(dev, RX_ADDR_P3, adr);
value = value | 0x08;
Nrf24_configRegister(dev, EN_RXADDR, value);
} else if (pipe == 4) {
Nrf24_configRegister(dev, RX_PW_P4, dev->payload);
Nrf24_configRegister(dev, RX_ADDR_P4, adr);
value = value | 0x10;
Nrf24_configRegister(dev, EN_RXADDR, value);
} else if (pipe == 5) {
Nrf24_configRegister(dev, RX_PW_P5, dev->payload);
Nrf24_configRegister(dev, RX_ADDR_P5, adr);
value = value | 0x20;
Nrf24_configRegister(dev, EN_RXADDR, value);
}
}
// Checks if data is available for reading
extern bool Nrf24_dataReady(NRF24_t * dev)
{
// See note in getData() function - just checking RX_DR isn't good enough
uint8_t status = Nrf24_getStatus(dev);
//printf("Nrf24_dataReady status=0x%x\n", status);
if ( status & (1 << RX_DR) ) {
// Save status
dev->status = status;
return 1;
}
// We can short circuit on RX_DR, but if it's not set, we still need
// to check the FIFO for any pending packets
//return !Nrf24_rxFifoEmpty(dev);
return 0;
}
// Get pipe number for reading
uint8_t Nrf24_getDataPipe(NRF24_t * dev) {
//uint8_t status = Nrf24_getStatus(dev);
//printf("dev->status=0x%x\n",dev->status);
return ((dev->status & 0x0E) >> 1);
}
extern bool Nrf24_rxFifoEmpty(NRF24_t * dev)
{
uint8_t fifoStatus;
Nrf24_readRegister(dev, FIFO_STATUS, &fifoStatus, sizeof(fifoStatus));
return (fifoStatus & (1 << RX_EMPTY));
}
// Reads payload bytes into data array
extern void Nrf24_getData(NRF24_t * dev, uint8_t * data)
{
spi_csnLow(dev); // Pull down chip select
spi_transfer(dev, R_RX_PAYLOAD ); // Send cmd to read rx payload
spi_read_byte(dev, data, data, dev->payload); // Read payload
spi_csnHi(dev); // Pull up chip select
// NVI: per product spec, p 67, note c:
// "The RX_DR IRQ is asserted by a new packet arrival event. The procedure
// for handling this interrupt should be: 1) read payload through SPI,
// 2) clear RX_DR IRQ, 3) read FIFO_STATUS to check if there are more
// payloads available in RX FIFO, 4) if there are more data in RX FIFO,
// repeat from step 1)."
// So if we're going to clear RX_DR here, we need to check the RX FIFO
// in the dataReady() function
Nrf24_configRegister(dev, STATUS, (1 << RX_DR)); // Reset status register
}
// Clocks only one byte into the given MiRF register
void Nrf24_configRegister(NRF24_t * dev, uint8_t reg, uint8_t value)
{
spi_csnLow(dev);
spi_transfer(dev, W_REGISTER | (REGISTER_MASK & reg));
spi_transfer(dev, value);
spi_csnHi(dev);
}
// Reads an array of bytes from the given start position in the MiRF registers
void Nrf24_readRegister(NRF24_t * dev, uint8_t reg, uint8_t * value, uint8_t len)
{
spi_csnLow(dev);
spi_transfer(dev, R_REGISTER | (REGISTER_MASK & reg));
spi_read_byte(dev, value, value, len);
spi_csnHi(dev);
}
// Writes an array of bytes into inte the MiRF registers
void Nrf24_writeRegister(NRF24_t * dev, uint8_t reg, uint8_t * value, uint8_t len)
{
spi_csnLow(dev);
spi_transfer(dev, W_REGISTER | (REGISTER_MASK & reg));
spi_write_byte(dev, value, len);
spi_csnHi(dev);
}
// Sends a data package to the default address. Be sure to send the correct
// amount of bytes as configured as payload on the receiver.
void Nrf24_send(NRF24_t * dev, uint8_t * value)
{
uint8_t status;
status = Nrf24_getStatus(dev);
while (dev->PTX) // Wait until last paket is send
{
status = Nrf24_getStatus(dev);
if ((status & ((1 << TX_DS) | (1 << MAX_RT))))
{
dev->PTX = 0;
break;
}
}
Nrf24_ceLow(dev);
Nrf24_powerUpTx(dev); // Set to transmitter mode , Power up
spi_csnLow(dev); // Pull down chip select
spi_transfer(dev, FLUSH_TX ); // Write cmd to flush tx fifo
spi_csnHi(dev); // Pull up chip select
spi_csnLow(dev); // Pull down chip select
spi_transfer(dev, W_TX_PAYLOAD ); // Write cmd to write payload
spi_write_byte(dev, value, dev->payload); // Write payload
spi_csnHi(dev); // Pull up chip select
Nrf24_ceHi(dev); // Start transmission
}
// Test if chip is still sending.
// When sending has finished return chip to listening.
bool Nrf24_isSending(NRF24_t * dev) {
uint8_t status;
if (dev->PTX)
{
status = Nrf24_getStatus(dev);
if ((status & ((1 << TX_DS) | (1 << MAX_RT)))) {// if sending successful (TX_DS) or max retries exceded (MAX_RT).
Nrf24_powerUpRx(dev);
return false;
}
return true;
}
return false;
}
// Test if Sending has finished or retry is over.
// When sending has finished return trur.
// When reach maximum number of TX retries return false.
bool Nrf24_isSend(NRF24_t * dev, int timeout) {
uint8_t status;
TickType_t startTick = xTaskGetTickCount();
if (dev->PTX) {
while(1) {
status = Nrf24_getStatus(dev);
/*
if sending successful (TX_DS) or max retries exceded (MAX_RT).
*/
if (status & (1 << TX_DS)) { // Data Sent TX FIFO interrup
Nrf24_powerUpRx(dev);
return true;
}
if (status & (1 << MAX_RT)) { // Maximum number of TX retries interrupt
ESP_LOGW(TAG, "Maximum number of TX retries interrupt");
Nrf24_powerUpRx(dev);
return false;
}
// I believe either TX_DS or MAX_RT will always be notified.
// Therefore, it is unusual for neither to be notified for a period of time.
// I don't know exactly how to respond.
TickType_t diffTick = xTaskGetTickCount() - startTick;
if ( (diffTick * portTICK_PERIOD_MS) > timeout) {
ESP_LOGE(TAG, "Status register timeout. status=0x%x", status);
return false;
}
vTaskDelay(1);
}
}
return false;
}
uint8_t Nrf24_getStatus(NRF24_t * dev) {
uint8_t rv;
Nrf24_readRegister(dev, STATUS, &rv, 1);
return rv;
}
void Nrf24_powerUpRx(NRF24_t * dev) {
dev->PTX = 0;
Nrf24_ceLow(dev);
Nrf24_configRegister(dev, CONFIG, mirf_CONFIG | ( (1 << PWR_UP) | (1 << PRIM_RX) ) ); //set device as RX mode
Nrf24_ceHi(dev);
Nrf24_configRegister(dev, STATUS, (1 << TX_DS) | (1 << MAX_RT)); //Clear seeded interrupt and max tx number interrupt
}
void Nrf24_flushRx(NRF24_t * dev)
{
spi_csnLow(dev);
spi_transfer(dev, FLUSH_RX );
spi_csnHi(dev);
}
void Nrf24_powerUpTx(NRF24_t * dev) {
dev->PTX = 1;
Nrf24_configRegister(dev, CONFIG, mirf_CONFIG | ( (1 << PWR_UP) | (0 << PRIM_RX) ) ); //set device as TX mode
Nrf24_configRegister(dev, STATUS, (1 << TX_DS) | (1 << MAX_RT)); //Clear seeded interrupt and max tx number interrupt
}
void Nrf24_ceHi(NRF24_t * dev) {
gpio_set_level( dev->cePin, 1 );
}
void Nrf24_ceLow(NRF24_t * dev) {
gpio_set_level( dev->cePin, 0 );
}
void Nrf24_powerDown(NRF24_t * dev)
{
Nrf24_ceLow(dev);
Nrf24_configRegister(dev, CONFIG, mirf_CONFIG );
}
//Set tx power : 0=-18dBm,1=-12dBm,2=-6dBm,3=0dBm
void Nrf24_SetOutputRF_PWR(NRF24_t * dev, uint8_t val)
{
if (val > 3) return;
uint8_t value;
Nrf24_readRegister(dev, RF_SETUP, &value, 1);
value = value & 0xF9;
value = value | (val<< RF_PWR);
//Nrf24_configRegister(dev, RF_SETUP, (val<< RF_PWR) );
Nrf24_configRegister(dev, RF_SETUP, value);
}
//Select between the high speed data rates:0=1Mbps, 1=2Mbps, 2=250Kbps
void Nrf24_SetSpeedDataRates(NRF24_t * dev, uint8_t val)
{
if (val > 2) return;
uint8_t value;
Nrf24_readRegister(dev, RF_SETUP, &value, 1);
if(val == 2)
{
value = value | 0x20;
value = value & 0xF7;
//Nrf24_configRegister(dev, RF_SETUP, (1 << RF_DR_LOW) );
Nrf24_configRegister(dev, RF_SETUP, value);
}
else
{
value = value & 0xD7;
value = value | (val << RF_DR_HIGH);
//Nrf24_configRegister(dev, RF_SETUP, (val << RF_DR_HIGH) );
Nrf24_configRegister(dev, RF_SETUP, value);
}
}
//Set Auto Retransmit Delay 0=250us, 1=500us, ... 15=4000us
void Nrf24_setRetransmitDelay(NRF24_t * dev, uint8_t val)
{
uint8_t value;
Nrf24_readRegister(dev, SETUP_RETR, &value, 1);
value = value & 0x0F;
value = value | (val << ARD);
Nrf24_configRegister(dev, SETUP_RETR, value);
}
void Nrf24_printDetails(NRF24_t * dev)
{
printf("================ SPI Configuration ================\n" );
printf("CSN Pin \t = GPIO%d\n",dev->csnPin);
printf("CE Pin \t = GPIO%d\n", dev->cePin);
printf("Clock Speed\t = %d\n", SPI_Frequency);
printf("================ NRF Configuration ================\n");
Nrf24_print_status(Nrf24_getStatus(dev));
Nrf24_print_address_register(dev, "RX_ADDR_P0-1", RX_ADDR_P0, 2);
Nrf24_print_byte_register(dev, "RX_ADDR_P2-5", RX_ADDR_P2, 4);
Nrf24_print_address_register(dev, "TX_ADDR\t", TX_ADDR, 1);
Nrf24_print_byte_register(dev, "RX_PW_P0-6", RX_PW_P0, 6);
Nrf24_print_byte_register(dev, "EN_AA\t", EN_AA, 1);
Nrf24_print_byte_register(dev, "EN_RXADDR", EN_RXADDR, 1);
Nrf24_print_byte_register(dev, "RF_CH\t", RF_CH, 1);
Nrf24_print_byte_register(dev, "RF_SETUP", RF_SETUP, 1);
Nrf24_print_byte_register(dev, "CONFIG\t", CONFIG, 1);
Nrf24_print_byte_register(dev, "DYNPD/FEATURE", DYNPD, 2);
//printf("getDataRate()=%d\n",Nrf24_getDataRate(dev));
printf("Data Rate\t = %s\n",rf24_datarates[Nrf24_getDataRate(dev)]);
#if 0
printf_P(PSTR("Model\t\t = "
PRIPSTR
"\r\n"),pgm_read_ptr(&rf24_model_e_str_P[isPVariant()]));
#endif
//printf("getCRCLength()=%d\n",Nrf24_getCRCLength(dev));
printf("CRC Length\t = %s\n", rf24_crclength[Nrf24_getCRCLength(dev)]);
//printf("getPALevel()=%d\n",Nrf24_getPALevel(dev));
printf("PA Power\t = %s\n", rf24_pa_dbm[Nrf24_getPALevel(dev)]);
uint8_t retransmit = Nrf24_getRetransmitDelay(dev);
int16_t delay = (retransmit+1)*250;
printf("Retransmit\t = %d us\n", delay);
}
#define _BV(x) (1<<(x))
void Nrf24_print_status(uint8_t status)
{
printf("STATUS\t\t = 0x%02x RX_DR=%x TX_DS=%x MAX_RT=%x RX_P_NO=%x TX_FULL=%x\r\n", status, (status & _BV(RX_DR)) ? 1 : 0,
(status & _BV(TX_DS)) ? 1 : 0, (status & _BV(MAX_RT)) ? 1 : 0, ((status >> RX_P_NO) & 0x07), (status & _BV(TX_FULL)) ? 1 : 0);
}
void Nrf24_print_address_register(NRF24_t * dev, const char* name, uint8_t reg, uint8_t qty)
{
printf("%s\t =",name);
while (qty--) {
//uint8_t buffer[addr_width];
uint8_t buffer[5];
Nrf24_readRegister(dev, reg++, buffer, sizeof(buffer));
printf(" 0x");
#if 0
uint8_t* bufptr = buffer + sizeof buffer;
while (--bufptr >= buffer) {
printf("%02x", *bufptr);
}
#endif
for(int i=0;i<5;i++) {
printf("%02x", buffer[i]);
}
}
printf("\r\n");
}
void Nrf24_print_byte_register(NRF24_t * dev, const char* name, uint8_t reg, uint8_t qty)
{
printf("%s\t =", name);
while (qty--) {
uint8_t buffer[1];
Nrf24_readRegister(dev, reg++, buffer, 1);
printf(" 0x%02x", buffer[0]);
}
printf("\r\n");
}
uint8_t Nrf24_getDataRate(NRF24_t * dev)
{
rf24_datarate_e result;
uint8_t dr;
Nrf24_readRegister(dev, RF_SETUP, &dr, sizeof(dr));
//printf("RF_SETUP=%x\n",dr);
dr = dr & (_BV(RF_DR_LOW) | _BV(RF_DR_HIGH));
// switch uses RAM (evil!)
// Order matters in our case below
if (dr == _BV(RF_DR_LOW)) {
// '10' = 250KBPS
result = RF24_250KBPS;
} else if (dr == _BV(RF_DR_HIGH)) {
// '01' = 2MBPS
result = RF24_2MBPS;
} else {
// '00' = 1MBPS
result = RF24_1MBPS;
}
return result;
}
char * Nrf24_getDataRateString(NRF24_t * dev)
{
return rf24_datarates[Nrf24_getDataRate(dev)];
}
uint8_t Nrf24_getCRCLength(NRF24_t * dev)
{
rf24_crclength_e result = RF24_CRC_DISABLED;
uint8_t config;
Nrf24_readRegister(dev, CONFIG, &config, sizeof(config));
//printf("CONFIG=%x\n",config);
config = config & (_BV(CRCO) | _BV(EN_CRC));
uint8_t AA;
Nrf24_readRegister(dev, EN_AA, &AA, sizeof(AA));
if (config & _BV(EN_CRC) || AA) {
if (config & _BV(CRCO)) {
result = RF24_CRC_16;
} else {
result = RF24_CRC_8;
}
}
return result;
}
uint8_t Nrf24_getPALevel(NRF24_t * dev)
{
uint8_t level;
Nrf24_readRegister(dev, RF_SETUP, &level, sizeof(level));
//printf("RF_SETUP=%x\n",level);
level = (level & (_BV(RF_PWR_LOW) | _BV(RF_PWR_HIGH))) >> 1;
return (level);
}
char * Nrf24_getPALevelString(NRF24_t * dev)
{
return rf24_pa_dbm[Nrf24_getPALevel(dev)];
}
uint8_t Nrf24_getRetransmitDelay(NRF24_t * dev)
{
uint8_t value;
Nrf24_readRegister(dev, SETUP_RETR, &value, 1);
return (value >> 4);
}
uint8_t Nrf24_getChannle(NRF24_t * dev)
{
return dev->channel;
}
uint8_t Nrf24_getPayload(NRF24_t * dev)
{
return dev->payload;
}

View File

@ -0,0 +1,211 @@
#ifndef MAIN_MIRF_H_
#define MAIN_MIRF_H_
#include "driver/spi_master.h"
typedef struct {
uint8_t PTX; //In sending mode.
uint8_t cePin;// CE Pin controls RX / TX, default 8.
uint8_t csnPin;//CSN Pin Chip Select Not, default 7.
uint8_t channel;//Channel 0 - 127 or 0 - 84 in the US.
uint8_t payload;// Payload width in bytes default 16 max 32.
spi_device_handle_t _SPIHandle;
uint8_t status;// Receive status
} NRF24_t;
/* Memory Map */
#define CONFIG 0x00
#define EN_AA 0x01
#define EN_RXADDR 0x02
#define SETUP_AW 0x03
#define SETUP_RETR 0x04
#define RF_CH 0x05
#define RF_SETUP 0x06
#define STATUS 0x07
#define OBSERVE_TX 0x08
#define CD 0x09
#define RX_ADDR_P0 0x0A
#define RX_ADDR_P1 0x0B
#define RX_ADDR_P2 0x0C
#define RX_ADDR_P3 0x0D
#define RX_ADDR_P4 0x0E
#define RX_ADDR_P5 0x0F
#define TX_ADDR 0x10
#define RX_PW_P0 0x11
#define RX_PW_P1 0x12
#define RX_PW_P2 0x13
#define RX_PW_P3 0x14
#define RX_PW_P4 0x15
#define RX_PW_P5 0x16
#define FIFO_STATUS 0x17
#define DYNPD 0x1C
#define FEATURE 0x1D
/* Bit Mnemonics */
#define MASK_RX_DR 6
#define MASK_TX_DS 5
#define MASK_MAX_RT 4
#define EN_CRC 3
#define CRCO 2
#define PWR_UP 1
#define PRIM_RX 0
#define ENAA_P5 5
#define ENAA_P4 4
#define ENAA_P3 3
#define ENAA_P2 2
#define ENAA_P1 1
#define ENAA_P0 0
#define ERX_P5 5
#define ERX_P4 4
#define ERX_P3 3
#define ERX_P2 2
#define ERX_P1 1
#define ERX_P0 0
#define AW 0
#define ARD 4
#define ARC 0
#define RF_DR_LOW 5
#define PLL_LOCK 4
#define RF_DR_HIGH 3
#define RF_PWR 1
#define LNA_HCURR 0
#define RX_DR 6
#define TX_DS 5
#define MAX_RT 4
#define RX_P_NO 1
#define TX_FULL 0
#define PLOS_CNT 4
#define ARC_CNT 0
#define TX_REUSE 6
#define FIFO_FULL 5
#define TX_EMPTY 4
#define RX_FULL 1
#define RX_EMPTY 0
/* Instruction Mnemonics */
#define R_REGISTER 0x00
#define W_REGISTER 0x20
#define REGISTER_MASK 0x1F
#define R_RX_PAYLOAD 0x61
#define W_TX_PAYLOAD 0xA0
#define FLUSH_TX 0xE1
#define FLUSH_RX 0xE2
#define REUSE_TX_PL 0xE3
#define NOP 0xFF
/* Non-P omissions */
#define LNA_HCURR 0
/* P model memory Map */
#define RPD 0x09
#define W_TX_PAYLOAD_NO_ACK 0xB0
/* P model bit Mnemonics */
#define RF_DR_LOW 5
#define RF_DR_HIGH 3
#define RF_PWR_LOW 1
#define RF_PWR_HIGH 2
/* Device addrees length:3~5 bytes */
#define mirf_ADDR_LEN 5
/*
enable interrupt caused by RX_DR.
enable interrupt caused by TX_DS.
enable interrupt caused by MAX_RT.
enable CRC and CRC data len=1
mirf_CONFIG = 00001000B
*/
//#define mirf_CONFIG ((1<<EN_CRC) | (0<<CRCO) )
/*
enable interrupt caused by RX_DR.
disable interrupt caused by TX_DS.
enable interrupt caused by MAX_RT.
enable CRC and CRC data len=1
mirf_CONFIG == 00101000B
*/
#define mirf_CONFIG ((1<<MASK_TX_DS) | (1<<EN_CRC) | (0<<CRCO) )
/**
* Power Amplifier level.
*
* For use with setPALevel()
*/
typedef enum {
RF24_PA_MIN = 0,
RF24_PA_LOW,
RF24_PA_HIGH,
RF24_PA_MAX,
RF24_PA_ERROR
} rf24_pa_dbm_e;
/**
* Data rate. How fast data moves through the air.
*
* For use with setDataRate()
*/
typedef enum {
RF24_1MBPS = 0,
RF24_2MBPS,
RF24_250KBPS
} rf24_datarate_e;
/**
* CRC Length. How big (if any) of a CRC is included.
*
* For use with setCRCLength()
*/
typedef enum {
RF24_CRC_DISABLED = 0,
RF24_CRC_8,
RF24_CRC_16
} rf24_crclength_e;
void Nrf24_init(NRF24_t * dev);
bool spi_write_byte(NRF24_t * dev, uint8_t* Dataout, size_t DataLength );
bool spi_read_byte(NRF24_t * dev, uint8_t* Datain, uint8_t* Dataout, size_t DataLength );
uint8_t spi_transfer(NRF24_t * dev, uint8_t address);
void spi_csnLow(NRF24_t * dev);
void spi_csnHi(NRF24_t * dev);
void Nrf24_config(NRF24_t * dev, uint8_t channel, uint8_t payload);
void Nrf24_send(NRF24_t * dev, uint8_t *value);
esp_err_t Nrf24_setRADDR(NRF24_t * dev, uint8_t * adr);
esp_err_t Nrf24_setTADDR(NRF24_t * dev, uint8_t * adr);
void Nrf24_addRADDR(NRF24_t * dev, uint8_t pipe, uint8_t adr);
bool Nrf24_dataReady(NRF24_t * dev);
uint8_t Nrf24_getDataPipe(NRF24_t * dev);
bool Nrf24_isSending(NRF24_t * dev);
bool Nrf24_isSend(NRF24_t * dev, int timeout);
bool Nrf24_rxFifoEmpty(NRF24_t * dev);
bool Nrf24_txFifoEmpty(NRF24_t * dev);
void Nrf24_getData(NRF24_t * dev, uint8_t * data);
uint8_t Nrf24_getStatus(NRF24_t * dev);
void Nrf24_configRegister(NRF24_t * dev, uint8_t reg, uint8_t value);
void Nrf24_readRegister(NRF24_t * dev, uint8_t reg, uint8_t * value, uint8_t len);
void Nrf24_writeRegister(NRF24_t * dev, uint8_t reg, uint8_t * value, uint8_t len);
void Nrf24_powerUpRx(NRF24_t * dev);
void Nrf24_powerUpTx(NRF24_t * dev);
void Nrf24_powerDown(NRF24_t * dev);
void Nrf24_SetOutputRF_PWR(NRF24_t * dev, uint8_t val);
void Nrf24_SetSpeedDataRates(NRF24_t * dev, uint8_t val);
void Nrf24_setRetransmitDelay(NRF24_t * dev, uint8_t val);
void Nrf24_ceHi(NRF24_t * dev);
void Nrf24_ceLow(NRF24_t * dev);
void Nrf24_flushRx(NRF24_t * dev);
void Nrf24_printDetails(NRF24_t * dev);
void Nrf24_print_status(uint8_t status);
void Nrf24_print_address_register(NRF24_t * dev, const char* name, uint8_t reg, uint8_t qty);
void Nrf24_print_byte_register(NRF24_t * dev, const char* name, uint8_t reg, uint8_t qty);
uint8_t Nrf24_getDataRate(NRF24_t * dev);
char * Nrf24_getDataRateString(NRF24_t * dev);
uint8_t Nrf24_getCRCLength(NRF24_t * dev);
uint8_t Nrf24_getPALevel(NRF24_t * dev);
char * Nrf24_getPALevelString(NRF24_t * dev);
uint8_t Nrf24_getRetransmitDelay(NRF24_t * dev);
uint8_t Nrf24_getChannle(NRF24_t * dev);
uint8_t Nrf24_getPayload(NRF24_t * dev);
#endif /* MAIN_MIRF_H_ */

View File

@ -0,0 +1,8 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS ../components/mirf)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(mirf)

View File

@ -0,0 +1,78 @@
# HTTP Example
This is nRF24L01 and HTTP gateway application.
```
+-----------+ +-----------+ +-----------+
| | | | | |
|HTTP Client|--(HTTP)-->| ESP32 |--(SPI)--->| nRF24L01 |==(Radio)==>
| | | | | |
+-----------+ +-----------+ +-----------+
+-----------+ +-----------+ +-----------+
| | | | | |
==(Radio)==>| nRF24L01 |--(SPI)--->| ESP32 |--(HTTP)-->|HTTP Server|
| | | | | |
+-----------+ +-----------+ +-----------+
```
# Configuration
![config-top](https://github.com/nopnop2002/esp-idf-mirf/assets/6020549/e8e22c35-da61-4d5b-82ab-751b05d54d98)
![config-app](https://github.com/nopnop2002/esp-idf-mirf/assets/6020549/aeb5992b-ca2e-4ec9-aa56-7b70e8a06491)
## WiFi Setting
![config-wifi](https://github.com/nopnop2002/esp-idf-mirf/assets/6020549/49cba564-dd2b-46b9-bcc4-c928a816697c)
## Radioi Setting
### HTTP to Radio
Subscribe with HTTP and send to Radio.
ESP32 acts as HTTP Server.
You can use curl as HTTP Client.
```sh ./http-client.sh```
```
+-----------+ +-----------+ +-----------+
| | | | | |
|HTTP Client|--(HTTP)-->| ESP32 |--(SPI)--->| nRF24L01 |==(Radio)==>
| | | | | |
+-----------+ +-----------+ +-----------+
```
![config-radio-1](https://github.com/nopnop2002/esp-idf-mirf/assets/6020549/562285e0-3c3a-4315-b960-ab27186e9c95)
### Radio to HTTP
Receive from Radio and publish as HTTP.
ESP32 acts as HTTP Client.
You can use nc(netcat) as HTTP Server.
```sh ./http-server.sh```
```
+-----------+ +-----------+ +-----------+
| | | | | |
==(Radio)==>| nRF24L01 |--(SPI)--->| ESP32 |--(HTTP)-->|HTTP Server|
| | | | | |
+-----------+ +-----------+ +-----------+
```
![config-radio-2](https://github.com/nopnop2002/esp-idf-mirf/assets/6020549/118b4d07-7c43-48d3-84fd-670e0e678370)
### Specifying an HTTP Server
You can specify your HTTP Server in one of the following ways:
- IP address
```192.168.10.20```
- mDNS host name
```http-server.local```
- Fully Qualified Domain Name
```http-server.public.io```
# Communicate with Arduino Environment
Run this sketch.
ArduinoCode\Peer-to-peer\StringTest

View File

@ -0,0 +1,32 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import time
import datetime
import socket
import requests
server = "esp32-server.local"
port = 8080
try:
ip = socket.gethostbyname(server)
except socket.gaierror as e:
print(f'Invalid hostname, error raised is {e}')
exit()
ip = socket.gethostbyname(server)
print("ip={}".format(ip))
uri = "http://{}:{}/post".format(ip, port)
print("uri={}".format(uri))
timezone = datetime.timedelta(hours=9)
while True:
dt_now = datetime.datetime.now(datetime.timezone(timezone))
#payload = "{}".format(datetime.datetime.now())
#payload = "{}".format(datetime.datetime.now(datetime.timezone(timezone)))
payload = dt_now.strftime('%Y/%m/%d %H:%M:%S')
#print(payload)
response = requests.post(uri, data=payload)
#print(response.status_code)
print("{}-->{}".format(payload, response.text))
#print(response.text)
time.sleep(1)

View File

@ -0,0 +1,17 @@
#!/bin/bash
#sudo apt install avahi-utils
#set -x
SERVER="esp32-server.local"
HOST=`avahi-resolve -4 -n ${SERVER} | cut -f 2`
echo $HOST
URI="http://${HOST}:8080/post"
while :
do
payload=`date "+%Y/%m/%d %H:%M:%S"`
#echo ${payload}
echo curl -d "${payload}" ${URI}
curl -d "${payload}" ${URI}
echo ""
sleep 1
done

View File

@ -0,0 +1,37 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# https://qiita.com/tkj/items/210a66213667bc038110
from http.server import HTTPServer
from http.server import BaseHTTPRequestHandler
from urllib.parse import urlparse
from urllib.parse import parse_qs
class class1(BaseHTTPRequestHandler):
def do_POST(self):
#parsed = urlparse(self.path)
#print("parsed={}".format(parsed))
#params = parse_qs(parsed.query)
#print("params={}".format(params))
content_len = int(self.headers.get("content-length"))
#print("content_len={}".format(content_len))
req_body = self.rfile.read(content_len).decode("utf-8")
#print("req_body={}".format(req_body))
print("{}".format(req_body))
body = "OK"
self.send_response(200)
self.send_header('Content-type', 'text/html; charset=utf-8')
self.send_header('Content-length', len(body.encode()))
self.end_headers()
self.wfile.write(body.encode())
#host = '127.0.0.1'
host = '0.0.0.0'
port = 8080
print("Listening on port {}". format(port))
server = HTTPServer((host, port), class1)
server.serve_forever()

View File

@ -0,0 +1,12 @@
#!/bin/bash
PORT=8080
echo "Listening on port" ${PORT}
while true
do
# Header & payload
#( echo "HTTP/1.0 200 Ok"; echo; echo -n "OK") | nc -l -p ${PORT} -w 1
# Payload only
( echo "HTTP/1.0 200 Ok"; echo; echo -n "OK") | nc -l -p ${PORT} -w 1 | tail -n 1
echo ""
done

View File

@ -0,0 +1,4 @@
set(component_srcs "main.c" "http_client.c" "http_server.c")
idf_component_register(SRCS "${component_srcs}"
INCLUDE_DIRS ".")

View File

@ -0,0 +1,71 @@
menu "Application Configuration"
menu "WiFi Setting"
config ESP_WIFI_SSID
string "WiFi SSID"
default "myssid"
help
SSID (network name) to connect to.
config ESP_WIFI_PASSWORD
string "WiFi Password"
default "mypassword"
help
WiFi password (WPA or WPA2) to connect to.
config ESP_MAXIMUM_RETRY
int "Maximum retry"
default 5
help
Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent.
config MDNS_HOSTNAME
string "mDNS Hostname"
default "esp32-server"
help
The mDNS host name used by the ESP32.
endmenu
menu "Radio Setting"
choice DIRECTION
prompt "Communication polarity"
default SENDER
help
Select Communication polarity.
config SENDER
bool "HTTP to Radio"
help
HTTP to Radio.
config RECEIVER
bool "Radio to HTTP"
help
Radio to HTTP.
endchoice
config WEB_SERVER_HOST
depends on RECEIVER
string "server to connect to"
default "http-server.local"
help
server to connect to.
config WEB_SERVER_PORT
depends on RECEIVER
int "port to connect to"
default 8080
help
port to connect to.
config WEB_SERVER_PORT
depends on SENDER
int "Listening port"
default 8080
help
Listening port.
endmenu
endmenu

View File

@ -0,0 +1,5 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

View File

@ -0,0 +1,195 @@
/* ESP HTTP Client Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <inttypes.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/message_buffer.h"
#include "esp_log.h"
#include "esp_system.h"
#include "esp_tls.h"
#include "esp_http_client.h"
#if CONFIG_RECEIVER
static const char *TAG = "CLIENT";
extern MessageBufferHandle_t xMessageBufferTrans;
extern size_t xItemSize;
esp_err_t _http_event_handler(esp_http_client_event_t *evt)
{
static char *output_buffer; // Buffer to store response of http request from event handler
static int output_len; // Stores number of bytes read
switch(evt->event_id) {
case HTTP_EVENT_ERROR:
ESP_LOGD(TAG, "HTTP_EVENT_ERROR");
break;
case HTTP_EVENT_ON_CONNECTED:
ESP_LOGI(TAG, "HTTP_EVENT_ON_CONNECTED");
break;
case HTTP_EVENT_HEADER_SENT:
ESP_LOGD(TAG, "HTTP_EVENT_HEADER_SENT");
break;
case HTTP_EVENT_ON_HEADER:
ESP_LOGD(TAG, "HTTP_EVENT_ON_HEADER, key=%s, value=%s", evt->header_key, evt->header_value);
break;
case HTTP_EVENT_ON_DATA:
ESP_LOGI(TAG, "HTTP_EVENT_ON_DATA, len=%d", evt->data_len);
/*
* Check for chunked encoding is added as the URL for chunked encoding used in this example returns binary data.
* However, event handler can also be used in case chunked encoding is used.
*/
if (!esp_http_client_is_chunked_response(evt->client)) {
// If user_data buffer is configured, copy the response into the buffer
if (evt->user_data) {
memcpy(evt->user_data + output_len, evt->data, evt->data_len);
} else {
if (output_buffer == NULL) {
output_buffer = (char *) malloc(esp_http_client_get_content_length(evt->client));
output_len = 0;
if (output_buffer == NULL) {
ESP_LOGE(TAG, "Failed to allocate memory for output buffer");
return ESP_FAIL;
}
}
memcpy(output_buffer + output_len, evt->data, evt->data_len);
}
output_len += evt->data_len;
}
break;
case HTTP_EVENT_ON_FINISH:
ESP_LOGD(TAG, "HTTP_EVENT_ON_FINISH");
if (output_buffer != NULL) {
// Response is accumulated in output_buffer. Uncomment the below line to print the accumulated response
// ESP_LOG_BUFFER_HEX(TAG, output_buffer, output_len);
free(output_buffer);
output_buffer = NULL;
}
output_len = 0;
break;
case HTTP_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "HTTP_EVENT_DISCONNECTED");
int mbedtls_err = 0;
esp_err_t err = esp_tls_get_and_clear_last_error(evt->data, &mbedtls_err, NULL);
ESP_LOGI(TAG, "Last esp error code: 0x%x", err);
ESP_LOGI(TAG, "Last mbedtls failure: 0x%x", mbedtls_err);
if (output_buffer != NULL) {
free(output_buffer);
output_buffer = NULL;
}
output_len = 0;
break;
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
case HTTP_EVENT_REDIRECT:
ESP_LOGD(TAG, "HTTP_EVENT_REDIRECT");
esp_http_client_set_header(evt->client, "From", "user@example.com");
esp_http_client_set_header(evt->client, "Accept", "text/html");
esp_http_client_set_redirection(evt->client);
break;
#endif
}
return ESP_OK;
}
#define MAX_HTTP_OUTPUT_BUFFER 128
esp_err_t http_post_with_url(char *url, char * post_data, size_t post_len)
{
ESP_LOGI(TAG, "http_post_with_url url=[%s]", url);
char local_response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};
/**
* NOTE: All the configuration parameters for http_client must be spefied either in URL or as host and path parameters.
* If host and path parameters are not set, query parameter will be ignored. In such cases,
* query parameter should be specified in URL.
*
* If URL as well as host and path parameters are specified, values of host and path will be considered.
*/
#if 1
esp_http_client_config_t config = {
.url = url,
.path = "/post",
.event_handler = _http_event_handler,
.user_data = local_response_buffer, // Pass address of local buffer to get response
.disable_auto_redirect = true,
};
#endif
#if 0
esp_http_client_config_t config = {
.url = "http://192.168.10.46:8080",
.path = "/post",
.event_handler = _http_event_handler,
.user_data = local_response_buffer, // Pass address of local buffer to get response
.disable_auto_redirect = true,
};
#endif
esp_http_client_handle_t client = esp_http_client_init(&config);
// POST
esp_http_client_set_method(client, HTTP_METHOD_POST);
esp_http_client_set_header(client, "Content-Type", "application/json");
//esp_http_client_set_post_field(client, post_data, strlen(post_data));
esp_http_client_set_post_field(client, post_data, post_len);
esp_err_t err = esp_http_client_perform(client);
if (err == ESP_OK) {
ESP_LOGI(TAG, "HTTP POST Status = %d, content_length = %d",
esp_http_client_get_status_code(client),
(int)esp_http_client_get_content_length(client));
ESP_LOGI(TAG, "local_response_buffer=[%s]", local_response_buffer);
} else {
ESP_LOGE(TAG, "HTTP POST request failed: %s", esp_err_to_name(err));
}
esp_http_client_cleanup(client);
return err;
}
esp_err_t query_mdns_host(const char * host_name, char *ip);
void convert_mdns_host(char * from, char * to);
void http_client(void *pvParameters)
{
ESP_LOGI(TAG, "Start WEB_SERVER_HOST:%s WEB_SERVER_PORT:%d", CONFIG_WEB_SERVER_HOST, CONFIG_WEB_SERVER_PORT);
// Resolve mDNS host name
char ip[128];
ESP_LOGI(TAG, "CONFIG_WEB_SERVER_HOST=[%s]", CONFIG_WEB_SERVER_HOST);
convert_mdns_host(CONFIG_WEB_SERVER_HOST, ip);
ESP_LOGI(TAG, "ip=[%s]", ip);
char url[142];
sprintf(url, "http://%s:%d", ip, CONFIG_WEB_SERVER_PORT);
ESP_LOGI(TAG, "url=[%s]", url);
char buffer[xItemSize];
while (1) {
size_t received = xMessageBufferReceive(xMessageBufferTrans, buffer, sizeof(buffer), portMAX_DELAY);
ESP_LOGI(TAG, "xMessageBufferReceive received=%d", received);
if (received > 0) {
ESP_LOGI(TAG, "xMessageBufferReceive buffer=[%.*s]",received, buffer);
//http_post_with_url("http://192.168.10.46:8000", buffer, received);
if (http_post_with_url(url, buffer, received) != ESP_OK) {
ESP_LOGE(TAG, "http_post_with_url fail");
}
} else {
ESP_LOGE(TAG, "xMessageBufferReceive fail");
break;
}
} // end while
// Stop connection
vTaskDelete(NULL);
}
#endif

View File

@ -0,0 +1,117 @@
/* Simple HTTP Server Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <inttypes.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/message_buffer.h"
#include "esp_log.h"
#include "esp_http_server.h"
#if CONFIG_SENDER
static const char *TAG = "SERVER";
extern MessageBufferHandle_t xMessageBufferRecv;
extern size_t xItemSize;
/* root post handler */
static esp_err_t root_post_handler(httpd_req_t *req)
{
ESP_LOGI(TAG, "root_post_handler. req->content_len=%d", req->content_len);
/* Allocate memory */
char *buf = NULL;
buf = malloc(req->content_len);
if (buf == NULL) {
ESP_LOGE(TAG, "malloc fail. req->content_len=%d", req->content_len);
return ESP_FAIL;
}
/* Read the data for the request */
if (httpd_req_recv(req, buf, req->content_len) != req->content_len) {
ESP_LOGE(TAG, "httpd_req_recv fail");
free(buf);
return ESP_FAIL;
}
/* Log data received */
ESP_LOGI(TAG, "%.*s", req->content_len, buf);
size_t sended = xMessageBufferSend(xMessageBufferRecv, buf, req->content_len, portMAX_DELAY);
if (sended != req->content_len) {
ESP_LOGE(TAG, "xMessageBufferSend fail. sended=%d req->content_len=%d", sended, req->content_len);
}
free(buf);
/* Send response */
httpd_resp_sendstr_chunk(req, "OK");
/* Send empty chunk to signal HTTP response completion */
httpd_resp_sendstr_chunk(req, NULL);
return ESP_OK;
}
/* favicon get handler */
static esp_err_t favicon_get_handler(httpd_req_t *req)
{
ESP_LOGI(TAG, "favicon_get_handler");
return ESP_OK;
}
/* Function to start the web server */
esp_err_t start_server(int port)
{
httpd_handle_t server = NULL;
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
// Purge“"Least Recently Used” connection
config.lru_purge_enable = true;
// TCP Port number for receiving and transmitting HTTP traffic
config.server_port = port;
// Start the httpd server
if (httpd_start(&server, &config) != ESP_OK) {
ESP_LOGE(TAG, "Failed to starting server!");
return ESP_FAIL;
}
// Set URI handlers
httpd_uri_t _root_post_handler = {
.uri = "/post",
.method = HTTP_POST,
.handler = root_post_handler,
.user_ctx = NULL,
};
httpd_register_uri_handler(server, &_root_post_handler);
httpd_uri_t _favicon_get_handler = {
.uri = "/favicon.ico",
.method = HTTP_GET,
.handler = favicon_get_handler,
.user_ctx = NULL,
};
httpd_register_uri_handler(server, &_favicon_get_handler);
return ESP_OK;
}
void http_server(void *pvParameters)
{
char *task_parameter = (char *)pvParameters;
ESP_LOGI(TAG, "Start task_parameter=%s", task_parameter);
char url[64];
int port = CONFIG_WEB_SERVER_PORT;
sprintf(url, "http://%s:%d", task_parameter, port);
ESP_LOGI(TAG, "Starting HTTP server on %s", url);
ESP_ERROR_CHECK(start_server(port));
vTaskDelete(NULL);
}
#endif

View File

@ -0,0 +1,6 @@
## IDF Component Manager Manifest File
dependencies:
espressif/mdns:
version: "^1.0.3"
rules:
- if: "idf_version >=5.0"

View File

@ -0,0 +1,369 @@
/* Mirf Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "freertos/message_buffer.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "mdns.h"
#include "mirf.h"
/* FreeRTOS event group to signal when we are connected*/
static EventGroupHandle_t s_wifi_event_group;
/* The event group allows multiple bits for each event, but we only care about two events:
* - we are connected to the AP with an IP
* - we failed to connect after the maximum amount of retries */
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
static const char *TAG = "MAIN";
static int s_retry_num = 0;
MessageBufferHandle_t xMessageBufferTrans;
MessageBufferHandle_t xMessageBufferRecv;
// The total number of bytes (not single messages) the message buffer will be able to hold at any one time.
size_t xBufferSizeBytes = 1024;
// The size, in bytes, required to hold each item in the message,
size_t xItemSize = 32;
static void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
{
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
esp_wifi_connect();
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
if (s_retry_num < CONFIG_ESP_MAXIMUM_RETRY) {
esp_wifi_connect();
s_retry_num++;
ESP_LOGI(TAG, "retry to connect to the AP");
} else {
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
}
ESP_LOGI(TAG,"connect to the AP fail");
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
s_retry_num = 0;
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}
}
bool wifi_init_sta(void)
{
bool ret = false;
s_wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_sta();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
esp_event_handler_instance_t instance_any_id;
esp_event_handler_instance_t instance_got_ip;
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
ESP_EVENT_ANY_ID,
&event_handler,
NULL,
&instance_any_id));
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
IP_EVENT_STA_GOT_IP,
&event_handler,
NULL,
&instance_got_ip));
wifi_config_t wifi_config = {
.sta = {
.ssid = CONFIG_ESP_WIFI_SSID,
.password = CONFIG_ESP_WIFI_PASSWORD,
/* Setting a password implies station will connect to all security modes including WEP/WPA.
* However these modes are deprecated and not advisable to be used. Incase your Access point
* doesn't support WPA2, these mode can be enabled by commenting below line */
.threshold.authmode = WIFI_AUTH_WPA2_PSK,
.pmf_cfg = {
.capable = true,
.required = false
},
},
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
ESP_ERROR_CHECK(esp_wifi_start() );
ESP_LOGI(TAG, "wifi_init_sta finished.");
/* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
* number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
pdFALSE,
pdFALSE,
portMAX_DELAY);
/* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
* happened. */
if (bits & WIFI_CONNECTED_BIT) {
ESP_LOGI(TAG, "connected to ap SSID:%s password:%s", CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD);
ret = true;
} else if (bits & WIFI_FAIL_BIT) {
ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD);
} else {
ESP_LOGE(TAG, "UNEXPECTED EVENT");
}
/* The event will not be processed after unregister */
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
vEventGroupDelete(s_wifi_event_group);
return ret;
}
esp_err_t query_mdns_host(const char * host_name, char *ip)
{
ESP_LOGD(__FUNCTION__, "Query A: %s", host_name);
struct esp_ip4_addr addr;
addr.addr = 0;
esp_err_t err = mdns_query_a(host_name, 10000, &addr);
if(err){
if(err == ESP_ERR_NOT_FOUND){
ESP_LOGW(__FUNCTION__, "%s: Host was not found!", esp_err_to_name(err));
return ESP_FAIL;
}
ESP_LOGE(__FUNCTION__, "Query Failed: %s", esp_err_to_name(err));
return ESP_FAIL;
}
ESP_LOGD(__FUNCTION__, "Query A: %s.local resolved to: " IPSTR, host_name, IP2STR(&addr));
sprintf(ip, IPSTR, IP2STR(&addr));
return ESP_OK;
}
void convert_mdns_host(char * from, char * to)
{
ESP_LOGI(__FUNCTION__, "from=[%s]",from);
strcpy(to, from);
char *sp;
sp = strstr(from, ".local");
if (sp == NULL) return;
int _len = sp - from;
ESP_LOGD(__FUNCTION__, "_len=%d", _len);
char _from[128];
strcpy(_from, from);
_from[_len] = 0;
ESP_LOGI(__FUNCTION__, "_from=[%s]", _from);
char _ip[128];
esp_err_t ret = query_mdns_host(_from, _ip);
ESP_LOGI(__FUNCTION__, "query_mdns_host=%d _ip=[%s]", ret, _ip);
if (ret != ESP_OK) return;
strcpy(to, _ip);
ESP_LOGI(__FUNCTION__, "to=[%s]", to);
}
void initialize_mdns(void)
{
//initialize mDNS
ESP_ERROR_CHECK( mdns_init() );
//set mDNS hostname (required if you want to advertise services)
ESP_ERROR_CHECK( mdns_hostname_set(CONFIG_MDNS_HOSTNAME) );
ESP_LOGI(TAG, "mdns hostname set to: [%s]", CONFIG_MDNS_HOSTNAME);
#if 0
//set default mDNS instance name
ESP_ERROR_CHECK( mdns_instance_name_set("ESP32 with mDNS") );
#endif
}
#if CONFIG_ADVANCED
void AdvancedSettings(NRF24_t * dev)
{
#if CONFIG_RF_RATIO_2M
ESP_LOGW(pcTaskGetName(0), "Set RF Data Ratio to 2MBps");
Nrf24_SetSpeedDataRates(dev, 1);
#endif // CONFIG_RF_RATIO_2M
#if CONFIG_RF_RATIO_1M
ESP_LOGW(pcTaskGetName(0), "Set RF Data Ratio to 1MBps");
Nrf24_SetSpeedDataRates(dev, 0);
#endif // CONFIG_RF_RATIO_2M
#if CONFIG_RF_RATIO_250K
ESP_LOGW(pcTaskGetName(0), "Set RF Data Ratio to 250KBps");
Nrf24_SetSpeedDataRates(dev, 2);
#endif // CONFIG_RF_RATIO_2M
ESP_LOGW(pcTaskGetName(0), "CONFIG_RETRANSMIT_DELAY=%d", CONFIG_RETRANSMIT_DELAY);
Nrf24_setRetransmitDelay(dev, CONFIG_RETRANSMIT_DELAY);
}
#endif // CONFIG_ADVANCED
#if CONFIG_RECEIVER
void receiver(void *pvParameters)
{
ESP_LOGI(pcTaskGetName(0), "Start");
NRF24_t dev;
Nrf24_init(&dev);
uint8_t payload = 32;
uint8_t channel = CONFIG_RADIO_CHANNEL;
Nrf24_config(&dev, channel, payload);
// Set my own address using 5 characters
esp_err_t ret = Nrf24_setRADDR(&dev, (uint8_t *)"FGHIJ");
if (ret != ESP_OK) {
ESP_LOGE(pcTaskGetName(0), "nrf24l01 not installed");
while(1) { vTaskDelay(1); }
}
#if CONFIG_ADVANCED
AdvancedSettings(&dev);
#endif // CONFIG_ADVANCED
// Print settings
Nrf24_printDetails(&dev);
uint8_t buf[xItemSize];
// Clear RX FiFo
while(1) {
if (Nrf24_dataReady(&dev) == false) break;
Nrf24_getData(&dev, buf);
}
while(1) {
// Wait for received data
if (Nrf24_dataReady(&dev)) {
Nrf24_getData(&dev, buf);
ESP_LOGI(pcTaskGetName(NULL), "Nrf24_getData buf=[%.*s]",payload, buf);
size_t spacesAvailable = xMessageBufferSpacesAvailable( xMessageBufferTrans );
ESP_LOGI(pcTaskGetName(NULL), "spacesAvailable=%d", spacesAvailable);
if (spacesAvailable < xItemSize*2) {
ESP_LOGW(pcTaskGetName(NULL), "xMessageBuffer available less than %d", xItemSize*2);
} else {
size_t sended = xMessageBufferSend(xMessageBufferTrans, buf, payload, portMAX_DELAY);
if (sended != payload) {
ESP_LOGE(pcTaskGetName(NULL), "xMessageBufferSend fail");
}
}
}
vTaskDelay(1); // Avoid WatchDog alerts
} // end while
}
#endif // CONFIG_RECEIVER
#if CONFIG_SENDER
void sender(void *pvParameters)
{
ESP_LOGI(pcTaskGetName(0), "Start");
NRF24_t dev;
Nrf24_init(&dev);
uint8_t payload = 32;
uint8_t channel = CONFIG_RADIO_CHANNEL;
Nrf24_config(&dev, channel, payload);
// Set destination address using 5 characters
esp_err_t ret = Nrf24_setTADDR(&dev, (uint8_t *)"FGHIJ");
if (ret != ESP_OK) {
ESP_LOGE(pcTaskGetName(0), "nrf24l01 not installed");
while(1) { vTaskDelay(1); }
}
#if CONFIG_ADVANCED
AdvancedSettings(&dev);
#endif // CONFIG_ADVANCED
// Print settings
Nrf24_printDetails(&dev);
ESP_LOGI(pcTaskGetName(0), "Wait for http...");
uint8_t buf[xItemSize];
while(1) {
size_t received = xMessageBufferReceive(xMessageBufferRecv, buf, sizeof(buf), portMAX_DELAY);
ESP_LOGI(pcTaskGetName(NULL), "xMessageBufferReceive received=%d", received);
Nrf24_send(&dev, buf);
vTaskDelay(1);
ESP_LOGI(pcTaskGetName(0), "Wait for sending.....");
if (Nrf24_isSend(&dev, 1000)) {
ESP_LOGI(pcTaskGetName(0),"Send success");
} else {
ESP_LOGW(pcTaskGetName(0),"Send fail");
}
}
}
#endif // CONFIG_SENDER
void http_client(void *pvParameters);
void http_server(void *pvParameters);
void app_main(void)
{
// Initialize NVS
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
// Initialize WiFi
if (wifi_init_sta() == false) {
while(1) vTaskDelay(10);
}
// Create MessageBuffer
xMessageBufferTrans = xMessageBufferCreate(xBufferSizeBytes);
configASSERT( xMessageBufferTrans );
xMessageBufferRecv = xMessageBufferCreate(xBufferSizeBytes);
configASSERT( xMessageBufferRecv );
// Initialize mDNS
initialize_mdns();
// Get the local IP address
esp_netif_ip_info_t ip_info;
ESP_ERROR_CHECK(esp_netif_get_ip_info(esp_netif_get_handle_from_ifkey("WIFI_STA_DEF"), &ip_info));
char cparam0[64];
sprintf(cparam0, IPSTR, IP2STR(&ip_info.ip));
ESP_LOGI(TAG, "cparam0=[%s]", cparam0);
#if CONFIG_SENDER
xTaskCreate(&sender, "TX", 1024*3, NULL, 2, NULL);
xTaskCreate(&http_server, "HTTP_SERVER", 1024*4, (void *)cparam0, 5, NULL);
#endif
#if CONFIG_RECEIVER
xTaskCreate(&receiver, "RX", 1024*3, NULL, 2, NULL);
xTaskCreate(&http_client, "HTTP_CLIENT", 1024*4, NULL, 5, NULL);
#endif
while(1) {
vTaskDelay(10);
}
}

View File

@ -0,0 +1,8 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
set(EXTRA_COMPONENT_DIRS ../components/mirf)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(mirf)

View File

@ -0,0 +1,80 @@
# MQTT Example
This is nRF24L01 and MQTT gateway application.
```
+----------+ +----------+ +----------+ +----------+
| | | | | | | |
|Publisher |--(MQTT)-->| Broker |--(MQTT)-->| ESP32 |--(SPI)--->| nRF24L01 |==(Radio)==>
| | | | | | | |
+----------+ +----------+ +----------+ +----------+
+----------+ +----------+ +----------+ +----------+
| | | | | | | |
==(Radio)==>| nRF24L01 |--(SPI)--->| ESP32 |--(MQTT)-->| Broker |--(MQTT)-->|Subscriber|
| | | | | | | |
+----------+ +----------+ +----------+ +----------+
```
# Configuration
![config-top](https://github.com/nopnop2002/esp-idf-mirf/assets/6020549/bea8b4a8-cb37-4aed-b88c-06910018dfb2)
![config-app](https://github.com/nopnop2002/esp-idf-mirf/assets/6020549/e440b0c8-1b5f-48ec-880d-ee756da23d0d)
## WiFi Setting
![config-wifi](https://github.com/nopnop2002/esp-idf-mirf/assets/6020549/4930402d-5cbf-4880-98b9-75509eb76981)
## Radioi Setting
### MQTT to Radio
Subscribe with MQTT and send to Radio.
You can use mosquitto_pub as Publisher.
```sh ./mqtt_pub.sh```
```
+----------+ +----------+ +----------+ +----------+
| | | | | | | |
|Publisher |--(MQTT)-->| Broker |--(MQTT)-->| ESP32 |--(SPI)--->| nRF24L01 |==(Radio)==>
| | | | | | | |
+----------+ +----------+ +----------+ +----------+
```
![config-radio-2](https://github.com/nopnop2002/esp-idf-mirf/assets/6020549/ad66e20f-ae63-4b33-b50a-1cc9faa9f7f2)
### Radio to MQTT
Receive from Radio and publish as MQTT.
You can use mosquitto_sub as Subscriber.
```sh ./mqtt_sub.sh```
```
+----------+ +----------+ +----------+ +----------+
| | | | | | | |
==(Radio)==>| nRF24L01 |--(SPI)--->| ESP32 |--(MQTT)-->| Broker |--(MQTT)-->|Subscriber|
| | | | | | | |
+----------+ +----------+ +----------+ +----------+
```
![config-radio-1](https://github.com/nopnop2002/esp-idf-mirf/assets/6020549/d8d0bb38-e9ad-4b86-b15f-7abd94bfb932)
### Specifying an MQTT Broker
You can specify your MQTT broker in one of the following ways:
- IP address
```192.168.10.20```
- mDNS host name
```mqtt-broker.local```
- Fully Qualified Domain Name
```broker.emqx.io```
You can use this as broker.
https://github.com/nopnop2002/esp-idf-mqtt-broker
# Communicate with Arduino Environment
Run this sketch.
ArduinoCode\Peer-to-peer\StringTest

View File

@ -0,0 +1,4 @@
set(component_srcs "main.c" "mqtt_pub.c" "mqtt_sub.c")
idf_component_register(SRCS "${component_srcs}"
INCLUDE_DIRS ".")

View File

@ -0,0 +1,84 @@
menu "Application Configuration"
menu "WiFi Setting"
config ESP_WIFI_SSID
string "WiFi SSID"
default "myssid"
help
SSID (network name) to connect to.
config ESP_WIFI_PASSWORD
string "WiFi Password"
default "mypassword"
help
WiFi password (WPA or WPA2) to connect to.
config ESP_MAXIMUM_RETRY
int "Maximum retry"
default 5
help
Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent.
endmenu
menu "Radio Setting"
choice DIRECTION
prompt "Communication polarity"
default SENDER
help
Select Communication polarity.
config SENDER
bool "MQTT to Radio"
help
MQTT to Radio.
config RECEIVER
bool "Radio to MQTT"
help
Radio to MQTT.
endchoice
config MQTT_BROKER
string "MQTT Broker"
default "broker.emqx.io"
help
Host name or IP address of the broker to connect to
config BROKER_AUTHENTICATION
bool "Server requests for password when connecting"
default false
help
Server requests for password when connecting.
config AUTHENTICATION_USERNAME
depends on BROKER_AUTHENTICATION
string "Username used for connecting to the broker"
default "user"
help
Username used for connecting to the broker.
config AUTHENTICATION_PASSWORD
depends on BROKER_AUTHENTICATION
string "Password used for connecting to the broker"
default "password"
help
Username used for connecting to the broker.
config MQTT_PUB_TOPIC
depends on RECEIVER
string "Publish Topic"
default "/topic/mirf/test"
help
Topic of publish
config MQTT_SUB_TOPIC
depends on SENDER
string "Subscribe Topic"
default "/topic/mirf/test"
help
Topic of subscribe
endmenu
endmenu

View File

@ -0,0 +1,5 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

View File

@ -0,0 +1,6 @@
## IDF Component Manager Manifest File
dependencies:
espressif/mdns:
version: "^1.0.3"
rules:
- if: "idf_version >=5.0"

View File

@ -0,0 +1,346 @@
/* Mirf Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <inttypes.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "freertos/message_buffer.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "mdns.h"
#include "mirf.h"
#include "mqtt.h"
/* FreeRTOS event group to signal when we are connected*/
static EventGroupHandle_t s_wifi_event_group;
/* The event group allows multiple bits for each event, but we only care about two events:
* - we are connected to the AP with an IP
* - we failed to connect after the maximum amount of retries */
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
static const char *TAG = "MAIN";
static int s_retry_num = 0;
MessageBufferHandle_t xMessageBufferTrans;
MessageBufferHandle_t xMessageBufferRecv;
// The total number of bytes (not single messages) the message buffer will be able to hold at any one time.
size_t xBufferSizeBytes = 1024;
// The size, in bytes, required to hold each item in the message,
size_t xItemSize = 32;
static void event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data)
{
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
esp_wifi_connect();
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
if (s_retry_num < CONFIG_ESP_MAXIMUM_RETRY) {
esp_wifi_connect();
s_retry_num++;
ESP_LOGI(TAG, "retry to connect to the AP");
} else {
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
}
ESP_LOGI(TAG,"connect to the AP fail");
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
s_retry_num = 0;
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}
}
bool wifi_init_sta(void)
{
bool ret = false;
s_wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_sta();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
esp_event_handler_instance_t instance_any_id;
esp_event_handler_instance_t instance_got_ip;
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
ESP_EVENT_ANY_ID,
&event_handler,
NULL,
&instance_any_id));
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
IP_EVENT_STA_GOT_IP,
&event_handler,
NULL,
&instance_got_ip));
wifi_config_t wifi_config = {
.sta = {
.ssid = CONFIG_ESP_WIFI_SSID,
.password = CONFIG_ESP_WIFI_PASSWORD,
/* Setting a password implies station will connect to all security modes including WEP/WPA.
* However these modes are deprecated and not advisable to be used. Incase your Access point
* doesn't support WPA2, these mode can be enabled by commenting below line */
.threshold.authmode = WIFI_AUTH_WPA2_PSK,
.pmf_cfg = {
.capable = true,
.required = false
},
},
};
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA) );
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config) );
ESP_ERROR_CHECK(esp_wifi_start() );
ESP_LOGI(TAG, "wifi_init_sta finished.");
/* Waiting until either the connection is established (WIFI_CONNECTED_BIT) or connection failed for the maximum
* number of re-tries (WIFI_FAIL_BIT). The bits are set by event_handler() (see above) */
EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group,
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
pdFALSE,
pdFALSE,
portMAX_DELAY);
/* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
* happened. */
if (bits & WIFI_CONNECTED_BIT) {
ESP_LOGI(TAG, "connected to ap SSID:%s password:%s", CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD);
ret = true;
} else if (bits & WIFI_FAIL_BIT) {
ESP_LOGI(TAG, "Failed to connect to SSID:%s, password:%s", CONFIG_ESP_WIFI_SSID, CONFIG_ESP_WIFI_PASSWORD);
} else {
ESP_LOGE(TAG, "UNEXPECTED EVENT");
}
/* The event will not be processed after unregister */
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, instance_got_ip));
ESP_ERROR_CHECK(esp_event_handler_instance_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, instance_any_id));
vEventGroupDelete(s_wifi_event_group);
return ret;
}
esp_err_t query_mdns_host(const char * host_name, char *ip)
{
ESP_LOGD(__FUNCTION__, "Query A: %s", host_name);
struct esp_ip4_addr addr;
addr.addr = 0;
esp_err_t err = mdns_query_a(host_name, 10000, &addr);
if(err){
if(err == ESP_ERR_NOT_FOUND){
ESP_LOGW(__FUNCTION__, "%s: Host was not found!", esp_err_to_name(err));
return ESP_FAIL;
}
ESP_LOGE(__FUNCTION__, "Query Failed: %s", esp_err_to_name(err));
return ESP_FAIL;
}
ESP_LOGD(__FUNCTION__, "Query A: %s.local resolved to: " IPSTR, host_name, IP2STR(&addr));
sprintf(ip, IPSTR, IP2STR(&addr));
return ESP_OK;
}
void convert_mdns_host(char * from, char * to)
{
ESP_LOGI(__FUNCTION__, "from=[%s]",from);
strcpy(to, from);
char *sp;
sp = strstr(from, ".local");
if (sp == NULL) return;
int _len = sp - from;
ESP_LOGD(__FUNCTION__, "_len=%d", _len);
char _from[128];
strcpy(_from, from);
_from[_len] = 0;
ESP_LOGI(__FUNCTION__, "_from=[%s]", _from);
char _ip[128];
esp_err_t ret = query_mdns_host(_from, _ip);
ESP_LOGI(__FUNCTION__, "query_mdns_host=%d _ip=[%s]", ret, _ip);
if (ret != ESP_OK) return;
strcpy(to, _ip);
ESP_LOGI(__FUNCTION__, "to=[%s]", to);
}
#if CONFIG_ADVANCED
void AdvancedSettings(NRF24_t * dev)
{
#if CONFIG_RF_RATIO_2M
ESP_LOGW(pcTaskGetName(0), "Set RF Data Ratio to 2MBps");
Nrf24_SetSpeedDataRates(dev, 1);
#endif // CONFIG_RF_RATIO_2M
#if CONFIG_RF_RATIO_1M
ESP_LOGW(pcTaskGetName(0), "Set RF Data Ratio to 1MBps");
Nrf24_SetSpeedDataRates(dev, 0);
#endif // CONFIG_RF_RATIO_2M
#if CONFIG_RF_RATIO_250K
ESP_LOGW(pcTaskGetName(0), "Set RF Data Ratio to 250KBps");
Nrf24_SetSpeedDataRates(dev, 2);
#endif // CONFIG_RF_RATIO_2M
ESP_LOGW(pcTaskGetName(0), "CONFIG_RETRANSMIT_DELAY=%d", CONFIG_RETRANSMIT_DELAY);
Nrf24_setRetransmitDelay(dev, CONFIG_RETRANSMIT_DELAY);
}
#endif // CONFIG_ADVANCED
#if CONFIG_RECEIVER
void receiver(void *pvParameters)
{
ESP_LOGI(pcTaskGetName(0), "Start");
NRF24_t dev;
Nrf24_init(&dev);
uint8_t payload = 32;
uint8_t channel = CONFIG_RADIO_CHANNEL;
Nrf24_config(&dev, channel, payload);
// Set my own address using 5 characters
esp_err_t ret = Nrf24_setRADDR(&dev, (uint8_t *)"FGHIJ");
if (ret != ESP_OK) {
ESP_LOGE(pcTaskGetName(0), "nrf24l01 not installed");
while(1) { vTaskDelay(1); }
}
#if CONFIG_ADVANCED
AdvancedSettings(&dev);
#endif // CONFIG_ADVANCED
// Print settings
Nrf24_printDetails(&dev);
uint8_t buf[xItemSize];
// Clear RX FiFo
while(1) {
if (Nrf24_dataReady(&dev) == false) break;
Nrf24_getData(&dev, buf);
}
while(1) {
// Wait for received data
if (Nrf24_dataReady(&dev)) {
Nrf24_getData(&dev, buf);
ESP_LOGI(pcTaskGetName(NULL), "Nrf24_getData buf=[%.*s]",payload, buf);
size_t spacesAvailable = xMessageBufferSpacesAvailable( xMessageBufferTrans );
ESP_LOGI(pcTaskGetName(NULL), "spacesAvailable=%d", spacesAvailable);
if (spacesAvailable < xItemSize*2) {
ESP_LOGW(pcTaskGetName(NULL), "xMessageBuffer available less than %d", xItemSize*2);
} else {
size_t sended = xMessageBufferSend(xMessageBufferTrans, buf, payload, portMAX_DELAY);
if (sended != payload) {
ESP_LOGE(pcTaskGetName(NULL), "xMessageBufferSend fail");
}
}
}
vTaskDelay(1); // Avoid WatchDog alerts
} // end while
}
#endif // CONFIG_RECEIVER
#if CONFIG_SENDER
void sender(void *pvParameters)
{
ESP_LOGI(pcTaskGetName(0), "Start");
NRF24_t dev;
Nrf24_init(&dev);
uint8_t payload = 32;
uint8_t channel = CONFIG_RADIO_CHANNEL;
Nrf24_config(&dev, channel, payload);
// Set destination address using 5 characters
esp_err_t ret = Nrf24_setTADDR(&dev, (uint8_t *)"FGHIJ");
if (ret != ESP_OK) {
ESP_LOGE(pcTaskGetName(0), "nrf24l01 not installed");
while(1) { vTaskDelay(1); }
}
#if CONFIG_ADVANCED
AdvancedSettings(&dev);
#endif // CONFIG_ADVANCED
// Print settings
Nrf24_printDetails(&dev);
ESP_LOGI(pcTaskGetName(0), "Wait for mqtt...");
uint8_t buf[xItemSize];
while(1) {
size_t received = xMessageBufferReceive(xMessageBufferRecv, buf, sizeof(buf), portMAX_DELAY);
ESP_LOGI(pcTaskGetName(NULL), "xMessageBufferReceive received=%d", received);
Nrf24_send(&dev, buf);
vTaskDelay(1);
ESP_LOGI(pcTaskGetName(0), "Wait for sending.....");
if (Nrf24_isSend(&dev, 1000)) {
ESP_LOGI(pcTaskGetName(0),"Send success");
} else {
ESP_LOGW(pcTaskGetName(0),"Send fail");
}
}
}
#endif // CONFIG_SENDER
void mqtt_pub(void *pvParameters);
void mqtt_sub(void *pvParameters);
void app_main(void)
{
// Initialize NVS
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
// Initialize WiFi
if (wifi_init_sta() == false) {
while(1) vTaskDelay(10);
}
// Create MessageBuffer
xMessageBufferTrans = xMessageBufferCreate(xBufferSizeBytes);
configASSERT( xMessageBufferTrans );
xMessageBufferRecv = xMessageBufferCreate(xBufferSizeBytes);
configASSERT( xMessageBufferRecv );
// Initialize mDNS
ESP_ERROR_CHECK( mdns_init() );
#if CONFIG_SENDER
xTaskCreate(&sender, "TX", 1024*3, NULL, 2, NULL);
xTaskCreate(&mqtt_sub, "SUB", 1024*4, NULL, 2, NULL);
#endif
#if CONFIG_RECEIVER
xTaskCreate(&receiver, "RX", 1024*3, NULL, 2, NULL);
xTaskCreate(&mqtt_pub, "PUB", 1024*4, NULL, 2, NULL);
#endif
}

View File

@ -0,0 +1,9 @@
typedef struct {
TaskHandle_t taskHandle;
int32_t event_id;
int topic_len;
char topic[64];
int data_len;
char data[32];
} MQTT_t;

View File

@ -0,0 +1,163 @@
/* MQTT (over TCP) Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <inttypes.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "freertos/message_buffer.h"
#include "esp_log.h"
#include "esp_event.h"
#include "esp_mac.h" // esp_base_mac_addr_get
#include "mqtt_client.h"
#if CONFIG_RECEIVER
static const char *TAG = "PUB";
EventGroupHandle_t mqtt_status_event_group;
#define MQTT_CONNECTED_BIT BIT2
extern MessageBufferHandle_t xMessageBufferTrans;
extern size_t xItemSize;
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
#else
static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
#endif
{
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
esp_mqtt_event_handle_t event = event_data;
#endif
switch (event->event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
xEventGroupSetBits(mqtt_status_event_group, MQTT_CONNECTED_BIT);
break;
case MQTT_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
xEventGroupClearBits(mqtt_status_event_group, MQTT_CONNECTED_BIT);
break;
case MQTT_EVENT_SUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_UNSUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_PUBLISHED:
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_DATA:
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
break;
case MQTT_EVENT_ERROR:
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
break;
default:
ESP_LOGI(TAG, "Other event id:%d", event->event_id);
break;
}
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
return ESP_OK;
#endif
}
esp_err_t query_mdns_host(const char * host_name, char *ip);
void convert_mdns_host(char * from, char * to);
void mqtt_pub(void *pvParameters)
{
ESP_LOGI(TAG, "Start Publish Broker:%s", CONFIG_MQTT_BROKER);
// Create Event Group
mqtt_status_event_group = xEventGroupCreate();
configASSERT( mqtt_status_event_group );
xEventGroupClearBits(mqtt_status_event_group, MQTT_CONNECTED_BIT);
// Set client id from mac
uint8_t mac[8];
ESP_ERROR_CHECK(esp_base_mac_addr_get(mac));
for(int i=0;i<8;i++) {
ESP_LOGD(TAG, "mac[%d]=%x", i, mac[i]);
}
char client_id[64];
sprintf(client_id, "pub-%02x%02x%02x%02x%02x%02x", mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
ESP_LOGI(TAG, "client_id=[%s]", client_id);
// Resolve mDNS host name
char ip[128];
ESP_LOGI(TAG, "CONFIG_MQTT_BROKER=[%s]", CONFIG_MQTT_BROKER);
convert_mdns_host(CONFIG_MQTT_BROKER, ip);
ESP_LOGI(TAG, "ip=[%s]", ip);
char uri[138];
sprintf(uri, "mqtt://%s", ip);
ESP_LOGI(TAG, "uri=[%s]", uri);
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
esp_mqtt_client_config_t mqtt_cfg = {
.broker.address.uri = uri,
.broker.address.port = 1883,
#if CONFIG_BROKER_AUTHENTICATION
.credentials.username = CONFIG_AUTHENTICATION_USERNAME,
.credentials.authentication.password = CONFIG_AUTHENTICATION_PASSWORD,
#endif
.credentials.client_id = client_id
};
#else
esp_mqtt_client_config_t mqtt_cfg = {
.uri = uri,
.port = 1883,
.event_handle = mqtt_event_handler,
#if CONFIG_BROKER_AUTHENTICATION
.username = CONFIG_AUTHENTICATION_USERNAME,
.password = CONFIG_AUTHENTICATION_PASSWORD,
#endif
.client_id = client_id
};
#endif
esp_mqtt_client_handle_t mqtt_client = esp_mqtt_client_init(&mqtt_cfg);
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
esp_mqtt_client_register_event(mqtt_client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
#endif
esp_mqtt_client_start(mqtt_client);
xEventGroupWaitBits(mqtt_status_event_group, MQTT_CONNECTED_BIT, false, true, portMAX_DELAY);
ESP_LOGI(TAG, "Connected to MQTT Broker");
char buffer[xItemSize];
while (1) {
size_t received = xMessageBufferReceive(xMessageBufferTrans, buffer, sizeof(buffer), portMAX_DELAY);
ESP_LOGI(TAG, "xMessageBufferReceive received=%d", received);
if (received > 0) {
ESP_LOGI(TAG, "xMessageBufferReceive buffer=[%.*s]",received, buffer);
EventBits_t EventBits = xEventGroupGetBits(mqtt_status_event_group);
ESP_LOGI(TAG, "EventBits=0x%"PRIx32, EventBits);
if (EventBits & MQTT_CONNECTED_BIT) {
int msg_id = esp_mqtt_client_publish(mqtt_client, CONFIG_MQTT_PUB_TOPIC, buffer, received, 1, 0);
ESP_LOGI(TAG, "sent publish successful, msg_id=%d", msg_id);
} else {
ESP_LOGW(TAG, "Disconnect to MQTT Broker. Skip to send");
}
} else {
ESP_LOGE(TAG, "xMessageBufferReceive fail");
break;
}
} // end while
// Stop connection
ESP_LOGI(TAG, "Task Delete");
esp_mqtt_client_stop(mqtt_client);
vTaskDelete(NULL);
}
#endif

View File

@ -0,0 +1,188 @@
/* MQTT (over TCP) Example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <inttypes.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/event_groups.h"
#include "freertos/message_buffer.h"
#include "esp_log.h"
#include "esp_event.h"
#include "lwip/dns.h"
#include "esp_mac.h"
#include "mqtt_client.h"
#include "mqtt.h"
#if CONFIG_SENDER
static const char *TAG = "SUB";
extern MessageBufferHandle_t xMessageBufferRecv;
extern size_t xItemSize;
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
#else
static esp_err_t mqtt_event_handler(esp_mqtt_event_handle_t event)
#endif
{
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
esp_mqtt_event_handle_t event = event_data;
MQTT_t *mqttBuf = handler_args;
#else
MQTT_t *mqttBuf = event->user_context;
#endif
ESP_LOGI(TAG, "taskHandle=0x%x", (unsigned int)mqttBuf->taskHandle);
mqttBuf->event_id = event->event_id;
switch (event->event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
xTaskNotifyGive( mqttBuf->taskHandle );
break;
case MQTT_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
xTaskNotifyGive( mqttBuf->taskHandle );
break;
case MQTT_EVENT_SUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_UNSUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_PUBLISHED:
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_DATA:
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
ESP_LOGI(TAG, "TOPIC=[%.*s] DATA=[%.*s]", event->topic_len, event->topic, event->data_len, event->data);
mqttBuf->topic_len = event->topic_len;
if (mqttBuf->topic_len > sizeof(mqttBuf->topic)) {
ESP_LOGW(TAG, "topic length too big");
mqttBuf->topic_len = sizeof(mqttBuf->topic);
}
for(int i=0;i<mqttBuf->topic_len;i++) {
mqttBuf->topic[i] = event->topic[i];
}
mqttBuf->data_len = event->data_len;
if (mqttBuf->data_len > sizeof(mqttBuf->data)) {
ESP_LOGW(TAG, "payload length too big");
mqttBuf->data_len = sizeof(mqttBuf->data);
}
for(int i=0;i<mqttBuf->data_len;i++) {
mqttBuf->data[i] = event->data[i];
}
xTaskNotifyGive( mqttBuf->taskHandle );
break;
case MQTT_EVENT_ERROR:
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
xTaskNotifyGive( mqttBuf->taskHandle );
break;
default:
ESP_LOGI(TAG, "Other event id:%d", event->event_id);
break;
}
#if ESP_IDF_VERSION < ESP_IDF_VERSION_VAL(5, 0, 0)
return ESP_OK;
#endif
}
esp_err_t query_mdns_host(const char * host_name, char *ip);
void convert_mdns_host(char * from, char * to);
void mqtt_sub(void *pvParameters)
{
ESP_LOGI(TAG, "Start");
ESP_LOGI(TAG, "CONFIG_MQTT_BROKER=[%s]", CONFIG_MQTT_BROKER);
// Set client id from mac
uint8_t mac[8];
ESP_ERROR_CHECK(esp_base_mac_addr_get(mac));
for(int i=0;i<8;i++) {
ESP_LOGD(TAG, "mac[%d]=%x", i, mac[i]);
}
char client_id[64];
sprintf(client_id, "esp32-%02x%02x%02x%02x%02x%02x", mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
ESP_LOGI(TAG, "client_id=[%s]", client_id);
// Resolve mDNS host name
char ip[128];
ESP_LOGI(TAG, "CONFIG_MQTT_BROKER=[%s]", CONFIG_MQTT_BROKER);
convert_mdns_host(CONFIG_MQTT_BROKER, ip);
ESP_LOGI(TAG, "ip=[%s]", ip);
char uri[138];
sprintf(uri, "mqtt://%s", ip);
ESP_LOGI(TAG, "uri=[%s]", uri);
// Initialize user context
MQTT_t mqttBuf;
mqttBuf.taskHandle = xTaskGetCurrentTaskHandle();
ESP_LOGI(TAG, "taskHandle=0x%x", (unsigned int)mqttBuf.taskHandle);
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
esp_mqtt_client_config_t mqtt_cfg = {
.broker.address.uri = uri,
.broker.address.port = 1883,
#if CONFIG_BROKER_AUTHENTICATION
.credentials.username = CONFIG_AUTHENTICATION_USERNAME,
.credentials.authentication.password = CONFIG_AUTHENTICATION_PASSWORD,
#endif
.credentials.client_id = client_id
};
#else
esp_mqtt_client_config_t mqtt_cfg = {
.user_context = &mqttBuf,
.uri = uri,
.port = 1883,
.event_handle = mqtt_event_handler,
#if CONFIG_BROKER_AUTHENTICATION
.username = CONFIG_AUTHENTICATION_USERNAME,
.password = CONFIG_AUTHENTICATION_PASSWORD,
#endif
.client_id = client_id
};
#endif
esp_mqtt_client_handle_t mqtt_client = esp_mqtt_client_init(&mqtt_cfg);
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
esp_mqtt_client_register_event(mqtt_client, ESP_EVENT_ANY_ID, mqtt_event_handler, &mqttBuf);
#endif
esp_mqtt_client_start(mqtt_client);
while (1) {
ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
ESP_LOGI(TAG, "ulTaskNotifyTake");
ESP_LOGI(TAG, "event_id=%"PRIi32, mqttBuf.event_id);
if (mqttBuf.event_id == MQTT_EVENT_CONNECTED) {
esp_mqtt_client_subscribe(mqtt_client, CONFIG_MQTT_SUB_TOPIC, 0);
ESP_LOGI(TAG, "Subscribe to MQTT Server");
} else if (mqttBuf.event_id == MQTT_EVENT_DISCONNECTED) {
break;
} else if (mqttBuf.event_id == MQTT_EVENT_DATA) {
ESP_LOGI(TAG, "TOPIC=[%.*s] DATA=[%.*s]", mqttBuf.topic_len, mqttBuf.topic, mqttBuf.data_len, mqttBuf.data);
size_t sended = xMessageBufferSend(xMessageBufferRecv, mqttBuf.data, mqttBuf.data_len, portMAX_DELAY);
if (sended != mqttBuf.data_len) {
ESP_LOGE(TAG, "xMessageBufferSend fail");
}
} else if (mqttBuf.event_id == MQTT_EVENT_ERROR) {
break;
}
} // end while
ESP_LOGI(TAG, "Task Delete");
esp_mqtt_client_stop(mqtt_client);
vTaskDelete(NULL);
}
#endif

View File

@ -0,0 +1,13 @@
#!/bin/bash
#set -x
count=1
while :
do
payload=`date "+%Y/%m/%d %H:%M:%S"`
#payload="count=${count}"
echo ${payload}
mosquitto_pub -h broker.emqx.io -p 1883 -t "/topic/mirf/test" -m "$payload"
count=$((++count))
sleep 1
done

View File

@ -0,0 +1,2 @@
#!/bin/bash
mosquitto_sub -d -h broker.emqx.io -t "/topic/mirf/test"

View File

218
include/zh_rf24.h Normal file
View File

@ -0,0 +1,218 @@
/**
* @file
* Header file for the zh_rf24 component.
*
*/
#pragma once
#include "string.h"
#include "esp_err.h"
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_log.h"
#include "esp_heap_caps.h"
#include "driver/spi_master.h"
#include "driver/gpio.h"
/**
* @brief Unique identifier of RF24 interface events base. Used when registering the event handler.
*
*/
#define ESP_EVENT_BASE ZH_RF24
/**
* @brief Default values for zh_rf24_init_config_t structure for initial initialization of RF24 interface.
*
*/
#define ZH_RF24_INIT_CONFIG_DEFAULT() \
{ \
.ce_pin = 1, \
.csn_pin = 2, \
.sck_pin = 3, \
.mosi_pin = 4, \
.miso_pin = 5, \
.irq_pin = 6, \
.work_mode = ZH_RF24_RECEIVER, \
.channel = 100, \
.pa_level = ZH_RF24_PA_MAX, \
.data_rate = ZH_RF24_250KBPS, \
.network_id = 0xFAFBFCFD, \
.task_priority = 4, \
.stack_size = 3072, \
.queue_size = 32, \
.max_waiting_time = 1000, \
.id_vector_size = 100, \
.route_vector_size = 100, \
.wifi_interface = WIFI_IF_STA \
}
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief Structure for initial initialization of RF24 interface.
*
* @note Before initialize cc interface recommend initialize zh_rf24_init_config_t structure with default values.
*
* @code
* zh_rf24_init_config_t config = ZH_RF24_INIT_CONFIG_DEFAULT()
* @endcode
*/
typedef struct
{
uint8_t ce_pin;
uint8_t csn_pin;
uint8_t sck_pin;
uint8_t mosi_pin;
uint8_t miso_pin;
uint8_t irq_pin;
zh_rf24_work_mode_t work_mode;
uint8_t channel;
zh_rf24_pa_level_t pa_level;
zh_rf24_data_rate_t data_rate;
uint8_t tx_address[5];
uint8_t rx_address_preamble[4];
uint8_t rx_pipe_1_address;
uint8_t rx_pipe_2_address;
uint8_t rx_pipe_3_address;
uint8_t rx_pipe_4_address;
uint8_t rx_pipe_5_address;
uint8_t task_priority; ///< Task priority for the ESP-NOW messages processing. @note It is not recommended to set a value less than 4.
uint16_t stack_size; ///< Stack size for task for the ESP-NOW messages processing. @note The minimum size is 3072 bytes.
uint8_t queue_size; ///< Queue size for task for the ESP-NOW messages processing. @note The size depends on the number of messages to be processed. It is not recommended to set the value less than 32.
} __attribute__((packed)) zh_rf24_init_config_t;
/// \cond
ESP_EVENT_DECLARE_BASE(ESP_EVENT_BASE);
/// \endcond
/**
* Power Amplifier level.
*
* For use with setPALevel()
*/
typedef enum
{
ZH_RF24_PA_MIN,
ZH_RF24_PA_LOW,
ZH_RF24_PA_HIGH,
ZH_RF24_PA_MAX,
} __attribute__((packed)) zh_rf24_pa_level_t;
/**
* Data rate. How fast data moves through the air.
*
* For use with setDataRate()
*/
typedef enum
{
ZH_RF24_1MBPS,
ZH_RF24_2MBPS,
ZH_RF24_250KBPS
} __attribute__((packed)) zh_rf24_data_rate_t;
/**
* CRC Length. How big (if any) of a CRC is included.
*
* For use with setCRCLength()
*/
typedef enum
{
ZH_RF24_TRANSMITTER,
ZH_RF24_RECEIVER
} __attribute__((packed)) zh_rf24_work_mode_t;
/**
* @brief Enumeration of possible RF24 events.
*
*/
typedef enum
{
ZH_RF24_ON_RECV_EVENT, ///< The event when the RF24 message was received.
ZH_RF24_ON_SEND_EVENT ///< The event when the RF24 message was sent.
} __attribute__((packed)) zh_rf24_event_type_t;
/**
* @brief Enumeration of possible status of sent ESP-NOW message.
*
*/
typedef enum
{
ZH_RF24_SEND_SUCCESS, ///< If RF24 message was sent success.
ZH_RF24_SEND_FAIL ///< If RF24 message was sent fail.
} __attribute__((packed)) zh_rf24_on_send_event_type_t;
/**
* @brief Structure for sending data to the event handler when an ESP-NOW message was sent.
*
* @note Should be used with ZH_NETWORK event base and ZH_NETWORK_ON_SEND_EVENT event.
*
*/
typedef struct
{
uint8_t pipe; ///< MAC address of the device to which the ESP-NOW message was sent. @note
zh_rf24_on_send_event_type_t status; ///< Status of sent ESP-NOW message. @note
} __attribute__((packed)) zh_rf24_event_on_send_t;
/**
* @brief Structure for sending data to the event handler when an ESP-NOW message was received.
*
* @note Should be used with ZH_NETWORK event base and ZH_NETWORK_ON_RECV_EVENT event.
*/
typedef struct
{
uint8_t pipe; ///< MAC address of the sender ESP-NOW message. @note
uint8_t *data; ///< Pointer to the data of the received ESP-NOW message. @note
uint8_t data_len; ///< Size of the received ESP-NOW message. @note
} __attribute__((packed)) zh_network_event_on_recv_t;
/**
* @brief Initialize ESP-NOW interface.
*
* @note Before initialize ESP-NOW interface recommend initialize zh_network_init_config_t structure with default values.
*
* @code
* zh_network_init_config_t config = ZH_NETWORK_INIT_CONFIG_DEFAULT()
* @endcode
*
* @param[in] config Pointer to ESP-NOW initialized configuration structure. Can point to a temporary variable.
*
* @return
* - ESP_OK if initialization was success
* - ESP_ERR_INVALID_ARG if parameter error
* - ESP_ERR_WIFI_NOT_INIT if WiFi is not initialized
* - ESP_FAIL if any internal error
*/
esp_err_t zh_network_init(zh_rf24_init_config_t *config);
/**
* @brief Deinitialize ESP-NOW interface.
*
* @return
* - ESP_OK if deinitialization was success
*/
esp_err_t zh_network_deinit(void);
/**
* @brief Send ESP-NOW data.
*
* @param[in] target Pointer to a buffer containing an eight-byte target MAC. Can be NULL for broadcast.
* @param[in] data Pointer to a buffer containing the data for send.
* @param[in] data_len Sending data length.
*
* @note The function will return an ESP_ERR_INVALID_STATE error if less than 50% of the size set at initialization remains in the message queue.
*
* @return
* - ESP_OK if sent was success
* - ESP_ERR_INVALID_ARG if parameter error
* - ESP_ERR_INVALID_STATE if queue for outgoing data is almost full
* - ESP_FAIL if ESP-NOW is not initialized
*/
esp_err_t zh_network_send(const uint8_t *data, const uint8_t data_len, const bool confirm);
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1 @@
1.0.0

11
zh_rf24.c Normal file
View File

@ -0,0 +1,11 @@
/**
* @file
* The main code of the zh_rf24 component.
*/
#include "zh_rf24.h"
#define ZH_RF24_MAX_MESSAGE_SIZE 32
ESP_EVENT_DEFINE_BASE(ZH_RF24);