#include #include #include #include "commons.hpp" #include "logging.hpp" #include "spi.hpp" /* * reserve PB11-PB15 for SPI2 */ // STM32VL-Discovery green led - PC9 #define BTN_PORT GPIOA #define LED_PORT GPIOC #define LED1_PIN GPIO_PIN_8 #define LED2_PIN GPIO_PIN_9 #define BTN_PIN GPIO_PIN_0 #define LED_PORT_CLK_ENABLE __HAL_RCC_GPIOC_CLK_ENABLE #define LoRa_RESET_Pin GPIO_PIN_4 #define LoRa_RESET_GPIO_Port GPIOC #define LoRa_CS_Pin GPIO_PIN_5 #define LoRa_CS_GPIO_Port GPIOC #include "rfm95.hpp" extern uint8_t LoRa_buff[RH_RF95_FIFO_SIZE]; extern SPI_HandleTypeDef hspi1; void print_version(void) { log::info("running PentaTrack v0.1.3"); } void print_help(void); void loglevel_error(void) { log::set_loglevel(LogLevel::ERROR); } void loglevel_info(void) { log::set_loglevel(LogLevel::INFO); } void loglevel_debug(void) { log::set_loglevel(LogLevel::DEBUG); } template class cmd_holder { public: typedef void (*functionPointerType)(void); using command_t = std::tuple; template using command_array_t = std::array; template constexpr cmd_holder(Args... command_list) : commands{std::forward(command_list)...} {} constexpr functionPointerType get_func(std::string_view message) const { for (const auto &[cmd_name, cmd_help, func] : commands) { if (message == cmd_name) { return func; } } return nullptr; } void print_help() const { log::info("Listing available commands:"); for (const auto &[cmd_name, cmd_help, func] : commands) { log::info("\t", cmd_name, " - ", cmd_help); } } private: std::array commands; }; static bool updated_main_buf = false; static buffer main_buffer; void print_buf(void) { main_buffer.print(); } class cmd_handler { public: static constexpr auto MaxCmdLength = 24; using array_t = std::array; using iterator_t = array_t::iterator; using const_iterator_t = array_t::const_iterator; constexpr cmd_handler() : symbols{}, iterator{symbols.begin()} {} static cmd_handler &get() { static auto c = cmd_handler{}; return c; }; void add_symbol(uint8_t symbol) { *iterator = symbol; iterator++; if (iterator == symbols.end()) { iterator = symbols.begin(); } } std::string_view get_current_cmd() const { return {reinterpret_cast(symbols.data()), static_cast( std::distance(symbols.begin(), const_iterator_t{iterator}))}; } bool exists() const { return commands.get_func(get_current_cmd()) != nullptr; } void execute() { const auto current_cmd = get_current_cmd(); log::debug("Try executing command: ", current_cmd); const auto func = commands.get_func(current_cmd); iterator = symbols.begin(); if (func == nullptr) { log::info("Unknown Command: ", current_cmd); log::info("Type 'help' to show available commands."); return; } func(); } void queue_execution() { ShouldExecute = true; } void run() { if (ShouldExecute) { execute(); ShouldExecute = false; } } void print_help_() const { commands.print_help(); } private: static constexpr cmd_holder<6> commands{ std::make_tuple("ver", "Prints current version.", &print_version), std::make_tuple("error", "Set LogLevel to Error.", &loglevel_error), std::make_tuple("info", "Set LogLevel to Info.", &loglevel_info), std::make_tuple("debug", "Set LogLevel to Debug.", &loglevel_debug), std::make_tuple("buf", "Prints gps uart buffer", &print_buf), std::make_tuple("help", "Prints available commands", &print_help)}; array_t symbols; iterator_t iterator; bool ShouldExecute = false; }; void print_help(void) { cmd_handler::get().print_help_(); } // This prevent name mangling for functions used in C/assembly files. extern "C" { void SysTick_Handler(void) { HAL_IncTick(); HAL_SYSTICK_IRQHandler(); } void USART2_IRQHandler(void) { HAL_UART_IRQHandler(&gps_interface::s_UARTHandle); HAL_UART_Receive_IT(&gps_interface::s_UARTHandle, uart_interface::get_buf(), 1); } void USART1_IRQHandler(void) { HAL_UART_IRQHandler(&uart_interface::s_UARTHandle); HAL_UART_Receive_IT(&uart_interface::s_UARTHandle, uart_interface::get_buf(), 1); } void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) { if (huart == &gps_interface::s_UARTHandle) { return; } const uint8_t value = *uart_interface::get_buf(); if (value == '\r') { cmd_handler::get().queue_execution(); HAL_GPIO_TogglePin(LED_PORT, LED2_PIN); return; } cmd_handler::get().add_symbol(value); } void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) { // const uint8_t value = *gps_interface::get_buf(); // gps_interface::write({reinterpret_cast(&value), 1}); } void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) { // log::debug("DMA Callback"); HAL_GPIO_WritePin(LED_PORT, LED1_PIN, GPIO_PIN_SET); if (main_buffer.copy_from(gps_interface::new_rx_buf, Size)) { log::debug("Copied to main buff"); updated_main_buf = true; } HAL_GPIO_WritePin(LED_PORT, LED1_PIN, GPIO_PIN_RESET); HAL_UARTEx_ReceiveToIdle_DMA(&gps_interface::s_UARTHandle, gps_interface::new_rx_buf.data(), gps_interface::new_rx_buf.size()); __HAL_DMA_DISABLE_IT(&gps_interface::s_DMAHandle, DMA_IT_HT); } /** * @brief This function handles DMA1 channel6 global interrupt. */ void DMA1_Channel6_IRQHandler(void) { /* USER CODE BEGIN DMA1_Channel6_IRQn 0 */ /* USER CODE END DMA1_Channel6_IRQn 0 */ HAL_DMA_IRQHandler(&gps_interface::s_DMAHandle); /* USER CODE BEGIN DMA1_Channel6_IRQn 1 */ /* USER CODE END DMA1_Channel6_IRQn 1 */ } } void initGPIO() { __HAL_RCC_GPIOC_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitTypeDef GPIO_Config2; GPIO_Config2.Mode = GPIO_MODE_INPUT; GPIO_Config2.Pull = GPIO_PULLDOWN; GPIO_Config2.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_Config2.Pin = BTN_PIN; GPIO_InitTypeDef GPIO_Config; GPIO_Config.Mode = GPIO_MODE_OUTPUT_PP; GPIO_Config.Pull = GPIO_NOPULL; GPIO_Config.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_Config.Pin = LED1_PIN | LED2_PIN; GPIO_InitTypeDef GPIO_ConfigSPI; GPIO_ConfigSPI.Mode = GPIO_MODE_OUTPUT_PP; // GPIO_ConfigSPI.Pull = GPIO_NOPULL; GPIO_ConfigSPI.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_ConfigSPI.Pin = LoRa_CS_Pin | LoRa_RESET_Pin; // bare metal init of led1: // volatile uint32_t* CRH = reinterpret_cast(0x40011000 + // 0x04); //*CRH |= 0x3; //*CRH &= (~0xC); HAL_GPIO_Init(LED_PORT, &GPIO_Config); HAL_GPIO_Init(BTN_PORT, &GPIO_Config2); HAL_GPIO_Init(LoRa_CS_GPIO_Port, &GPIO_ConfigSPI); // HAL_GPIO_WritePin(LoRa_CS_GPIO_Port, LoRa_CS_Pin, GPIO_PIN_SET); // HAL_GPIO_WritePin(LoRa_RESET_GPIO_Port, LoRa_RESET_Pin, // GPIO_PIN_SET); } extern "C" { #include void start_interrupt() { HAL_UARTEx_ReceiveToIdle_DMA(&gps_interface::s_UARTHandle, gps_interface::new_rx_buf.data(), gps_interface::new_rx_buf.size()); __HAL_DMA_DISABLE_IT(&gps_interface::s_DMAHandle, DMA_IT_HT); } } int main(void) { HAL_Init(); HAL_SYSTICK_Config(1); initGPIO(); if (!log::init()) { // toggle status led or something } log::set_loglevel(LogLevel::DEBUG); log::info("logging Initialized"); if (!MX_SPI1_Init()) { // toggle status led or something } if (!gps_interface::init()) { log::error("UART2 Initialization failed, needed for GPS"); } else { log::debug("Uart2 Initialized"); } HAL_GPIO_WritePin(LoRa_CS_GPIO_Port, LoRa_CS_Pin, GPIO_PIN_SET); HAL_GPIO_WritePin(LoRa_RESET_GPIO_Port, LoRa_RESET_Pin, GPIO_PIN_SET); HAL_Delay(1000); log::debug("SPI1 Initialized."); log::debug("Initialization done."); char OP_Mode = 0x01; char buff = 0x7F & OP_Mode; char res = 0; HAL_GPIO_WritePin(LoRa_CS_GPIO_Port, LoRa_CS_Pin, GPIO_PIN_RESET); [[maybe_unused]] auto result = HAL_SPI_Transmit(&hspi1, (uint8_t *)&buff, 1, 100); HAL_SPI_Receive(&hspi1, (uint8_t *)&res, 1, 100); HAL_GPIO_WritePin(LoRa_CS_GPIO_Port, LoRa_CS_Pin, GPIO_PIN_SET); // RF95_Init(); while (1) { cmd_handler::get().run(); // gps_interface::write("TEST"); // RF95_setModeRx_Continuous(); // HAL_GPIO_WritePin(LED_PORT, LED1_PIN, GPIO_PIN_RESET); // RF95_receive(LoRa_buff); // HAL_Delay(100); // HAL_GPIO_WritePin(LED_PORT, LED1_PIN, GPIO_PIN_SET); HAL_Delay(100); // if (updated_main_buf) { // log::debug("Printing main buf"); // updated_main_buf = !main_buffer.print(); // } // std::string_view msg{reinterpret_cast(LoRa_buff)}; // log::info("Received Message"); // log::debug("Received Message"); // log::debug(msg); // std::string_view foo{"Das ist ein test"}; // strcpy((char *)LoRa_buff, foo.data()); // RF95_send(LoRa_buff); } return 0; }