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..25d1e07 --- /dev/null +++ b/COMM.cpp @@ -0,0 +1,269 @@ +#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) +{ + // Inicializa o array de ponteiros command_tx_nrf para nullptr + for (int i = 0; i < MAX_ROBOTS; ++i) { + command_tx_nrf[i] = nullptr; + } +} + +// 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]; + } +} + +// 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 { + 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; +} + +// 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); + } + } + } + } + // 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); + } + } + } + } +} + +// 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)); + } + // 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)); + } + 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)); + } + // 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)); + } + return false; +} + +// 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) +} + +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; +} + +// 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 CommManager::SetVSSSCallback(comm_vsss_packet_handler_t handler) { + vsss_handler = handler; // Atribui o handler fornecido ao membro da classe +} + +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.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..6b5e760 --- /dev/null +++ b/COMM.hpp @@ -0,0 +1,154 @@ +#ifndef COMM_HPP_ // Guarda de inclusão (mantida) +#define COMM_HPP_ // Guarda de inclusão (mantida) + +#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 + +// Definições de tipos existentes (mantidas) +typedef enum { + COMM_ROBOT_TYPE_UNDEFINED, + COMM_ROBOT_TYPE_SSL, + COMM_ROBOT_TYPE_VSSS +} comm_robot_type_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 (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); + +// **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 + +// **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, + 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); +void Comm_Register_VSSS_Packet_Handler(comm_vsss_packet_handler_t callback); +void Comm_Register_DebugText_Packet_Handler(comm_debug_text_handler_t callback); + +// Função para processar pacotes recebidos (assinatura mantida, implementação interna muda) +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.c deleted file mode 100644 index 87bb713..0000000 --- a/NRF24_CORE.c +++ /dev/null @@ -1,292 +0,0 @@ -#include -#include -#include - -void nrf24_WriteReg(uint8_t Reg, uint8_t Data) { - 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(); -} - -void nrf24_WriteRegMulti(uint8_t Reg, uint8_t *data, uint8_t size) { - 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(); -} - -uint8_t nrf24_ReadReg(uint8_t Reg) { - 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(); - - return data; -} - -void nrf24_ReadReg_Multi(uint8_t Reg, uint8_t *data, uint8_t size) { - 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(); -} - -void nrfsendCmd(uint8_t cmd) { - NRF24_HAL_CS_Select(); - NRF24_HAL_SPI_Transmit(&cmd, 1, 100); - NRF24_HAL_CS_UnSelect(); -} - - -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)); - - - uint8_t rx_addr_p0_def[5] = {0xE7, 0xE7, 0xE7, 0xE7, 0xE7}; - nrf24_WriteRegMulti(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); - 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); -} - - -void nrf24_clear_interrupts(void) { - uint8_t status = nrf24_ReadReg(STATUS); - status |= (1 << RX_DR_BIT) | (1 << TX_DS_BIT) | (1 << MAX_RT_BIT); - nrf24_WriteReg(STATUS, status); -} - -void nrf24_flush_tx(void) { - nrfsendCmd(FLUSH_TX); -} - -void nrf24_flush_rx(void) { - nrfsendCmd(FLUSH_RX); -} - - -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); -} - - -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); - - uint8_t config = nrf24_ReadReg(CONFIG); - config &= ~(1 << 0); - config |= (1 << 1); - config |= (1 << 3); - config |= (1 << 2); - nrf24_WriteReg(CONFIG, config); - - NRF24_HAL_Delay(2); - - NRF24_HAL_CE_Enable(); - NRF24_HAL_Delay(1); -} - -uint8_t NRF24_Transmit(uint8_t *data, uint8_t size) { - 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(); - - - uint32_t start_tick = NRF24_HAL_GetTick(); - uint8_t status_reg; - while (1) { - status_reg = nrf24_ReadReg(STATUS); - - if (status_reg & ((1 << TX_DS_BIT) | (1 << MAX_RT_BIT))) { - break; - } - if (NRF24_HAL_GetTick() - start_tick > 200) { - nrf24_flush_tx(); - return 0; - } - } - - - - nrf24_WriteReg(STATUS, status_reg | (1 << TX_DS_BIT) | (1 << MAX_RT_BIT)); - - if (status_reg & (1 << TX_DS_BIT)) { - return 1; - - } else if (status_reg & (1 << MAX_RT_BIT)) { - nrf24_flush_tx(); - return 0; - } - return 0; -} - - -void NRF24_RxMode(uint8_t *AddressPipe1, uint8_t AddressPipe2LSB, uint8_t channel) { - NRF24_HAL_CE_Disable(); - NRF24_HAL_Delay(5); - - nrf24_clear_interrupts(); - nrf24_flush_rx(); - nrf24_flush_tx(); - - 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); - - - uint8_t config = nrf24_ReadReg(CONFIG); - config |= (1 << 0); - config |= (1 << 1); - config |= (1 << 3); - config |= (1 << 2); - nrf24_WriteReg(CONFIG, config); - - NRF24_HAL_Delay(2); - - NRF24_HAL_CE_Enable(); - NRF24_HAL_Delay(1); -} - -uint8_t isDataAvailable(uint8_t pipenum) { - uint8_t status = nrf24_ReadReg(STATUS); - 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) { - uint8_t cmdtosend; - - NRF24_HAL_CS_Select(); - 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)); - -} - - -void NRF24_ReadAll(uint8_t *data) { - uint8_t j = 0; - - for (int i = 0; i <= 0x09; i++) { - *(data + j++) = nrf24_ReadReg(i); - } - - nrf24_ReadReg_Multi(RX_ADDR_P0, (data + j), 5); - j += 5; - - nrf24_ReadReg_Multi(RX_ADDR_P1, (data + j), 5); - 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); - - nrf24_ReadReg_Multi(TX_ADDR, (data + j), 5); - j += 5; - - for (int i = 0x11; i <= 0x16; i++) { - *(data + j++) = nrf24_ReadReg(i); - } - - *(data + j++) = nrf24_ReadReg(FIFO_STATUS); - *(data + j++) = nrf24_ReadReg(DYNPD); - *(data + j++) = nrf24_ReadReg(FEATURE); - -} diff --git a/NRF24_CORE.cpp b/NRF24_CORE.cpp new file mode 100644 index 0000000..6b4f1e8 --- /dev/null +++ b/NRF24_CORE.cpp @@ -0,0 +1,329 @@ +#include // Inclui o cabeçalho da nova classe NRF24_Driver +#include // Inclui o cabeçalho da classe NRF24_Hardware refatorada +#include + +// 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; + + 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`. +} + +// 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; + + 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`. +} + +// 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; + + 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; +} + +// 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; + + 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`. +} + +// 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`. + + // 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}; + writeRegisterMulti(RX_ADDR_P0, rx_addr_p0_def, 5); + uint8_t tx_addr_def[5] = {0xE7, 0xE7, 0xE7, 0xE7, 0xE7}; + writeRegisterMulti(TX_ADDR, tx_addr_def, 5); + uint8_t rx_addr_p1_def[5] = {0xC2, 0xC2, 0xC2, 0xC2, 0xC2}; + 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`. +} + +// 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); + writeRegister(STATUS, status); // Alterado: Chama o método `this->writeRegister`. +} + +// 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`. +} + +// 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`. +} + +// 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`. + + 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 = 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`. + + hardware.Delay(2); // Alterado: Chama o método Delay da instância `hardware`. + + 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`. +} + +// 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; + 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 = hardware.GetTick(); // Alterado: Chama o método GetTick da instância `hardware`. + uint8_t status_reg; + while (1) { + status_reg = readRegister(STATUS); // Alterado: Chama o método `this->readRegister`. + + 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 (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; + } + } + + 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; // Transmissão bem-sucedida + } else if (status_reg & (1 << MAX_RT_BIT)) { + flushTx(); // Alterado: Chama o método `this->flushTx` em caso de retransmissões máximas. + return 0; // Falha na transmissão + } + 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`. + + clearInterrupts(); // Alterado: Chama o método `this->clearInterrupts`. + flushRx(); // Alterado: Chama o método `this->flushRx`. + flushTx(); // Alterado: Chama o método `this->flushTx`. + + 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 + + // 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`. + + hardware.Delay(2); // Alterado: Chama o método Delay da instância `hardware`. + + 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`. +} + +// 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; +} + +// 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; + + hardware.CS_Select(); // Alterado: Chama o método CS_Select da instância `hardware`. + cmdtosend = R_RX_PAYLOAD; + 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. +} + +// 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++) = readRegister(i); // Alterado: Chama o método `this->readRegister`. + } + + readRegisterMulti(RX_ADDR_P0, (data + j), 5); // Alterado: Chama o método `this->readRegisterMulti`. + j += 5; + + readRegisterMulti(RX_ADDR_P1, (data + j), 5); // Alterado: Chama o método `this->readRegisterMulti`. + j += 5; + + *(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`. + + readRegisterMulti(TX_ADDR, (data + j), 5); // Alterado: Chama o método `this->readRegisterMulti`. + j += 5; + + for (int i = 0x11; i <= 0x16; i++) { + *(data + j++) = readRegister(i); // Alterado: Chama o método `this->readRegister`. + } + + *(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.h b/NRF24_CORE.h deleted file mode 100644 index 58b1c21..0000000 --- a/NRF24_CORE.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef NRF24_CORE_H_ -#define NRF24_CORE_H_ - -#include -#include - - -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); - - -void nrf24_reset_registers(void); -void nrf24_clear_interrupts(void); -void nrf24_flush_tx(void); -void nrf24_flush_rx(void); - -void NRF24_Init(void); - -void NRF24_TxMode(uint8_t *Address, uint8_t channel); -uint8_t NRF24_Transmit(uint8_t *data, uint8_t size); - - -void NRF24_RxMode(uint8_t *AddressPipe1, uint8_t AddressPipe2LSB, uint8_t channel); - -uint8_t isDataAvailable(uint8_t pipenum); -void NRF24_Receive(uint8_t *data); - -void NRF24_ReadAll(uint8_t *data); - -#endif diff --git a/NRF24_CORE.hpp b/NRF24_CORE.hpp new file mode 100644 index 0000000..f0f8a38 --- /dev/null +++ b/NRF24_CORE.hpp @@ -0,0 +1,300 @@ +#ifndef NRF24_CORE_HPP_ +#define NRF24_CORE_HPP_ + +#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 + +// 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; + +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; + +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); + + /** + * @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); + + /** + * @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(); + + /** + * @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); + + /** + * @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); + + /** + * @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); + + /** + * @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); + + /** + * @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.h b/NRF24_DEF.h deleted file mode 100644 index 42229c2..0000000 --- a/NRF24_DEF.h +++ /dev/null @@ -1,71 +0,0 @@ -#ifndef NRF24_DEF_H_ -#define NRF24_DEF_H_ - -#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 diff --git a/NRF24_DEF.hpp b/NRF24_DEF.hpp new file mode 100644 index 0000000..0e2f196 --- /dev/null +++ b/NRF24_DEF.hpp @@ -0,0 +1,213 @@ +/** + * @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.c b/NRF24_HAL.c deleted file mode 100644 index d87afd5..0000000 --- a/NRF24_HAL.c +++ /dev/null @@ -1,33 +0,0 @@ -#include - -void NRF24_HAL_CE_Enable(void) { - HAL_GPIO_WritePin(NRF24_CE_PORT, NRF24_CE_PIN, GPIO_PIN_SET); -} - -void NRF24_HAL_CE_Disable(void) { - HAL_GPIO_WritePin(NRF24_CE_PORT, NRF24_CE_PIN, GPIO_PIN_RESET); -} - -void NRF24_HAL_CS_Select(void) { - HAL_GPIO_WritePin(NRF24_CSN_PORT, NRF24_CSN_PIN, GPIO_PIN_RESET); -} - -void NRF24_HAL_CS_UnSelect(void) { - HAL_GPIO_WritePin(NRF24_CSN_PORT, NRF24_CSN_PIN, GPIO_PIN_SET); -} - -HAL_StatusTypeDef NRF24_HAL_SPI_Transmit(uint8_t *pData, uint16_t Size, uint32_t Timeout) { - return HAL_SPI_Transmit(NRF24_SPI, pData, Size, Timeout); -} - -HAL_StatusTypeDef NRF24_HAL_SPI_Receive(uint8_t *pData, uint16_t Size, uint32_t Timeout) { - return HAL_SPI_Receive(NRF24_SPI, pData, Size, Timeout); -} - -void NRF24_HAL_Delay(uint32_t milliseconds) { - HAL_Delay(milliseconds); -} - -uint32_t NRF24_HAL_GetTick(void) { - return HAL_GetTick(); -} diff --git a/NRF24_HAL.cpp b/NRF24_HAL.cpp new file mode 100644 index 0000000..146c7be --- /dev/null +++ b/NRF24_HAL.cpp @@ -0,0 +1,74 @@ +#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. + +// 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); +} + +// 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); +} + +// 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); +} + +// 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); +} + +// 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); +} + +// 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); +} + +// 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); +} + +// 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.h b/NRF24_HAL.h deleted file mode 100644 index 9895cc2..0000000 --- a/NRF24_HAL.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef NRF24_HAL_H_ -#define NRF24_HAL_H_ - -#include - -void NRF24_HAL_CE_Enable(void); -void NRF24_HAL_CE_Disable(void); -void NRF24_HAL_CS_Select(void); -void NRF24_HAL_CS_UnSelect(void); - -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); - -void NRF24_HAL_Delay(uint32_t milliseconds); -uint32_t NRF24_HAL_GetTick(void); - -#endif diff --git a/NRF24_HAL.hpp b/NRF24_HAL.hpp new file mode 100644 index 0000000..d21a365 --- /dev/null +++ b/NRF24_HAL.hpp @@ -0,0 +1,102 @@ +#ifndef __NRF24_HAL_HPP +#define __NRF24_HAL_HPP + +#include "main.h" // Inclui o cabeçalho principal do STM32 HAL para acesso às funções e tipos de dados + +// 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. + +// 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 + +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. + } + + // 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) + } + + void CE_Disable() { + HAL_GPIO_WritePin(ce_port, ce_pin, GPIO_PIN_RESET); // Reseta o pino CE (desabilita o chip NRF) + } + + // 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 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.