Files
ESP-Nodes/ESP32-IDF_ESPNOW-Transmitter/main/espnow_transmitter.c
2025-06-18 00:56:06 -04:00

221 lines
7.5 KiB
C

/* ESPNOW Transmitter
by: Alexander Bobkov
Date Created: June 17, 2025
Updated: June 17, 2025
SDK:abort ESP-IDF v.5.4.1
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.
*/
/*
This program uses ESPNOW for transmitting joystick x- and y- axis values to the receiving device.
*/
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <assert.h>
#include "freertos/FreeRTOS.h"
#include "freertos/semphr.h"
#include "freertos/timers.h"
#include "esp_adc/adc_oneshot.h"
#include "nvs_flash.h"
#include "esp_random.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "esp_wifi.h"
#include "esp_log.h"
#include "esp_err.h"
#include "esp_mac.h"
#include "esp_now.h"
#include "esp_crc.h"
#include "espnow_example.h"
#include "config.h"
const char *TAG = "ESP-NOW_Transmitter";
esp_now_peer_info_t devices;
// Struct holding sensors values
typedef struct {
uint16_t crc; // CRC16 value of ESPNOW data
int x_axis; // Joystick x-position
int y_axis; // Joystick y-position
bool nav_bttn; // Joystick push button
uint8_t motor1_rpm_pcm; // PWMs for 4 DC motors
uint8_t motor2_rpm_pcm;
uint8_t motor3_rpm_pcm;
uint8_t motor4_rpm_pcm;
} __attribute__((packed)) sensors_data_t;
static int x, y; // Joystick x and y positions
adc_oneshot_unit_handle_t adc_xy_handle;
sensors_data_t buffer;
int convert_axis_to_pwm(int axis_value);
void get_joystick_xy_axis(int *x_axis, int *y_axis);
void sendRawData(void);
void deleteDev(void);
void deletePeer(void);
//static sensors_data_t buffer;
esp_err_t joystick_adc_init(void) {
adc_oneshot_unit_init_cfg_t adc_init_config_xy = {
.unit_id = ADC_UNIT_1,
.ulp_mode = ADC_ULP_MODE_DISABLE,
};
ESP_ERROR_CHECK(adc_oneshot_new_unit(&adc_init_config_xy, &adc_xy_handle));
adc_oneshot_chan_cfg_t config_x = {
.bitwidth = SOC_ADC_DIGI_MAX_BITWIDTH,
.atten = ADC_ATTEN_DB_12,
};
adc_oneshot_chan_cfg_t config_y = {
.bitwidth = SOC_ADC_DIGI_MAX_BITWIDTH,
.atten = ADC_ATTEN_DB_12,
};
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc_xy_handle, ADC_CHANNEL_0, &config_x));
ESP_ERROR_CHECK(adc_oneshot_config_channel(adc_xy_handle, ADC_CHANNEL_1, &config_y));
return ESP_OK;
}
void joystick_show_raw_xy() {
ESP_ERROR_CHECK(adc_oneshot_read(adc_xy_handle, ADC_CHANNEL_0, &x));
ESP_ERROR_CHECK(adc_oneshot_read(adc_xy_handle, ADC_CHANNEL_1, &y));
ESP_LOGI("(x,y)", "( %d, %d )", x, y);
}
void get_joystick_xy(int *x_axis, int *y_axis) {
ESP_ERROR_CHECK(adc_oneshot_read(adc_xy_handle, ADC_CHANNEL_0, x_axis));
ESP_ERROR_CHECK(adc_oneshot_read(adc_xy_handle, ADC_CHANNEL_1, y_axis));
}
void joystick_task(void *arg) {
while (true) {
joystick_show_raw_xy();
vTaskDelay (1000 / portTICK_PERIOD_MS);
}
}
// Function to delete peer (i.e. when communication error occurs)
void deletePeer (void) {
uint8_t delStatus = esp_now_del_peer(receiver_mac);
if (delStatus != 0) {
ESP_LOGE("ESP-NOW", "Could not delete peer");
}
}
void statusDataSend(const uint8_t *mac_addr, esp_now_send_status_t status) {
if (status == ESP_NOW_SEND_SUCCESS) {
ESP_LOGI(TAG, "Data sent successfully to: %02X:%02X:%02X:%02X:%02X:%02X",
mac_addr[0], mac_addr[1], mac_addr[2],
mac_addr[3], mac_addr[4], mac_addr[5]);
} else {
ESP_LOGE(TAG, "Error sending data to: %02X:%02X:%02X:%02X:%02X:%02X",
mac_addr[0], mac_addr[1], mac_addr[2],
mac_addr[3], mac_addr[4], mac_addr[5]);
ESP_LOGE("sendData()", "Error sending data. Error code: 0x%04X", status);
ESP_LOGE("sendData()", "esp_now_send() failed: %s", esp_err_to_name(status));
ESP_LOGE("sendData()", "Ensure that receiver is powered-on and MAC is correct.");
deletePeer();
}
}
// Function for sending the data to the receiver
void sendData (void)
{
buffer.crc = 0;
buffer.x_axis = 240;
buffer.y_axis = 256;
buffer.nav_bttn = 0;
buffer.motor1_rpm_pcm = 0; //10;
buffer.motor2_rpm_pcm = 0;
buffer.motor3_rpm_pcm = 0;
buffer.motor4_rpm_pcm = 0;
get_joystick_xy(&x, &y);
//ESP_LOGI("(x, y)", "[ %d, %d ]", x, y);
buffer.x_axis = x;
buffer.y_axis = y;
// Display brief summary of data being sent.
ESP_LOGI(TAG, "Joystick (x,y) position ( %d, %d )", buffer.x_axis, buffer.y_axis);
ESP_LOGI(TAG, "pcm 1, pcm 2 [ 0x%04X, 0x%04X ]", (uint8_t)buffer.motor1_rpm_pcm, (uint8_t)buffer.motor2_rpm_pcm);
ESP_LOGI(TAG, "pcm 3, pcm 4 [ 0x%04X, 0x%04X ]", (uint8_t)buffer.motor3_rpm_pcm, (uint8_t)buffer.motor4_rpm_pcm);
// Call ESP-NOW function to send data (MAC address of receiver, pointer to the memory holding data & data length)
uint8_t result = esp_now_send(receiver_mac, (uint8_t *)&buffer, sizeof(buffer));
// If status is NOT OK, display error message and error code (in hexadecimal).
if (result != 0) {
ESP_LOGE("sendData()", "Error sending data! Error code: 0x%04X", result);
ESP_LOGE("sendData()", "esp_now_send() failed: %s", esp_err_to_name(result));
ESP_LOGE("sendData()", "Ensure that receiver is powered-on.");
ESP_LOGE("sendData()", "Ensure that received MAC is: %02X:%02X:%02X:%02X:%02X:%02X",
receiver_mac[0], receiver_mac[1], receiver_mac[2],
receiver_mac[3], receiver_mac[4], receiver_mac[5]);
deletePeer();
}
}
/* WiFi should start before using ESPNOW */
void wifi_init() {
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK( esp_wifi_init(&cfg) );
ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) );
ESP_ERROR_CHECK( esp_wifi_set_mode(ESPNOW_WIFI_MODE));
ESP_ERROR_CHECK( esp_wifi_start());
ESP_ERROR_CHECK( esp_wifi_set_channel(CONFIG_ESPNOW_CHANNEL, WIFI_SECOND_CHAN_NONE));
#if CONFIG_ESPNOW_ENABLE_LONG_RANGE
ESP_ERROR_CHECK( esp_wifi_set_protocol(ESPNOW_WIFI_IF, WIFI_PROTOCOL_11B|WIFI_PROTOCOL_11G|WIFI_PROTOCOL_11N|WIFI_PROTOCOL_LR) );
#endif
}
void rc_send_data_task()
{
while (true) {
if (esp_now_is_peer_exist(receiver_mac)) {
sendData();
//sendRawData();
}
vTaskDelay (1000 / portTICK_PERIOD_MS);
}
}
void app_main(void)
{
joystick_adc_init();
// 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 );
wifi_init();
esp_err_t espnow_ret = esp_now_init();
if (espnow_ret != ESP_OK) {
//ESP_LOGE(TAG, "Error initializing ESPNOW: %s", espnow_ret);
ESP_LOGE(TAG, "esp_now_init() failed: %s", esp_err_to_name(espnow_ret));
return;
}
ESP_LOGI(TAG, "ESPNOW initialized successfully");
esp_now_register_send_cb(statusDataSend);
// Set ESP-NOW receiver device configuration values
memcpy(devices.peer_addr, receiver_mac, 6);
devices.channel = 1;
devices.encrypt = false;
esp_now_add_peer(&devices);
// Defince a task for periodically sending ESPNOW remote control data
xTaskCreate(rc_send_data_task, "RC", 2048, NULL, 4, NULL);
}