/*************************************************************************** * Copyright (C) 2023 by Federico Amedeo Izzo IU2NUO, * * Niccolò Izzo IU2KIN * * Frederik Saraci IU2NRO * * Silvano Seva IU2KWO * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, see * ***************************************************************************/ #include #include #include #include #include #include #include #if DT_NODE_HAS_STATUS(DT_ALIAS(gps), okay) #define UART_GPS_DEV_NODE DT_ALIAS(gps) #else #error "Please select the correct gps UART device" #endif #define NMEA_MSG_SIZE 82 K_MSGQ_DEFINE(gps_uart_msgq, NMEA_MSG_SIZE, 10, 4); static const struct device *const gps_dev = DEVICE_DT_GET(UART_GPS_DEV_NODE); // receive buffer used in UART ISR callback static char rx_buf[NMEA_MSG_SIZE]; static uint16_t rx_buf_pos; static void gps_serialCb(const struct device *dev, void *user_data) { uint8_t c; if (uart_irq_update(gps_dev) == false) return; if (uart_irq_rx_ready(gps_dev) == false) return; // read until FIFO empty while (uart_fifo_read(gps_dev, &c, 1) == 1) { if (c == '$' && rx_buf_pos > 0) { // terminate string rx_buf[rx_buf_pos] = '\0'; // if queue is full, message is silently dropped k_msgq_put(&gps_uart_msgq, &rx_buf, K_NO_WAIT); // reset the buffer (it was copied to the msgq) rx_buf_pos = 0; rx_buf[rx_buf_pos++] = '$'; } else if (rx_buf_pos < (sizeof(rx_buf) - 1)) { rx_buf[rx_buf_pos++] = c; } } } void gps_init(const uint16_t baud) { int ret = 0; // Check if GPS UART is ready if (device_is_ready(gps_dev) == false) { printk("UART device not found!\n"); return; } ret = uart_irq_callback_user_data_set(gps_dev, gps_serialCb, NULL); if (ret < 0) { if (ret == -ENOTSUP) { printk("Interrupt-driven UART support not enabled\n"); } else if (ret == -ENOSYS) { printk("UART device does not support interrupt-driven API\n"); } else { printk("Error setting UART callback: %d\n", ret); } return; } uart_irq_rx_enable(gps_dev); } void gps_terminate() { gps_disable(); } void gps_enable() { pmu_setGPSPower(true); } void gps_disable() { pmu_setGPSPower(false); } bool gps_detect(uint16_t timeout) { return true; } int gps_getNmeaSentence(char *buf, const size_t maxLength) { k_msgq_get(&gps_uart_msgq, buf, K_FOREVER); return 0; } bool gps_nmeaSentenceReady() { return k_msgq_num_used_get(&gps_uart_msgq) != 0; } void gps_waitForNmeaSentence() { while (k_msgq_num_used_get(&gps_uart_msgq) != 0) { sleepFor(0, 100); } }