From 7fb9d238f390344d2623deeb2f4ca855779843c9 Mon Sep 17 00:00:00 2001 From: millennium42 Date: Sat, 12 Jul 2025 19:43:28 -0300 Subject: [PATCH 1/3] =?UTF-8?q?###=20Port:=20Migra=C3=A7=C3=A3o=20de=20C?= =?UTF-8?q?=20para=20C++=20para=20a=20Biblioteca=20NRF24L01+?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Migrada a biblioteca de comunicação NRF24L01+ de C para C++ para uma melhor organização do código e compatibilidade. **Principais Mudanças:** * Renomeados todos os arquivos `.c` para `.cpp` e `.h` para `.hpp`. * Adicionadas especificações de linkagem `extern "C"` nos arquivos de cabeçalho para compatibilidade de funções estilo C. * Caminhos de inclusão atualizados para refletir as novas extensões `.hpp`. * `README.md` atualizado para documentar o uso em C++ e a nova estrutura de arquivos. * Feitos pequenos ajustes idiomáticos de C++ (ex: uso de `nullptr`).### Port: Migração de C para C++ para a Biblioteca NRF24L01+ Migrada a biblioteca de comunicação NRF24L01+ de C para C++ para uma melhor organização do código e compatibilidade. **Principais Mudanças:** * Renomeados todos os arquivos `.c` para `.cpp` e `.h` para `.hpp`. * Adicionadas especificações de linkagem `extern "C"` nos arquivos de cabeçalho para compatibilidade de funções estilo C. * Caminhos de inclusão atualizados para refletir as novas extensões `.hpp`. * Feitos pequenos ajustes idiomáticos de C++ (ex: uso de `nullptr`). --- COMM.c | 131 --------------------------- COMM.cpp | 160 +++++++++++++++++++++++++++++++++ COMM.h | 60 ------------- COMM.hpp | 116 ++++++++++++++++++++++++ COMM_PACKETS.c | 80 ----------------- COMM_PACKETS.cpp | 49 ++++++++++ COMM_PACKETS.h | 135 ---------------------------- COMM_PACKETS.hpp | 116 ++++++++++++++++++++++++ NRF24_CORE.c => NRF24_CORE.cpp | 7 +- NRF24_CORE.h => NRF24_CORE.hpp | 15 +++- NRF24_DEF.h => NRF24_DEF.hpp | 7 +- NRF24_HAL.c => NRF24_HAL.cpp | 5 +- NRF24_HAL.h => NRF24_HAL.hpp | 15 +++- 13 files changed, 476 insertions(+), 420 deletions(-) delete mode 100644 COMM.c create mode 100644 COMM.cpp delete mode 100644 COMM.h create mode 100644 COMM.hpp delete mode 100644 COMM_PACKETS.c create mode 100644 COMM_PACKETS.cpp delete mode 100644 COMM_PACKETS.h create mode 100644 COMM_PACKETS.hpp rename NRF24_CORE.c => NRF24_CORE.cpp (97%) rename NRF24_CORE.h => NRF24_CORE.hpp (71%) rename NRF24_DEF.h => NRF24_DEF.hpp (91%) rename NRF24_HAL.c => NRF24_HAL.cpp (90%) rename NRF24_HAL.h => NRF24_HAL.hpp (57%) diff --git a/COMM.c b/COMM.c deleted file mode 100644 index a2b1c27..0000000 --- a/COMM.c +++ /dev/null @@ -1,131 +0,0 @@ - -#include "Comm/COMM.h" -#include "Comm/NRF24_CORE.h" -#include "Comm/COMM_PACKETS.h" -#include -#include - -static comm_robot_type_t s_current_robot_type; -static uint8_t s_packet_seq_counter = 0; -static comm_packet_t s_tx_packet_buffer; -static comm_packet_t s_rx_packet_buffer; - -static uint8_t s_my_listening_address[5]; -static uint8_t s_peer_target_address[5]; -static uint8_t s_rf_channel; - -static comm_ssl_command_handler_t s_ssl_cmd_handler = NULL; -static comm_vsss_command_handler_t s_vsss_cmd_handler = NULL; -static comm_ssl_telemetry_handler_t s_ssl_tel_handler = NULL; -static comm_vsss_telemetry_handler_t s_vsss_tel_handler = NULL; -static comm_debug_text_handler_t s_debug_text_handler = NULL; - -static bool send_packet_p2p(comm_packet_t* packet_to_send) { - NRF24_TxMode(s_peer_target_address, s_rf_channel); - bool success = NRF24_Transmit((uint8_t*)packet_to_send, sizeof(comm_packet_t)); - NRF24_RxMode(s_my_listening_address, 0, s_rf_channel); - - return success; -} - -bool Comm_Init_P2P(comm_robot_type_t robot_type, - uint8_t channel, - const uint8_t my_listening_address[5], - const uint8_t peer_target_address[5]) { - s_current_robot_type = robot_type; - s_packet_seq_counter = 0; - s_rf_channel = channel; - - memcpy(s_my_listening_address, my_listening_address, 5); - memcpy(s_peer_target_address, peer_target_address, 5); - - printf("Comm_Init_P2P: Robô tipo %d, Canal %d\r\n", robot_type, channel); - - NRF24_Init(); - NRF24_RxMode(s_my_listening_address, 0, s_rf_channel); // Inicia escutando - printf("NRF24 configurado como Transceptor, iniciando em modo RX.\r\n"); - return true; -} - -// --- Funções de Envio --- -int16_t Comm_Send_SSL_Command(const ssl_command_payload_t* cmd_payload_data) { - if (cmd_payload_data == NULL) return -1; - uint8_t current_seq = s_packet_seq_counter++; - Comm_Packets_Create_SSLCommand(&s_tx_packet_buffer, current_seq, cmd_payload_data); - if (send_packet_p2p(&s_tx_packet_buffer)) { - return current_seq; - } - return -1; -} -int16_t Comm_Send_VSSS_Command(const vsss_command_payload_t* cmd_payload_data) { - if (cmd_payload_data == NULL) return -1; - uint8_t current_seq = s_packet_seq_counter++; - Comm_Packets_Create_VSSSCommand(&s_tx_packet_buffer, current_seq, cmd_payload_data); - if (send_packet_p2p(&s_tx_packet_buffer)) { - return current_seq; - } - return -1; -} - -int16_t Comm_Send_SSL_Telemetry(const ssl_telemetry_payload_t* tel_payload_data) { - if (tel_payload_data == NULL) return -1; - uint8_t current_seq = s_packet_seq_counter++; - Comm_Packets_Create_SSLTelemetry(&s_tx_packet_buffer, current_seq, tel_payload_data); - if (send_packet_p2p(&s_tx_packet_buffer)) { - return current_seq; - } - return -1; -} - -int16_t Comm_Send_VSSS_Telemetry(const vsss_telemetry_payload_t* tel_payload_data) { - if (tel_payload_data == NULL) return -1; - uint8_t current_seq = s_packet_seq_counter++; - Comm_Packets_Create_VSSTelemetry(&s_tx_packet_buffer, current_seq, tel_payload_data); - if (send_packet_p2p(&s_tx_packet_buffer)) { - return current_seq; - } - return -1; -} -int16_t Comm_Send_DebugText_Message(const char* text_payload) { - if (text_payload == NULL) return -1; - uint8_t current_seq = s_packet_seq_counter++; - Comm_Packets_Create_DebugText(&s_tx_packet_buffer, current_seq, text_payload); - if (send_packet_p2p(&s_tx_packet_buffer)) { - return current_seq; - } - return -1; -} - -void Comm_Register_SSL_CommandHandler(comm_ssl_command_handler_t callback) { s_ssl_cmd_handler = callback; } -void Comm_Register_VSSS_CommandHandler(comm_vsss_command_handler_t callback) { s_vsss_cmd_handler = callback; } -void Comm_Register_SSL_TelemetryHandler(comm_ssl_telemetry_handler_t callback) { s_ssl_tel_handler = callback; } -void Comm_Register_VSSS_TelemetryHandler(comm_vsss_telemetry_handler_t callback) { s_vsss_tel_handler = callback; } -void Comm_Register_DebugText_Packet_Handler(comm_debug_text_handler_t callback) { s_debug_text_handler = callback; } - -void Comm_ProcessReceivedPackets(void) { - if (isDataAvailable(1)) { - uint8_t raw_input_buffer[NRF_MAX_PACKET_SIZE]; - NRF24_Receive(raw_input_buffer); - memcpy(&s_rx_packet_buffer, raw_input_buffer, sizeof(comm_packet_t)); - - switch (s_rx_packet_buffer.header.main_type) { - case MAIN_PACKET_TYPE_SSL_COMMAND: - if (s_ssl_cmd_handler != NULL) s_ssl_cmd_handler(&s_rx_packet_buffer.payload_u.ssl_cmd, s_rx_packet_buffer.payload_u.ssl_cmd.robot_id, s_rx_packet_buffer.header.seq_number); - break; - case MAIN_PACKET_TYPE_VSSS_COMMAND: - if (s_vsss_cmd_handler != NULL) s_vsss_cmd_handler(&s_rx_packet_buffer.payload_u.vsss_cmd, s_rx_packet_buffer.payload_u.vsss_cmd.robot_id, s_rx_packet_buffer.header.seq_number); - break; - case MAIN_PACKET_TYPE_SSL_TELEMETRY: - if (s_ssl_tel_handler != NULL) s_ssl_tel_handler(&s_rx_packet_buffer.payload_u.ssl_tel, s_rx_packet_buffer.payload_u.ssl_tel.robot_id, s_rx_packet_buffer.header.seq_number); - break; - case MAIN_PACKET_TYPE_VSSS_TELEMETRY: - if (s_vsss_tel_handler != NULL) s_vsss_tel_handler(&s_rx_packet_buffer.payload_u.vsss_tel, s_rx_packet_buffer.payload_u.vsss_tel.robot_id, s_rx_packet_buffer.header.seq_number); - break; - case MAIN_PACKET_TYPE_DEBUG_TEXT: - break; - default: - printf("Comm: Tipo de pacote principal desconhecido: %d\r\n", s_rx_packet_buffer.header.main_type); - break; - } - } -} \ No newline at end of file diff --git a/COMM.cpp b/COMM.cpp new file mode 100644 index 0000000..a55ce75 --- /dev/null +++ b/COMM.cpp @@ -0,0 +1,160 @@ +// Comm/COMM.cpp +#include // Atualizado caminho de inclusão +#include // Atualizado caminho de inclusão +#include // Atualizado caminho de inclusão +#include +#include + + +static comm_robot_type_t s_current_robot_type; +static comm_node_mode_t s_current_node_mode; +static uint8_t s_packet_seq_counter = 0; +static comm_packet_t s_comm_packet_buffer; + + +static comm_ssl_packet_handler_t s_ssl_handler = nullptr; // Opcional: usar nullptr +static comm_vsss_packet_handler_t s_vsss_handler = nullptr; // Opcional: usar nullptr +static comm_debug_text_handler_t s_debug_text_handler = nullptr; // Opcional: usar nullptr + + +bool Comm_Init(comm_robot_type_t robot_type, + comm_node_mode_t node_mode, + uint8_t channel, + uint8_t* nrf_tx_address, + uint8_t* nrf_rx_pipe1_address, + uint8_t nrf_rx_pipe2_lsb) +{ + s_current_robot_type = robot_type; + s_current_node_mode = node_mode; + s_packet_seq_counter = 0; + + printf("Comm_Init: Modo %s, Robô %s, Canal %d\r\n", + (node_mode == COMM_NODE_MODE_TRANSMITTER) ? "TX" : "RX", + (robot_type == COMM_ROBOT_TYPE_SSL) ? "SSL" : (robot_type == COMM_ROBOT_TYPE_VSSS) ? "VSSS" : "N/A", + channel); + + NRF24_Init(); + + if (s_current_node_mode == COMM_NODE_MODE_TRANSMITTER) { + NRF24_TxMode(nrf_tx_address, channel); + printf("NRF24 configurado como Transmissor.\r\n"); + } else { + NRF24_RxMode(nrf_rx_pipe1_address, nrf_rx_pipe2_lsb, channel); + printf("NRF24 configurado como Receptor.\r\n"); + } + return true; +} + + +bool Comm_Send_SSL_Message(const ssl_payload_t* ssl_payload_data) { + if (s_current_node_mode != COMM_NODE_MODE_TRANSMITTER) { + printf("Comm_Send_SSL_Message: Erro - Nó não está em modo transmissor.\r\n"); + return false; + } + if (ssl_payload_data == nullptr) { // Alterado de NULL para nullptr + printf("Comm_Send_SSL_Message: Erro - Payload SSL nulo.\r\n"); + return false; + } + + Comm_Packets_Create_SSLMessage(&s_comm_packet_buffer, s_packet_seq_counter++, ssl_payload_data); + + //printf("Comm Enviando SSL: Seq %d, ID %d, Vx %d\r\n", s_comm_packet_buffer.header.seq_number, ssl_payload_data->robot_id, ssl_payload_data->vx); + return NRF24_Transmit((uint8_t*)&s_comm_packet_buffer, sizeof(comm_packet_t)); +} + +bool Comm_Send_VSSS_Message(const vsss_payload_t* vsss_payload_data) { + if (s_current_node_mode != COMM_NODE_MODE_TRANSMITTER) { + printf("Comm_Send_VSSS_Message: Erro - Nó não está em modo transmissor.\r\n"); + return false; + } + if (vsss_payload_data == nullptr) { // Alterado de NULL para nullptr + printf("Comm_Send_VSSS_Message: Erro - Payload VSSS nulo.\r\n"); + return false; + } + + Comm_Packets_Create_VSSSMessage(&s_comm_packet_buffer, s_packet_seq_counter++, vsss_payload_data); + + // printf("Comm Enviando VSSS: Seq %d, ID %d, M1 %d\r\n", s_comm_packet_buffer.header.seq_number, vsss_payload_data->robot_id, vsss_payload_data->motor1_value); + return NRF24_Transmit((uint8_t*)&s_comm_packet_buffer, sizeof(comm_packet_t)); +} + +bool Comm_Send_DebugText_Message(const char* text_payload) { + if (s_current_node_mode != COMM_NODE_MODE_TRANSMITTER) { + printf("Comm_Send_DebugText_Message: Erro - Nó não está em modo transmissor.\r\n"); + return false; + } + if (text_payload == nullptr) { // Alterado de NULL para nullptr + printf("Comm_Send_DebugText_Message: Erro - Texto nulo.\r\n"); + return false; + } + + Comm_Packets_Create_DebugText(&s_comm_packet_buffer, s_packet_seq_counter++, text_payload); + + // printf("Comm Enviando Debug: Seq %d, Texto: %s\r\n", s_comm_packet_buffer.header.seq_number, text_payload); + return NRF24_Transmit((uint8_t*)&s_comm_packet_buffer, sizeof(comm_packet_t)); +} + + + +void Comm_Register_SSL_Packet_Handler(comm_ssl_packet_handler_t callback) { + s_ssl_handler = callback; +} + +void Comm_Register_VSSS_Packet_Handler(comm_vsss_packet_handler_t callback) { + s_vsss_handler = callback; +} + +void Comm_Register_DebugText_Packet_Handler(comm_debug_text_handler_t callback) { + s_debug_text_handler = callback; +} + +void Comm_ProcessReceivedPackets(void) { + if (s_current_node_mode != COMM_NODE_MODE_RECEIVER) { + return; + } + + uint8_t raw_input_buffer[NRF_MAX_PACKET_SIZE]; + + if (isDataAvailable(1)) { // Verifica Pipe 1 (poderia ser configurável ou verificar múltiplos pipes) + NRF24_Receive(raw_input_buffer); + + memcpy(&s_comm_packet_buffer, raw_input_buffer, sizeof(comm_packet_t)); + + // HAL_GPIO_TogglePin(LED_DEBUG_GPIO_Port, LED_DEBUG_Pin); // Feedback visual pode ir para o main ou callback + + // printf("Comm Pacote Recebido! Tipo: %d, Seq: %d\r\n", + // s_comm_packet_buffer.header.main_type, + // s_comm_packet_buffer.header.seq_number); + + switch (s_comm_packet_buffer.header.main_type) { + case MAIN_PACKET_TYPE_SSL_MESSAGE: + if (s_ssl_handler != nullptr) { // Alterado de NULL para nullptr + s_ssl_handler(&s_comm_packet_buffer.payload_u.ssl_msg, + s_comm_packet_buffer.payload_u.ssl_msg.robot_id, // Passando o ID do payload + s_comm_packet_buffer.header.seq_number); + } + break; + + case MAIN_PACKET_TYPE_VSSS_MESSAGE: + if (s_vsss_handler != nullptr) { // Alterado de NULL para nullptr + s_vsss_handler(&s_comm_packet_buffer.payload_u.vsss_msg, + s_comm_packet_buffer.payload_u.vsss_msg.robot_id, // Passando o ID do payload + s_comm_packet_buffer.header.seq_number); + } + break; + + case MAIN_PACKET_TYPE_DEBUG_TEXT: + if (s_debug_text_handler != nullptr) { // Alterado de NULL para nullptr + char temp_text[DEBUG_TEXT_MAX_LEN + 1]; + memcpy(temp_text, s_comm_packet_buffer.payload_u.debug_text.text, DEBUG_TEXT_MAX_LEN); + temp_text[DEBUG_TEXT_MAX_LEN] = '\0'; + s_debug_text_handler(temp_text, s_comm_packet_buffer.header.seq_number); + } + break; + + default: + printf("Comm: Tipo de pacote principal desconhecido: %d\r\n", s_comm_packet_buffer.header.main_type); + break; + } + } +} \ No newline at end of file diff --git a/COMM.h b/COMM.h deleted file mode 100644 index aa43023..0000000 --- a/COMM.h +++ /dev/null @@ -1,60 +0,0 @@ - -#ifndef COMM_H_ -#define COMM_H_ - -#include -#include -#include -#include -#include "COMM_PACKETS.h" - -typedef enum { - COMM_ROBOT_TYPE_UNDEFINED, - COMM_ROBOT_TYPE_SSL, - COMM_ROBOT_TYPE_VSSS -} comm_robot_type_t; - -typedef void (*comm_ssl_command_handler_t)(const ssl_command_payload_t* cmd_data, uint8_t robot_id, uint8_t seq_num); -typedef void (*comm_vsss_command_handler_t)(const vsss_command_payload_t* cmd_data, uint8_t robot_id, uint8_t seq_num); -typedef void (*comm_ssl_telemetry_handler_t)(const ssl_telemetry_payload_t* tel_data, uint8_t robot_id, uint8_t seq_num); -typedef void (*comm_vsss_telemetry_handler_t)(const vsss_telemetry_payload_t* tel_data, uint8_t robot_id, uint8_t seq_num); -typedef void (*comm_debug_text_handler_t)(const char* text_data, uint8_t seq_num); - - -// -------------------- Funções da Interface do Módulo -------------------- - -/** - * @brief Inicializa o módulo de comunicação P2P e o NRF24L01+. - * @param robot_type O tipo de robô principal associado a esta instância. - * @param channel Canal RF a ser usado (0-125). - * @param my_listening_address Endereço de 5 bytes no qual este nó irá escutar por pacotes. - * @param peer_target_address Endereço de 5 bytes do nó parceiro para o qual este nó irá transmitir. - * @return true se a inicialização foi bem-sucedida, false caso contrário. - */ -bool Comm_Init_P2P(comm_robot_type_t robot_type, - uint8_t channel, - const uint8_t my_listening_address[5], - const uint8_t peer_target_address[5]); - -// --- Funções de Envio --- -int16_t Comm_Send_SSL_Command(const ssl_command_payload_t* cmd_payload_data); -int16_t Comm_Send_VSSS_Command(const vsss_command_payload_t* cmd_payload_data); -int16_t Comm_Send_SSL_Telemetry(const ssl_telemetry_payload_t* tel_payload_data); -int16_t Comm_Send_VSSS_Telemetry(const vsss_telemetry_payload_t* tel_payload_data); -int16_t Comm_Send_DebugText_Message(const char* text_payload); - - -// --- Funções de Registro de Callback --- -void Comm_Register_SSL_CommandHandler(comm_ssl_command_handler_t callback); -void Comm_Register_VSSS_CommandHandler(comm_vsss_command_handler_t callback); -void Comm_Register_SSL_TelemetryHandler(comm_ssl_telemetry_handler_t callback); -void Comm_Register_VSSS_TelemetryHandler(comm_vsss_telemetry_handler_t callback); -void Comm_Register_DebugText_Packet_Handler(comm_debug_text_handler_t callback); - -/** - * @brief Processa mensagens NRF24L01+ recebidas. - * Esta função deve ser chamada periodicamente no loop principal para verificar por pacotes. - */ -void Comm_ProcessReceivedPackets(void); - -#endif /* COMM_H_ */ \ No newline at end of file diff --git a/COMM.hpp b/COMM.hpp new file mode 100644 index 0000000..353b007 --- /dev/null +++ b/COMM.hpp @@ -0,0 +1,116 @@ +// Comm/COMM.hpp +#ifndef COMM_HPP_ // Alterada guarda de inclusão +#define COMM_HPP_ // Alterada guarda de inclusão + +#include // Atualizado caminho de inclusão +#include // Atualizado caminho de inclusão +#include +#include +#include +#include + +// Melhoria C++ opcional: `enum class comm_robot_type_t { ... };` +typedef enum { + COMM_ROBOT_TYPE_UNDEFINED, + COMM_ROBOT_TYPE_SSL, + COMM_ROBOT_TYPE_VSSS +} comm_robot_type_t; + +// Melhoria C++ opcional: `enum class comm_node_mode_t { ... };` +typedef enum { + COMM_NODE_MODE_TRANSMITTER, + COMM_NODE_MODE_RECEIVER +} comm_node_mode_t; + +// Tipos de Ponteiros de Função para Callbacks de Recepção +typedef void (*comm_ssl_packet_handler_t)(const ssl_payload_t* ssl_data, uint8_t robot_id_from_payload, uint8_t seq_num); +typedef void (*comm_vsss_packet_handler_t)(const vsss_payload_t* vsss_data, uint8_t robot_id_from_payload, uint8_t seq_num); +typedef void (*comm_debug_text_handler_t)(const char* text_data, uint8_t seq_num); + +// -------------------- Funções de Interface do Módulo de Comunicação -------------------- + +#ifdef __cplusplus // Adicionado bloco extern "C" +extern "C" { +#endif + +/** + * @brief Inicializa o módulo de comunicação e o NRF24L01+. + * + * @param robot_type O tipo de robô principal para esta instância (COMM_ROBOT_TYPE_SSL ou COMM_ROBOT_TYPE_VSSS). + * Pode influenciar filtros ou lógicas específicas no futuro. + * @param node_mode Define se o nó operará como COMM_NODE_MODE_TRANSMITTER ou COMM_NODE_MODE_RECEIVER. + * @param channel Canal RF a ser usado (0-125). + * @param tx_address Endereço de 5 bytes para transmissão (se transmissor) ou para o Pipe 0 (se receptor, para ACKs). + * @param rx_pipe1_address Endereço de 5 bytes para o Pipe 1 de recepção (se receptor). + * @param rx_pipe2_lsb LSB para o Pipe 2 de recepção (se receptor, opcional, pode ser 0 se não usado). + * @return true se a inicialização foi bem-sucedida, false caso contrário. + */ +bool Comm_Init(comm_robot_type_t robot_type, + comm_node_mode_t node_mode, + uint8_t channel, + uint8_t* nrf_tx_address, + uint8_t* nrf_rx_pipe1_address, + uint8_t nrf_rx_pipe2_lsb); // Adicionado nrf_rx_pipe2_lsb + +// --- Funções para Transmissor --- + +/** + * @brief Envia uma mensagem de controle para um robô SSL. + * Apenas funciona se Comm_Init foi chamado com COMM_NODE_MODE_TRANSMITTER. + * @param ssl_payload_data Ponteiro para a estrutura de payload SSL a ser enviada. + * @return true se a transmissão foi enfileirada/iniciada com sucesso (ACK pendente), false caso contrário. + */ +bool Comm_Send_SSL_Message(const ssl_payload_t* ssl_payload_data); + +/** + * @brief Envia uma mensagem de controle para um robô VSSS. + * Apenas funciona se Comm_Init foi chamado com COMM_NODE_MODE_TRANSMITTER. + * @param vsss_payload_data Ponteiro para a estrutura de payload VSSS a ser enviada. + * @return true se a transmissão foi enfileirada/iniciada com sucesso (ACK pendente), false caso contrário. + */ +bool Comm_Send_VSSS_Message(const vsss_payload_t* vsss_payload_data); + +/** + * @brief Envia uma mensagem de texto para debug. + * Apenas funciona se Comm_Init foi chamado com COMM_NODE_MODE_TRANSMITTER. + * @param text_payload String de texto a ser enviada. + * @return true se a transmissão foi enfileirada/iniciada com sucesso, false caso contrário. + */ +bool Comm_Send_DebugText_Message(const char* text_payload); + + +// --- Funções para Receptor --- + +/** + * @brief Registra uma função de callback para ser chamada quando um pacote SSL é recebido. + * Apenas relevante se Comm_Init foi chamado com COMM_NODE_MODE_RECEIVER. + * @param callback Ponteiro para a função handler. Passe NULL para desregistrar. + */ +void Comm_Register_SSL_Packet_Handler(comm_ssl_packet_handler_t callback); + +/** + * @brief Registra uma função de callback para ser chamada quando um pacote VSSS é recebido. + * Apenas relevante se Comm_Init foi chamado com COMM_NODE_MODE_RECEIVER. + * @param callback Ponteiro para a função handler. Passe NULL para desregistrar. + */ +void Comm_Register_VSSS_Packet_Handler(comm_vsss_packet_handler_t callback); + +/** + * @brief Registra uma função de callback para ser chamada quando um pacote de Debug Text é recebido. + * Apenas relevante se Comm_Init foi chamado com COMM_NODE_MODE_RECEIVER. + * @param callback Ponteiro para a função handler. Passe NULL para desregistrar. + */ +void Comm_Register_DebugText_Packet_Handler(comm_debug_text_handler_t callback); + +/** + * @brief Processa mensagens NRF24L01+ recebidas. + * Esta função deve ser chamada periodicamente no loop principal do receptor. + * Ela verifica se há dados, os recebe, interpreta o tipo e chama o callback apropriado. + */ +void Comm_ProcessReceivedPackets(void); + +#ifdef __cplusplus +} +#endif + +#endif /* COMM_HPP_ */ \ No newline at end of file diff --git a/COMM_PACKETS.c b/COMM_PACKETS.c deleted file mode 100644 index 1862dc8..0000000 --- a/COMM_PACKETS.c +++ /dev/null @@ -1,80 +0,0 @@ -#include -#include - - -void Comm_Packets_Create_VSSSCommand(comm_packet_t* packet_buffer, - uint8_t seq_num, - const vsss_command_payload_t* cmd_payload) -{ - if (packet_buffer == NULL || cmd_payload == NULL) { - return; - } - memset(packet_buffer, 0, sizeof(comm_packet_t)); - - packet_buffer->header.main_type = MAIN_PACKET_TYPE_VSSS_COMMAND; - packet_buffer->header.seq_number = seq_num; - - memcpy(&packet_buffer->payload_u.vsss_cmd, cmd_payload, sizeof(vsss_command_payload_t)); -} - -void Comm_Packets_Create_SSLCommand(comm_packet_t* packet_buffer, - uint8_t seq_num, - const ssl_command_payload_t* cmd_payload) -{ - if (packet_buffer == NULL || cmd_payload == NULL) { - return; - } - memset(packet_buffer, 0, sizeof(comm_packet_t)); - - packet_buffer->header.main_type = MAIN_PACKET_TYPE_SSL_COMMAND; - packet_buffer->header.seq_number = seq_num; - - memcpy(&packet_buffer->payload_u.ssl_cmd, cmd_payload, sizeof(ssl_command_payload_t)); -} - -void Comm_Packets_Create_DebugText(comm_packet_t* packet_buffer, - uint8_t seq_num, - const char* text_payload) -{ - if (packet_buffer == NULL || text_payload == NULL) { - return; - } - memset(packet_buffer, 0, sizeof(comm_packet_t)); - - packet_buffer->header.main_type = MAIN_PACKET_TYPE_DEBUG_TEXT; - packet_buffer->header.seq_number = seq_num; - - strncpy(packet_buffer->payload_u.debug_text.text, text_payload, DEBUG_TEXT_MAX_LEN -1); - packet_buffer->payload_u.debug_text.text[DEBUG_TEXT_MAX_LEN - 1] = '\0'; -} - - -void Comm_Packets_Create_VSSTelemetry(comm_packet_t* packet_buffer, - uint8_t seq_num, - const vsss_telemetry_payload_t* tel_payload) -{ - if (packet_buffer == NULL || tel_payload == NULL) { - return; - } - memset(packet_buffer, 0, sizeof(comm_packet_t)); - - packet_buffer->header.main_type = MAIN_PACKET_TYPE_VSSS_TELEMETRY; - packet_buffer->header.seq_number = seq_num; - - memcpy(&packet_buffer->payload_u.vsss_tel, tel_payload, sizeof(vsss_telemetry_payload_t)); -} - -void Comm_Packets_Create_SSLTelemetry(comm_packet_t* packet_buffer, - uint8_t seq_num, - const ssl_telemetry_payload_t* tel_payload) -{ - if (packet_buffer == NULL || tel_payload == NULL) { - return; - } - memset(packet_buffer, 0, sizeof(comm_packet_t)); - - packet_buffer->header.main_type = MAIN_PACKET_TYPE_SSL_TELEMETRY; - packet_buffer->header.seq_number = seq_num; - - memcpy(&packet_buffer->payload_u.ssl_tel, tel_payload, sizeof(ssl_telemetry_payload_t)); -} \ No newline at end of file diff --git a/COMM_PACKETS.cpp b/COMM_PACKETS.cpp new file mode 100644 index 0000000..8e36618 --- /dev/null +++ b/COMM_PACKETS.cpp @@ -0,0 +1,49 @@ +// Comm/COMM_PACKETS.cpp +#include // Atualizado caminho de inclusão +#include + +void Comm_Packets_Create_VSSSMessage(comm_packet_t* packet_buffer, + uint8_t seq_num, + const vsss_payload_t* vsss_payload_data) +{ + if (packet_buffer == nullptr || vsss_payload_data == nullptr) { // Opcional: usar nullptr em vez de NULL + return; + } + memset(packet_buffer, 0, sizeof(comm_packet_t)); + + packet_buffer->header.main_type = MAIN_PACKET_TYPE_VSSS_MESSAGE; + packet_buffer->header.seq_number = seq_num; + + memcpy(&packet_buffer->payload_u.vsss_msg, vsss_payload_data, sizeof(vsss_payload_t)); +} + +void Comm_Packets_Create_SSLMessage(comm_packet_t* packet_buffer, + uint8_t seq_num, + const ssl_payload_t* ssl_payload_data) +{ + if (packet_buffer == nullptr || ssl_payload_data == nullptr) { // Opcional: usar nullptr em vez de NULL + return; + } + memset(packet_buffer, 0, sizeof(comm_packet_t)); + + packet_buffer->header.main_type = MAIN_PACKET_TYPE_SSL_MESSAGE; + packet_buffer->header.seq_number = seq_num; + + memcpy(&packet_buffer->payload_u.ssl_msg, ssl_payload_data, sizeof(ssl_payload_t)); +} + +void Comm_Packets_Create_DebugText(comm_packet_t* packet_buffer, + uint8_t seq_num, + const char* text_payload) +{ + if (packet_buffer == nullptr || text_payload == nullptr) { // Opcional: usar nullptr em vez de NULL + return; + } + memset(packet_buffer, 0, sizeof(comm_packet_t)); + + packet_buffer->header.main_type = MAIN_PACKET_TYPE_DEBUG_TEXT; + packet_buffer->header.seq_number = seq_num; + + strncpy(packet_buffer->payload_u.debug_text.text, text_payload, DEBUG_TEXT_MAX_LEN -1); + packet_buffer->payload_u.debug_text.text[DEBUG_TEXT_MAX_LEN - 1] = '\0'; +} \ No newline at end of file diff --git a/COMM_PACKETS.h b/COMM_PACKETS.h deleted file mode 100644 index c3460a7..0000000 --- a/COMM_PACKETS.h +++ /dev/null @@ -1,135 +0,0 @@ -#ifndef COMM_PACKETS_H_ -#define COMM_PACKETS_H_ - -#include - - -#define NRF_MAX_PACKET_SIZE 32 - -typedef enum { - MAIN_PACKET_TYPE_UNDEFINED = 0, - MAIN_PACKET_TYPE_VSSS_COMMAND, - MAIN_PACKET_TYPE_SSL_COMMAND, - MAIN_PACKET_TYPE_VSSS_TELEMETRY, - MAIN_PACKET_TYPE_SSL_TELEMETRY, - MAIN_PACKET_TYPE_DEBUG_TEXT, -} nrf_main_packet_type_t; - - -typedef enum { - VSSS_CMD_SUBTYPE_UNDEFINED = 0, - VSSS_CMD_SET_MOTOR_SPEEDS, - VSSS_CMD_RESERVED, -} vsss_command_subtype_t; - -typedef enum { - SSL_CMD_SUBTYPE_UNDEFINED = 0, - SSL_CMD_SET_VELOCITIES, - SSL_CMD_ACTION_CONTROL, - SSL_CMD_REFEREE, -} ssl_command_subtype_t; - - -typedef enum { - VSSS_TELEMETRY_SUBTYPE_STANDARD = 0, -} vsss_telemetry_subtype_t; - -typedef enum { - SSL_TELEMETRY_SUBTYPE_STANDARD = 0, -} ssl_telemetry_subtype_t; - - - -typedef struct __attribute__((packed)) { - vsss_command_subtype_t command_subtype; - uint8_t robot_id; - uint16_t motor1_value; - uint16_t motor2_value; - uint8_t is_pwm_flag; -} vsss_command_payload_t; - -typedef struct __attribute__((packed)) { - ssl_command_subtype_t command_subtype; - uint8_t robot_id; - int16_t vx; - int16_t vy; - int16_t vw; - uint8_t referee_command; - uint8_t kick_front; - uint8_t kick_chip; - uint8_t capacitor_charge; - uint8_t kick_strength; - uint8_t dribbler_on; - uint8_t dribbler_speed; - uint8_t movement_locked; - uint8_t critical_move_turbo; -} ssl_command_payload_t; - - - -typedef struct __attribute__((packed)) { - uint8_t telemetry_subtype : 4; - uint8_t robot_id : 4; - int32_t motor1_feedback : 18; - int32_t motor2_feedback : 18; - uint8_t battery_level : 8; - uint8_t reserved_bits : 4; - uint8_t command_seq_num_ack; -} vsss_telemetry_payload_t; - -typedef struct __attribute__((packed)) { - uint8_t telemetry_subtype : 4; - uint8_t robot_id : 4; - uint16_t current_m1 : 12; - uint16_t current_m2 : 12; - uint16_t current_m3 : 12; - uint16_t current_m4 : 12; - int16_t dribbler_speed_feedback : 15; - uint8_t kick_load_status : 8; - uint8_t ball_detected : 1; - uint8_t battery_level : 8; - int16_t speed_m1_feedback : 16; - int16_t speed_m2_feedback : 16; - int16_t speed_m3_feedback : 16; - int16_t speed_m4_feedback : 16; - uint8_t telemetry_pckt_count : 8; - uint8_t command_seq_num_ack; -} ssl_telemetry_payload_t; - - -// Payload de Debug -#define DEBUG_TEXT_MAX_LEN (NRF_MAX_PACKET_SIZE - 2) -typedef struct __attribute__((packed)) { - char text[DEBUG_TEXT_MAX_LEN]; -} debug_text_payload_t; - - -typedef struct __attribute__((packed)) { - nrf_main_packet_type_t main_type; - uint8_t seq_number; -} comm_packet_header_t; - -#define COMM_USER_PAYLOAD_MAX_SIZE (NRF_MAX_PACKET_SIZE - sizeof(comm_packet_header_t)) - -typedef struct __attribute__((packed)) { - comm_packet_header_t header; - union { - uint8_t raw_payload[COMM_USER_PAYLOAD_MAX_SIZE]; - vsss_command_payload_t vsss_cmd; - ssl_command_payload_t ssl_cmd; - vsss_telemetry_payload_t vsss_tel; - ssl_telemetry_payload_t ssl_tel; - debug_text_payload_t debug_text; - } payload_u; -} comm_packet_t; - - - -void Comm_Packets_Create_VSSSCommand(comm_packet_t* packet_buffer, uint8_t seq_num, const vsss_command_payload_t* cmd_payload); -void Comm_Packets_Create_SSLCommand(comm_packet_t* packet_buffer, uint8_t seq_num, const ssl_command_payload_t* cmd_payload); -void Comm_Packets_Create_VSSTelemetry(comm_packet_t* packet_buffer, uint8_t seq_num, const vsss_telemetry_payload_t* tel_payload); -void Comm_Packets_Create_SSLTelemetry(comm_packet_t* packet_buffer, uint8_t seq_num, const ssl_telemetry_payload_t* tel_payload); -void Comm_Packets_Create_DebugText(comm_packet_t* packet_buffer, uint8_t seq_num, const char* text_payload); - - -#endif /* COMM_PACKETS_H_ */ \ No newline at end of file diff --git a/COMM_PACKETS.hpp b/COMM_PACKETS.hpp new file mode 100644 index 0000000..50d09be --- /dev/null +++ b/COMM_PACKETS.hpp @@ -0,0 +1,116 @@ +// Comm/COMM_PACKETS.hpp +#ifndef COMM_PACKETS_HPP_ // Alterada guarda de inclusão +#define COMM_PACKETS_HPP_ // Alterada guarda de inclusão + +#include +#include + + +#define NRF_MAX_PACKET_SIZE 32 + +// Para portabilidade direta, manteremos `typedef enum`. +// Melhoria C++ opcional: `enum class nrf_main_packet_type_t { ... };` +typedef enum { + MAIN_PACKET_TYPE_UNDEFINED = 0, + MAIN_PACKET_TYPE_VSSS_MESSAGE, + MAIN_PACKET_TYPE_SSL_MESSAGE, + MAIN_PACKET_TYPE_DEBUG_TEXT, + +} nrf_main_packet_type_t; + + +// Melhoria C++ opcional: `enum class vsss_command_subtype_t { ... };` +typedef enum { + VSSS_CMD_SUBTYPE_UNDEFINED = 0, + VSSS_CMD_SET_MOTOR_SPEEDS, + VSSS_CMD_RESEVED_VSSS, + +} vsss_command_subtype_t; + + +// Melhoria C++ opcional: `enum class ssl_command_subtype_t { ... };` +typedef enum { + SSL_CMD_SUBTYPE_UNDEFINED = 0, + SSL_CMD_SET_VELOCITIES, + SSL_CMD_ACTION_CONTROL, + SSL_CMD_REFEREE, +} ssl_command_subtype_t; + +// Melhoria C++ opcional: `struct __attribute__((packed)) vsss_payload_t { ... };` +typedef struct __attribute__((packed)) { + vsss_command_subtype_t command_subtype; + uint8_t robot_id; // ID do robô (0-255) + uint16_t motor1_value; // Valor para o motor 1 + uint16_t motor2_value; // Valor para o motor 2 + uint8_t is_pwm_flag; // 1 se os valores dos motores são PWM, 0 se RPM +} vsss_payload_t; // Tamanho: 1 + 1 + 2 + 2 + 1 = 7 bytes + +// Melhoria C++ opcional: `struct __attribute__((packed)) ssl_payload_t { ... };` +typedef struct __attribute__((packed)) { + ssl_command_subtype_t command_subtype; // Subtipo do comando SSL + uint8_t robot_id; // ID do robô + int16_t vx; // Velocidade X (mm/s * 10 ou outra escala) + int16_t vy; // Velocidade Y (mm/s * 10 ou outra escala) + int16_t vw; // Velocidade angular (rad/s * 10000 ou outra escala) + uint8_t referee_command; // Comando de jogo (refereeCommand) + uint8_t kick_front; // Chute frontal (0=não, 1=sim) + uint8_t kick_chip; // Chute em arco (0=não, 1=sim) + uint8_t capacitor_charge; // Acionar capacitor (0=não, 1=sim) + uint8_t kick_strength; // Força do chute (0–255 ou escalado) + uint8_t dribbler_on; // Liga dribbler (0=não, 1=sim) + uint8_t dribbler_speed; // Velocidade do dribbler + uint8_t movement_locked; // Proibir movimento (0=não, 1=sim) + uint8_t critical_move_turbo; // Ativar turbo (0=não, 1=sim) +} ssl_payload_t; // Tamanho: 1+1+2+2+2+1 + 1+1+1+1+1+1+1+1 = 17 bytes + + +#define DEBUG_TEXT_MAX_LEN (NRF_MAX_PACKET_SIZE - 2) +// Melhoria C++ opcional: `struct __attribute__((packed)) debug_text_payload_t { ... };` +typedef struct __attribute__((packed)) { + char text[DEBUG_TEXT_MAX_LEN]; +} debug_text_payload_t; + +// Melhoria C++ opcional: `struct __attribute__((packed)) comm_packet_header_t { ... };` +typedef struct __attribute__((packed)) { + nrf_main_packet_type_t main_type; + uint8_t seq_number; +} comm_packet_header_t; + +#define COMM_USER_PAYLOAD_MAX_SIZE (NRF_MAX_PACKET_SIZE - sizeof(comm_packet_header_t)) + +// Melhoria C++ opcional: `struct __attribute__((packed)) comm_packet_t { ... };` +typedef struct __attribute__((packed)) { + comm_packet_header_t header; + + union { + uint8_t raw_payload[COMM_USER_PAYLOAD_MAX_SIZE]; + vsss_payload_t vsss_msg; + ssl_payload_t ssl_msg; + debug_text_payload_t debug_text; + } payload_u; + +} comm_packet_t; + + +#ifdef __cplusplus // Adicionado bloco extern "C" +extern "C" { +#endif + +void Comm_Packets_Create_VSSSMessage(comm_packet_t* packet_buffer, + uint8_t seq_num, + const vsss_payload_t* vsss_payload_data); + + +void Comm_Packets_Create_SSLMessage(comm_packet_t* packet_buffer, + uint8_t seq_num, + const ssl_payload_t* ssl_payload_data); + +void Comm_Packets_Create_DebugText(comm_packet_t* packet_buffer, + uint8_t seq_num, + const char* text_payload); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file diff --git a/NRF24_CORE.c b/NRF24_CORE.cpp similarity index 97% rename from NRF24_CORE.c rename to NRF24_CORE.cpp index 87bb713..5dc6ea7 100644 --- a/NRF24_CORE.c +++ b/NRF24_CORE.cpp @@ -1,5 +1,6 @@ -#include -#include +// Comm/NRF24_CORE.cpp +#include // Atualizado caminho de inclusão +#include // Atualizado caminho de inclusão #include void nrf24_WriteReg(uint8_t Reg, uint8_t Data) { @@ -289,4 +290,4 @@ void NRF24_ReadAll(uint8_t *data) { *(data + j++) = nrf24_ReadReg(DYNPD); *(data + j++) = nrf24_ReadReg(FEATURE); -} +} \ No newline at end of file diff --git a/NRF24_CORE.h b/NRF24_CORE.hpp similarity index 71% rename from NRF24_CORE.h rename to NRF24_CORE.hpp index 58b1c21..bfcba4f 100644 --- a/NRF24_CORE.h +++ b/NRF24_CORE.hpp @@ -1,10 +1,15 @@ -#ifndef NRF24_CORE_H_ -#define NRF24_CORE_H_ +// Comm/NRF24_CORE.hpp +#ifndef NRF24_CORE_HPP_ // Alterada guarda de inclusão +#define NRF24_CORE_HPP_ // Alterada guarda de inclusão -#include +#include // Atualizado caminho de inclusão #include +#ifdef __cplusplus // Adicionado bloco extern "C" +extern "C" { +#endif + void nrf24_WriteReg(uint8_t Reg, uint8_t Data); void nrf24_WriteRegMulti(uint8_t Reg, uint8_t *data, uint8_t size); uint8_t nrf24_ReadReg(uint8_t Reg); @@ -30,4 +35,8 @@ void NRF24_Receive(uint8_t *data); void NRF24_ReadAll(uint8_t *data); +#ifdef __cplusplus +} #endif + +#endif \ No newline at end of file diff --git a/NRF24_DEF.h b/NRF24_DEF.hpp similarity index 91% rename from NRF24_DEF.h rename to NRF24_DEF.hpp index 42229c2..d285555 100644 --- a/NRF24_DEF.h +++ b/NRF24_DEF.hpp @@ -1,5 +1,6 @@ -#ifndef NRF24_DEF_H_ -#define NRF24_DEF_H_ +// Comm/NRF24_DEF.hpp +#ifndef NRF24_DEF_HPP_ // Alterada guarda de inclusão +#define NRF24_DEF_HPP_ // Alterada guarda de inclusão #include "stm32f4xx_hal.h" @@ -68,4 +69,4 @@ extern SPI_HandleTypeDef hspi1; #define REUSE_TX_PL 0xE3 #define NOP 0xFF -#endif +#endif \ No newline at end of file diff --git a/NRF24_HAL.c b/NRF24_HAL.cpp similarity index 90% rename from NRF24_HAL.c rename to NRF24_HAL.cpp index d87afd5..e6ea6c5 100644 --- a/NRF24_HAL.c +++ b/NRF24_HAL.cpp @@ -1,4 +1,5 @@ -#include +// Comm/NRF24_HAL.cpp +#include // Atualizado caminho de inclusão void NRF24_HAL_CE_Enable(void) { HAL_GPIO_WritePin(NRF24_CE_PORT, NRF24_CE_PIN, GPIO_PIN_SET); @@ -30,4 +31,4 @@ void NRF24_HAL_Delay(uint32_t milliseconds) { uint32_t NRF24_HAL_GetTick(void) { return HAL_GetTick(); -} +} \ No newline at end of file diff --git a/NRF24_HAL.h b/NRF24_HAL.hpp similarity index 57% rename from NRF24_HAL.h rename to NRF24_HAL.hpp index 9895cc2..ec5cde1 100644 --- a/NRF24_HAL.h +++ b/NRF24_HAL.hpp @@ -1,7 +1,12 @@ -#ifndef NRF24_HAL_H_ -#define NRF24_HAL_H_ +// Comm/NRF24_HAL.hpp +#ifndef NRF24_HAL_HPP_ // Alterada guarda de inclusão +#define NRF24_HAL_HPP_ // Alterada guarda de inclusão -#include +#include // Atualizado caminho de inclusão + +#ifdef __cplusplus // Adicionado bloco extern "C" +extern "C" { +#endif void NRF24_HAL_CE_Enable(void); void NRF24_HAL_CE_Disable(void); @@ -14,4 +19,8 @@ HAL_StatusTypeDef NRF24_HAL_SPI_Receive(uint8_t *pData, uint16_t Size, uint32_t void NRF24_HAL_Delay(uint32_t milliseconds); uint32_t NRF24_HAL_GetTick(void); +#ifdef __cplusplus +} #endif + +#endif \ No newline at end of file From 8da62984dfd43b05bbc6a07fea786961ace0502a Mon Sep 17 00:00:00 2001 From: Pablo Belinaso Millani <74194360+millennium42@users.noreply.github.com> Date: Sun, 13 Jul 2025 13:42:02 -0300 Subject: [PATCH 2/3] Update README.md --- README.md | 242 ++++++++++++++++++++++++------------------------------ 1 file changed, 106 insertions(+), 136 deletions(-) diff --git a/README.md b/README.md index f83f7f4..a5feff6 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,15 @@ -# Biblioteca NRF24L01+ para STM32 com Sistema de Pacotes Customizado para `SSL` e `VSSS` +# Biblioteca NRF24L01+ para STM32 com Sistema de Pacotes Customizado para `SSL` e `VSSS` (Portado para C++) -Esta biblioteca fornece uma interface para comunicação sem fio utilizando o módulo NRF24L01+ com microcontroladores STM32, utilizando a camada HAL da ST. Inclui um sistema para gerenciamento de pacotes customizados, permitindo a transmissão de diferentes tipos de dados estruturados, como comandos para robôs VSSS e SSL. +Esta biblioteca fornece uma interface para comunicação sem fio utilizando o módulo NRF24L01+ com microcontroladores STM32, utilizando a camada HAL da ST. Inclui um sistema para gerenciamento de pacotes customizados, permitindo a transmissão de diferentes tipos de dados estruturados, como comandos para robôs VSSS e SSL. Esta versão foi portada da linguagem C para C++. ## Visão Geral A biblioteca é modularizada em: -* **Camada de Definições (`NRF24_DEF.h`):** Constantes, definições de pinos, registradores do NRF24L01+. -* **Camada de Abstração de Hardware (`NRF24_HAL.c/h`):** Funções de baixo nível para controle de pinos (CE, CSN) e comunicação SPI, utilizando as funções HAL do STM32. -* **Núcleo do Driver NRF24 (`NRF24_CORE.c/h`):** Lógica principal para operar o NRF24L01+, incluindo inicialização, configuração de modos (TX/RX), envio e recepção de dados. -* **Gerenciamento de Pacotes (`COMM_PACKETS.c/h`):** Definição de estruturas de pacotes, tipos de mensagens e funções auxiliares para criar e interpretar pacotes específicos para diferentes aplicações (ex: VSSS, SSL). +* **Camada de Definições (`NRF24_DEF.hpp`):** Constantes, definições de pinos, registradores do NRF24L01+. +* **Camada de Abstração de Hardware (`NRF24_HAL.cpp/hpp`):** Funções de baixo nível para controle de pinos (CE, CSN) e comunicação SPI, utilizando as funções HAL do STM32. +* **Núcleo do Driver NRF24 (`NRF24_CORE.cpp/hpp`):** Lógica principal para operar o NRF24L01+, incluindo inicialização, configuração de modos (TX/RX), envio e recepção de dados. +* **Gerenciamento de Pacotes (`COMM_PACKETS.cpp/hpp`):** Definição de estruturas de pacotes, tipos de mensagens e funções auxiliares para criar e interpretar pacotes específicos para diferentes aplicações (ex: VSSS, SSL). +* **Interface de Comunicação (`COMM.cpp/hpp`):** Camada de alto nível para inicialização e gerenciamento da comunicação, encapsulando as funcionalidades do NRF24 e dos pacotes. ## Pré-requisitos @@ -23,28 +24,30 @@ A biblioteca é modularizada em: ### Software * Ambiente de desenvolvimento STM32 (ex: STM32CubeIDE) * Bibliotecas STM32 HAL -* Compilador C (gnu11 ou similar) +* Compilador C++ (g++ ou similar) ## Estrutura de Arquivos da Biblioteca Assumindo que os arquivos da biblioteca estão em uma subpasta `Comm` dentro da pasta de includes e fontes do seu projeto (ex: `Core/Inc/Comm/`): -* `Core/Inc/Comm/NRF24_DEF.h`: Definições de hardware, registradores e constantes do NRF24. -* `Core/Inc/Comm/NRF24_HAL.h`: Protótipos para a camada de abstração de hardware. -* `Core/Inc/Comm/NRF24_HAL.c`: Implementações da camada de abstração de hardware. -* `Core/Inc/Comm/NRF24_CORE.h`: Protótipos para o núcleo do driver NRF24. -* `Core/Inc/Comm/NRF24_CORE.c`: Implementações do núcleo do driver NRF24. -* `Core/Inc/Comm/COMM_PACKETS.h`: Definições de tipos de pacotes, subtipos e estruturas de payload. -* `Core/Inc/Comm/COMM_PACKETS.c`: Funções auxiliares para criar pacotes. +* `Core/Inc/Comm/NRF24_DEF.hpp`: Definições de hardware, registradores e constantes do NRF24. +* `Core/Inc/Comm/NRF24_HAL.hpp`: Protótipos para a camada de abstração de hardware. +* `Core/Inc/Comm/NRF24_HAL.cpp`: Implementações da camada de abstração de hardware. +* `Core/Inc/Comm/NRF24_CORE.hpp`: Protótipos para o núcleo do driver NRF24. +* `Core/Inc/Comm/NRF24_CORE.cpp`: Implementações do núcleo do driver NRF24. +* `Core/Inc/Comm/COMM_PACKETS.hpp`: Definições de tipos de pacotes, subtipos e estruturas de payload. +* `Core/Inc/Comm/COMM_PACKETS.cpp`: Funções auxiliares para criar pacotes. +* `Core/Inc/Comm/COMM.hpp`: Protótipos para a interface de comunicação de alto nível. +* `Core/Inc/Comm/COMM.cpp`: Implementações da interface de comunicação de alto nível. ## Configuração -### 1. Configuração de Pinos e SPI (`NRF24_DEF.h`) +### 1. Configuração de Pinos e SPI (`NRF24_DEF.hpp`) -Edite o arquivo `NRF24_DEF.h` para corresponder à sua configuração de hardware: +Edite o arquivo `NRF24_DEF.hpp` para corresponder à sua configuração de hardware: -```c -// NRF24_DEF.h +```cpp +// NRF24_DEF.hpp // Definições de pinos NRF24 - Adapte conforme sua placa #include "stm32f4xx_hal.h" @@ -55,13 +58,13 @@ Edite o arquivo `NRF24_DEF.h` para corresponder à sua configuração de hardwar #define NRF24_CSN_PORT GPIOB // Porta do pino CSN (ex: GPIOB) #define NRF24_CSN_PIN GPIO_PIN_0 // Pino CSN (ex: GPIO_PIN_0) -// Handle SPI (deve ser o mesmo definido e inicializado em main.c) +// Handle SPI (deve ser o mesmo definido e inicializado em main.cpp) extern SPI_HandleTypeDef hspi1; // Mude hspi1 se seu handle SPI for diferente #define NRF24_SPI &hspi1 ``` -Importante: Assegure-se de que os pinos CE_Pin e CSN_Pin configurados no CubeMX (e definidos em main.h) correspondem aos NRF24_CE_PIN e NRF24_CSN_PIN em NRF24_DEF.h para a respectiva porta. +Importante: Assegure-se de que os pinos CE_Pin e CSN_Pin configurados no CubeMX (e definidos em main.h) correspondem aos NRF24_CE_PIN e NRF24_CSN_PIN em NRF24_DEF.hpp para a respectiva porta. -### **2. Definição de Pacotes de Comunicação** (`COMM_PACKETS.h`) +### **2. Definição de Pacotes de Comunicação** (`COMM_PACKETS.hpp`) Este arquivo é crucial para definir a estrutura dos seus dados. @@ -71,9 +74,9 @@ Este arquivo é crucial para definir a estrutura dos seus dados. Crie enums como `vsss_command_subtype_t` e `ssl_command_subtype_t` para detalhar os comandos específicos dentro de cada tipo principal de pacote. -```c +```cpp -// Em COMM_PACKETS.h +// Em COMM_PACKETS.hpp typedef enum { VSSS_CMD_SUBTYPE_UNDEFINED = 0, VSSS_CMD_SET_MOTOR_SPEEDS, @@ -93,141 +96,91 @@ typedef enum { Define o cabeçalho comum (tipo principal, número de sequência). * `comm_packet_t`: A estrutura final do pacote de 32 bytes, com o cabeçalho e uma union para os diferentes payloads. -### **3. Seleção de Nó em `main.c` (DEPRECATED)** - -No topo do seu `main.c` (dentro de `/* USER CODE BEGIN 0 */`), defina qual modo o dispositivo operará: - -```c - -// Em main.c -// Defina UM dos dois para cada placa: -#define TRANSMITTER_NODE 1 -// #define RECEIVER_NODE 1 -``` - - -## Como Utilizar (`API`) (DEPRECATED) +## Como Utilizar (`API`) ### **1. Inclusão de Headers** -No seu `main.c` ou em outros arquivos que utilizarão a biblioteca: +No seu `main.cpp` ou em outros arquivos que utilizarão a biblioteca: -```c -#include "Comm/NRF24_CORE.h" -#include "Comm/COMM_PACKETS.h" +```cpp +#include "Comm/COMM.hpp" ``` ### **2. Inicialização do Módulo NRF24** -```c -// Em main.c, dentro de /* USER CODE BEGIN 2 */ -printf("Inicializando NRF24L01+...\r\n"); -NRF24_Init(); -``` +Agora, a inicialização é feita através da classe `Comm`: -### **3. Configuração do Modo de Operação** - -Também em /* USER CODE BEGIN 2 */, configure o modo conforme o nó: +```cpp +// Em main.cpp, dentro de /* USER CODE BEGIN 2 */ +printf("Inicializando NRF24L01+...\r\n"); -```c -// Variáveis de endereço e canal (definidas em /* USER CODE BEGIN 0 */) -// extern uint8_t nrf_tx_address[5]; -// extern uint8_t nrf_rx_pipe1_address[5]; -// extern uint8_t NRF_COM_CHANNEL; +// Instancie a classe Comm +Comm myComm; -#if defined(TRANSMITTER_NODE) && !defined(RECEIVER_NODE) - printf("Configurado como TRANSMISSOR\r\n"); - NRF24_TxMode(nrf_tx_address, NRF_COM_CHANNEL); -#elif defined(RECEIVER_NODE) && !defined(TRANSMITTER_NODE) - printf("Configurado como RECEPTOR\r\n"); - NRF24_RxMode(nrf_rx_pipe1_address, nrf_rx_pipe2_lsb, NRF_COM_CHANNEL); // nrf_rx_pipe2_lsb é opcional -#endif +// Configure e inicialize a comunicação +// Os parâmetros são os mesmos da versão anterior, mas agora passados para o método Init +if (!myComm.Init(COMM_ROBOT_TYPE_SSL, + COMM_NODE_MODE_TRANSMITTER, + NRF_CHANNEL_MAIN, + NRF_TX_ADDRESS, + NRF_RX_P1_ADDRESS, + 0 )) { + printf("Falha ao inicializar módulo de comunicação!\r\n"); + Error_Handler(); +} +printf("Módulo COMM inicializado como Transmissor SSL.\r\n"); ``` +### **3. Trabalhando com Pacotes (`COMM_PACKETS.hpp` e `COMM_PACKETS.cpp`)** -### **4. Trabalhando com Pacotes (`COMM_PACKETS.h` e `COMM_PACKETS.c`)** - -As funções em COMM_PACKETS.c ajudam a criar pacotes formatados. +As funções em COMM_PACKETS.cpp ajudam a criar pacotes formatados. A criação de pacotes pode ser feita diretamente ou através dos métodos da classe `Comm`. * `Comm_Packets_Create_VSSSMessage(comm_packet_t* packet_buffer, uint8_t seq_num, const vsss_payload_t* vsss_payload_data);` * `Comm_Packets_Create_SSLMessage(comm_packet_t* packet_buffer, uint8_t seq_num, const ssl_payload_t* ssl_payload_data);` * `Comm_Packets_Create_DebugText(comm_packet_t* packet_buffer, uint8_t seq_num, const char* text_payload);` -### **5. Enviando Dados (Exemplo Transmissor) (DEPRECATED)** +### **4. Enviando Dados (Exemplo Transmissor)** No loop principal do transmissor (`/* USER CODE BEGIN 3 */`): -```c -// Em main.c (bloco TRANSMITTER_NODE) -static comm_packet_t nrf_packet_buffer; // Declarada global estática em PV -static uint8_t packet_seq_counter = 0; // Declarada global estática em PV - -ssl_payload_t ssl_command_data; // Ou vsss_payload_t +```cpp +// Em main.cpp (bloco TRANSMITTER_NODE) +ssl_payload_t ssl_command_data; // Preencher ssl_command_data ou vsss_data ssl_command_data.command_subtype = SSL_CMD_SET_VELOCITIES; ssl_command_data.robot_id = 1; -ssl_command_data.vx = 100; +ssl_command_data.vx = (int16_t)(100 + (local_packet_seq_counter % 10) * 5); // ... preencher o resto dos campos ... -// Criar o pacote completo -Comm_Packets_Create_SSLMessage(&nrf_packet_buffer, packet_seq_counter++, &ssl_command_data); - -// Transmitir -if (NRF24_Transmit((uint8_t *)&nrf_packet_buffer, sizeof(comm_packet_t))) { - printf("Pacote SSL enviado! Seq: %d\r\n", nrf_packet_buffer.header.seq_number); - HAL_GPIO_TogglePin(LED_DEBUG_GPIO_Port, LED_DEBUG_Pin); +// Transmitir usando o método da instância Comm +if (myComm.Send_SSL_Message(&ssl_command_data)) { + printf("Main: Pacote SSL (ID:%d, Vx:%d) enviado.\r\n", + ssl_command_data.robot_id, ssl_command_data.vx); + HAL_GPIO_TogglePin(LED_DEBUG_GPIO_Port, LED_DEBUG_Pin); } else { - printf("Falha ao enviar pacote SSL.\r\n"); + printf("Main: Falha ao enviar pacote SSL pela camada Comm.\r\n"); } HAL_Delay(100); // Intervalo entre envios ``` -### **6. Recebendo Dados (Exemplo Receptor) (DEPRECATED)** +### **5. Recebendo Dados (Exemplo Receptor)** No loop principal do receptor (`/* USER CODE BEGIN 3 */`): -```c - -// Em main.c (bloco RECEIVER_NODE) -static comm_packet_t nrf_packet_buffer; // Declarada global estática em PV -uint8_t raw_nrf_input_buffer[NRF_MAX_PACKET_SIZE]; - -if (isDataAvailable(1)) { // Verifica dados no Pipe 1 - NRF24_Receive(raw_nrf_input_buffer); // Lê 32 bytes brutos - - // Copia para a estrutura de pacote para facilitar o acesso - memcpy(&nrf_packet_buffer, raw_nrf_input_buffer, sizeof(comm_packet_t)); - - HAL_GPIO_TogglePin(LED_DEBUG_GPIO_Port, LED_DEBUG_Pin); // Feedback visual - printf("Pacote Recebido! Tipo: %d, Seq: %d\r\n", - nrf_packet_buffer.header.main_type, - nrf_packet_buffer.header.seq_number); - - switch (nrf_packet_buffer.header.main_type) { - case MAIN_PACKET_TYPE_SSL_MESSAGE: - { - ssl_payload_t* ssl_data = &nrf_packet_buffer.payload_u.ssl_msg; - printf(" SSL: ID=%d, Subtipo=%d, Vx=%d\r\n", - ssl_data->robot_id, ssl_data->command_subtype, ssl_data->vx); - // Processar dados SSL ... - break; - } - case MAIN_PACKET_TYPE_VSSS_MESSAGE: - { - vsss_payload_t* vsss_data = &nrf_packet_buffer.payload_u.vsss_msg; - printf(" VSSS: ID=%d, Subtipo=%d, M1=%d\r\n", - vsss_data->robot_id, vsss_data->command_subtype, vsss_data->motor1_value); - // Processar dados VSSS ... - break; - } - // Outros cases ... - default: - printf(" Tipo de pacote desconhecido: %d\r\n", nrf_packet_buffer.header.main_type); - break; - } -} -HAL_Delay(10); +```cpp + +// Em main.cpp (bloco RECEIVER_NODE) +// As funções de callback agora são registradas na instância da classe Comm + +// Exemplo de registro de callbacks (deve ser feito após a inicialização da Comm) +myComm.Register_SSL_Packet_Handler(App_HandleSSLData); +myComm.Register_VSSS_Packet_Handler(App_HandleVSSSData); +myComm.Register_DebugText_Packet_Handler(App_HandleDebugText); + +// Processar pacotes recebidos no loop principal +myComm.ProcessReceivedPackets(); +HAL_Delay(1); ``` ### STM32 @@ -237,10 +190,10 @@ HAL_Delay(10); ## Exemplo no Robô `SSL` -### Transmissor (DEPRECATED): -```c +### Transmissor: +```cpp -#include "comm/COMM.h" +#include "comm/COMM.hpp" uint8_t NRF_TX_ADDRESS[5] = {0xE7, 0xE7, 0xE7, 0xE7, 0xE7}; // Endereço de transmissão uint8_t NRF_RX_P1_ADDRESS[5] = {0xE7, 0xE7, 0xE7, 0xE7, 0xE7}; // Endereço do Pipe 0 para ACKs no transmissor @@ -265,7 +218,8 @@ int main(void) { printf("\r\n-- Transmissor NRF24 com Camada COMM --\r\n"); - if (!Comm_Init(COMM_ROBOT_TYPE_SSL, + Comm myComm; // Instancia a classe Comm + if (!myComm.Init(COMM_ROBOT_TYPE_SSL, COMM_NODE_MODE_TRANSMITTER, NRF_CHANNEL_MAIN, NRF_TX_ADDRESS, @@ -298,7 +252,7 @@ int main(void) ssl_command_data.critical_move_turbo = 0; - if (Comm_Send_SSL_Message(&ssl_command_data)) { + if (myComm.Send_SSL_Message(&ssl_command_data)) { // Usa o método da instância printf("Main: Pacote SSL (ID:%d, Vx:%d) enviado.\r\n", ssl_command_data.robot_id, ssl_command_data.vx); HAL_GPIO_TogglePin(LED_DEBUG_GPIO_Port, LED_DEBUG_Pin); @@ -310,9 +264,9 @@ int main(void) } } ``` -### Receptor (DEPRECATED): -```c -#include "Comm/COMM.h" +### Receptor: +```cpp +#include "Comm/COMM.hpp" uint8_t NRF_RECEIVER_TX_ADDRESS_FOR_ACKS[5] = {0xD7, 0xD7, 0xD7, 0xD7, 0xD7}; uint8_t NRF_RECEIVER_RX_P1_ADDRESS[5] = {0xE7, 0xE7, 0xE7, 0xE7, 0xE7}; @@ -331,6 +285,7 @@ PUTCHAR_PROTOTYPE return ch; } +// Funções de callback (podem ser métodos estáticos ou funções globais) void App_HandleSSLData(const ssl_payload_t* ssl_data, uint8_t robot_id, uint8_t seq_num); void App_HandleVSSSData(const vsss_payload_t* vsss_data, uint8_t robot_id, uint8_t seq_num); void App_HandleDebugText(const char* text_data, uint8_t seq_num); @@ -366,7 +321,7 @@ void App_HandleVSSSData(const vsss_payload_t* vsss_data, uint8_t robot_id, uint8 } void App_HandleDebugText(const char* text_data, uint8_t seq_num) { - printf("CALLBACK DEBUG: Seq=%d -> Texto='%s'\r\n", seq_num, text_data); + printf("CALLBACK DEBUG: Seq=%d -> Texto=\'%s\'\r\n", seq_num, text_data); HAL_GPIO_TogglePin(LED_DEBUG_GPIO_Port, LED_DEBUG_Pin); // Pisca LED ao processar } @@ -376,7 +331,8 @@ int main(void) printf("\r\n-- Receptor NRF24 com Camada COMM --\r\n"); - if (!Comm_Init(COMM_ROBOT_TYPE_UNDEFINED, // Este nó é um receptor genérico ou específico + Comm myComm; // Instancia a classe Comm + if (!myComm.Init(COMM_ROBOT_TYPE_UNDEFINED, // Este nó é um receptor genérico ou específico COMM_NODE_MODE_RECEIVER, NRF_COMMON_CHANNEL, NRF_RECEIVER_TX_ADDRESS_FOR_ACKS, // Endereço que o NRF usaria para enviar ACKs (Pipe0) @@ -386,16 +342,30 @@ int main(void) Error_Handler(); } - Comm_Register_SSL_Packet_Handler(App_HandleSSLData); - Comm_Register_VSSS_Packet_Handler(App_HandleVSSSData); - Comm_Register_DebugText_Packet_Handler(App_HandleDebugText); + myComm.Register_SSL_Packet_Handler(App_HandleSSLData); + myComm.Register_VSSS_Packet_Handler(App_HandleVSSSData); + myComm.Register_DebugText_Packet_Handler(App_HandleDebugText); printf("Módulo COMM inicializado como Receptor. Aguardando pacotes...\r\n"); while (1) { - Comm_ProcessReceivedPackets(); + myComm.ProcessReceivedPackets(); // Usa o método da instância HAL_Delay(1); } } ``` + +## Mudanças Realizadas + +As principais mudanças realizadas nesta versão da biblioteca, em comparação com a versão original em C (`CommAntiga`), são: + +1. **Portabilidade para C++**: Todos os arquivos de código-fonte (`.c`) foram convertidos para C++ (`.cpp`) e os arquivos de cabeçalho (`.h`) para `.hpp`. +2. **Orientação a Objetos**: A funcionalidade principal da comunicação, anteriormente exposta como funções globais em C, foi encapsulada em uma classe `Comm` (definida em `COMM.hpp` e implementada em `COMM.cpp`). Isso melhora a modularidade, reusabilidade e organização do código. +3. **Inicialização da Comunicação**: A função `Comm_Init` agora é um método da classe `Comm` (ex: `myComm.Init(...)`). +4. **Envio de Pacotes**: As funções de envio de pacotes (ex: `Comm_Send_SSL_Message`) agora são métodos da classe `Comm` (ex: `myComm.Send_SSL_Message(...)`). +5. **Processamento de Pacotes Recebidos**: A função `Comm_ProcessReceivedPackets` agora é um método da classe `Comm` (ex: `myComm.ProcessReceivedPackets()`). +6. **Registro de Callbacks**: As funções para registrar callbacks (ex: `Comm_Register_SSL_Packet_Handler`) agora são métodos da classe `Comm` (ex: `myComm.Register_SSL_Packet_Handler(...)`). +7. **Remoção de Seções Depreciadas**: As seções marcadas como `(DEPRECATED)` na versão anterior do README, que se referiam a uma API C mais antiga ou a métodos de uso menos recomendados, foram removidas ou atualizadas para refletir a nova abordagem orientada a objetos em C++. + +Essas mudanças visam modernizar a base de código, aproveitando os recursos da programação orientada a objetos em C++ para uma API mais limpa e um design mais robusto. From 30b4824e1ab3b1cdff02f03aa1ed823facbfd531 Mon Sep 17 00:00:00 2001 From: millennium42 Date: Sun, 13 Jul 2025 14:38:43 -0300 Subject: [PATCH 3/3] =?UTF-8?q?feat:=20Refatora=C3=A7=C3=A3o=20da=20biblio?= =?UTF-8?q?teca=20para=20suporte=20Multi-NRF24L01+?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Esta atualização introduz uma nova arquitetura para a biblioteca de comunicação, permitindo o gerenciamento de múltiplos módulos NRF24L01+ por STM32. Principais alterações: - **NRF24_HAL**: Convertido para a classe `NRF24_Hardware` para encapsular a configuração de hardware de cada NRF (SPI, pinos CE/CSN). - **NRF24_CORE**: Convertido para a classe `NRF24_Driver` para gerenciar as operações de um NRF individual usando a nova `NRF24_Hardware`. - **COMM**: Convertido para a classe `CommManager` (ou `Comm`) para orquestrar a comunicação multi-NRF (gerenciando múltiplos `NRF24_Driver` para RX e TX). - **NRF24_DEF**: Atualizado para refletir que as definições de pinos agora são passadas para as classes. - **Exemplos (RECEIVER/TRANSMITTER)**: Adaptados para utilizar a nova classe `CommManager` e suportar a topologia multi-NRF (robôs com 2 NRFs, torre com 6 NRFs). --- COMM.cpp | 373 +++++++++++++++++++++++++++++---------------- COMM.hpp | 194 ++++++++++++++---------- NRF24_CORE.cpp | 400 +++++++++++++++++++++++++++---------------------- NRF24_CORE.hpp | 314 ++++++++++++++++++++++++++++++++++---- NRF24_DEF.hpp | 285 ++++++++++++++++++++++++++--------- NRF24_HAL.cpp | 74 ++++++--- NRF24_HAL.hpp | 114 +++++++++++--- 7 files changed, 1226 insertions(+), 528 deletions(-) diff --git a/COMM.cpp b/COMM.cpp index a55ce75..25d1e07 100644 --- a/COMM.cpp +++ b/COMM.cpp @@ -1,160 +1,269 @@ -// Comm/COMM.cpp -#include // Atualizado caminho de inclusão -#include // Atualizado caminho de inclusão -#include // Atualizado caminho de inclusão -#include -#include - - -static comm_robot_type_t s_current_robot_type; -static comm_node_mode_t s_current_node_mode; -static uint8_t s_packet_seq_counter = 0; -static comm_packet_t s_comm_packet_buffer; - - -static comm_ssl_packet_handler_t s_ssl_handler = nullptr; // Opcional: usar nullptr -static comm_vsss_packet_handler_t s_vsss_handler = nullptr; // Opcional: usar nullptr -static comm_debug_text_handler_t s_debug_text_handler = nullptr; // Opcional: usar nullptr - - -bool Comm_Init(comm_robot_type_t robot_type, - comm_node_mode_t node_mode, - uint8_t channel, - uint8_t* nrf_tx_address, - uint8_t* nrf_rx_pipe1_address, - uint8_t nrf_rx_pipe2_lsb) +#include "COMM.hpp" // Inclui o novo cabeçalho da classe CommManager +#include "NRF24_CORE.hpp" // Inclui a nova classe NRF24_Driver (anteriormente NRF24_CORE) +#include "COMM_PACKETS.hpp" // Permanece inalterado, define as estruturas de pacotes + +// Definições de endereços para NRF24L01+ +// Estes endereços são exemplos e devem ser únicos para cada robô/torre +// e para os pipes de comunicação. +// Alterado: Movido de variáveis estáticas globais para constantes globais visíveis neste arquivo. +const uint8_t ADDR_BASE_LISTEN[5] = {0xB1, 0xB2, 0xB3, 0xB4, 0xB5}; // Endereço de escuta comum para a torre +const uint8_t ADDR_ROBOT_LISTEN[MAX_ROBOTS][5] = { // Endereços de escuta específicos para cada robô (RX do robô, TX da torre) + {0xA1, 0xA2, 0xA3, 0xA4, 0xA5}, // Robô 1 + {0xC1, 0xC2, 0xC3, 0xC4, 0xC5}, // Robô 2 + {0xD1, 0xD2, 0xD3, 0xD4, 0xD5}, // Robô 3 + {0xE1, 0xE2, 0xE3, 0xE4, 0xE5}, // Robô 4 + {0xF1, 0xF2, 0xF3, 0xF4, 0xF5} // Robô 5 +}; + +// --- Início da Implementação da Classe CommManager --- +// A classe CommManager encapsula toda a lógica de comunicação de alto nível. +// Ela substitui as funções C globais e variáveis estáticas da versão anterior, +// fornecendo uma interface orientada a objetos para gerenciar múltiplos NRFs. + +// Construtor: Inicializa os membros da classe. +// Alterado: Agora é um construtor de classe, inicializando ponteiros NRF para nulos e callbacks. +CommManager::CommManager() : + current_robot_type(COMM_ROBOT_TYPE_NONE), // Inicializa o tipo de robô como 'nenhum' + current_node_mode(COMM_NODE_MODE_NONE), // Inicializa o modo do nó como 'nenhum' + packet_seq_counter(0), // Contador de sequência de pacotes + ssl_handler(nullptr), // Handlers de callback inicializados como nulos + vsss_handler(nullptr), + debug_text_handler(nullptr), + rx_nrf(nullptr), // Ponteiros para NRF_Driver inicializados como nulos + tx_nrf(nullptr), + telemetry_rx_nrf(nullptr) { - s_current_robot_type = robot_type; - s_current_node_mode = node_mode; - s_packet_seq_counter = 0; - - printf("Comm_Init: Modo %s, Robô %s, Canal %d\r\n", - (node_mode == COMM_NODE_MODE_TRANSMITTER) ? "TX" : "RX", - (robot_type == COMM_ROBOT_TYPE_SSL) ? "SSL" : (robot_type == COMM_ROBOT_TYPE_VSSS) ? "VSSS" : "N/A", - channel); + // Inicializa o array de ponteiros command_tx_nrf para nullptr + for (int i = 0; i < MAX_ROBOTS; ++i) { + command_tx_nrf[i] = nullptr; + } +} - NRF24_Init(); +// Destrutor: Libera a memória alocada dinamicamente para as instâncias de NRF24_Driver. +// Adicionado: Essencial para gerenciar a memória quando se usa 'new'. +CommManager::~CommManager() { + if (rx_nrf) delete rx_nrf; + if (tx_nrf) delete tx_nrf; + if (telemetry_rx_nrf) delete telemetry_rx_nrf; + for (int i = 0; i < MAX_ROBOTS; ++i) { + if (command_tx_nrf[i]) delete command_tx_nrf[i]; + } +} - if (s_current_node_mode == COMM_NODE_MODE_TRANSMITTER) { - NRF24_TxMode(nrf_tx_address, channel); - printf("NRF24 configurado como Transmissor.\r\n"); +// O método Init configura a CommManager para operar como Torre ou Robô, +// inicializando os módulos NRF24_Driver com as configurações de hardware e endereços apropriados. +// Alterado: Substitui a função global Comm_Init. Recebe configurações de hardware para todos os NRFs. +bool CommManager::Init( + comm_robot_type_t robot_type, + comm_node_mode_t node_mode, + const NRF24_Hardware_Config& nrf_config_main_rx, // Config para o NRF RX principal (Robô: RX, Torre: Telemetria RX) + const NRF24_Hardware_Config& nrf_config_main_tx, // Config para o NRF TX principal (Robô: TX) + const NRF24_Hardware_Config command_tx_configs[MAX_ROBOTS], // Array de configs para NRFs TX de comando (Torre) + uint8_t robot_id // ID do robô (1-5) se for um robô, 0 se for a torre +) { + current_robot_type = robot_type; + current_node_mode = node_mode; + + // Dependendo do modo (Torre/Robô), instanciar e configurar os NRFs apropriados + if (current_node_mode == COMM_NODE_MODE_RECEIVER) { // Modo Robô + if (robot_id == 0 || robot_id > MAX_ROBOTS) return false; // ID do robô inválido + + // NRF de Recepção (RX) de Comandos: escuta no seu próprio endereço de robô + // Instancia NRF24_Hardware para o RX do robô com base na config fornecida + NRF24_Hardware rx_hw( + nrf_config_main_rx.hspi, + nrf_config_main_rx.ce_port, nrf_config_main_rx.ce_pin, + nrf_config_main_rx.csn_port, nrf_config_main_rx.csn_pin, + nrf_config_main_rx.spi_timeout_ms + ); + rx_nrf = new NRF24_Driver(rx_hw); // Cria uma nova instância do driver NRF para RX + // Inicializa em modo RX com o endereço do robô (ADDR_ROBOT_LISTEN) + // O segundo parâmetro é o endereço de TX do pipe 0, usado para ACKs. + // O terceiro parâmetro é o endereço de TX padrão para quando o NRF está em modo RX + // e responde com um pacote (não utilizado para RX). + if (!rx_nrf->Init(NRF_RX_MODE, ADDR_ROBOT_LISTEN[robot_id - 1], ADDR_BASE_LISTEN, NRF24_RF_CHANNEL)) return false; + if (!rx_nrf->RxMode()) return false; // Coloca o NRF em modo de escuta + + // NRF de Transmissão (TX) de Telemetria: transmite para o endereço base da torre + // Instancia NRF24_Hardware para o TX do robô com base na config fornecida + NRF24_Hardware tx_hw( + nrf_config_main_tx.hspi, + nrf_config_main_tx.ce_port, nrf_config_main_tx.ce_pin, + nrf_config_main_tx.csn_port, nrf_config_main_tx.csn_pin, + nrf_config_main_tx.spi_timeout_ms + ); + tx_nrf = new NRF24_Driver(tx_hw); // Cria uma nova instância do driver NRF para TX + // Inicializa em modo TX com o endereço base da torre como endereço de TX (Pipe 0) + // O segundo parâmetro é o endereço de escuta do próprio NRF em modo TX (não usado). + // O terceiro parâmetro é o endereço de TX para o Pipe 0. + if (!tx_nrf->Init(NRF_TX_MODE, ADDR_BASE_LISTEN, ADDR_BASE_LISTEN, NRF24_RF_CHANNEL)) return false; + if (!tx_nrf->TxMode()) return false; // Coloca o NRF em modo de transmissão + + } else if (current_node_mode == COMM_NODE_MODE_TRANSMITTER) { // Modo Torre + // NRF de Recepção (RX) de Telemetria: escuta em múltiplos pipes para todos os robôs + // Instancia NRF24_Hardware para o RX de telemetria da torre + NRF24_Hardware telemetry_rx_hw( + nrf_config_main_rx.hspi, + nrf_config_main_rx.ce_port, nrf_config_main_rx.ce_pin, + nrf_config_main_rx.csn_port, nrf_config_main_rx.csn_pin, + nrf_config_main_rx.spi_timeout_ms + ); + telemetry_rx_nrf = new NRF24_Driver(telemetry_rx_hw); // Instância para o NRF de RX de telemetria + + // Inicializa o NRF de telemetria para escutar no endereço base da torre (Pipe 0). + // Este é o endereço que os robôs irão transmitir. + if (!telemetry_rx_nrf->Init(NRF_RX_MODE, ADDR_BASE_LISTEN, ADDR_BASE_LISTEN, NRF24_RF_CHANNEL)) return false; + + // Configura pipes adicionais para escutar a telemetria de cada robô. + // A torre deve ouvir no endereço de transmissão de cada robô para receber ACKs e dados diretos. + // Pipe 1 ao Pipe 5 para os 5 robôs. + // Alterado: Adiciona a configuração dos pipes de leitura para cada robô. + for (int i = 0; i < MAX_ROBOTS; ++i) { + if (!telemetry_rx_nrf->OpenReadingPipe(i + 1, ADDR_ROBOT_LISTEN[i])) return false; // Pipe i+1 escuta no endereço do robô i + } + if (!telemetry_rx_nrf->RxMode()) return false; // Coloca o NRF em modo de escuta + + + // NRFs de Transmissão (TX) de Comandos: um NRF por robô, transmite para o endereço do robô específico + // Alterado: Cria e inicializa um array de NRF24_Driver para cada robô. + for (int i = 0; i < MAX_ROBOTS; ++i) { + NRF24_Hardware command_tx_hw( + command_tx_configs[i].hspi, + command_tx_configs[i].ce_port, command_tx_configs[i].ce_pin, + command_tx_configs[i].csn_port, command_tx_configs[i].csn_pin, + command_tx_configs[i].spi_timeout_ms + ); + command_tx_nrf[i] = new NRF24_Driver(command_tx_hw); // Cria uma instância para cada NRF de TX + + // Inicializa cada NRF de comando para transmitir para o endereço de escuta do robô correspondente + if (!command_tx_nrf[i]->Init(NRF_TX_MODE, ADDR_ROBOT_LISTEN[i], ADDR_ROBOT_LISTEN[i], NRF24_RF_CHANNEL)) return false; + if (!command_tx_nrf[i]->TxMode()) return false; // Coloca em modo de transmissão + } } else { - NRF24_RxMode(nrf_rx_pipe1_address, nrf_rx_pipe2_lsb, channel); - printf("NRF24 configurado como Receptor.\r\n"); + return false; // Modo desconhecido } + + // O canal de RF é configurado individualmente para cada NRF_Driver durante sua inicialização, + // garantindo consistência através de todos os módulos NRF. + return true; } - -bool Comm_Send_SSL_Message(const ssl_payload_t* ssl_payload_data) { - if (s_current_node_mode != COMM_NODE_MODE_TRANSMITTER) { - printf("Comm_Send_SSL_Message: Erro - Nó não está em modo transmissor.\r\n"); - return false; +// O método Loop() é responsável por processar os pacotes de comunicação. +// Deve ser chamado repetidamente no loop principal da aplicação. +// Alterado: Substitui a função global Comm_Loop. Gerencia a leitura de pacotes +// de múltiplos NRFs dependendo do modo do nó. +void CommManager::Loop() { + comm_packet_t received_packet; // Buffer para o pacote recebido + uint8_t pipe_num; // Número do pipe de onde o pacote foi recebido + + // Lógica para Robô (Receiver) + if (current_node_mode == COMM_NODE_MODE_RECEIVER && rx_nrf != nullptr) { + if (rx_nrf->IsPacketAvailable(&pipe_num)) { // Verifica se há pacote disponível no NRF de RX do robô + if (rx_nrf->ReadPacket((uint8_t*)&received_packet, sizeof(comm_packet_t))) { // Lê o pacote + // Dispara o callback apropriado com base no tipo de pacote + if (received_packet.type == NRF_MAIN_PACKET_TYPE_SSL_COMMAND && ssl_handler) { + ssl_handler(current_robot_type, received_packet.payload.ssl_payload); + } else if (received_packet.type == NRF_MAIN_PACKET_TYPE_VSSS_COMMAND && vsss_handler) { + vsss_handler(current_robot_type, received_packet.payload.vsss_payload); + } else if (received_packet.type == NRF_MAIN_PACKET_TYPE_DEBUG_TEXT && debug_text_handler) { + debug_text_handler(current_robot_type, received_packet.payload.debug_text_payload.text); + } + } + } } - if (ssl_payload_data == nullptr) { // Alterado de NULL para nullptr - printf("Comm_Send_SSL_Message: Erro - Payload SSL nulo.\r\n"); - return false; + // Lógica para Torre (Transmitter) + else if (current_node_mode == COMM_NODE_MODE_TRANSMITTER && telemetry_rx_nrf != nullptr) { + if (telemetry_rx_nrf->IsPacketAvailable(&pipe_num)) { // Verifica se há telemetria disponível no NRF de RX da torre + if (telemetry_rx_nrf->ReadPacket((uint8_t*)&received_packet, sizeof(comm_packet_t))) { // Lê o pacote + // A telemetria deve conter o ID do robô no payload para identificação. + // O pipe_num também pode indicar a origem (pipe 1 para robô 1, etc.). + // Alterado: O callback para telemetria na torre precisa ser capaz de identificar o robô de origem. + // Aqui, o ssl_handler (que era para comandos) está sendo reutilizado, mas para telemetria SSL. + // Pode ser necessário criar um novo tipo de callback para telemetria que inclua o ID do robô. + if (received_packet.type == NRF_MAIN_PACKET_TYPE_SSL_TELEMETRY && ssl_handler) { + // Nota: 'current_robot_type' aqui se refere ao tipo da Torre (ex: COMM_ROBOT_TYPE_SSL), + // não ao tipo do robô que enviou. O ID do robô de origem pode ser extraído de `received_packet.payload.ssl_telemetry_payload.robot_id`. + ssl_handler(current_robot_type, received_packet.payload.ssl_telemetry_payload); + } + else if (received_packet.type == NRF_MAIN_PACKET_TYPE_DEBUG_TEXT && debug_text_handler) { + debug_text_handler(current_robot_type, received_packet.payload.debug_text_payload.text); + } + } + } } - - Comm_Packets_Create_SSLMessage(&s_comm_packet_buffer, s_packet_seq_counter++, ssl_payload_data); - - //printf("Comm Enviando SSL: Seq %d, ID %d, Vx %d\r\n", s_comm_packet_buffer.header.seq_number, ssl_payload_data->robot_id, ssl_payload_data->vx); - return NRF24_Transmit((uint8_t*)&s_comm_packet_buffer, sizeof(comm_packet_t)); } -bool Comm_Send_VSSS_Message(const vsss_payload_t* vsss_payload_data) { - if (s_current_node_mode != COMM_NODE_MODE_TRANSMITTER) { - printf("Comm_Send_VSSS_Message: Erro - Nó não está em modo transmissor.\r\n"); - return false; +// Métodos para envio de mensagens (comandos da torre, telemetria do robô) +// Alterado: Substituem as funções globais Comm_Send_*. Agora são métodos da classe. +// Incluem lógica para selecionar o NRF_Driver correto com base no modo e no target_robot_id. + +bool CommManager::Send_VSSS_Message(uint8_t target_robot_id, const vsss_payload_t* vsss_payload_data) { + // Se for robô, usa seu NRF de TX (target_robot_id é ignorado aqui, pois robô só envia sua própria telemetria ou debug) + if (current_node_mode == COMM_NODE_MODE_RECEIVER && tx_nrf != nullptr) { + Comm_Packets_Create_VSSSMessage(packet_seq_counter++, vsss_payload_data, &comm_packet_buffer); + return tx_nrf->Transmit((uint8_t*)&comm_packet_buffer, sizeof(comm_packet_t)); } - if (vsss_payload_data == nullptr) { // Alterado de NULL para nullptr - printf("Comm_Send_VSSS_Message: Erro - Payload VSSS nulo.\r\n"); - return false; + // Se for torre, usa o NRF TX específico do robô alvo. + else if (current_node_mode == COMM_NODE_MODE_TRANSMITTER && target_robot_id > 0 && target_robot_id <= MAX_ROBOTS && command_tx_nrf[target_robot_id - 1] != nullptr) { + Comm_Packets_Create_VSSSMessage(packet_seq_counter++, vsss_payload_data, &comm_packet_buffer); + return command_tx_nrf[target_robot_id - 1]->Transmit((uint8_t*)&comm_packet_buffer, sizeof(comm_packet_t)); } - - Comm_Packets_Create_VSSSMessage(&s_comm_packet_buffer, s_packet_seq_counter++, vsss_payload_data); - - // printf("Comm Enviando VSSS: Seq %d, ID %d, M1 %d\r\n", s_comm_packet_buffer.header.seq_number, vsss_payload_data->robot_id, vsss_payload_data->motor1_value); - return NRF24_Transmit((uint8_t*)&s_comm_packet_buffer, sizeof(comm_packet_t)); + return false; } -bool Comm_Send_DebugText_Message(const char* text_payload) { - if (s_current_node_mode != COMM_NODE_MODE_TRANSMITTER) { - printf("Comm_Send_DebugText_Message: Erro - Nó não está em modo transmissor.\r\n"); - return false; +bool CommManager::Send_SSL_Message(uint8_t target_robot_id, const ssl_payload_t* ssl_payload_data) { + // Se for robô, usa seu NRF de TX + if (current_node_mode == COMM_NODE_MODE_RECEIVER && tx_nrf != nullptr) { + Comm_Packets_Create_SSLMessage(packet_seq_counter++, ssl_payload_data, &comm_packet_buffer); + return tx_nrf->Transmit((uint8_t*)&comm_packet_buffer, sizeof(comm_packet_t)); } - if (text_payload == nullptr) { // Alterado de NULL para nullptr - printf("Comm_Send_DebugText_Message: Erro - Texto nulo.\r\n"); - return false; + // Se for torre, usa o NRF TX específico do robô alvo. + else if (current_node_mode == COMM_NODE_MODE_TRANSMITTER && target_robot_id > 0 && target_robot_id <= MAX_ROBOTS && command_tx_nrf[target_robot_id - 1] != nullptr) { + Comm_Packets_Create_SSLMessage(packet_seq_counter++, ssl_payload_data, &comm_packet_buffer); + return command_tx_nrf[target_robot_id - 1]->Transmit((uint8_t*)&comm_packet_buffer, sizeof(comm_packet_t)); } - - Comm_Packets_Create_DebugText(&s_comm_packet_buffer, s_packet_seq_counter++, text_payload); - - // printf("Comm Enviando Debug: Seq %d, Texto: %s\r\n", s_comm_packet_buffer.header.seq_number, text_payload); - return NRF24_Transmit((uint8_t*)&s_comm_packet_buffer, sizeof(comm_packet_t)); + return false; } - - -void Comm_Register_SSL_Packet_Handler(comm_ssl_packet_handler_t callback) { - s_ssl_handler = callback; +// Método de envio de telemetria SSL (geralmente usado pelo Robô) +// Alterado: Novo método, específico para telemetria SSL, transmitido pelo NRF TX do robô. +bool CommManager::Send_SSL_Telemetry(uint8_t target_robot_id, const ssl_telemetry_payload_t* telemetry_payload_data) { + // A telemetria é sempre enviada pelo robô para a torre. + // O target_robot_id neste contexto é o ID do robô que está enviando a telemetria, + // garantindo que a telemetria contém essa informação. + // O NRF_TX_MODE do robô já está configurado para transmitir para o endereço da torre. + if (current_node_mode == COMM_NODE_MODE_RECEIVER && tx_nrf != nullptr) { + Comm_Packets_Create_SSLTelemetryMessage(packet_seq_counter++, telemetry_payload_data, &comm_packet_buffer); + return tx_nrf->Transmit((uint8_t*)&comm_packet_buffer, sizeof(comm_packet_t)); + } + return false; // A torre não envia telemetria SSL (ela recebe) } -void Comm_Register_VSSS_Packet_Handler(comm_vsss_packet_handler_t callback) { - s_vsss_handler = callback; +bool CommManager::Send_DebugText_Message(uint8_t target_robot_id, const char* text_payload) { + // Se for robô, usa seu NRF de TX + if (current_node_mode == COMM_NODE_MODE_RECEIVER && tx_nrf != nullptr) { + Comm_Packets_Create_DebugTextMessage(packet_seq_counter++, text_payload, &comm_packet_buffer); + return tx_nrf->Transmit((uint8_t*)&comm_packet_buffer, sizeof(comm_packet_t)); + } + // Se for torre, usa o NRF TX específico do robô alvo. + else if (current_node_mode == COMM_NODE_MODE_TRANSMITTER && target_robot_id > 0 && target_robot_id <= MAX_ROBOTS && command_tx_nrf[target_robot_id - 1] != nullptr) { + Comm_Packets_Create_DebugTextMessage(packet_seq_counter++, text_payload, &comm_packet_buffer); + return command_tx_nrf[target_robot_id - 1]->Transmit((uint8_t*)&comm_packet_buffer, sizeof(comm_packet_t)); + } + return false; } -void Comm_Register_DebugText_Packet_Handler(comm_debug_text_handler_t callback) { - s_debug_text_handler = callback; +// Métodos para registrar os callbacks de tratamento de pacotes. +// Alterado: Substituem as funções globais Set*Callback. Agora são métodos da classe. +void CommManager::SetSSLCallback(comm_ssl_packet_handler_t handler) { + ssl_handler = handler; // Atribui o handler fornecido ao membro da classe } -void Comm_ProcessReceivedPackets(void) { - if (s_current_node_mode != COMM_NODE_MODE_RECEIVER) { - return; - } - - uint8_t raw_input_buffer[NRF_MAX_PACKET_SIZE]; - - if (isDataAvailable(1)) { // Verifica Pipe 1 (poderia ser configurável ou verificar múltiplos pipes) - NRF24_Receive(raw_input_buffer); - - memcpy(&s_comm_packet_buffer, raw_input_buffer, sizeof(comm_packet_t)); - - // HAL_GPIO_TogglePin(LED_DEBUG_GPIO_Port, LED_DEBUG_Pin); // Feedback visual pode ir para o main ou callback - - // printf("Comm Pacote Recebido! Tipo: %d, Seq: %d\r\n", - // s_comm_packet_buffer.header.main_type, - // s_comm_packet_buffer.header.seq_number); - - switch (s_comm_packet_buffer.header.main_type) { - case MAIN_PACKET_TYPE_SSL_MESSAGE: - if (s_ssl_handler != nullptr) { // Alterado de NULL para nullptr - s_ssl_handler(&s_comm_packet_buffer.payload_u.ssl_msg, - s_comm_packet_buffer.payload_u.ssl_msg.robot_id, // Passando o ID do payload - s_comm_packet_buffer.header.seq_number); - } - break; - - case MAIN_PACKET_TYPE_VSSS_MESSAGE: - if (s_vsss_handler != nullptr) { // Alterado de NULL para nullptr - s_vsss_handler(&s_comm_packet_buffer.payload_u.vsss_msg, - s_comm_packet_buffer.payload_u.vsss_msg.robot_id, // Passando o ID do payload - s_comm_packet_buffer.header.seq_number); - } - break; - - case MAIN_PACKET_TYPE_DEBUG_TEXT: - if (s_debug_text_handler != nullptr) { // Alterado de NULL para nullptr - char temp_text[DEBUG_TEXT_MAX_LEN + 1]; - memcpy(temp_text, s_comm_packet_buffer.payload_u.debug_text.text, DEBUG_TEXT_MAX_LEN); - temp_text[DEBUG_TEXT_MAX_LEN] = '\0'; - s_debug_text_handler(temp_text, s_comm_packet_buffer.header.seq_number); - } - break; +void CommManager::SetVSSSCallback(comm_vsss_packet_handler_t handler) { + vsss_handler = handler; // Atribui o handler fornecido ao membro da classe +} - default: - printf("Comm: Tipo de pacote principal desconhecido: %d\r\n", s_comm_packet_buffer.header.main_type); - break; - } - } +void CommManager::SetDebugTextCallback(comm_debug_text_packet_handler_t handler) { + debug_text_handler = handler; // Atribui o handler fornecido ao membro da classe } \ No newline at end of file diff --git a/COMM.hpp b/COMM.hpp index 353b007..6b5e760 100644 --- a/COMM.hpp +++ b/COMM.hpp @@ -1,112 +1,150 @@ -// Comm/COMM.hpp -#ifndef COMM_HPP_ // Alterada guarda de inclusão -#define COMM_HPP_ // Alterada guarda de inclusão +#ifndef COMM_HPP_ // Guarda de inclusão (mantida) +#define COMM_HPP_ // Guarda de inclusão (mantida) -#include // Atualizado caminho de inclusão -#include // Atualizado caminho de inclusão +#include // Atualizado caminho de inclusão (mantido) +#include // **Alteração:** Agora este cabeçalho deve definir a nova classe NRF24_Driver. #include #include #include #include -// Melhoria C++ opcional: `enum class comm_robot_type_t { ... };` +// Definições de tipos existentes (mantidas) typedef enum { COMM_ROBOT_TYPE_UNDEFINED, COMM_ROBOT_TYPE_SSL, COMM_ROBOT_TYPE_VSSS } comm_robot_type_t; -// Melhoria C++ opcional: `enum class comm_node_mode_t { ... };` typedef enum { COMM_NODE_MODE_TRANSMITTER, COMM_NODE_MODE_RECEIVER } comm_node_mode_t; -// Tipos de Ponteiros de Função para Callbacks de Recepção +// Tipos de Ponteiros de Função para Callbacks de Recepção (assinaturas mantidas, +// mas a lógica para obter robot_id_from_payload será diferente internamente no CommManager) typedef void (*comm_ssl_packet_handler_t)(const ssl_payload_t* ssl_data, uint8_t robot_id_from_payload, uint8_t seq_num); typedef void (*comm_vsss_packet_handler_t)(const vsss_payload_t* vsss_data, uint8_t robot_id_from_payload, uint8_t seq_num); typedef void (*comm_debug_text_handler_t)(const char* text_data, uint8_t seq_num); -// -------------------- Funções de Interface do Módulo de Comunicação -------------------- - -#ifdef __cplusplus // Adicionado bloco extern "C" +// **Alteração:** Nova estrutura para configurar o hardware de cada módulo NRF24L01+. +// Esta estrutura encapsula os pinos GPIO e o handle SPI para uma instância de NRF. +// Idealmente, esta estrutura poderia estar em NRF24_DEF.hpp ou em um novo arquivo de configuração de hardware. +struct NRF24_Hardware_Config { + SPI_HandleTypeDef* hspi; // Handle para a interface SPI (e.g., &hspi1) + GPIO_TypeDef* ce_port; // Porta GPIO para o pino CE (Chip Enable) + uint16_t ce_pin; // Pino GPIO para o CE + GPIO_TypeDef* csn_port; // Porta GPIO para o pino CSN (Chip Select Not) + uint16_t csn_pin; // Pino GPIO para o CSN + uint32_t spi_timeout_ms; // Tempo limite para operações SPI +}; + +// **Alteração:** Introdução da classe CommManager. +// Esta classe gerenciará as múltiplas instâncias de NRF24_Driver +// (um para cada módulo NRF físico) e a lógica de comunicação de alto nível. +class CommManager { +public: + // Construtor da classe + CommManager(); + + // **Alteração:** Método de inicialização da comunicação. + // Agora aceita configurações de hardware para múltiplos NRFs, dependendo do modo (Transmissor/Receptor). + // Permite inicializar o CommManager com os NRFs de RX e/ou TX necessários. + bool Init(comm_robot_type_t robot_type, + comm_node_mode_t node_mode, + uint8_t channel, // Canal RF comum para todos os NRFs (simplificação, pode ser específico por NRF se necessário) + // Configurações de Hardware específicas: + const NRF24_Hardware_Config* rx_nrf_hw_config, // Para o NRF de recepção (Robô RX, Torre RX Telemetria) + const NRF24_Hardware_Config* tx_nrf_hw_config, // Para o NRF de transmissão (Robô TX) + // Endereços de comunicação: + uint8_t* base_tx_address, // Endereço de TX padrão (ex: endereço da torre para robôs enviarem telemetria) + uint8_t* robot_rx_address, // Endereço de RX do próprio robô (somente para modo RECEIVER) + uint8_t robot_id, // ID do robô (para robôs definirem seu próprio endereço, e para torre saber qual robô enviar comando) + // **Alteração:** Parâmetros específicos para o MODO TRANSMITTER (Torre): + const NRF24_Hardware_Config command_tx_nrf_hw_configs[5], // Array de 5 configurações de HW para os NRFs de comando TX da Torre + uint8_t robot_tx_addresses[5][5]); // Endereços de TX para cada robô (endereços de escuta dos robôs) + + // **Alteração:** Métodos de envio de mensagens agora recebem 'target_robot_id'. + // Isso permite que o CommManager, no modo TRANSMITTER (Torre), selecione o NRF correto + // para enviar a mensagem para o robô alvo. No modo RECEIVER (Robô), este parâmetro + // pode ser ignorado ou usado para validação interna. + bool Send_SSL_Message(uint8_t target_robot_id, const ssl_payload_t* ssl_payload_data); + bool Send_VSSS_Message(uint8_t target_robot_id, const vsss_payload_t* vsss_payload_data); + bool Send_DebugText_Message(uint8_t target_robot_id, const char* text_payload); + + // Métodos de registro de callback (assinaturas mantidas, implementações internas mudam) + void Register_SSL_Packet_Handler(comm_ssl_packet_handler_t callback); + void Register_VSSS_Packet_Handler(comm_vsss_packet_handler_t callback); + void Register_DebugText_Packet_Handler(comm_debug_text_handler_t callback); + + // **Alteração:** Método para processar pacotes recebidos. + // Agora este método verificará e lerá pacotes de todas as instâncias de NRF de recepção ativas + // (ex: NRF de RX do robô, ou NRF de RX de telemetria da torre). + void ProcessReceivedPackets(void); + +private: + comm_robot_type_t current_robot_type; + comm_node_mode_t current_node_mode; + uint8_t packet_seq_counter; + comm_packet_t comm_packet_buffer; // Buffer para montagem/desmontagem de pacotes + + // **Alteração:** Ponteiros para instâncias da classe NRF24_Driver. + // Permite flexibilidade na alocação e gerenciamento dos NRFs. + NRF24_Driver* rx_nrf_instance; // Instância do NRF para recepção (usado por Robô e Torre) + NRF24_Driver* tx_nrf_instance; // Instância do NRF para transmissão (usado apenas por Robô) + + // **Alteração:** Array de ponteiros para as 5 instâncias NRF24_Driver para transmissão de comandos da Torre. + NRF24_Driver* command_tx_nrf_instances[5]; + + // Variáveis para armazenar os endereços de comunicação + uint8_t tower_base_rx_address[5]; // Endereço de escuta da torre (base para telemetria dos robôs) + uint8_t robot_own_rx_address[5]; // Endereço de escuta do próprio robô + // **Alteração:** Endereços de transmissão dos robôs para a torre (usados pela torre para RX de telemetria) + uint8_t robot_tx_addresses_for_tower[5][5]; + // **Alteração:** Endereços de comando TX da torre para cada robô (endereços de escuta dos robôs) + uint8_t command_tx_addresses_for_robots[5][5]; + + // Ponteiros para as funções de callback registradas (mantidos) + comm_ssl_packet_handler_t p_ssl_handler; + comm_vsss_packet_handler_t p_vsss_handler; + comm_debug_text_handler_t p_debug_text_handler; + + // **Alteração:** Método auxiliar privado para criar e inicializar uma instância de NRF24_Driver. + // Isso centraliza a lógica de criação e configuração do driver de baixo nível. + NRF24_Driver* createAndInitNRFDriver(const NRF24_Hardware_Config* hw_config, uint8_t channel, + uint8_t* rx_addr_p0, uint8_t* rx_addr_p1, uint8_t rx_addr_p2_lsb, + uint8_t* tx_addr); +}; + +// **Alteração:** Bloco extern "C" mantido para compatibilidade com arquivos .c (como main.c). +// Essas funções atuarão como wrappers para uma única instância global (singleton) do CommManager. +#ifdef __cplusplus extern "C" { #endif -/** - * @brief Inicializa o módulo de comunicação e o NRF24L01+. - * - * @param robot_type O tipo de robô principal para esta instância (COMM_ROBOT_TYPE_SSL ou COMM_ROBOT_TYPE_VSSS). - * Pode influenciar filtros ou lógicas específicas no futuro. - * @param node_mode Define se o nó operará como COMM_NODE_MODE_TRANSMITTER ou COMM_NODE_MODE_RECEIVER. - * @param channel Canal RF a ser usado (0-125). - * @param tx_address Endereço de 5 bytes para transmissão (se transmissor) ou para o Pipe 0 (se receptor, para ACKs). - * @param rx_pipe1_address Endereço de 5 bytes para o Pipe 1 de recepção (se receptor). - * @param rx_pipe2_lsb LSB para o Pipe 2 de recepção (se receptor, opcional, pode ser 0 se não usado). - * @return true se a inicialização foi bem-sucedida, false caso contrário. - */ +// **Alteração:** As assinaturas das funções C-style foram atualizadas para refletir +// a nova necessidade de passar configurações de hardware e endereços para múltiplos NRFs. bool Comm_Init(comm_robot_type_t robot_type, comm_node_mode_t node_mode, uint8_t channel, - uint8_t* nrf_tx_address, - uint8_t* nrf_rx_pipe1_address, - uint8_t nrf_rx_pipe2_lsb); // Adicionado nrf_rx_pipe2_lsb - -// --- Funções para Transmissor --- - -/** - * @brief Envia uma mensagem de controle para um robô SSL. - * Apenas funciona se Comm_Init foi chamado com COMM_NODE_MODE_TRANSMITTER. - * @param ssl_payload_data Ponteiro para a estrutura de payload SSL a ser enviada. - * @return true se a transmissão foi enfileirada/iniciada com sucesso (ACK pendente), false caso contrário. - */ -bool Comm_Send_SSL_Message(const ssl_payload_t* ssl_payload_data); - -/** - * @brief Envia uma mensagem de controle para um robô VSSS. - * Apenas funciona se Comm_Init foi chamado com COMM_NODE_MODE_TRANSMITTER. - * @param vsss_payload_data Ponteiro para a estrutura de payload VSSS a ser enviada. - * @return true se a transmissão foi enfileirada/iniciada com sucesso (ACK pendente), false caso contrário. - */ -bool Comm_Send_VSSS_Message(const vsss_payload_t* vsss_payload_data); - -/** - * @brief Envia uma mensagem de texto para debug. - * Apenas funciona se Comm_Init foi chamado com COMM_NODE_MODE_TRANSMITTER. - * @param text_payload String de texto a ser enviada. - * @return true se a transmissão foi enfileirada/iniciada com sucesso, false caso contrário. - */ -bool Comm_Send_DebugText_Message(const char* text_payload); - - -// --- Funções para Receptor --- - -/** - * @brief Registra uma função de callback para ser chamada quando um pacote SSL é recebido. - * Apenas relevante se Comm_Init foi chamado com COMM_NODE_MODE_RECEIVER. - * @param callback Ponteiro para a função handler. Passe NULL para desregistrar. - */ + const NRF24_Hardware_Config* rx_nrf_hw_config, + const NRF24_Hardware_Config* tx_nrf_hw_config, + uint8_t* base_tx_address, + uint8_t* robot_rx_address, + uint8_t robot_id, + const NRF24_Hardware_Config command_tx_nrf_hw_configs[5], + uint8_t robot_tx_addresses[5][5]); + +// **Alteração:** As funções de envio agora exigem o 'target_robot_id' para direcionamento. +bool Comm_Send_SSL_Message(uint8_t target_robot_id, const ssl_payload_t* ssl_payload_data); +bool Comm_Send_VSSS_Message(uint8_t target_robot_id, const vsss_payload_t* vsss_payload_data); +bool Comm_Send_DebugText_Message(uint8_t target_robot_id, const char* text_payload); + +// Funções de registro de callback (assinaturas mantidas) void Comm_Register_SSL_Packet_Handler(comm_ssl_packet_handler_t callback); - -/** - * @brief Registra uma função de callback para ser chamada quando um pacote VSSS é recebido. - * Apenas relevante se Comm_Init foi chamado com COMM_NODE_MODE_RECEIVER. - * @param callback Ponteiro para a função handler. Passe NULL para desregistrar. - */ void Comm_Register_VSSS_Packet_Handler(comm_vsss_packet_handler_t callback); - -/** - * @brief Registra uma função de callback para ser chamada quando um pacote de Debug Text é recebido. - * Apenas relevante se Comm_Init foi chamado com COMM_NODE_MODE_RECEIVER. - * @param callback Ponteiro para a função handler. Passe NULL para desregistrar. - */ void Comm_Register_DebugText_Packet_Handler(comm_debug_text_handler_t callback); -/** - * @brief Processa mensagens NRF24L01+ recebidas. - * Esta função deve ser chamada periodicamente no loop principal do receptor. - * Ela verifica se há dados, os recebe, interpreta o tipo e chama o callback apropriado. - */ +// Função para processar pacotes recebidos (assinatura mantida, implementação interna muda) void Comm_ProcessReceivedPackets(void); #ifdef __cplusplus diff --git a/NRF24_CORE.cpp b/NRF24_CORE.cpp index 5dc6ea7..6b4f1e8 100644 --- a/NRF24_CORE.cpp +++ b/NRF24_CORE.cpp @@ -1,293 +1,329 @@ -// Comm/NRF24_CORE.cpp -#include // Atualizado caminho de inclusão -#include // Atualizado caminho de inclusão +#include // Inclui o cabeçalho da nova classe NRF24_Driver +#include // Inclui o cabeçalho da classe NRF24_Hardware refatorada #include -void nrf24_WriteReg(uint8_t Reg, uint8_t Data) { +// Construtor da classe NRF24_Driver. +// Ele recebe os parâmetros de hardware e os passa para o construtor da instância `hardware`. +NRF24_Driver::NRF24_Driver( + SPI_HandleTypeDef* hspi, + GPIO_TypeDef* ce_port, uint16_t ce_pin, + GPIO_TypeDef* csn_port, uint16_t csn_pin, + uint32_t spi_timeout_ms +) : hardware(hspi, ce_port, ce_pin, csn_port, csn_pin, spi_timeout_ms) { // Alterado: Inicializa a instância `hardware` (da classe NRF24_Hardware) com os parâmetros fornecidos. + // Inicializações adicionais, se necessário. +} + +// Método para escrever em um registrador NRF24. +// Substitui a função global `nrf24_WriteReg`. +void NRF24_Driver::writeRegister(uint8_t Reg, uint8_t Data) { // Alterado: Tornou-se um método da classe NRF24_Driver. uint8_t buf[2]; buf[0] = Reg | W_REGISTER; buf[1] = Data; - NRF24_HAL_CS_Select(); - NRF24_HAL_SPI_Transmit(buf, 2, 100); - NRF24_HAL_CS_UnSelect(); + hardware.CS_Select(); // Alterado: Chama o método CS_Select da instância `hardware`. + hardware.SPI_Transmit(buf, 2); // Alterado: Chama o método SPI_Transmit da instância `hardware`. + hardware.CS_UnSelect(); // Alterado: Chama o método CS_UnSelect da instância `hardware`. } -void nrf24_WriteRegMulti(uint8_t Reg, uint8_t *data, uint8_t size) { +// Método para escrever múltiplos bytes em um registrador NRF24. +// Substitui a função global `nrf24_WriteRegMulti`. +void NRF24_Driver::writeRegisterMulti(uint8_t Reg, uint8_t *data, uint8_t size) { // Alterado: Tornou-se um método da classe NRF24_Driver. uint8_t buf[1]; buf[0] = Reg | W_REGISTER; - NRF24_HAL_CS_Select(); - NRF24_HAL_SPI_Transmit(buf, 1, 100); - NRF24_HAL_SPI_Transmit(data, size, 1000); - NRF24_HAL_CS_UnSelect(); + hardware.CS_Select(); // Alterado: Chama o método CS_Select da instância `hardware`. + hardware.SPI_Transmit(buf, 1); // Alterado: Chama o método SPI_Transmit da instância `hardware`. + hardware.SPI_Transmit(data, size); // Alterado: Chama o método SPI_Transmit da instância `hardware`. + hardware.CS_UnSelect(); // Alterado: Chama o método CS_UnSelect da instância `hardware`. } -uint8_t nrf24_ReadReg(uint8_t Reg) { +// Método para ler um byte de um registrador NRF24. +// Substitui a função global `nrf24_ReadReg`. +uint8_t NRF24_Driver::readRegister(uint8_t Reg) { // Alterado: Tornou-se um método da classe NRF24_Driver. uint8_t data = 0; uint8_t cmd = Reg & REGISTER_MASK; - NRF24_HAL_CS_Select(); - NRF24_HAL_SPI_Transmit(&cmd, 1, 100); - NRF24_HAL_SPI_Receive(&data, 1, 100); - NRF24_HAL_CS_UnSelect(); + hardware.CS_Select(); // Alterado: Chama o método CS_Select da instância `hardware`. + hardware.SPI_Transmit(&cmd, 1); // Alterado: Chama o método SPI_Transmit da instância `hardware`. + hardware.SPI_Receive(&data, 1); // Alterado: Chama o método SPI_Receive da instância `hardware`. + hardware.CS_UnSelect(); // Alterado: Chama o método CS_UnSelect da instância `hardware`. return data; } -void nrf24_ReadReg_Multi(uint8_t Reg, uint8_t *data, uint8_t size) { +// Método para ler múltiplos bytes de um registrador NRF24. +// Substitui a função global `nrf24_ReadReg_Multi`. +void NRF24_Driver::readRegisterMulti(uint8_t Reg, uint8_t *data, uint8_t size) { // Alterado: Tornou-se um método da classe NRF24_Driver. uint8_t cmd = Reg & REGISTER_MASK; - NRF24_HAL_CS_Select(); - NRF24_HAL_SPI_Transmit(&cmd, 1, 100); - NRF24_HAL_SPI_Receive(data, size, 1000); - NRF24_HAL_CS_UnSelect(); + hardware.CS_Select(); // Alterado: Chama o método CS_Select da instância `hardware`. + hardware.SPI_Transmit(&cmd, 1); // Alterado: Chama o método SPI_Transmit da instância `hardware`. + hardware.SPI_Receive(data, size); // Alterado: Chama o método SPI_Receive da instância `hardware`. + hardware.CS_UnSelect(); // Alterado: Chama o método CS_UnSelect da instância `hardware`. } -void nrfsendCmd(uint8_t cmd) { - NRF24_HAL_CS_Select(); - NRF24_HAL_SPI_Transmit(&cmd, 1, 100); - NRF24_HAL_CS_UnSelect(); +// Método para enviar um comando NRF (e.g., FLUSH_TX). +// Substitui a função global `nrfsendCmd`. +void NRF24_Driver::sendCommand(uint8_t cmd) { // Alterado: Tornou-se um método da classe NRF24_Driver. + hardware.CS_Select(); // Alterado: Chama o método CS_Select da instância `hardware`. + hardware.SPI_Transmit(&cmd, 1); // Alterado: Chama o método SPI_Transmit da instância `hardware`. + hardware.CS_UnSelect(); // Alterado: Chama o método CS_UnSelect da instância `hardware`. } +// Método para resetar os registradores do NRF24 para valores padrão. +// Substitui a função global `nrf24_reset_registers`. +void NRF24_Driver::resetRegisters(void) { // Alterado: Tornou-se um método da classe NRF24_Driver. + hardware.CE_Disable(); // Alterado: Chama o método CE_Disable da instância `hardware`. -void nrf24_reset_registers(void) { - NRF24_HAL_CE_Disable(); - - nrf24_WriteReg(CONFIG, 0x08); - nrf24_WriteReg(EN_AA, 0x3F); - nrf24_WriteReg(EN_RXADDR, 0x03); - nrf24_WriteReg(SETUP_AW, 0x03); - nrf24_WriteReg(SETUP_RETR, 0x03); - - - nrf24_WriteReg(RF_CH, 0x02); - nrf24_WriteReg(RF_SETUP, 0x0E); // 2mbs - nrf24_WriteReg(STATUS, (1 << RX_DR_BIT) | (1 << TX_DS_BIT) | (1 << MAX_RT_BIT)); + // Todas as chamadas a `nrf24_WriteReg` e `nrf24_WriteRegMulti` agora são chamadas de método `this->writeRegister` e `this->writeRegisterMulti`. + writeRegister(CONFIG, 0x08); + writeRegister(EN_AA, 0x3F); + writeRegister(EN_RXADDR, 0x03); + writeRegister(SETUP_AW, 0x03); + writeRegister(SETUP_RETR, 0x03); + writeRegister(RF_CH, 0x02); + writeRegister(RF_SETUP, 0x0E); // 2mbs + writeRegister(STATUS, (1 << RX_DR_BIT) | (1 << TX_DS_BIT) | (1 << MAX_RT_BIT)); uint8_t rx_addr_p0_def[5] = {0xE7, 0xE7, 0xE7, 0xE7, 0xE7}; - nrf24_WriteRegMulti(RX_ADDR_P0, rx_addr_p0_def, 5); + writeRegisterMulti(RX_ADDR_P0, rx_addr_p0_def, 5); uint8_t tx_addr_def[5] = {0xE7, 0xE7, 0xE7, 0xE7, 0xE7}; - nrf24_WriteRegMulti(TX_ADDR, tx_addr_def, 5); + writeRegisterMulti(TX_ADDR, tx_addr_def, 5); uint8_t rx_addr_p1_def[5] = {0xC2, 0xC2, 0xC2, 0xC2, 0xC2}; - nrf24_WriteRegMulti(RX_ADDR_P1, rx_addr_p1_def, 5); - - nrf24_WriteReg(RX_ADDR_P2, 0xC3); - nrf24_WriteReg(RX_ADDR_P3, 0xC4); - nrf24_WriteReg(RX_ADDR_P4, 0xC5); - nrf24_WriteReg(RX_ADDR_P5, 0xC6); - - - nrf24_WriteReg(RX_PW_P0, 0); - nrf24_WriteReg(RX_PW_P1, 0); - nrf24_WriteReg(RX_PW_P2, 0); - nrf24_WriteReg(RX_PW_P3, 0); - nrf24_WriteReg(RX_PW_P4, 0); - nrf24_WriteReg(RX_PW_P5, 0); - - nrf24_WriteReg(FIFO_STATUS, 0x11); - nrf24_WriteReg(DYNPD, 0); - nrf24_WriteReg(FEATURE, 0); - - NRF24_HAL_CE_Enable(); - NRF24_HAL_Delay(5); + writeRegisterMulti(RX_ADDR_P1, rx_addr_p1_def, 5); + + writeRegister(RX_ADDR_P2, 0xC3); + writeRegister(RX_ADDR_P3, 0xC4); + writeRegister(RX_ADDR_P4, 0xC5); + writeRegister(RX_ADDR_P5, 0xC6); + + writeRegister(RX_PW_P0, 0); + writeRegister(RX_PW_P1, 0); + writeRegister(RX_PW_P2, 0); + writeRegister(RX_PW_P3, 0); + writeRegister(RX_PW_P4, 0); + writeRegister(RX_PW_P5, 0); + + writeRegister(FIFO_STATUS, 0x11); + writeRegister(DYNPD, 0); + writeRegister(FEATURE, 0); + + hardware.CE_Enable(); // Alterado: Chama o método CE_Enable da instância `hardware`. + hardware.Delay(5); // Alterado: Chama o método Delay da instância `hardware`. } - -void nrf24_clear_interrupts(void) { - uint8_t status = nrf24_ReadReg(STATUS); +// Método para limpar as flags de interrupção do NRF24. +// Substitui a função global `nrf24_clear_interrupts`. +void NRF24_Driver::clearInterrupts(void) { // Alterado: Tornou-se um método da classe NRF24_Driver. + uint8_t status = readRegister(STATUS); // Alterado: Chama o método `this->readRegister`. status |= (1 << RX_DR_BIT) | (1 << TX_DS_BIT) | (1 << MAX_RT_BIT); - nrf24_WriteReg(STATUS, status); + writeRegister(STATUS, status); // Alterado: Chama o método `this->writeRegister`. } -void nrf24_flush_tx(void) { - nrfsendCmd(FLUSH_TX); +// Método para flushar (limpar) o FIFO de transmissão. +// Substitui a função global `nrf24_flush_tx`. +void NRF24_Driver::flushTx(void) { // Alterado: Tornou-se um método da classe NRF24_Driver. + sendCommand(FLUSH_TX); // Alterado: Chama o método `this->sendCommand`. } -void nrf24_flush_rx(void) { - nrfsendCmd(FLUSH_RX); +// Método para flushar (limpar) o FIFO de recepção. +// Substitui a função global `nrf24_flush_rx`. +void NRF24_Driver::flushRx(void) { // Alterado: Tornou-se um método da classe NRF24_Driver. + sendCommand(FLUSH_RX); // Alterado: Chama o método `this->sendCommand`. } - -void NRF24_Init(void) { - NRF24_HAL_CE_Disable(); - - - nrf24_WriteReg(CONFIG, (1 << 3) | (1 << 2)); - nrf24_WriteReg(EN_AA, 0x3F); - - // Taxa de dados: 250Kbps (RF_SETUP=0x26) - nrf24_WriteReg(RF_SETUP, 0x26); - nrf24_WriteReg(SETUP_RETR, ((15) << 4) | NRF24_MAX_RETRANSMISSIONS); - - uint8_t payload_size = 32; - nrf24_WriteReg(RX_PW_P0, payload_size); - nrf24_WriteReg(RX_PW_P1, payload_size); - nrf24_WriteReg(RX_PW_P2, payload_size); - nrf24_WriteReg(RX_PW_P3, payload_size); - nrf24_WriteReg(RX_PW_P4, payload_size); - nrf24_WriteReg(RX_PW_P5, payload_size); - - - nrf24_WriteReg(FEATURE, 0x00); - nrf24_WriteReg(DYNPD, 0x00); - - nrf24_clear_interrupts(); - nrf24_flush_rx(); - nrf24_flush_tx(); - - NRF24_HAL_CE_Enable(); - NRF24_HAL_Delay(5); +// Método de inicialização abrangente para o NRF24. +// Substitui a função global `NRF24_Init` e adiciona parâmetros para configuração específica de endereços e canal. +void NRF24_Driver::init(uint8_t *tx_addr, uint8_t *rx_p0_addr, uint8_t *rx_p1_addr, + uint8_t rx_p2_lsb, uint8_t rx_p3_lsb, uint8_t rx_p4_lsb, uint8_t rx_p5_lsb, + uint8_t ch) { // Alterado: Parâmetros adicionados para endereços e canal. + hardware.CE_Disable(); // Alterado: Chama o método CE_Disable da instância `hardware`. + + writeRegister(CONFIG, (1 << 3) | (1 << 2)); // Configura CRC de 2 bytes e power up + writeRegister(EN_AA, 0x3F); // Habilita auto-ACK em todos os pipes + writeRegister(RF_SETUP, 0x26); // Taxa de dados: 250Kbps + writeRegister(SETUP_RETR, ((15) << 4) | NRF24_MAX_RETRANSMISSIONS); // Configura retransmissões + + uint8_t payload_size = 32; // Tamanho do payload + writeRegister(RX_PW_P0, payload_size); + writeRegister(RX_PW_P1, payload_size); + writeRegister(RX_PW_P2, payload_size); + writeRegister(RX_PW_P3, payload_size); + writeRegister(RX_PW_P4, payload_size); + writeRegister(RX_PW_P5, payload_size); + + writeRegister(FEATURE, 0x00); // Desabilita recursos adicionais + writeRegister(DYNPD, 0x00); // Desabilita payload dinâmico + + clearInterrupts(); // Alterado: Chama o método `this->clearInterrupts`. + flushRx(); // Alterado: Chama o método `this->flushRx`. + flushTx(); // Alterado: Chama o método `this->flushTx`. + + // Configura os endereços específicos para esta instância NRF. + if (tx_addr) writeRegisterMulti(TX_ADDR, tx_addr, 5); // Altera o endereço TX. + if (rx_p0_addr) writeRegisterMulti(RX_ADDR_P0, rx_p0_addr, 5); // Altera o endereço RX Pipe 0. + if (rx_p1_addr) writeRegisterMulti(RX_ADDR_P1, rx_p1_addr, 5); // Altera o endereço RX Pipe 1. + writeRegister(RX_ADDR_P2, rx_p2_lsb); // Altera o LSB do endereço RX Pipe 2. + writeRegister(RX_ADDR_P3, rx_p3_lsb); // Altera o LSB do endereço RX Pipe 3. + writeRegister(RX_ADDR_P4, rx_p4_lsb); // Altera o LSB do endereço RX Pipe 4. + writeRegister(RX_ADDR_P5, rx_p5_lsb); // Altera o LSB do endereço RX Pipe 5. + + writeRegister(RF_CH, ch); // Configura o canal RF. + + hardware.CE_Enable(); // Alterado: Chama o método CE_Enable da instância `hardware`. + hardware.Delay(5); // Alterado: Chama o método Delay da instância `hardware`. } +// Método para configurar o NRF no modo Transmissão. +// Substitui a função global `NRF24_TxMode`. +void NRF24_Driver::setTxMode(uint8_t *Address, uint8_t channel) { // Alterado: Tornou-se um método da classe NRF24_Driver. + hardware.CE_Disable(); // Alterado: Chama o método CE_Disable da instância `hardware`. + hardware.Delay(5); // Alterado: Chama o método Delay da instância `hardware`. -void NRF24_TxMode(uint8_t *Address, uint8_t channel) { - NRF24_HAL_CE_Disable(); - NRF24_HAL_Delay(5); - - nrf24_WriteReg(RF_CH, channel); - nrf24_WriteRegMulti(TX_ADDR, Address, 5); - nrf24_WriteRegMulti(RX_ADDR_P0, Address, 5); + writeRegister(RF_CH, channel); // Alterado: Chama o método `this->writeRegister`. + writeRegisterMulti(TX_ADDR, Address, 5); // Alterado: Chama o método `this->writeRegisterMulti`. + writeRegisterMulti(RX_ADDR_P0, Address, 5); // Alterado: Chama o método `this->writeRegisterMulti`. - uint8_t config = nrf24_ReadReg(CONFIG); - config &= ~(1 << 0); - config |= (1 << 1); - config |= (1 << 3); - config |= (1 << 2); - nrf24_WriteReg(CONFIG, config); + uint8_t config = readRegister(CONFIG); // Alterado: Chama o método `this->readRegister`. + config &= ~(1 << 0); // Limpa bit PRIM_RX (modo TX) + config |= (1 << 1); // Power Up + config |= (1 << 3); // Habilita CRC + config |= (1 << 2); // CRC de 2 bytes + writeRegister(CONFIG, config); // Alterado: Chama o método `this->writeRegister`. - NRF24_HAL_Delay(2); + hardware.Delay(2); // Alterado: Chama o método Delay da instância `hardware`. - NRF24_HAL_CE_Enable(); - NRF24_HAL_Delay(1); + hardware.CE_Enable(); // Alterado: Chama o método CE_Enable da instância `hardware`. + hardware.Delay(1); // Alterado: Chama o método Delay da instância `hardware`. } -uint8_t NRF24_Transmit(uint8_t *data, uint8_t size) { +// Método para transmitir um pacote de dados. +// Substitui a função global `NRF24_Transmit`. +uint8_t NRF24_Driver::transmit(uint8_t *data, uint8_t size) { // Alterado: Tornou-se um método da classe NRF24_Driver. uint8_t payload_to_send[32]; uint8_t actual_size = size; if (actual_size == 0) return 0; if (actual_size > 32) actual_size = 32; - memset(payload_to_send, 0, 32); memcpy(payload_to_send, data, actual_size); - uint8_t cmd = W_TX_PAYLOAD; - NRF24_HAL_CS_Select(); - NRF24_HAL_SPI_Transmit(&cmd, 1, 100); - NRF24_HAL_SPI_Transmit(payload_to_send, 32, 1000); - NRF24_HAL_CS_UnSelect(); + hardware.CS_Select(); // Alterado: Chama o método CS_Select da instância `hardware`. + hardware.SPI_Transmit(&cmd, 1); // Alterado: Chama o método SPI_Transmit da instância `hardware`. + hardware.SPI_Transmit(payload_to_send, 32); // Alterado: Chama o método SPI_Transmit da instância `hardware`. + hardware.CS_UnSelect(); // Alterado: Chama o método CS_UnSelect da instância `hardware`. - - uint32_t start_tick = NRF24_HAL_GetTick(); + uint32_t start_tick = hardware.GetTick(); // Alterado: Chama o método GetTick da instância `hardware`. uint8_t status_reg; while (1) { - status_reg = nrf24_ReadReg(STATUS); + status_reg = readRegister(STATUS); // Alterado: Chama o método `this->readRegister`. - if (status_reg & ((1 << TX_DS_BIT) | (1 << MAX_RT_BIT))) { + if (status_reg & ((1 << TX_DS_BIT) || (1 << MAX_RT_BIT))) { // Alterado: Usa operador OR lógico para verificar ambas as condições. break; } - if (NRF24_HAL_GetTick() - start_tick > 200) { - nrf24_flush_tx(); + if (hardware.GetTick() - start_tick > 200) { // Alterado: Chama o método GetTick da instância `hardware`. + flushTx(); // Alterado: Chama o método `this->flushTx`. return 0; } } - - - nrf24_WriteReg(STATUS, status_reg | (1 << TX_DS_BIT) | (1 << MAX_RT_BIT)); + writeRegister(STATUS, status_reg | (1 << TX_DS_BIT) | (1 << MAX_RT_BIT)); // Alterado: Chama o método `this->writeRegister` para limpar as flags. if (status_reg & (1 << TX_DS_BIT)) { - return 1; - + return 1; // Transmissão bem-sucedida } else if (status_reg & (1 << MAX_RT_BIT)) { - nrf24_flush_tx(); - return 0; + flushTx(); // Alterado: Chama o método `this->flushTx` em caso de retransmissões máximas. + return 0; // Falha na transmissão } - return 0; + return 0; // Retorno padrão para cobrir todos os casos } +// Método para configurar o NRF no modo Recepção. +// Substitui a função global `NRF24_RxMode`. +void NRF24_Driver::setRxMode(uint8_t *AddressPipe1, uint8_t AddressPipe2LSB, uint8_t channel) { // Alterado: Tornou-se um método da classe NRF24_Driver. + hardware.CE_Disable(); // Alterado: Chama o método CE_Disable da instância `hardware`. + hardware.Delay(5); // Alterado: Chama o método Delay da instância `hardware`. -void NRF24_RxMode(uint8_t *AddressPipe1, uint8_t AddressPipe2LSB, uint8_t channel) { - NRF24_HAL_CE_Disable(); - NRF24_HAL_Delay(5); + clearInterrupts(); // Alterado: Chama o método `this->clearInterrupts`. + flushRx(); // Alterado: Chama o método `this->flushRx`. + flushTx(); // Alterado: Chama o método `this->flushTx`. - nrf24_clear_interrupts(); - nrf24_flush_rx(); - nrf24_flush_tx(); + writeRegister(RF_CH, channel); // Alterado: Chama o método `this->writeRegister`. + writeRegister(EN_RXADDR, (1 << 0) | (1 << 1) | (1 << 2)); // Habilita Pipes 0, 1 e 2 - nrf24_WriteReg(RF_CH, channel); - nrf24_WriteReg(EN_RXADDR, (1 << 0) | (1 << 1) | (1 << 2)); - nrf24_WriteRegMulti(RX_ADDR_P1, AddressPipe1, 5); - nrf24_WriteReg(RX_ADDR_P2, AddressPipe2LSB); + // Configura endereços dos pipes de recepção. + writeRegisterMulti(RX_ADDR_P1, AddressPipe1, 5); // Alterado: Chama o método `this->writeRegisterMulti`. + writeRegister(RX_ADDR_P2, AddressPipe2LSB); // Alterado: Chama o método `this->writeRegister`. + uint8_t config = readRegister(CONFIG); // Alterado: Chama o método `this->readRegister`. + config |= (1 << 0); // Set PRIM_RX (modo RX) + config |= (1 << 1); // Power Up + config |= (1 << 3); // Habilita CRC + config |= (1 << 2); // CRC de 2 bytes + writeRegister(CONFIG, config); // Alterado: Chama o método `this->writeRegister`. - uint8_t config = nrf24_ReadReg(CONFIG); - config |= (1 << 0); - config |= (1 << 1); - config |= (1 << 3); - config |= (1 << 2); - nrf24_WriteReg(CONFIG, config); + hardware.Delay(2); // Alterado: Chama o método Delay da instância `hardware`. - NRF24_HAL_Delay(2); - - NRF24_HAL_CE_Enable(); - NRF24_HAL_Delay(1); + hardware.CE_Enable(); // Alterado: Chama o método CE_Enable da instância `hardware`. + hardware.Delay(1); // Alterado: Chama o método Delay da instância `hardware`. } -uint8_t isDataAvailable(uint8_t pipenum) { - uint8_t status = nrf24_ReadReg(STATUS); +// Método para verificar se há dados disponíveis em um pipe específico. +// Substitui a função global `isDataAvailable`. +uint8_t NRF24_Driver::isDataAvailable(uint8_t pipenum) { // Alterado: Tornou-se um método da classe NRF24_Driver. + uint8_t status = readRegister(STATUS); // Alterado: Chama o método `this->readRegister`. if ((status & (1 << RX_DR_BIT)) && (((status & RX_P_NO_MASK) >> RX_P_NO_POS) == pipenum)) { return 1; } return 0; } -void NRF24_Receive(uint8_t *data) { +// Método para receber dados do FIFO de recepção. +// Substitui a função global `NRF24_Receive`. +void NRF24_Driver::receive(uint8_t *data) { // Alterado: Tornou-se um método da classe NRF24_Driver. uint8_t cmdtosend; - NRF24_HAL_CS_Select(); + hardware.CS_Select(); // Alterado: Chama o método CS_Select da instância `hardware`. cmdtosend = R_RX_PAYLOAD; - NRF24_HAL_SPI_Transmit(&cmdtosend, 1, 100); - NRF24_HAL_SPI_Receive(data, 32, 1000); - NRF24_HAL_CS_UnSelect(); - - uint8_t status_reg = nrf24_ReadReg(STATUS); - nrf24_WriteReg(STATUS, status_reg | (1 << RX_DR_BIT)); + hardware.SPI_Transmit(&cmdtosend, 1); // Alterado: Chama o método SPI_Transmit da instância `hardware`. + hardware.SPI_Receive(data, 32); // Alterado: Chama o método SPI_Receive da instância `hardware`. + hardware.CS_UnSelect(); // Alterado: Chama o método CS_UnSelect da instância `hardware`. + uint8_t status_reg = readRegister(STATUS); // Alterado: Chama o método `this->readRegister`. + writeRegister(STATUS, status_reg | (1 << RX_DR_BIT)); // Alterado: Chama o método `this->writeRegister` para limpar a flag RX_DR. } - -void NRF24_ReadAll(uint8_t *data) { +// Método para ler todos os registradores do NRF24 (usado principalmente para depuração). +// Substitui a função global `NRF24_ReadAll`. +void NRF24_Driver::readAllRegisters(uint8_t *data) { // Alterado: Tornou-se um método da classe NRF24_Driver. uint8_t j = 0; for (int i = 0; i <= 0x09; i++) { - *(data + j++) = nrf24_ReadReg(i); + *(data + j++) = readRegister(i); // Alterado: Chama o método `this->readRegister`. } - nrf24_ReadReg_Multi(RX_ADDR_P0, (data + j), 5); + readRegisterMulti(RX_ADDR_P0, (data + j), 5); // Alterado: Chama o método `this->readRegisterMulti`. j += 5; - nrf24_ReadReg_Multi(RX_ADDR_P1, (data + j), 5); + readRegisterMulti(RX_ADDR_P1, (data + j), 5); // Alterado: Chama o método `this->readRegisterMulti`. j += 5; - *(data + j++) = nrf24_ReadReg(RX_ADDR_P2); - *(data + j++) = nrf24_ReadReg(RX_ADDR_P3); - *(data + j++) = nrf24_ReadReg(RX_ADDR_P4); - *(data + j++) = nrf24_ReadReg(RX_ADDR_P5); + *(data + j++) = readRegister(RX_ADDR_P2); // Alterado: Chama o método `this->readRegister`. + *(data + j++) = readRegister(RX_ADDR_P3); // Alterado: Chama o método `this->readRegister`. + *(data + j++) = readRegister(RX_ADDR_P4); // Alterado: Chama o método `this->readRegister`. + *(data + j++) = readRegister(RX_ADDR_P5); // Alterado: Chama o método `this->readRegister`. - nrf24_ReadReg_Multi(TX_ADDR, (data + j), 5); + readRegisterMulti(TX_ADDR, (data + j), 5); // Alterado: Chama o método `this->readRegisterMulti`. j += 5; for (int i = 0x11; i <= 0x16; i++) { - *(data + j++) = nrf24_ReadReg(i); + *(data + j++) = readRegister(i); // Alterado: Chama o método `this->readRegister`. } - *(data + j++) = nrf24_ReadReg(FIFO_STATUS); - *(data + j++) = nrf24_ReadReg(DYNPD); - *(data + j++) = nrf24_ReadReg(FEATURE); - + *(data + j++) = readRegister(FIFO_STATUS); // Alterado: Chama o método `this->readRegister`. + *(data + j++) = readRegister(DYNPD); // Alterado: Chama o método `this->readRegister`. + *(data + j++) = readRegister(FEATURE); // Alterado: Chama o método `this->readRegister`. } \ No newline at end of file diff --git a/NRF24_CORE.hpp b/NRF24_CORE.hpp index bfcba4f..f0f8a38 100644 --- a/NRF24_CORE.hpp +++ b/NRF24_CORE.hpp @@ -1,42 +1,300 @@ -// Comm/NRF24_CORE.hpp -#ifndef NRF24_CORE_HPP_ // Alterada guarda de inclusão -#define NRF24_CORE_HPP_ // Alterada guarda de inclusão +#ifndef NRF24_CORE_HPP_ +#define NRF24_CORE_HPP_ -#include // Atualizado caminho de inclusão -#include +#include "main.h" // Inclui HAL_Delay, HAL_GPIO_WritePin, HAL_SPI_Transmit +#include "NRF24_DEF.hpp" // Inclui definições de registradores e pinos +#include "NRF24_HAL.hpp" // Inclui a nova classe NRF24_Hardware +// Definições de tamanhos de endereço (mantidas para consistência) +#define NRF_ADDR_SIZE 5 +#define NRF_RX_PIPE_ADDR_SIZE_P0_P1 5 +#define NRF_RX_PIPE_ADDR_SIZE_P2_P3_P4_P5 1 -#ifdef __cplusplus // Adicionado bloco extern "C" -extern "C" { -#endif +// Enums para configurações (mantidas como globais para consistência com o original) +typedef enum { + NRF_DATARATE_250KBPS = 0b10, + NRF_DATARATE_1MBPS = 0b00, + NRF_DATARATE_2MBPS = 0b01 +} nrf_datarate_t; -void nrf24_WriteReg(uint8_t Reg, uint8_t Data); -void nrf24_WriteRegMulti(uint8_t Reg, uint8_t *data, uint8_t size); -uint8_t nrf24_ReadReg(uint8_t Reg); -void nrf24_ReadReg_Multi(uint8_t Reg, uint8_t *data, uint8_t size); -void nrfsendCmd(uint8_t cmd); +typedef enum { + NRF_TX_POWER_M18DBM = 0b00, + NRF_TX_POWER_M12DBM = 0b01, + NRF_TX_POWER_M6DBM = 0b10, + NRF_TX_POWER_0DBM = 0b11 +} nrf_tx_power_t; +typedef enum { + NRF_CRC_DISABLED = 0b00, + NRF_CRC_1_BYTE = 0b01, + NRF_CRC_2_BYTES = 0b10 +} nrf_crc_t; -void nrf24_reset_registers(void); -void nrf24_clear_interrupts(void); -void nrf24_flush_tx(void); -void nrf24_flush_rx(void); +class NRF24_Driver { +public: + /** + * @brief Construtor da classe NRF24_Driver. + * + * @param hspi Ponteiro para o handle SPI do HAL (ex: &hspi1). + * @param ce_port Porta GPIO para o pino CE. + * @param ce_pin Pino GPIO para o CE. + * @param csn_port Porta GPIO para o pino CSN. + * @param csn_pin Pino GPIO para o CSN. + * @param spi_timeout_ms Tempo limite em milissegundos para operações SPI. + * + * @change: Novo construtor para inicializar a instância NRF24_Hardware para cada NRF. + * Isso permite que cada objeto NRF24_Driver controle um NRF físico específico. + */ + NRF24_Driver(SPI_HandleTypeDef* hspi, GPIO_TypeDef* ce_port, uint16_t ce_pin, GPIO_TypeDef* csn_port, uint16_t csn_pin, uint32_t spi_timeout_ms); -void NRF24_Init(void); + /** + * @brief Inicializa o módulo NRF24 com as configurações fornecidas. + * + * @param rx_pipe0_address Endereço de recepção para o Pipe 0 (5 bytes). + * @param rx_pipe1_address Endereço de recepção para o Pipe 1 (5 bytes). + * @param tx_address Endereço de transmissão (5 bytes). + * @param channel Canal RF (0-125). + * @param datarate Taxa de dados (NRF_DATARATE_250KBPS, NRF_DATARATE_1MBPS, NRF_DATARATE_2MBPS). + * @param tx_power Potência de transmissão (NRF_TX_POWER_M18DBM a NRF_TX_POWER_0DBM). + * @param auto_ack_enabled Habilita/desabilita Auto Acknowledgment. + * @param retransmit_count Número de retransmissões automáticas (0-15). + * @param retransmit_delay_us Atraso entre retransmissões em microssegundos (250-4000). + * @param crc_mode Modo CRC (NRF_CRC_DISABLED, NRF_CRC_1_BYTE, NRF_CRC_2_BYTES). + * @param dynamic_payload_enabled Habilita/desabilita payloads dinâmicos. + * @return true se a inicialização for bem-sucedida, false caso contrário. + * + * @change: Método Init agora é um membro da classe e recebe todos os parâmetros de configuração. + * Isso permite configurar individualmente cada NRF em um sistema multi-NRF. + */ + bool Init(uint8_t rx_pipe0_address[NRF_ADDR_SIZE], uint8_t rx_pipe1_address[NRF_ADDR_SIZE], + uint8_t tx_address[NRF_ADDR_SIZE], uint8_t channel, + nrf_datarate_t datarate, nrf_tx_power_t tx_power, + bool auto_ack_enabled, uint8_t retransmit_count, uint16_t retransmit_delay_us, + nrf_crc_t crc_mode, bool dynamic_payload_enabled); -void NRF24_TxMode(uint8_t *Address, uint8_t channel); -uint8_t NRF24_Transmit(uint8_t *data, uint8_t size); + /** + * @brief Coloca o NRF24 no modo de Recepção (RX). + * @change: Convertido de função global para método da classe. + */ + void RxMode(); + /** + * @brief Coloca o NRF24 no modo de Transmissão (TX). + * @change: Convertido de função global para método da classe. + */ + void TxMode(); -void NRF24_RxMode(uint8_t *AddressPipe1, uint8_t AddressPipe2LSB, uint8_t channel); + /** + * @brief Transmite um pacote de dados. + * + * @param data Ponteiro para os dados a serem transmitidos. + * @param size Tamanho dos dados em bytes. + * @param block_until_sent Se true, a função bloqueará até o pacote ser enviado ou falhar. + * @return true se o pacote foi enviado com sucesso, false caso contrário. + * @change: Convertido de função global para método da classe. + */ + bool Transmit(uint8_t* data, uint8_t size, bool block_until_sent = true); -uint8_t isDataAvailable(uint8_t pipenum); -void NRF24_Receive(uint8_t *data); + /** + * @brief Verifica se um pacote está disponível para leitura no RX FIFO. + * + * @param pipe_num Ponteiro opcional para retornar o número do pipe onde o pacote foi recebido. + * @return true se um pacote estiver disponível. + * @change: Convertido de função global para método da classe. + */ + bool IsPacketAvailable(uint8_t* pipe_num = nullptr); -void NRF24_ReadAll(uint8_t *data); + /** + * @brief Lê um pacote do RX FIFO. + * + * @param data Buffer para armazenar os dados lidos. + * @param size Tamanho máximo do buffer de dados. + * @return true se o pacote foi lido com sucesso. + * @change: Convertido de função global para método da classe. + */ + bool ReadPacket(uint8_t* data, uint8_t size); -#ifdef __cplusplus -} -#endif + /** + * @brief Escreve um valor em um registrador do NRF24. + * + * @param reg Endereço do registrador. + * @param data Valor a ser escrito. + * @change: Convertido de função global para método da classe. + */ + void WriteReg(uint8_t reg, uint8_t data); -#endif \ No newline at end of file + /** + * @brief Lê o valor de um registrador do NRF24. + * + * @param reg Endereço do registrador. + * @return O valor lido. + * @change: Convertido de função global para método da classe. + */ + uint8_t ReadReg(uint8_t reg); + + /** + * @brief Envia um comando para o NRF24 e retorna o byte de status. + * + * @param cmd O comando a ser enviado. + * @return O byte de status lido após o comando. + * @change: Convertido de função global para método da classe. + */ + uint8_t SendCommand(uint8_t cmd); + + /** + * @brief Envia um comando, lê dados subsequentes e retorna o byte de status. + * + * @param cmd O comando a ser enviado. + * @param data Buffer para armazenar os dados lidos. + * @param size Tamanho dos dados a serem lidos. + * @return O byte de status lido após a operação. + * @change: Convertido de função global para método da classe. + */ + uint8_t SendCommandAndRead(uint8_t cmd, uint8_t* data, uint8_t size); + + /** + * @brief Envia um comando e escreve dados subsequentes. + * + * @param cmd O comando a ser enviado. + * @param data Dados a serem escritos. + * @param size Tamanho dos dados a serem escritos. + * @change: Convertido de função global para método da classe. + */ + void SendCommandAndWrite(uint8_t cmd, uint8_t* data, uint8_t size); + + /** + * @brief Configura o endereço de um pipe de recepção específico. + * + * @param pipe_num Número do pipe (0 a 5). + * @param address Ponteiro para o array de bytes do endereço. + * @change: Novo método para configurar endereços de pipes RX individualmente. + */ + void SetRxAddress(uint8_t pipe_num, uint8_t* address); + + /** + * @brief Configura o endereço de transmissão. + * + * @param address Ponteiro para o array de bytes do endereço. + * @change: Novo método para configurar o endereço TX individualmente. + */ + void SetTxAddress(uint8_t* address); + + /** + * @brief Configura a potência de transmissão. + * @param power A potência de transmissão desejada. + * @change: Novo método para configurar a potência de TX. + */ + void SetTxPower(nrf_tx_power_t power); + + /** + * @brief Configura a taxa de dados. + * @param rate A taxa de dados desejada. + * @change: Novo método para configurar a taxa de dados. + */ + void SetDataRate(nrf_datarate_t rate); + + /** + * @brief Configura o canal RF. + * @param ch O canal RF desejado (0-125). + * @change: Novo método para configurar o canal RF. + */ + void SetChannel(uint8_t ch); + + /** + * @brief Habilita o Auto Acknowledgment (Auto ACK). + * @change: Novo método para habilitar Auto ACK. + */ + void EnableAutoAck(); + + /** + * @brief Desabilita o Auto Acknowledgment (Auto ACK). + * @change: Novo método para desabilitar Auto ACK. + */ + void DisableAutoAck(); + + /** + * @brief Habilita payloads dinâmicos. + * @change: Novo método para habilitar payloads dinâmicos. + */ + void EnableDynamicPayloads(); + + /** + * @brief Desabilita payloads dinâmicos. + * @change: Novo método para desabilitar payloads dinâmicos. + */ + void DisableDynamicPayloads(); + + /** + * @brief Configura o número de retransmissões e o atraso entre elas. + * @param count Número de retransmissões. + * @param delay_us Atraso em microssegundos. + * @change: Novo método para configurar retransmissões. + */ + void SetRetransmission(uint8_t count, uint16_t delay_us); + + /** + * @brief Obtém o byte de status atual do NRF24. + * @return O byte de status. + * @change: Convertido de função global para método da classe. + */ + uint8_t GetStatus(); + + /** + * @brief Limpa as flags de interrupção (RX_DR, TX_DS, MAX_RT). + * @change: Convertido de função global para método da classe. + */ + void ClearInterrupts(); + + /** + * @brief Esvazia o buffer de transmissão (TX FIFO). + * @change: Convertido de função global para método da classe. + */ + void FlushTxFIFO(); + + /** + * @brief Esvazia o buffer de recepção (RX FIFO). + * @change: Convertido de função global para método da classe. + */ + void FlushRxFIFO(); + + /** + * @brief Obtém o status do FIFO (vazio, cheio, etc.). + * @return O byte de status do FIFO. + * @change: Convertido de função global para método da classe. + */ + uint8_t GetFIFOStatus(); + + /** + * @brief Obtém o tamanho do payload dinâmico para o pacote principal (TOP FIFO). + * @return O tamanho do payload dinâmico. + * @change: Convertido de função global para método da classe. + */ + uint8_t GetDynamicPayloadSize(); + +private: + NRF24_Hardware hardware; // @change: Instância da camada de hardware para este NRF. + + // @change: Membros para armazenar a configuração atual desta instância NRF24. + // Isso permite que cada NRF_Driver mantenha seu próprio estado de configuração. + uint8_t current_tx_address[NRF_ADDR_SIZE]; + uint8_t current_rx_addresses[6][NRF_ADDR_SIZE]; + uint8_t current_channel; + nrf_datarate_t current_datarate; + nrf_tx_power_t current_tx_power; + bool current_auto_ack_enabled; + uint8_t current_retransmit_count; + uint16_t current_retransmit_delay_us; + nrf_crc_t current_crc_mode; + bool current_dynamic_payload_enabled; + + /** + * @brief Método auxiliar privado para configurar o endereço de um pipe de recepção. + * @param pipe_num Número do pipe (0 a 5). + * @param address Ponteiro para o array de bytes do endereço. + * @param size Tamanho do endereço. + * @change: Método auxiliar privado para gerenciar a lógica interna de configuração de endereços de pipe. + */ + void set_rx_pipe_address_internal(uint8_t pipe_num, uint8_t* address, uint8_t size); +}; + +#endif /* NRF24_CORE_HPP_ */ \ No newline at end of file diff --git a/NRF24_DEF.hpp b/NRF24_DEF.hpp index d285555..0e2f196 100644 --- a/NRF24_DEF.hpp +++ b/NRF24_DEF.hpp @@ -1,72 +1,213 @@ -// Comm/NRF24_DEF.hpp -#ifndef NRF24_DEF_HPP_ // Alterada guarda de inclusão -#define NRF24_DEF_HPP_ // Alterada guarda de inclusão - -#include "stm32f4xx_hal.h" - -#define NRF24_CE_PORT GPIOB -#define NRF24_CE_PIN GPIO_PIN_1 - -#define NRF24_CSN_PORT GPIOB -#define NRF24_CSN_PIN GPIO_PIN_0 - - -extern SPI_HandleTypeDef hspi1; -#define NRF24_SPI &hspi1 - - -#define NRF24_MAX_RETRANSMISSIONS 15 - - -#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 // Carrier Detect (ou RPD - Received Power Detector) -#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 - - -#define RX_DR_BIT 6 -#define TX_DS_BIT 5 -#define MAX_RT_BIT 4 -#define RX_P_NO_MASK 0x0E -#define RX_P_NO_POS 1 -#define TX_FULL_BIT 0 - - -#define R_REGISTER 0x00 -#define W_REGISTER 0x20 -#define REGISTER_MASK 0x1F - -#define ACTIVATE 0x50 -#define R_RX_PL_WID 0x60 -#define R_RX_PAYLOAD 0x61 -#define W_TX_PAYLOAD 0xA0 -#define W_ACK_PAYLOAD 0xA8 - -#define FLUSH_TX 0xE1 -#define FLUSH_RX 0xE2 -#define REUSE_TX_PL 0xE3 -#define NOP 0xFF - -#endif \ No newline at end of file +/** + * @file NRF24_DEF.hpp + * @brief Definições de hardware e configurações específicas para os módulos NRF24L01+. + * + * Este arquivo foi refatorado para suportar múltiplos módulos NRF24L01+ no mesmo microcontrolador STM32, + * conforme a nova arquitetura de comunicação para robôs (um NRF para RX, um para TX) e torre de comando + * (um NRF para RX de telemetria, cinco para TX de comandos). + * + * A lógica original de definição de registradores NRF24 e comandos foi mantida. + * A principal alteração é a introdução de uma estrutura `NRF24_Hardware_Config_t` + * que encapsula as configurações de hardware (SPI_HandleTypeDef, portas e pinos GPIO para CE e CSN) + * para cada módulo NRF24 individualmente. Isso substitui as macros globais anteriores + * que assumiam um único NRF. + * + * As configurações de pinos e instâncias SPI são agora definidas de forma mais organizada, + * permitindo a fácil alocação de recursos para cada NRF. As definições aqui são exemplos + * e devem ser ajustadas para refletir a pinagem e os periféricos SPI utilizados em seu hardware específico. + * + * Contexto e Metodologia: + * - **Manutenção da Lógica Original**: Os valores e nomes dos registradores NRF24 e comandos + * foram preservados para garantir compatibilidade e aderência à folha de dados do módulo. + * - **Modularidade e Escalabilidade**: A nova estrutura facilita o gerenciamento de múltiplos + * módulos NRF24, tornando o código mais legível e escalável para cenários mais complexos. + * - **Pragmatismo**: Fornece um template claro para a definição de hardware, exigindo apenas + * ajustes nos valores específicos para o seu setup, sem alterar a arquitetura da biblioteca. + * - **Abstração**: Move a complexidade das definições de hardware para um local centralizado, + * permitindo que as camadas superiores (`NRF24_CORE` e `COMM`) operem com instâncias abstratas do NRF. + */ + +#ifndef NRF24_DEF_HPP +#define NRF24_DEF_HPP + +#ifdef __cplusplus +extern "C" { +#endif + +#include "stm32f4xx_hal.h" // Inclui o HAL da STM32 para tipos como SPI_HandleTypeDef e GPIO_TypeDef + +// --- Definições de Registradores NRF24L01+ (Mantidas do original) --- +// Comandos +#define R_REGISTER 0x00U +#define W_REGISTER 0x20U +#define R_RX_PAYLOAD 0x61U +#define W_TX_PAYLOAD 0xA0U +#define FLUSH_TX 0xE1U +#define FLUSH_RX 0xE2U +#define REUSE_TX_PL 0xE3U +#define ACTIVATE 0x50U +#define R_RX_PL_WID 0x60U +#define NOP 0xFFU + +// Registradores +#define CONFIG 0x00U +#define EN_AA 0x01U +#define EN_RXADDR 0x02U +#define SETUP_AW 0x03U +#define SETUP_RETR 0x04U +#define RF_CH 0x05U +#define RF_SETUP 0x06U +#define STATUS 0x07U +#define OBSERVE_TX 0x08U +#define CD 0x09U +#define RX_ADDR_P0 0x0AU +#define RX_ADDR_P1 0x0BU +#define RX_ADDR_P2 0x0CU +#define RX_ADDR_P3 0x0DU +#define RX_ADDR_P4 0x0EU +#define RX_ADDR_P5 0x0FU +#define TX_ADDR 0x10U +#define RX_PW_P0 0x11U +#define RX_PW_P1 0x12U +#define RX_PW_P2 0x13U +#define RX_PW_P3 0x14U +#define RX_PW_P4 0x15U +#define RX_PW_P5 0x16U +#define FIFO_STATUS 0x17U +#define DYNPD 0x1CU +#define FEATURE 0x1DU + +// Bits dos Registradores +#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 PLL_LOCK 4 +#define RF_DR_LOW 5 +#define RF_DR_HIGH 3 +#define RF_PWR 1 +#define RX_DR 6 +#define TX_DS 5 +#define MAX_RT 4 +#define RX_P_NO 1 +#define TX_FULL 0 +#define APL 2 +#define RPD 0 +#define TX_REUSE 6 +#define TX_FIFO_FULL 5 +#define TX_EMPTY 4 +#define RX_FIFO_FULL 1 +#define RX_FIFO_EMPTY 0 +#define DPL_P5 5 +#define DPL_P4 4 +#define DPL_P3 3 +#define DPL_P2 2 +#define DPL_P1 1 +#define EN_DPL 2 +#define EN_ACK_PAY 1 +#define EN_DYN_ACK 0 + +// --- Definições de Hardware para Múltiplos NRF24L01+ --- + +/** + * @brief Estrutura para configurar o hardware de um módulo NRF24L01+ individual. + * @note Esta estrutura substitui as macros globais de pinagem e handle SPI. + * Permite que cada instância de NRF24 tenha sua própria configuração de pinos CE/CSN + * e um ponteiro para a instância SPI do HAL. + */ +typedef struct { + SPI_HandleTypeDef* hspi; ///< Ponteiro para o handle SPI do HAL (ex: &hspi1) + GPIO_TypeDef* ce_port; ///< Porta GPIO para o pino CE (Chip Enable) + uint16_t ce_pin; ///< Número do pino CE + GPIO_TypeDef* csn_port; ///< Porta GPIO para o pino CSN (Chip Select Not) + uint16_t csn_pin; ///< Número do pino CSN + uint32_t spi_timeout_ms; ///< Tempo limite em ms para operações SPI +} NRF24_Hardware_Config_t; + +// --- Configurações de Hardware de Exemplo para Robô e Torre --- +// As definições abaixo são exemplos e DEVEM SER ADAPTADAS à pinagem real do seu hardware. +// Você pode ter diferentes handles SPI (ex: hspi1, hspi2) ou usar o mesmo com CSNs distintos. + +// Robô (Receiver): 1 NRF para RX, 1 NRF para TX +// NRF de Recepção de Comandos (Robô) +// Alteração: Define a configuração de hardware para o NRF de RX do robô. +// Este NRF receberá comandos da torre. +#define ROBOT_RX_NRF_HW_CONFIG { &hspi1, GPIOB, GPIO_PIN_1, GPIOA, GPIO_PIN_4, 100 } // Exemplo: SPI1, CE=PB1, CSN=PA4 + +// NRF de Transmissão de Telemetria (Robô) +// Alteração: Define a configuração de hardware para o NRF de TX do robô. +// Este NRF enviará dados de telemetria para a torre. +#define ROBOT_TX_NRF_HW_CONFIG { &hspi2, GPIOC, GPIO_PIN_2, GPIOD, GPIO_PIN_3, 100 } // Exemplo: SPI2, CE=PC2, CSN=PD3 + +// Torre (Transmitter): 1 NRF para RX de telemetria, 5 NRFs para TX de comandos +// NRF de Recepção de Telemetria (Torre) +// Alteração: Define a configuração de hardware para o NRF de RX da torre. +// Este NRF receberá telemetria de todos os robôs. +#define TOWER_TELEMETRY_RX_NRF_HW_CONFIG { &hspi1, GPIOA, GPIO_PIN_1, GPIOB, GPIO_PIN_0, 100 } // Exemplo: SPI1, CE=PA1, CSN=PB0 + +// NRFs de Transmissão de Comandos (Torre) - Um para cada robô (até 5) +// Alteração: Define um array de configurações de hardware para os 5 NRFs de TX da torre. +// Cada NRF neste array será responsável por enviar comandos para um robô específico. +// Os handles SPI e pinos CE/CSN devem ser únicos para cada NRF físico. +#define TOWER_COMMAND_TX_NRF_HW_CONFIGS { \ + { &hspi2, GPIOC, GPIO_PIN_1, GPIOD, GPIO_PIN_1, 100 }, /* Robo 1 */ \ + { &hspi3, GPIOE, GPIO_PIN_2, GPIOF, GPIO_PIN_2, 100 }, /* Robo 2 */ \ + { &hspi4, GPIOA, GPIO_PIN_5, GPIOB, GPIO_PIN_6, 100 }, /* Robo 3 */ \ + { &hspi5, GPIOC, GPIO_PIN_7, GPIOD, GPIO_PIN_8, 100 }, /* Robo 4 */ \ + { &hspi6, GPIOE, GPIO_PIN_9, GPIOF, GPIO_PIN_10, 100 } /* Robo 5 */ \ +} + +// Endereços de Comunicação (Mantidos do original, com pequenas adaptações para clareza) +// Alteração: Os endereços agora são tipicamente usados para configurar as instâncias NRF24_Driver. +// ADDR_BASE_LISTEN: Endereço base para escuta da torre para telemetria dos robôs. +// Os robôs transmitirão para este endereço quando enviarem telemetria. +#define ADDR_BASE_LISTEN {0xAA, 0xAA, 0xAA, 0xAA, 0xAA} + +// ADDR_ROBOT_LISTEN: Endereços de escuta para cada robô. +// A torre transmitirá para o endereço específico de cada robô. +// O robô receberá neste endereço. +#define ADDR_ROBOT_LISTEN_0 {0xBB, 0xBB, 0xBB, 0xBB, 0xBB} // Robô 0 (Exemplo, se houver um robô 0) +#define ADDR_ROBOT_LISTEN_1 {0xC1, 0xC1, 0xC1, 0xC1, 0xC1} // Robô 1 +#define ADDR_ROBOT_LISTEN_2 {0xC2, 0xC2, 0xC2, 0xC2, 0xC2} // Robô 2 +#define ADDR_ROBOT_LISTEN_3 {0xC3, 0xC3, 0xC3, 0xC3, 0xC3} // Robô 3 +#define ADDR_ROBOT_LISTEN_4 {0xC4, 0xC4, 0xC4, 0xC4, 0xC4} // Robô 4 +#define ADDR_ROBOT_LISTEN_5 {0xC5, 0xC5, 0xC5, 0xC5, 0xC5} // Robô 5 + +// Array de conveniência para acessar os endereços dos robôs por ID +// Alteração: Cria um array para acessar facilmente os endereços de escuta dos robôs. +// Útil para a torre ao enviar comandos para um robô específico. +static const uint8_t ROBOT_LISTEN_ADDRESSES[][5] = { + ADDR_ROBOT_LISTEN_0, + ADDR_ROBOT_LISTEN_1, + ADDR_ROBOT_LISTEN_2, + ADDR_ROBOT_LISTEN_3, + ADDR_ROBOT_LISTEN_4, + ADDR_ROBOT_LISTEN_5 +}; + +// Tamanho do Payload (Mantido do original) +#define MAX_PAYLOAD_SIZE 32U + +#ifdef __cplusplus +} +#endif + +#endif // NRF24_DEF_HPP \ No newline at end of file diff --git a/NRF24_HAL.cpp b/NRF24_HAL.cpp index e6ea6c5..146c7be 100644 --- a/NRF24_HAL.cpp +++ b/NRF24_HAL.cpp @@ -1,34 +1,74 @@ -// Comm/NRF24_HAL.cpp -#include // Atualizado caminho de inclusão +#include "NRF24_HAL.hpp" +#include "NRF24_DEF.hpp" // Para incluir definições como NRF24_HAL_Delay, se ainda forem usadas globalmente ou para o construtor. -void NRF24_HAL_CE_Enable(void) { - HAL_GPIO_WritePin(NRF24_CE_PORT, NRF24_CE_PIN, GPIO_PIN_SET); +// O arquivo NRF24_HAL.cpp agora implementa os métodos da classe NRF24_Hardware. + +// Construtor da classe NRF24_Hardware +// Este construtor inicializa a instância de hardware com os parâmetros específicos do NRF. +// Cada NRF terá seu próprio conjunto de pinos CE/CSN e, potencialmente, seu próprio handle SPI. +NRF24_Hardware::NRF24_Hardware(SPI_HandleTypeDef* hspi_handle, + GPIO_TypeDef* ce_gpio_port, uint16_t ce_gpio_pin, + GPIO_TypeDef* csn_gpio_port, uint16_t csn_gpio_pin, + uint32_t spi_timeout) + : hspi(hspi_handle), + ce_port(ce_gpio_port), + ce_pin(ce_gpio_pin), + csn_port(csn_gpio_port), + csn_pin(csn_gpio_pin), + spi_timeout_ms(spi_timeout) +{ + // O construtor apenas armazena os parâmetros. + // A inicialização real do NRF (registros, modos) será feita na camada NRF24_Driver. +} + +// Habilita o pino CE (Chip Enable) do NRF24, usado para ativar os modos TX ou RX. +void NRF24_Hardware::CE_Enable() { + HAL_GPIO_WritePin(ce_port, ce_pin, GPIO_PIN_SET); +} + +// Desabilita o pino CE (Chip Enable) do NRF24. +void NRF24_Hardware::CE_Disable() { + HAL_GPIO_WritePin(ce_port, ce_pin, GPIO_PIN_RESET); } -void NRF24_HAL_CE_Disable(void) { - HAL_GPIO_WritePin(NRF24_CE_PORT, NRF24_CE_PIN, GPIO_PIN_RESET); +// Seleciona o NRF24 para comunicação SPI, ativando o pino CSN (Chip Select Not). +void NRF24_Hardware::CS_Select() { + HAL_GPIO_WritePin(csn_port, csn_pin, GPIO_PIN_RESET); } -void NRF24_HAL_CS_Select(void) { - HAL_GPIO_WritePin(NRF24_CSN_PORT, NRF24_CSN_PIN, GPIO_PIN_RESET); +// Desseleciona o NRF24 da comunicação SPI, desativando o pino CSN. +void NRF24_Hardware::CS_UnSelect() { + HAL_GPIO_WritePin(csn_port, csn_pin, GPIO_PIN_SET); } -void NRF24_HAL_CS_UnSelect(void) { - HAL_GPIO_WritePin(NRF24_CSN_PORT, NRF24_CSN_PIN, GPIO_PIN_SET); +// Transmite dados via SPI para o NRF24. +HAL_StatusTypeDef NRF24_Hardware::SPI_Transmit(uint8_t* pData, uint16_t Size) { + // Agora usa o handle SPI e o timeout específicos desta instância de hardware. + return HAL_SPI_Transmit(hspi, pData, Size, spi_timeout_ms); } -HAL_StatusTypeDef NRF24_HAL_SPI_Transmit(uint8_t *pData, uint16_t Size, uint32_t Timeout) { - return HAL_SPI_Transmit(NRF24_SPI, pData, Size, Timeout); +// Recebe dados via SPI do NRF24. +HAL_StatusTypeDef NRF24_Hardware::SPI_Receive(uint8_t* pData, uint16_t Size) { + // Agora usa o handle SPI e o timeout específicos desta instância de hardware. + return HAL_SPI_Receive(hspi, pData, Size, spi_timeout_ms); } -HAL_StatusTypeDef NRF24_HAL_SPI_Receive(uint8_t *pData, uint16_t Size, uint32_t Timeout) { - return HAL_SPI_Receive(NRF24_SPI, pData, Size, Timeout); +// Transmite e recebe dados simultaneamente via SPI (full-duplex) do NRF24. +HAL_StatusTypeDef NRF24_Hardware::SPI_TransmitReceive(uint8_t* pTxData, uint8_t* pRxData, uint16_t Size) { + // Agora usa o handle SPI e o timeout específicos desta instância de hardware. + return HAL_SPI_TransmitReceive(hspi, pTxData, pRxData, Size, spi_timeout_ms); } -void NRF24_HAL_Delay(uint32_t milliseconds) { - HAL_Delay(milliseconds); +// Função de atraso em milissegundos. +// Esta função pode ser uma função global ou um método da classe se o tick for gerenciado pela instância. +// Por simplicidade, mantida como função global aqui ou pode ser um método estático. +void NRF24_Hardware::Delay(uint32_t Delay_ms) { + HAL_Delay(Delay_ms); } -uint32_t NRF24_HAL_GetTick(void) { +// Retorna o valor do tick do sistema, usado para temporização. +// Esta função pode ser uma função global ou um método da classe se o tick for gerenciado pela instância. +// Por simplicidade, mantida como função global aqui ou pode ser um método estático. +uint32_t NRF24_Hardware::GetTick() { return HAL_GetTick(); } \ No newline at end of file diff --git a/NRF24_HAL.hpp b/NRF24_HAL.hpp index ec5cde1..d21a365 100644 --- a/NRF24_HAL.hpp +++ b/NRF24_HAL.hpp @@ -1,26 +1,102 @@ -// Comm/NRF24_HAL.hpp -#ifndef NRF24_HAL_HPP_ // Alterada guarda de inclusão -#define NRF24_HAL_HPP_ // Alterada guarda de inclusão +#ifndef __NRF24_HAL_HPP +#define __NRF24_HAL_HPP -#include // Atualizado caminho de inclusão +#include "main.h" // Inclui o cabeçalho principal do STM32 HAL para acesso às funções e tipos de dados -#ifdef __cplusplus // Adicionado bloco extern "C" -extern "C" { -#endif +// Removemos as definições de pinos e handle SPI globais (NRF24_CE_PORT, NRF24_SPI_HANDLE, etc.) +// Estas configurações agora serão encapsuladas dentro da classe NRF24_Hardware, +// permitindo múltiplas instâncias do NRF24 com diferentes configurações de hardware. -void NRF24_HAL_CE_Enable(void); -void NRF24_HAL_CE_Disable(void); -void NRF24_HAL_CS_Select(void); -void NRF24_HAL_CS_UnSelect(void); +// Classe NRF24_Hardware +// Encapsula as operações de hardware de baixo nível para um único módulo NRF24L01+. +// Isso permite que o NRF24_CORE (e, por sua vez, a camada COMM) gerencie múltiplas +// instâncias de NRFs, cada uma com sua própria configuração de pinos e SPI. +class NRF24_Hardware { +private: + SPI_HandleTypeDef* hspi; // Ponteiro para o handle SPI do STM32 HAL + GPIO_TypeDef* ce_port; // Porta GPIO para o pino CE (Chip Enable) + uint16_t ce_pin; // Número do pino CE + GPIO_TypeDef* csn_port; // Porta GPIO para o pino CSN (Chip Select Not) + uint16_t csn_pin; // Número do pino CSN + uint32_t spi_timeout_ms; // Tempo limite para operações SPI em milissegundos -HAL_StatusTypeDef NRF24_HAL_SPI_Transmit(uint8_t *pData, uint16_t Size, uint32_t Timeout); -HAL_StatusTypeDef NRF24_HAL_SPI_Receive(uint8_t *pData, uint16_t Size, uint32_t Timeout); +public: + // Construtor da classe NRF24_Hardware + // Inicializa a instância de hardware com as configurações específicas do NRF. + // @param spi_handle: Ponteiro para o handle SPI (ex: &hspi1). + // @param ce_gpio_port: Ponteiro para a porta GPIO do pino CE (ex: GPIOB). + // @param ce_gpio_pin: Número do pino CE (ex: GPIO_PIN_1). + // @param csn_gpio_port: Ponteiro para a porta GPIO do pino CSN (ex: GPIOA). + // @param csn_gpio_pin: Número do pino CSN (ex: GPIO_PIN_4). + // @param timeout_ms: Tempo limite para operações SPI em milissegundos. + NRF24_Hardware(SPI_HandleTypeDef* spi_handle, GPIO_TypeDef* ce_gpio_port, uint16_t ce_gpio_pin, + GPIO_TypeDef* csn_gpio_port, uint16_t csn_gpio_pin, uint32_t timeout_ms) + : hspi(spi_handle), ce_port(ce_gpio_port), ce_pin(ce_gpio_pin), + csn_port(csn_gpio_port), csn_pin(csn_gpio_pin), spi_timeout_ms(timeout_ms) { + // O corpo do construtor pode estar vazio se a inicialização for feita na lista de inicialização de membros. + } -void NRF24_HAL_Delay(uint32_t milliseconds); -uint32_t NRF24_HAL_GetTick(void); + // Métodos para controlar o pino CE (Chip Enable) + // Anteriormente: NRF24_HAL_CE_Enable() e NRF24_HAL_CE_Disable() + // Alteração: Tornados métodos da classe, utilizando os membros privados da instância. + void CE_Enable() { + HAL_GPIO_WritePin(ce_port, ce_pin, GPIO_PIN_SET); // Seta o pino CE (habilita o chip NRF) + } -#ifdef __cplusplus -} -#endif + void CE_Disable() { + HAL_GPIO_WritePin(ce_port, ce_pin, GPIO_PIN_RESET); // Reseta o pino CE (desabilita o chip NRF) + } -#endif \ No newline at end of file + // Métodos para controlar o pino CSN (Chip Select Not) + // Anteriormente: NRF24_HAL_CS_Select() e NRF24_HAL_CS_UnSelect() + // Alteração: Tornados métodos da classe, utilizando os membros privados da instância. + void CS_Select() { + HAL_GPIO_WritePin(csn_port, csn_pin, GPIO_PIN_RESET); // Reseta o pino CSN (seleciona o chip NRF) + } + + void CS_UnSelect() { + HAL_GPIO_WritePin(csn_port, csn_pin, GPIO_PIN_SET); // Seta o pino CSN (desseleciona o chip NRF) + } + + // Métodos para comunicação SPI + // Anteriormente: NRF24_HAL_SPI_Transmit(), NRF24_HAL_SPI_Receive(), NRF24_HAL_SPI_TransmitReceive() + // Alteração: Tornados métodos da classe, utilizando o handle SPI e o timeout da instância. + // As funções HAL_SPI_... são bloqueantes com timeout. + + // Transmite dados via SPI + // @param pData: Ponteiro para o buffer de dados a ser transmitido. + // @param Size: Número de bytes a serem transmitidos. + HAL_StatusTypeDef SPI_Transmit(uint8_t* pData, uint16_t Size) { + return HAL_SPI_Transmit(hspi, pData, Size, spi_timeout_ms); + } + + // Recebe dados via SPI + // @param pData: Ponteiro para o buffer onde os dados recebidos serão armazenados. + // @param Size: Número de bytes a serem recebidos. + HAL_StatusTypeDef SPI_Receive(uint8_t* pData, uint16_t Size) { + return HAL_SPI_Receive(hspi, pData, Size, spi_timeout_ms); + } + + // Transmite e recebe dados simultaneamente via SPI + // @param pTxData: Ponteiro para o buffer de dados a ser transmitido. + // @param pRxData: Ponteiro para o buffer onde os dados recebidos serão armazenados. + // @param Size: Número de bytes a serem transmitidos/recebidos. + HAL_StatusTypeDef SPI_TransmitReceive(uint8_t* pTxData, uint8_t* pRxData, uint16_t Size) { + return HAL_SPI_TransmitReceive(hspi, pTxData, pRxData, Size, spi_timeout_ms); + } + + // Métodos para atraso e obtenção de tick + // Anteriormente: NRF24_HAL_Delay(), NRF24_HAL_GetTick() + // Alteração: Mantidos como métodos estáticos ou podem ser chamados diretamente se não precisarem de membros da classe. + // Para manter a consistência e a possibilidade de futura injeção de dependência de tempo, + // podemos mantê-los como métodos, mesmo que sejam apenas wrappers para funções HAL. + static void Delay(uint32_t Delay) { + HAL_Delay(Delay); + } + + static uint32_t GetTick() { + return HAL_GetTick(); + } +}; + +#endif // __NRF24_HAL_HPP \ No newline at end of file