#include <stdio.h>
#include <string.h>
#include "driver/uart.h"
#include "driver/gpio.h"
#include "esp_system.h"
#include "esp_timer.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/adc.h"
#include "esp_adc/adc_oneshot.h"
#include "esp_crc.h"
#include "esp_log.h"
// Paramètres du port série
#define UART_NUM UART_NUM_0
#define TXD_PIN GPIO_NUM_25
#define RXD_PIN GPIO_NUM_26
#define BUF_SIZE 1024
#define BAUD_RATE 115200
// Définition de la broche du bouton
#define BUTTON23_PIN 23
#define BUTTON22_PIN 22
#define BUTTON21_PIN 21
#define BUTTON19_PIN 19
#define BUTTON18_PIN 18
#define BUTTON05_PIN 5
#define BUTTON17_PIN 17
#define BUTTON16_PIN 16
#define BUTTON04_PIN 4
#define BUTTON00_PIN 0
#define LED_COMM_PIN 12
#define LED_1_PIN 14
#define LED_2_PIN 27
#define LED_3_PIN 26
// Joystick 1
#define JOYSTICK1_X_PIN ADC1_CHANNEL_4 // GPIO32
#define JOYSTICK1_Y_PIN ADC1_CHANNEL_5 // GPIO33
#define JOYSTICK1_SW_PIN 25 // GPIO25
// Joystick 2
#define JOYSTICK2_X_PIN ADC1_CHANNEL_6 // GPIO34
#define JOYSTICK2_Y_PIN ADC1_CHANNEL_7 // GPIO35
#define JOYSTICK2_SW_PIN 26 // GPIO26
// Initialiser l'UART
void init_uart() {
// Configuration du port série UART0
uart_config_t uart_config = {
.baud_rate = BAUD_RATE,
.data_bits = UART_DATA_8_BITS, // 8 bits de données
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_DISABLE
};
uart_param_config(UART_NUM, &uart_config);
uart_set_pin(UART_NUM, TXD_PIN, RXD_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
uart_driver_install(UART_NUM, BUF_SIZE, 0, 0, NULL, 0);
}
// Initialiser les leds et entrées boutons
void init_gpio() {
gpio_set_direction(LED_COMM_PIN, GPIO_MODE_OUTPUT);
gpio_set_level(LED_COMM_PIN, 0); // LED éteinte au démarrage
gpio_set_direction(LED_1_PIN, GPIO_MODE_OUTPUT);
gpio_set_level(LED_1_PIN, 0); // LED éteinte au démarrage
gpio_set_direction(LED_2_PIN, GPIO_MODE_OUTPUT);
gpio_set_level(LED_2_PIN, 0); // LED éteinte au démarrage
gpio_set_direction(LED_3_PIN, GPIO_MODE_OUTPUT);
gpio_set_level(LED_3_PIN, 0); // LED éteinte au démarrage
// Configuration du GPIO pour le bouton avec résistance pull-up interne
gpio_set_direction(BUTTON23_PIN, GPIO_MODE_INPUT); // Définir le bouton comme entrée
gpio_set_direction(BUTTON22_PIN, GPIO_MODE_INPUT); // Définir le bouton comme entrée
gpio_set_direction(BUTTON21_PIN, GPIO_MODE_INPUT); // Définir le bouton comme entrée
gpio_set_direction(BUTTON19_PIN, GPIO_MODE_INPUT); // Définir le bouton comme entrée
gpio_set_direction(BUTTON18_PIN, GPIO_MODE_INPUT); // Définir le bouton comme entrée
gpio_set_direction(BUTTON05_PIN, GPIO_MODE_INPUT); // Définir le bouton comme entrée
gpio_set_direction(BUTTON17_PIN, GPIO_MODE_INPUT); // Définir le bouton comme entrée
gpio_set_direction(BUTTON16_PIN, GPIO_MODE_INPUT); // Définir le bouton comme entrée
gpio_set_direction(BUTTON04_PIN, GPIO_MODE_INPUT); // Définir le bouton comme entrée
gpio_set_direction(BUTTON00_PIN, GPIO_MODE_INPUT); // Définir le bouton comme entrée
gpio_pullup_en(BUTTON23_PIN); // Activer la résistance pull-up
gpio_pullup_en(BUTTON22_PIN); // Activer la résistance pull-up
gpio_pullup_en(BUTTON21_PIN); // Activer la résistance pull-up
gpio_pullup_en(BUTTON19_PIN); // Activer la résistance pull-up
gpio_pullup_en(BUTTON18_PIN); // Activer la résistance pull-up
gpio_pullup_en(BUTTON05_PIN); // Activer la résistance pull-up
gpio_pullup_en(BUTTON17_PIN); // Activer la résistance pull-up
gpio_pullup_en(BUTTON16_PIN); // Activer la résistance pull-up
gpio_pullup_en(BUTTON04_PIN); // Activer la résistance pull-up
gpio_pullup_en(BUTTON00_PIN); // Activer la résistance pull-up
}
// Initialiser le convertisseur analogique numérique
adc_oneshot_unit_handle_t init_adc() {
adc_oneshot_unit_handle_t adc_handle;
// Configuration de l'ADC
adc_oneshot_unit_init_cfg_t init_config = {
.unit_id = ADC_UNIT_1
};
adc_oneshot_new_unit(&init_config, &adc_handle);
// Configuration des canaux ADC
adc_oneshot_chan_cfg_t chan_config = {
.bitwidth = ADC_BITWIDTH_DEFAULT,
.atten = ADC_ATTEN_DB_11
};
adc_oneshot_config_channel(adc_handle, JOYSTICK1_X_PIN, &chan_config);
adc_oneshot_config_channel(adc_handle, JOYSTICK1_Y_PIN, &chan_config);
adc_oneshot_config_channel(adc_handle, JOYSTICK2_X_PIN, &chan_config);
adc_oneshot_config_channel(adc_handle, JOYSTICK2_Y_PIN, &chan_config);
// // Configuration des broches des boutons
// gpio_pad_select_gpio(JOYSTICK1_SW_PIN);
// gpio_set_direction(JOYSTICK1_SW_PIN, GPIO_MODE_INPUT);
// gpio_pullup_en(JOYSTICK1_SW_PIN);
// gpio_pad_select_gpio(JOYSTICK2_SW_PIN);
// gpio_set_direction(JOYSTICK2_SW_PIN, GPIO_MODE_INPUT);
// gpio_pullup_en(JOYSTICK2_SW_PIN);
return adc_handle;
}
// Fonction pour calculer le CRC32 et ajouter le CRC à la trame
size_t create_frame_with_crc(adc_oneshot_unit_handle_t adc_handle, uint8_t *frame_out) {
// Lire l'état des boutons (0 si appuyé, 1 si relâché)
int button23_state = gpio_get_level(BUTTON23_PIN);
int button22_state = gpio_get_level(BUTTON22_PIN);
int button21_state = gpio_get_level(BUTTON21_PIN);
int button19_state = gpio_get_level(BUTTON19_PIN);
int button18_state = gpio_get_level(BUTTON18_PIN);
int button05_state = gpio_get_level(BUTTON05_PIN);
int button17_state = gpio_get_level(BUTTON17_PIN);
int button16_state = gpio_get_level(BUTTON16_PIN);
int button04_state = gpio_get_level(BUTTON04_PIN);
int button00_state = gpio_get_level(BUTTON00_PIN);
// Lire l'état des joystick
int buttonJ1A_state;
adc_oneshot_read(adc_handle, JOYSTICK1_X_PIN, &buttonJ1A_state);
int buttonJ1R_state;
adc_oneshot_read(adc_handle, JOYSTICK1_Y_PIN, &buttonJ1R_state);
int buttonJ2A_state;
adc_oneshot_read(adc_handle, JOYSTICK2_X_PIN, &buttonJ2A_state);
int buttonJ2R_state;
adc_oneshot_read(adc_handle, JOYSTICK2_Y_PIN, &buttonJ2R_state);
// Création de la trame à envoyer
char message[128];
int message_length = snprintf(message, sizeof(message),
"\nT%s%s%s%s%s%s%s%s%s%s%.4d%.4d%.4d%.4d",
button23_state == 0 ? "1" : "0", // pinces int + bloque planche
button22_state == 0 ? "1" : "0", // pinces ext
button21_state == 0 ? "1" : "0", // pousse planche
button19_state == 0 ? "1" : "0", // N0
button18_state == 0 ? "1" : "0", // N1
button05_state == 0 ? "1" : "0", // N2
button17_state == 0 ? "1" : "0", // N3
button16_state == 0 ? "1" : "0", // Tempo Pami
button04_state == 0 ? "1" : "0", // Increment points
button00_state == 0 ? "1" : "0", // Ouverture affiche
buttonJ1A_state,
buttonJ1R_state,
buttonJ2A_state,
buttonJ2R_state);
// Calculer le CRC32
memcpy(frame_out, message, message_length);
uint32_t crc = esp_crc32_le(0, (const uint8_t *)message, message_length);
// Ajouter le CRC à la fin de la trame (little-endian)
frame_out[message_length] = (uint8_t)(crc & 0xFF);
frame_out[message_length + 1] = (uint8_t)((crc >> 8) & 0xFF);
frame_out[message_length + 2] = (uint8_t)((crc >> 16) & 0xFF);
frame_out[message_length + 3] = (uint8_t)((crc >> 24) & 0xFF);
// Retourner la longueur totale de la trame (données + CRC)
return message_length + 4;
}
// Fonction pour vérifier le CRC32 d'une trame
bool verify_crc32(const uint8_t *frame, size_t length) {
if (length < 4) {
// La longueur doit être au moins 4 octets (pour contenir un CRC32)
return false;
}
// Extraire le CRC32 reçu (les 4 derniers octets de la trame)
uint32_t received_crc = (uint32_t)frame[length - 4] |
((uint32_t)frame[length - 3] << 8) |
((uint32_t)frame[length - 2] << 16) |
((uint32_t)frame[length - 1] << 24);
// Calculer le CRC32 des données, sans inclure les 4 derniers octets
uint32_t calculated_crc = esp_crc32_le(0, frame, length - 4);
// Comparer le CRC reçu avec le CRC calculé
return (calculated_crc == received_crc);
}
// Fonction pour lire la trame et allumer la LED si elle commence par "R"
void check_uart_data() {
uint8_t data[BUF_SIZE];
int length = uart_read_bytes(UART_NUM, data, BUF_SIZE, 20 / portTICK_PERIOD_MS);
if (length > 0) {
ESP_LOGI("UART", "Données reçues : %.*s", length, data);
if (verify_crc32(data, length))
{
// Vérifier si la trame commence par 'R'
if (data[0] == 'R') {
ESP_LOGI("UART", "Trame valide reçue, allumer la LED.");
gpio_set_level(LED_COMM_PIN, 1); // Allumer la LED
} else {
gpio_set_level(LED_COMM_PIN, 0); // Éteindre la LED
}
// LED 1
if (data[1] == '1') {
ESP_LOGI("UART", "Data[1]=1");
gpio_set_level(LED_1_PIN, 1); // Allumer la LED
} else {
ESP_LOGI("UART", "Data[1]=0");
gpio_set_level(LED_1_PIN, 0); // Éteindre la LED
}
// LED 2
if (data[2] == '1') {
ESP_LOGI("UART", "Data[2]=1");
gpio_set_level(LED_2_PIN, 1); // Allumer la LED
} else {
ESP_LOGI("UART", "Data[2]=0");
gpio_set_level(LED_2_PIN, 0); // Éteindre la LED
}
// LED 3
if (data[3] == '1') {
ESP_LOGI("UART", "Data[3]=1");
gpio_set_level(LED_3_PIN, 1); // Allumer la LED
} else {
ESP_LOGI("UART", "Data[3]=0");
gpio_set_level(LED_3_PIN, 0); // Éteindre la LED
}
} else {
ESP_LOGI("UART", "CRC trame invalide");
gpio_set_level(LED_COMM_PIN, 0); // Éteindre la LED
}
} else {
gpio_set_level(LED_COMM_PIN, 0); // Éteindre la LED
}
}
void app_main(void)
{
init_uart();
init_gpio();
adc_oneshot_unit_handle_t adc_handle = init_adc();
// Envoi de trames en continu
while (1) {
// Buffer pour la trame avec CRC
uint8_t frame[128];
// Créer la trame avec CRC
size_t frame_length = create_frame_with_crc(adc_handle, frame);
// Envoi de la trame sur le port série
uart_write_bytes(UART_NUM, (const char *)frame, frame_length);
// Attente de 10 milliseconde avant la prochaine trame
vTaskDelay(10 / portTICK_PERIOD_MS);
// Recevoir la réponse préfixée par 'R'
check_uart_data();
}
}