diff --git a/.vscode/settings.json b/.vscode/settings.json index 43e514f2603ebb9bb2b90fdab6c1c80067e2f17d..e1a98af224ab9e9c71af4a5ba32200cd6d082039 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -126,6 +126,7 @@ "Baro", "boardcore", "Boardcorev", + "boudrate", "Corigliano", "CORTEXM", "cpitch", @@ -149,6 +150,7 @@ "fiprintf", "Gatttr", "getdetahstate", + "GNSS", "Gpio", "GPIOA", "GPIOB", @@ -183,6 +185,7 @@ "NDTR", "NGPS", "NMAG", + "NMEA", "NMEKF", "nord", "NVIC", @@ -215,6 +218,9 @@ "testsuite", "TSCPP", "Ublox", + "UBXACK", + "UBXGPS", + "UBXNAV", "Unsync", "upcounter", "USART", diff --git a/CMakeLists.txt b/CMakeLists.txt index d7ac92ec3282024cfc6891855abbc3b381bcff1c..26363322d4e7e677b86a8fc4fdb4e8264736d062 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -349,15 +349,11 @@ sbs_target(test-mpu9250 stm32f429zi_parafoil) add_executable(test-ms5803 src/tests/sensors/test-ms5803.cpp) sbs_target(test-ms5803 stm32f429zi_skyward_death_stack_x) -add_executable(test-ubxgps src/tests/sensors/test-ubxgps.cpp) -sbs_target(test-ubxgps stm32f429zi_skyward_death_stack_x) +add_executable(test-ubxgps-serial src/tests/sensors/test-ubxgps-serial.cpp) +sbs_target(test-ubxgps-serial stm32f429zi_skyward_death_stack_x) -add_executable(test-ubloxgps-serial src/tests/sensors/test-ubloxgps.cpp) -sbs_target(test-ubloxgps-serial stm32f429zi_skyward_death_stack_x) - -add_executable(test-ubloxgps-spi src/tests/sensors/test-ubloxgps.cpp) -target_compile_definitions(test-ubloxgps-spi PRIVATE USE_SPI) -sbs_target(test-ubloxgps-spi stm32f407vg_stm32f4discovery) +add_executable(test-ubxgps-spi src/tests/sensors/test-ubxgps-spi.cpp) +sbs_target(test-ubxgps-spi stm32f429zi_skyward_death_stack_x) add_executable(test-vn100 src/tests/sensors/test-vn100.cpp) sbs_target(test-vn100 stm32f407vg_stm32f4discovery) diff --git a/cmake/boardcore.cmake b/cmake/boardcore.cmake index 5c4264138caf1c3acb46abbdd7cece140b7f27ab..a38c686066fed81df16df3fd247bf487af8f56e9 100644 --- a/cmake/boardcore.cmake +++ b/cmake/boardcore.cmake @@ -83,8 +83,8 @@ foreach(OPT_BOARD ${BOARDS}) ${SBS_BASE}/src/shared/sensors/MS5803/MS5803.cpp ${SBS_BASE}/src/shared/sensors/SensorManager.cpp ${SBS_BASE}/src/shared/sensors/SensorSampler.cpp - ${SBS_BASE}/src/shared/sensors/UbloxGPS/UbloxGPS.cpp - ${SBS_BASE}/src/shared/sensors/UBXGPS/UBXGPS.cpp + ${SBS_BASE}/src/shared/sensors/UBXGPS/UBXGPSSerial.cpp + ${SBS_BASE}/src/shared/sensors/UBXGPS/UBXGPSSpi.cpp ${SBS_BASE}/src/shared/sensors/VN100/VN100.cpp # Calibration diff --git a/src/shared/logger/LogTypes.h b/src/shared/logger/LogTypes.h index 6623fbf11bee706926ebb76ddb2c3d2c66aca122..741e0113bd37b467a30d2f72857caf59253db7eb 100644 --- a/src/shared/logger/LogTypes.h +++ b/src/shared/logger/LogTypes.h @@ -47,7 +47,6 @@ #include <sensors/MS5803/MS5803Data.h> #include <sensors/SensorData.h> #include <sensors/UBXGPS/UBXGPSData.h> -#include <sensors/UbloxGPS/UbloxGPSData.h> #include <sensors/VN100/VN100Data.h> #include <sensors/analog/BatteryVoltageSensorData.h> #include <sensors/analog/CurrentSensorData.h> @@ -98,7 +97,6 @@ void registerTypes(Deserializer& ds) ds.registerType<MPU9250Data>(); ds.registerType<MS5803Data>(); ds.registerType<TemperatureData>(); - ds.registerType<UbloxGPSData>(); ds.registerType<UBXGPSData>(); ds.registerType<VN100Data>(); ds.registerType<BatteryVoltageSensorData>(); diff --git a/src/shared/sensors/UBXGPS/UBXFrame.h b/src/shared/sensors/UBXGPS/UBXFrame.h index 9f1593baaa01a1ce8b3d7be31488e9ba12cfd05d..46437171199cdad96bf4477b06d8629969f4dfda 100644 --- a/src/shared/sensors/UBXGPS/UBXFrame.h +++ b/src/shared/sensors/UBXGPS/UBXFrame.h @@ -35,14 +35,15 @@ namespace Boardcore */ enum class UBXMessage : uint16_t { - UBX_NAV_PVT = 0x0701, // Navigation position velocity time solution - UBX_ACK_NAK = 0x0005, // Message acknowledged - UBX_ACK_ACK = 0x0105, // Message not acknowledged - UBX_CFG_PRT = 0x0006, // Port configuration - UBX_CFG_MSG = 0x0106, // Set message rate - UBX_CFG_RST = 0x0406, // Reset receiver - UBX_CFG_RATE = 0x0806, // Navigation/measurement rate settings - UBX_CFG_NAV5 = 0x2406, // Navigation engine settings + UBX_NAV_PVT = 0x0701, // Navigation position velocity time solution + UBX_ACK_NAK = 0x0005, // Message acknowledged + UBX_ACK_ACK = 0x0105, // Message not acknowledged + UBX_CFG_PRT = 0x0006, // Port configuration + UBX_CFG_MSG = 0x0106, // Set message rate + UBX_CFG_RST = 0x0406, // Reset receiver + UBX_CFG_RATE = 0x0806, // Navigation/measurement rate settings + UBX_CFG_NAV5 = 0x2406, // Navigation engine settings + UBX_CFG_VALSET = 0x8a06, // TODO: Update to newer command }; /** diff --git a/src/shared/sensors/UBXGPS/UBXGPSSerial.cpp b/src/shared/sensors/UBXGPS/UBXGPSSerial.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3c63ac353610543a18299cbfedf5739986b268ab --- /dev/null +++ b/src/shared/sensors/UBXGPS/UBXGPSSerial.cpp @@ -0,0 +1,438 @@ +/* Copyright (c) 2021 Skyward Experimental Rocketry + * Authors: Davide Bonomini, Davide Mor, Alberto Nidasio + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "UBXGPSSerial.h" + +#include <diagnostic/StackLogger.h> +#include <drivers/serial.h> +#include <drivers/timer/TimestampTimer.h> +#include <fcntl.h> +#include <filesystem/file_access.h> + +using namespace miosix; + +namespace Boardcore +{ + +UBXGPSSerial::UBXGPSSerial(int baudrate, uint8_t sampleRate, int serialPortNum, + const char* serialPortName, int defaultBaudrate) + : baudrate(baudrate), sampleRate(sampleRate), + serialPortNumber(serialPortNum), serialPortName(serialPortName), + defaultBaudrate(defaultBaudrate) +{ + // Prepare the gps file path with the specified name + strcpy(gpsFilePath, "/dev/"); + strcat(gpsFilePath, serialPortName); +} + +bool UBXGPSSerial::init() +{ + LOG_DEBUG(logger, "Changing device baudrate..."); + + if (!setSerialCommunication()) + { + lastError = SensorErrors::INIT_FAIL; + LOG_ERR(logger, "Error while setting serial communication"); + return false; + } + + LOG_DEBUG(logger, "Resetting the device..."); + + if (!reset()) + { + lastError = SensorErrors::INIT_FAIL; + LOG_ERR(logger, "Could not reset the device"); + return false; + } + + LOG_DEBUG(logger, "Setting the UBX protocol..."); + + if (!setUBXProtocol()) + { + lastError = SensorErrors::INIT_FAIL; + LOG_ERR(logger, "Could not set the UBX protocol"); + return false; + } + + LOG_DEBUG(logger, "Setting the dynamic model..."); + + if (!setDynamicModelToAirborne4g()) + { + lastError = SensorErrors::INIT_FAIL; + LOG_ERR(logger, "Could not set the dynamic model"); + return false; + } + + LOG_DEBUG(logger, "Setting the sample rate..."); + + if (!setSampleRate()) + { + lastError = SensorErrors::INIT_FAIL; + LOG_ERR(logger, "Could not set the sample rate"); + return false; + } + + LOG_DEBUG(logger, "Setting the PVT message rate..."); + + if (!setPVTMessageRate()) + { + lastError = SensorErrors::INIT_FAIL; + LOG_ERR(logger, "Could not set the PVT message rate"); + return false; + } + + return true; +} + +bool UBXGPSSerial::selfTest() { return true; } + +UBXGPSData UBXGPSSerial::sampleImpl() +{ + Lock<FastMutex> l(mutex); + return threadSample; +} + +bool UBXGPSSerial::reset() +{ + uint8_t payload[] = { + 0x00, 0x00, // Hot start + 0x00, // Hardware reset + 0x00 // Reserved + }; + + UBXFrame frame{UBXMessage::UBX_CFG_RST, payload, sizeof(payload)}; + + // The reset message will not be followed by an acknowledgment + if (!writeUBXFrame(frame)) + return false; + + // Do not interact with the module while it is resetting + miosix::Thread::sleep(RESET_SLEEP_TIME); + + return true; +} + +bool UBXGPSSerial::setBaudrate() +{ + uint8_t payload[] = { + 0x00, // Version + 0xff, // All layers + 0x00, 0x00, // Reserved + 0x01, 0x00, 0x52, 0x40, // Configuration item key ID + 0xff, 0xff, 0xff, 0xff, // Value + }; + + // Prepare baudrate + payload[8] = baudrate; + payload[9] = baudrate >> 8; + payload[10] = baudrate >> 16; + payload[11] = baudrate >> 24; + + UBXFrame frame{UBXMessage::UBX_CFG_VALSET, payload, sizeof(payload)}; + + return safeWriteUBXFrame(frame); +} + +bool UBXGPSSerial::setSerialCommunication() +{ + intrusive_ref_ptr<DevFs> devFs = FilesystemManager::instance().getDevFs(); + + // Change the baudrate only if it is different than the default + if (baudrate != defaultBaudrate) + { + // Close the gps file if already opened + devFs->remove(serialPortName); + + // Open the serial port device with the default boudrate + if (!devFs->addDevice(serialPortName, + intrusive_ref_ptr<Device>(new STM32Serial( + serialPortNumber, defaultBaudrate)))) + { + LOG_ERR(logger, + "[gps] Failed to open serial port {0} with baudrate {1} as " + "file {2}", + serialPortNumber, defaultBaudrate, serialPortName); + return false; + } + + // Open the gps file + if ((gpsFile = open(gpsFilePath, O_RDWR)) < 0) + { + LOG_ERR(logger, "Failed to open gps file {}", gpsFilePath); + return false; + } + + // Change boudrate + if (!setBaudrate()) + { + return false; + }; + + // Close the gps file + if (close(gpsFile) < 0) + { + LOG_ERR(logger, "Failed to close gps file {}", gpsFilePath); + return false; + } + + // Close the serial port + if (!devFs->remove(serialPortName)) + { + LOG_ERR(logger, "Failed to close serial port {} as file {}", + serialPortNumber, serialPortName); + return false; + } + } + + // Reopen the serial port with the configured boudrate + if (!devFs->addDevice(serialPortName, + intrusive_ref_ptr<Device>( + new STM32Serial(serialPortNumber, baudrate)))) + { + LOG_ERR(logger, + "Failed to open serial port {} with baudrate {} as file {}\n", + serialPortNumber, defaultBaudrate, serialPortName); + return false; + } + + // Reopen the gps file + if ((gpsFile = open(gpsFilePath, O_RDWR)) < 0) + { + LOG_ERR(logger, "Failed to open gps file {}", gpsFilePath); + return false; + } + + return true; +} + +bool UBXGPSSerial::setUBXProtocol() +{ + uint8_t payload[] = { + 0x04, // SPI port + 0x00, // reserved0 + 0x00, 0x00, // txReady + 0x00, 0x00, 0x00, 0x00, // spiMode = 0, ffCnt = 0 (mechanism off) + 0x00, 0x00, 0x00, 0x00, // reserved1 + 0x01, 0x00, // inProtoMask = UBX + 0x01, 0x00, // outProtoMask = UBX + 0x00, 0x00, // flags + 0x00, 0x00 // reserved2 + }; + + UBXFrame frame{UBXMessage::UBX_CFG_PRT, payload, sizeof(payload)}; + + return safeWriteUBXFrame(frame); +} + +bool UBXGPSSerial::setDynamicModelToAirborne4g() +{ + uint8_t payload[] = { + 0x01, 0x00, // Parameters bitmask, apply dynamic model configuration + 0x08, // Dynamic model = airbone 4g + 0x00, // Fix mode + 0x00, 0x00, 0x00, 0x00, // Fixed altitude for 2D mode + 0x00, 0x00, 0x00, 0x00, // Fixed altitude variance for 2D mode + 0x00, // Minimun elevation for a GNSS satellite to be used + 0x00, // Reserved + 0x00, 0x00, // Position DOP mask to use + 0x00, 0x00, // Time DOP mask to use + 0x00, 0x00, // Position accuracy mask + 0x00, 0x00, // Time accuracy mask + 0x00, // Static hold threshold + 0x00, // DGNSS timeout + 0x00, // C/NO threshold number SVs + 0x00, // C/NO threshold + 0x00, 0x00, // Reserved + 0x00, 0x00, // Static hold distance threshold + 0x00, // UTC standard to be used + 0x00, 0x00, 0x00, 0x00, 0x00 // Reserved + }; + + UBXFrame frame{UBXMessage::UBX_CFG_NAV5, payload, sizeof(payload)}; + + return safeWriteUBXFrame(frame); +} + +bool UBXGPSSerial::setSampleRate() +{ + uint8_t payload[] = { + 0x00, 0x00, // Measurement rate + 0x01, 0x00, // One navigation solution per measurement + 0x01, 0x01 // GPS time + }; + + uint16_t sampleRateMs = 1000 / sampleRate; + payload[0] = sampleRateMs; + payload[1] = sampleRateMs >> 8; + + UBXFrame frame{UBXMessage::UBX_CFG_RATE, payload, sizeof(payload)}; + + return safeWriteUBXFrame(frame); +} + +bool UBXGPSSerial::setPVTMessageRate() +{ + uint8_t payload[] = { + 0x01, 0x07, // PVT message + 0x01 // Rate = 1 navigation solution update + }; + + UBXFrame frame{UBXMessage::UBX_CFG_MSG, payload, sizeof(payload)}; + + return safeWriteUBXFrame(frame); +} + +bool UBXGPSSerial::readUBXFrame(UBXFrame& frame) +{ + // Search UBX frame preamble byte by byte + size_t i = 0; + while (i < 2) + { + uint8_t c; + if (read(gpsFile, &c, 1) <= 0) // No more data available + return false; + + if (c == UBXFrame::PREAMBLE[i]) + { + frame.preamble[i++] = c; + } + else if (c == UBXFrame::PREAMBLE[0]) + { + i = 0; + frame.preamble[i++] = c; + } + else + { + i = 0; + LOG_DEBUG(logger, "Received unexpected byte: {:02x} {:#c}", c, c); + } + } + + if (read(gpsFile, &frame.message, 2) <= 0 || + read(gpsFile, &frame.payloadLength, 2) <= 0 || + read(gpsFile, frame.payload, frame.getRealPayloadLength()) <= 0 || + read(gpsFile, frame.checksum, 2) <= 0) + return false; + + if (!frame.isValid()) + { + LOG_ERR(logger, "Received invalid UBX frame"); + return false; + } + + return true; +} + +bool UBXGPSSerial::writeUBXFrame(const UBXFrame& frame) +{ + if (!frame.isValid()) + { + LOG_ERR(logger, "Trying to send an invalid UBX frame"); + return false; + } + + uint8_t packedFrame[frame.getLength()]; + frame.writePacked(packedFrame); + + if (write(gpsFile, packedFrame, frame.getLength()) < 0) + { + LOG_ERR(logger, "Failed to write ubx message"); + return false; + } + + return true; +} + +bool UBXGPSSerial::safeWriteUBXFrame(const UBXFrame& frame) +{ + for (unsigned int i = 0; i < MAX_TRIES; i++) + { + if (i > 0) + LOG_DEBUG(logger, "Retrying (attempt {:#d} of {:#d})...", i + 1, + MAX_TRIES); + + if (!writeUBXFrame(frame)) + return false; + + UBXAckFrame ack; + + if (!readUBXFrame(ack)) + continue; + + if (ack.isNack()) + { + if (ack.getAckMessage() == frame.getMessage()) + LOG_DEBUG(logger, "Received NAK"); + else + LOG_DEBUG(logger, "Received NAK for different UBX frame {:04x}", + static_cast<uint16_t>(ack.getPayload().ackMessage)); + continue; + } + + if (ack.isAck() && ack.getAckMessage() != frame.getMessage()) + { + LOG_DEBUG(logger, "Received ACK for different UBX frame {:04x}", + static_cast<uint16_t>(ack.getPayload().ackMessage)); + continue; + } + + return true; + } + + LOG_ERR(logger, "Gave up after {:#d} tries", MAX_TRIES); + return false; +} + +void UBXGPSSerial::run() +{ + while (!shouldStop()) + { + UBXPvtFrame pvt; + + // Try to read the message + if (!readUBXFrame(pvt)) + { + LOG_DEBUG(logger, "Unable to read a UBX message"); + continue; + } + + UBXPvtFrame::Payload& pvtP = pvt.getPayload(); + + threadSample.gpsTimestamp = + TimestampTimer::getInstance().getTimestamp(); + threadSample.latitude = (float)pvtP.lat / 1e7; + threadSample.longitude = (float)pvtP.lon / 1e7; + threadSample.height = (float)pvtP.height / 1e3; + threadSample.velocityNorth = (float)pvtP.velN / 1e3; + threadSample.velocityEast = (float)pvtP.velE / 1e3; + threadSample.velocityDown = (float)pvtP.velD / 1e3; + threadSample.speed = (float)pvtP.gSpeed / 1e3; + threadSample.track = (float)pvtP.headMot / 1e5; + threadSample.positionDOP = (float)pvtP.pDOP / 1e2; + threadSample.satellites = pvtP.numSV; + threadSample.fix = pvtP.fixType; + + StackLogger::getInstance().updateStack(THID_GPS); + } +} + +} // namespace Boardcore diff --git a/src/shared/sensors/UBXGPS/UBXGPSSerial.h b/src/shared/sensors/UBXGPS/UBXGPSSerial.h new file mode 100644 index 0000000000000000000000000000000000000000..7f8bcc646cac712ac3395a15c6ff15aad9d3503f --- /dev/null +++ b/src/shared/sensors/UBXGPS/UBXGPSSerial.h @@ -0,0 +1,179 @@ +/* Copyright (c) 2021 Skyward Experimental Rocketry + * Authors: Davide Bonomini, Davide Mor, Alberto Nidasio + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include <ActiveObject.h> +#include <diagnostic/PrintLogger.h> +#include <miosix.h> +#include <sensors/Sensor.h> + +#include "UBXFrame.h" +#include "UBXGPSData.h" + +namespace Boardcore +{ + +/** + * @brief Driver for Ublox GPSs + * + * This driver handles communication and setup with Ublox GPSs. It uses the + * binary UBX protocol to retrieve and parse navigation data quicker than using + * the string based NMEA. + * + * At initialization it configures the device with the specified baudrate, reset + * the configuration and sets up UBX messages and GNSS parameters. + * + * Communication with the device is performed through a file, the driver opens + * the serial port under the filepath /dev/<serialPortName>. + * There is no need for the file to be setted up beforhand. + * + * This driver was written for a NEO-M9N gps with the latest version of UBX. + */ +class UBXGPSSerial : public Sensor<UBXGPSData>, public ActiveObject +{ +public: + /** + * @brief Construct a new UBXGPSSerial object. + * + * @param baudrate Baudrate to communicate with the device (max: 921600, + * min: 4800 for NEO-M9N). + * @param sampleRate GPS sample rate (max: 25 for NEO-M9N). + * @param serialPortNumber Number of the serial port connected to the GPS. + * @param serialPortName Name of the file for the gps device. + * @param defaultBaudrate Startup baudrate (38400 for NEO-M9N). + */ + UBXGPSSerial(int baudrate = 921600, uint8_t sampleRate = 10, + int serialPortNumber = 2, const char *serialPortName = "gps", + int defaultBaudrate = 38400); + + /** + * @brief Sets up the serial port baudrate, disables the NMEA messages, + * configures GNSS options and enables UBX-PVT message. + * + * @return True if the operation succeeded. + */ + bool init() override; + + /** + * @brief Read a single message form the GPS, waits 2 sample cycle. + * + * @return True if a message was sampled. + */ + bool selfTest() override; + +private: + UBXGPSData sampleImpl() override; + + /** + * @brief Resets the device to its default configuration. + * + * @return True if the device reset succeeded. + */ + bool reset(); + + bool setBaudrate(); + + /** + * @brief Sets up the serial port with the correct baudrate. + * + * Opens the serial port with the default baudrate and changes it to the + * value specified in the constructor, then it reopens the serial port. If + * the device is already using the correct baudrate this won't have effect. + * However if the gps is using a different baudrate the diver won't be able + * to communicate. + */ + bool setSerialCommunication(); + + /** + * @brief Enables UBX and disables NMEA on the SPI port. + * + * @return True if the configuration received an acknowledgement. + */ + bool setUBXProtocol(); + + /** + * @brief Configures the dynamic model to airborn 4g. + * + * @return True if the configuration received an acknowledgement. + */ + bool setDynamicModelToAirborne4g(); + + /** + * @brief Configures the navigation solution sample rate. + * + * @return True if the configuration received an acknowledgement. + */ + bool setSampleRate(); + + /** + * @brief Configures the PVT message output rate. + * + * @return True if the configuration received an acknowledgement. + */ + bool setPVTMessageRate(); + + /** + * @brief Reads a UBX frame. + * + * @param frame The received frame. + * @return True if a valid frame was read. + */ + bool readUBXFrame(UBXFrame &frame); + + /** + * @brief Writes a UBX frame. + * + * @param frame The frame to write. + * @return True if the frame is valid. + */ + bool writeUBXFrame(const UBXFrame &frame); + + /** + * @brief Writes a UBX frame and waits for its acknowledgement. + * + * @param frame The frame to write. + * @return True if the frame is valid and acknowledged. + */ + bool safeWriteUBXFrame(const UBXFrame &frame); + + void run() override; + + const int baudrate; // [baud] + const uint8_t sampleRate; // [Hz] + const int serialPortNumber; + const char *serialPortName; + const int defaultBaudrate; // [baud] + + char gpsFilePath[16]; ///< Allows for a filename of up to 10 characters + int gpsFile = -1; + + mutable miosix::FastMutex mutex; + UBXGPSData threadSample{}; + + PrintLogger logger = Logging::getLogger("ubloxgps"); + + static constexpr unsigned int RESET_SLEEP_TIME = 5000; // [ms] + static constexpr unsigned int MAX_TRIES = 5; // [1] +}; + +} // namespace Boardcore diff --git a/src/shared/sensors/UBXGPS/UBXGPS.cpp b/src/shared/sensors/UBXGPS/UBXGPSSpi.cpp similarity index 91% rename from src/shared/sensors/UBXGPS/UBXGPS.cpp rename to src/shared/sensors/UBXGPS/UBXGPSSpi.cpp index a3b75fa617bddfcdae0df5b6771aa0e986a57d9b..832059373b8c67d9aaff5f75850f75ad5e0e05c7 100644 --- a/src/shared/sensors/UBXGPS/UBXGPS.cpp +++ b/src/shared/sensors/UBXGPS/UBXGPSSpi.cpp @@ -20,7 +20,7 @@ * THE SOFTWARE. */ -#include "UBXGPS.h" +#include "UBXGPSSpi.h" #include <drivers/timer/TimestampTimer.h> #include <interfaces/endianness.h> @@ -33,19 +33,19 @@ constexpr uint16_t UBXFrame::MAX_FRAME_LENGTH; constexpr uint8_t UBXFrame::PREAMBLE[]; constexpr uint8_t UBXFrame::WAIT; -constexpr float UBXGPS::MS_TO_TICK; +constexpr float UBXGPSSpi::MS_TO_TICK; -constexpr unsigned int UBXGPS::RESET_SLEEP_TIME; -constexpr unsigned int UBXGPS::READ_TIMEOUT; -constexpr unsigned int UBXGPS::MAX_TRIES; +constexpr unsigned int UBXGPSSpi::RESET_SLEEP_TIME; +constexpr unsigned int UBXGPSSpi::READ_TIMEOUT; +constexpr unsigned int UBXGPSSpi::MAX_TRIES; -UBXGPS::UBXGPS(SPIBusInterface& spiBus, miosix::GpioPin spiCs, - SPIBusConfig spiConfig, uint8_t sampleRate) +UBXGPSSpi::UBXGPSSpi(SPIBusInterface& spiBus, miosix::GpioPin spiCs, + SPIBusConfig spiConfig, uint8_t sampleRate) : spiSlave(spiBus, spiCs, spiConfig), sampleRate(sampleRate) { } -SPIBusConfig UBXGPS::getDefaultSPIConfig() +SPIBusConfig UBXGPSSpi::getDefaultSPIConfig() { /* From data sheet of series NEO-M8: * "Minimum initialization time" (setup time): 10 us @@ -54,9 +54,9 @@ SPIBusConfig UBXGPS::getDefaultSPIConfig() SPI::BitOrder::MSB_FIRST, 10, 1000}; } -uint8_t UBXGPS::getSampleRate() { return sampleRate; } +uint8_t UBXGPSSpi::getSampleRate() { return sampleRate; } -bool UBXGPS::init() +bool UBXGPSSpi::init() { LOG_DEBUG(logger, "Resetting the device..."); @@ -106,9 +106,9 @@ bool UBXGPS::init() return true; } -bool UBXGPS::selfTest() { return true; } +bool UBXGPSSpi::selfTest() { return true; } -UBXGPSData UBXGPS::sampleImpl() +UBXGPSData UBXGPSSpi::sampleImpl() { UBXPvtFrame pvt; @@ -134,7 +134,7 @@ UBXGPSData UBXGPS::sampleImpl() return sample; } -bool UBXGPS::reset() +bool UBXGPSSpi::reset() { uint8_t payload[] = { 0x00, 0x00, // Hot start @@ -154,7 +154,7 @@ bool UBXGPS::reset() return true; } -bool UBXGPS::setUBXProtocol() +bool UBXGPSSpi::setUBXProtocol() { uint8_t payload[] = { 0x04, // SPI port @@ -173,7 +173,7 @@ bool UBXGPS::setUBXProtocol() return safeWriteUBXFrame(frame); } -bool UBXGPS::setDynamicModelToAirborne4g() +bool UBXGPSSpi::setDynamicModelToAirborne4g() { uint8_t payload[] = { 0x01, 0x00, // Parameters bitmask, apply dynamic model configuration @@ -202,7 +202,7 @@ bool UBXGPS::setDynamicModelToAirborne4g() return safeWriteUBXFrame(frame); } -bool UBXGPS::setSampleRate() +bool UBXGPSSpi::setSampleRate() { uint8_t payload[] = { 0x00, 0x00, // Measurement rate @@ -219,7 +219,7 @@ bool UBXGPS::setSampleRate() return safeWriteUBXFrame(frame); } -bool UBXGPS::setPVTMessageRate() +bool UBXGPSSpi::setPVTMessageRate() { uint8_t payload[] = { 0x01, 0x07, // PVT message @@ -231,7 +231,7 @@ bool UBXGPS::setPVTMessageRate() return safeWriteUBXFrame(frame); } -bool UBXGPS::readUBXFrame(UBXFrame& frame) +bool UBXGPSSpi::readUBXFrame(UBXFrame& frame) { long long start = miosix::getTick(); long long end = start + READ_TIMEOUT * MS_TO_TICK; @@ -296,7 +296,7 @@ bool UBXGPS::readUBXFrame(UBXFrame& frame) return true; } -bool UBXGPS::writeUBXFrame(const UBXFrame& frame) +bool UBXGPSSpi::writeUBXFrame(const UBXFrame& frame) { if (!frame.isValid()) { @@ -315,7 +315,7 @@ bool UBXGPS::writeUBXFrame(const UBXFrame& frame) return true; } -bool UBXGPS::safeWriteUBXFrame(const UBXFrame& frame) +bool UBXGPSSpi::safeWriteUBXFrame(const UBXFrame& frame) { for (unsigned int i = 0; i < MAX_TRIES; i++) { diff --git a/src/shared/sensors/UBXGPS/UBXGPS.h b/src/shared/sensors/UBXGPS/UBXGPSSpi.h similarity index 92% rename from src/shared/sensors/UBXGPS/UBXGPS.h rename to src/shared/sensors/UBXGPS/UBXGPSSpi.h index 8918b2ea878c8d39b76dbaf75ce78e755fffe5d1..e20bc3bfcec2c8b36e69093291be5af048d80ce6 100644 --- a/src/shared/sensors/UBXGPS/UBXGPS.h +++ b/src/shared/sensors/UBXGPS/UBXGPSSpi.h @@ -33,9 +33,9 @@ namespace Boardcore { /** - * @brief Sensor for u-blox GPS. + * @brief Sensor for UBlox GPS. * - * This sensor handles communication and setup with u-blox GPSs. It uses the + * This sensor handles communication and setup with UBlox GPSs. It uses the * binary UBX protocol to retrieve and parse navigation data faster than using * the string-based NMEA. * @@ -46,7 +46,7 @@ namespace Boardcore * * This sensor is compatible with series NEO-M8 and NEO-M9. */ -class UBXGPS : public Sensor<UBXGPSData> +class UBXGPSSpi : public Sensor<UBXGPSData> { public: /** @@ -57,9 +57,9 @@ public: * @param spiConfig The SPI configuration. * @param sampleRate The GPS sample rate [kHz]. */ - UBXGPS(SPIBusInterface& spiBus, miosix::GpioPin spiCs, - SPIBusConfig spiConfig = getDefaultSPIConfig(), - uint8_t sampleRate = 5); + UBXGPSSpi(SPIBusInterface& spiBus, miosix::GpioPin spiCs, + SPIBusConfig spiConfig = getDefaultSPIConfig(), + uint8_t sampleRate = 5); /** * @brief Constructs the default config for the SPI bus. diff --git a/src/shared/sensors/UbloxGPS/UbloxGPS.cpp b/src/shared/sensors/UbloxGPS/UbloxGPS.cpp deleted file mode 100644 index dff24046dfefeca63f88c4499f1d0b2bf4c9f9ce..0000000000000000000000000000000000000000 --- a/src/shared/sensors/UbloxGPS/UbloxGPS.cpp +++ /dev/null @@ -1,537 +0,0 @@ -/* Copyright (c) 2021 Skyward Experimental Rocketry - * Authors: Davide Bonomini, Davide Mor, Alberto Nidasio - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include "UbloxGPS.h" - -#include <diagnostic/StackLogger.h> -#include <drivers/serial.h> -#include <drivers/timer/TimestampTimer.h> -#include <fcntl.h> -#include <filesystem/file_access.h> - -using namespace miosix; - -namespace Boardcore -{ - -UbloxGPS::UbloxGPS(int baudrate_, uint8_t sampleRate_, int serialPortNum_, - const char* serialPortName_, int defaultBaudrate_) - : baudrate(baudrate_), sampleRate(sampleRate_), - serialPortNumber(serialPortNum_), serialPortName(serialPortName_), - defaultBaudrate(defaultBaudrate_) -{ - // Prepare the gps file path with the specified name - strcpy(gpsFilePath, "/dev/"); - strcat(gpsFilePath, serialPortName); -} - -bool UbloxGPS::init() -{ - // Change the baud rate from the default value - if (!serialCommuinicationSetup()) - { - return false; - } - - Thread::sleep(10); - - // Reset configuration to default - // TODO: maybe move this on serial communication setup - if (!resetConfiguration()) - { - return false; - } - - // Disable NMEA messages - if (!disableNMEAMessages()) - { - return false; - } - - Thread::sleep(100); - - // Set GNSS configuration - if (!setGNSSConfiguration()) - { - return false; - } - - Thread::sleep(100); - - // Enable UBX messages - if (!enableUBXMessages()) - { - return false; - } - - Thread::sleep(100); - - // Set rate - if (!setRate()) - { - return false; - } - - return true; -} - -bool UbloxGPS::selfTest() { return true; } - -UbloxGPSData UbloxGPS::sampleImpl() -{ - Lock<FastMutex> l(mutex); - return threadSample; -} - -void UbloxGPS::run() -{ - /** - * UBX message structure: - * - 2B: Preamble - * - 1B: Message class - * - 1B: Message id - * - 2B: Payload length - * - lB: Payload - * - 2B: Checksum - */ - uint8_t message[6 + UBX_MAX_PAYLOAD_LENGTH + 2]; - uint16_t payloadLength; - - while (!shouldStop()) - { - StackLogger::getInstance().updateStack(THID_GPS); - - // Try to read the message - if (!readUBXMessage(message, payloadLength)) - { - LOG_DEBUG(logger, "Unable to read a UBX message"); - continue; - } - - // Parse the message - if (!parseUBXMessage(message)) - { - LOG_DEBUG(logger, - "UBX message not recognized (class:0x{02x}, id: 0x{02x})", - message[2], message[3]); - } - } -} - -void UbloxGPS::ubxChecksum(uint8_t* msg, int len) -{ - uint8_t ck_a = 0, ck_b = 0; - - // The length must be valid, at least 8 bytes (preamble, msg, length, - // checksum) - if (len <= 8) - { - return; - } - - // Checksum calculation from byte 2 to end of payload - for (int i = 2; i < len - 2; i++) - { - ck_a = ck_a + msg[i]; - ck_b = ck_b + ck_a; - } - - msg[len - 2] = ck_a; - msg[len - 1] = ck_b; -} - -bool UbloxGPS::writeUBXMessage(uint8_t* message, int length) -{ - // Compute the checksum - ubxChecksum(message, length); - - // Write configuration - if (write(gpsFile, message, length) < 0) - { - LOG_ERR(logger, - "Failed to write ubx message (class:0x{02x}, id: 0x{02x})", - message[2], message[3]); - return false; - } - - return true; -} - -bool UbloxGPS::serialCommuinicationSetup() -{ - intrusive_ref_ptr<DevFs> devFs = FilesystemManager::instance().getDevFs(); - - // Change the baudrate only if it is different than the default - if (baudrate != defaultBaudrate) - { - // Close the gps file if already opened - devFs->remove(serialPortName); - - // Open the serial port device with the default boudrate - if (!devFs->addDevice(serialPortName, - intrusive_ref_ptr<Device>(new STM32Serial( - serialPortNumber, defaultBaudrate)))) - { - LOG_ERR(logger, - "[gps] Faild to open serial port {0} with baudrate {1} as " - "file {2}", - serialPortNumber, defaultBaudrate, serialPortName); - return false; - } - - // Open the gps file - if ((gpsFile = open(gpsFilePath, O_RDWR)) < 0) - { - LOG_ERR(logger, "Failed to open gps file {}", gpsFilePath); - return false; - } - - // Change boudrate - if (!setBaudrate()) - { - return false; - }; - - // Close the gps file - if (close(gpsFile) < 0) - { - LOG_ERR(logger, "Failed to close gps file {}", gpsFilePath); - return false; - } - - // Close the serial port - if (!devFs->remove(serialPortName)) - { - LOG_ERR(logger, "Failed to close serial port {} as file {}", - serialPortNumber, serialPortName); - return false; - } - } - - // Reopen the serial port with the configured boudrate - if (!devFs->addDevice(serialPortName, - intrusive_ref_ptr<Device>( - new STM32Serial(serialPortNumber, baudrate)))) - { - LOG_ERR(logger, - "Faild to open serial port {} with baudrate {} as file {}\n", - serialPortNumber, defaultBaudrate, serialPortName); - return false; - } - - // Reopen the gps file - if ((gpsFile = open(gpsFilePath, O_RDWR)) < 0) - { - LOG_ERR(logger, "Failed to open gps file {}", gpsFilePath); - return false; - } - - return true; -} - -bool UbloxGPS::resetConfiguration() -{ - uint8_t ubx_cfg_prt[RESET_CONFIG_MSG_LEN] = { - 0Xb5, 0x62, // Preamble - 0x06, 0x04, // Message UBX-CFG-RST - 0x04, 0x00, // Length - 0x00, 0x00, // navBbrMask (Hot start) - 0x00, // Hardware reset immediately - 0x00, // Reserved - 0xff, 0xff // Checksum - }; - - return writeUBXMessage(ubx_cfg_prt, RESET_CONFIG_MSG_LEN); -} - -bool UbloxGPS::setBaudrate() -{ - uint8_t ubx_cfg_prt[SET_BAUDRATE_MSG_LEN] = { - 0Xb5, 0x62, // Preamble - 0x06, 0x8a, // Message UBX-CFG-VALSET - 0x0c, 0x00, // Length - 0x00, // Version - 0xff, // All layers - 0x00, 0x00, // Reserved - 0x01, 0x00, 0x52, 0x40, // Configuration item key ID - 0xff, 0xff, 0xff, 0xff, // Value - 0xff, 0xff // Checksum - }; - - // Prepare boud rate - ubx_cfg_prt[14] = baudrate; - ubx_cfg_prt[15] = baudrate >> 8; - ubx_cfg_prt[16] = baudrate >> 16; - ubx_cfg_prt[17] = baudrate >> 24; - - return writeUBXMessage(ubx_cfg_prt, SET_BAUDRATE_MSG_LEN); -} - -bool UbloxGPS::disableNMEAMessages() -{ - uint8_t ubx_cfg_valset[DISABLE_NMEA_MESSAGES_MSG_LEN] = { - 0Xb5, 0x62, // Preamble - 0x06, 0x8a, // Message UBX-CFG-VALSET - 0x22, 0x00, // Length - 0x00, // Version - 0xff, // All layers - 0x00, 0x00, // Reserved - 0xbb, 0x00, 0x91, 0x20, // CFG-MSGOUT-NMEA_ID_GGA_UART1 key ID - 0x00, // CFG-MSGOUT-NMEA_ID_GGA_UART1 value - 0xca, 0x00, 0x91, 0x20, // CFG-MSGOUT-NMEA_ID_GLL_UART1 key ID - 0x00, // CFG-MSGOUT-NMEA_ID_GLL_UART1 value - 0xc0, 0x00, 0x91, 0x20, // CFG-MSGOUT-NMEA_ID_GSA_UART1 key ID - 0x00, // CFG-MSGOUT-NMEA_ID_GSA_UART1 value - 0xc5, 0x00, 0x91, 0x20, // CFG-MSGOUT-NMEA_ID_GSV_UART1 key ID - 0x00, // CFG-MSGOUT-NMEA_ID_GSV_UART1 value - 0xac, 0x00, 0x91, 0x20, // CFG-MSGOUT-NMEA_ID_RMC_UART1 key ID - 0x00, // CFG-MSGOUT-NMEA_ID_RMC_UART1 value - 0xb1, 0x00, 0x91, 0x20, // CFG-MSGOUT-NMEA_ID_VTG_UART1 key ID - 0x00, // CFG-MSGOUT-NMEA_ID_VTG_UART1 value - 0xff, 0xff // Checksum - }; - - return writeUBXMessage(ubx_cfg_valset, DISABLE_NMEA_MESSAGES_MSG_LEN); -} - -bool UbloxGPS::setGNSSConfiguration() -{ - uint8_t ubx_cfg_valset[SET_GNSS_CONF_LEN] = { - 0Xb5, 0x62, // Preamble - 0x06, 0x8a, // Message UBX-CFG-VALSET - 0x09, 0x00, // Length - 0x00, // Version - 0x07, // All layers - 0x00, 0x00, // Reserved - 0x21, 0x00, 0x11, 0x20, // CFG-NAVSPG-DYNMODEL key ID - 0x08, // CFG-NAVSPG-DYNMODEL value - 0xff, 0xff // Checksum - }; - - return writeUBXMessage(ubx_cfg_valset, SET_GNSS_CONF_LEN); -} - -bool UbloxGPS::enableUBXMessages() -{ - uint8_t ubx_cfg_valset[ENABLE_UBX_MESSAGES_MSG_LEN] = { - 0Xb5, 0x62, // Preamble - 0x06, 0x8a, // Message UBX-CFG-VALSET - 0x09, 0x00, // Length - 0x00, // Version - 0xff, // All layers - 0x00, 0x00, // Reserved - 0x07, 0x00, 0x91, 0x20, // CFG-MSGOUT-UBX_NAV_PVT_UART1 key ID - 0x01, // CFG-MSGOUT-UBX_NAV_PVT_UART1 value - 0xff, 0xff // Checksum - }; - - return writeUBXMessage(ubx_cfg_valset, ENABLE_UBX_MESSAGES_MSG_LEN); -} - -bool UbloxGPS::setRate() -{ - uint16_t rate = 1000 / sampleRate; - LOG_DEBUG(logger, "Rate: {}", rate); - - uint8_t ubx_cfg_valset[SET_RATE_MSG_LEN] = { - 0Xb5, 0x62, // Preamble - 0x06, 0x8a, // Message UBX-CFG-VALSET - 0x0a, 0x00, // Length - 0x00, // Version - 0x07, // All layers - 0x00, 0x00, // Reserved - 0x01, 0x00, 0x21, 0x30, // CFG-RATE-MEAS key ID - 0xff, 0xff, // CFG-RATE-MEAS value - 0xff, 0xff // Checksum - }; - - // Prepare rate - ubx_cfg_valset[14] = rate; - ubx_cfg_valset[15] = rate >> 8; - - return writeUBXMessage(ubx_cfg_valset, SET_RATE_MSG_LEN); -} - -bool UbloxGPS::readUBXMessage(uint8_t* message, uint16_t& payloadLength) -{ - // Read preamble - do - { - // Read util the first byte of the preamble - do - { - if (read(gpsFile, &message[0], 1) <= 0) // No more data available - { - return false; - } - } while (message[0] != PREAMBLE[0]); - - // Read the next byte - if (read(gpsFile, &message[1], 1) <= 0) // No more data available - { - return false; - } - } while (message[1] != PREAMBLE[1]); // Continue - - // Read message class and ID - if (read(gpsFile, &message[2], 1) <= 0) - { - return false; - } - if (read(gpsFile, &message[3], 1) <= 0) - { - return false; - } - - // Read length - if (read(gpsFile, &message[4], 2) <= 0) - { - return false; - } - payloadLength = message[4] | (message[5] << 8); - if (payloadLength > UBX_MAX_PAYLOAD_LENGTH) - { - return false; - } - - // Read paylaod and checksum - for (auto i = 0; i < payloadLength + 2; i++) - { - if (read(gpsFile, &message[6 + i], 1) <= 0) - { - return false; - } - } - - // Verify the checksum - uint8_t msgChecksum1 = message[6 + payloadLength]; - uint8_t msgChecksum2 = message[6 + payloadLength + 1]; - ubxChecksum(message, 6 + payloadLength + 2); - if (msgChecksum1 != message[6 + payloadLength] || - msgChecksum2 != message[6 + payloadLength + 1]) - { - LOG_ERR(logger, "Message checksum verification failed"); - return false; - } - - return true; -} - -bool UbloxGPS::parseUBXMessage(uint8_t* message) -{ - switch (message[2]) // Message class - { - case 0x01: // UBX-NAV - return parseUBXNAVMessage(message); - case 0x05: // UBX-ACK - return parseUBXACKMessage(message); - } - return false; -} - -bool UbloxGPS::parseUBXNAVMessage(uint8_t* message) -{ - switch (message[3]) // Message id - { - case 0x07: // UBX-NAV-PVT - // Lock the threadSample variable - Lock<FastMutex> l(mutex); - - // Latitude - int32_t rawLatitude = message[6 + 28] | message[6 + 29] << 8 | - message[6 + 30] << 16 | message[6 + 31] << 24; - threadSample.latitude = (float)rawLatitude / 1e7; - - // Longitude - int32_t rawLongitude = message[6 + 24] | message[6 + 25] << 8 | - message[6 + 26] << 16 | - message[6 + 27] << 24; - threadSample.longitude = (float)rawLongitude / 1e7; - - // Height - int32_t rawHeight = message[6 + 32] | message[6 + 33] << 8 | - message[6 + 34] << 16 | message[6 + 35] << 24; - threadSample.height = (float)rawHeight / 1e3; - - // Velocity north - int32_t rawVelocityNorth = message[6 + 48] | message[6 + 49] << 8 | - message[6 + 50] << 16 | - message[6 + 51] << 24; - threadSample.velocityNorth = (float)rawVelocityNorth / 1e3; - - // Velocity east - int32_t rawVelocityEast = message[6 + 52] | message[6 + 53] << 8 | - message[6 + 54] << 16 | - message[6 + 55] << 24; - threadSample.velocityEast = (float)rawVelocityEast / 1e3; - - // Velocity down - int32_t rawVelocityDown = message[6 + 56] | message[6 + 57] << 8 | - message[6 + 58] << 16 | - message[6 + 59] << 24; - threadSample.velocityDown = (float)rawVelocityDown / 1e3; - - // Speed - int32_t rawSpeed = message[6 + 60] | message[6 + 61] << 8 | - message[6 + 62] << 16 | message[6 + 63] << 24; - threadSample.speed = (float)rawSpeed / 1e3; - - // Track (heading of motion) - int32_t rawTrack = message[6 + 64] | message[6 + 65] << 8 | - message[6 + 66] << 16 | message[6 + 67] << 24; - threadSample.track = (float)rawTrack / 1e5; - - // Number of satellite - threadSample.satellites = (uint8_t)message[6 + 23]; - - // Fix (every type of fix accepted) - threadSample.fix = message[6 + 20] != 0; - - // Timestamp - threadSample.gpsTimestamp = - TimestampTimer::getInstance().getTimestamp(); - - return true; - } - - return false; -} - -bool UbloxGPS::parseUBXACKMessage(uint8_t* message) -{ - switch (message[3]) // Message id - { - case 0x00: // UBX-ACK-NAC - LOG_DEBUG(logger, - "Received NAC for message (class:0x{02x}, id: 0x{02x})", - message[6], message[7]); - return true; - case 0x01: // UBX-ACK-ACK - LOG_DEBUG(logger, - "Received ACK for message (class:0x{02x}, id: 0x{02x})", - message[6], message[7]); - return true; - } - return false; -} - -} // namespace Boardcore diff --git a/src/shared/sensors/UbloxGPS/UbloxGPS.h b/src/shared/sensors/UbloxGPS/UbloxGPS.h deleted file mode 100644 index 9495bc6f5fe792774f0bb9a59c32f35c6e97e5b8..0000000000000000000000000000000000000000 --- a/src/shared/sensors/UbloxGPS/UbloxGPS.h +++ /dev/null @@ -1,151 +0,0 @@ -/* Copyright (c) 2021 Skyward Experimental Rocketry - * Authors: Davide Bonomini, Davide Mor, Alberto Nidasio - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#pragma once - -#include <ActiveObject.h> -#include <diagnostic/PrintLogger.h> -#include <miosix.h> -#include <sensors/Sensor.h> - -#include "UbloxGPSData.h" - -namespace Boardcore -{ - -/** - * @brief Driver for Ublox GPSs - * - * This driver handles communication and setup with Ublox GPSs. It uses the - * binary UBX protocol to retrieve and parse navigation data quicker than using - * the string based NMEA. - * - * At initialization it configures the device with the specified baudrate, reset - * the configuration and sets up UBX messages and GNSS parameters. - * - * Communication with the device is performed through a file, the driver opens - * the serial port under the filepath /dev/<serialPortName>. - * There is no need for the file to be setted up beforhand. - * - * This driver was written for a NEO-M9N gps with the latest version of UBX. - */ -class UbloxGPS : public Sensor<UbloxGPSData>, public ActiveObject -{ -public: - /** - * @brief Construct a new UbloxGPS object - * - * @param boudrate_ Baudrate to communicate with the device (max: 921600, - * min: 4800 for NEO-M9N) - * @param sampleRate_ GPS sample rate (max: 25 for NEO-M9N) - * @param serialPortName_ Name of the file for the gps device - * @param defaultBaudrate_ Startup baudrate (38400 for NEO-M9N) - */ - UbloxGPS(int boudrate_ = 921600, uint8_t sampleRate_ = 10, - int serialPortNumber_ = 2, const char *serialPortName_ = "gps", - int defaultBaudrate_ = 38400); - - /** - * @brief Sets up the serial port baudrate, disables the NMEA messages, - * configures GNSS options and enables UBX-PVT message - * - * @return True if the operation succeeded - */ - bool init() override; - - /** - * @brief Read a single message form the GPS, waits 2 sample cycle - * - * @return True if a message was sampled - */ - bool selfTest() override; - -private: - UbloxGPSData sampleImpl() override; - - void run() override; - - void ubxChecksum(uint8_t *msg, int len); - - /** - * @brief Compute the checksum and write the message to the device - */ - bool writeUBXMessage(uint8_t *message, int length); - - /** - * @brief Sets up the serial port with the correct baudrate - * - * Opens the serial port with the defaul baudrate and changes it to - * the value specified in the constructor, then it reopens the serial port. - * If the device is already using the correct baudrate this won't have - * effect. However if the gps is using a different baudrate the diver won't - * be able to communicate. - */ - bool serialCommuinicationSetup(); - - bool resetConfiguration(); - - bool setBaudrate(); - - bool disableNMEAMessages(); - - bool setGNSSConfiguration(); - - bool enableUBXMessages(); - - bool setRate(); - - bool readUBXMessage(uint8_t *message, uint16_t &payloadLength); - - bool parseUBXMessage(uint8_t *message); - - bool parseUBXNAVMessage(uint8_t *message); - - bool parseUBXACKMessage(uint8_t *message); - - const int baudrate; // [baud] - const uint8_t sampleRate; // [Hz] - const int serialPortNumber; - const char *serialPortName; - const int defaultBaudrate; // [baud] - - char gpsFilePath[16]; ///< Allows for a filename of up to 10 characters - int gpsFile = -1; - - mutable miosix::FastMutex mutex; - UbloxGPSData threadSample{}; - - static constexpr int SET_BAUDRATE_MSG_LEN = 20; - static constexpr int RESET_CONFIG_MSG_LEN = 12; - static constexpr int DISABLE_NMEA_MESSAGES_MSG_LEN = 42; - static constexpr int SET_GNSS_CONF_LEN = 17; - static constexpr int ENABLE_UBX_MESSAGES_MSG_LEN = 17; - static constexpr int SET_RATE_MSG_LEN = 18; - - static constexpr uint8_t PREAMBLE[] = {0xb5, 0x62}; - - static constexpr int UBX_MAX_PAYLOAD_LENGTH = 92; - - PrintLogger logger = Logging::getLogger("ubloxgps"); -}; - -} // namespace Boardcore diff --git a/src/shared/sensors/UbloxGPS/UbloxGPSData.h b/src/shared/sensors/UbloxGPS/UbloxGPSData.h deleted file mode 100644 index 7f5570000b78b915a956b96e754d784e08f7611f..0000000000000000000000000000000000000000 --- a/src/shared/sensors/UbloxGPS/UbloxGPSData.h +++ /dev/null @@ -1,47 +0,0 @@ -/* Copyright (c) 2020 Skyward Experimental Rocketry - * Author: Davide Bonomini - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#pragma once - -#include <sensors/SensorData.h> - -namespace Boardcore -{ - -struct UbloxGPSData : public GPSData -{ - static std::string header() - { - return "gps_timestamp,latitude,longitude,height,velocity_north," - "velocity_east,velocity_down,speed,track,num_satellites,fix\n"; - } - - void print(std::ostream &os) const - { - os << gpsTimestamp << "," << latitude << "," << longitude << "," - << height << "," << velocityNorth << "," << velocityEast << "," - << velocityDown << "," << speed << "," << track << "," - << (int)satellites << "," << (int)fix << "\n"; - } -}; - -} // namespace Boardcore diff --git a/src/tests/algorithms/NAS/test-nas-parafoil.cpp b/src/tests/algorithms/NAS/test-nas-parafoil.cpp index 57fd167c839ec3bdef2d24c69417ddb7f118aab1..06f5bccae190975ac036c7a61806baed7af9845c 100644 --- a/src/tests/algorithms/NAS/test-nas-parafoil.cpp +++ b/src/tests/algorithms/NAS/test-nas-parafoil.cpp @@ -26,7 +26,7 @@ #include <miosix.h> #include <sensors/MPU9250/MPU9250.h> #include <sensors/SensorManager.h> -#include <sensors/UbloxGPS/UbloxGPS.h> +#include <sensors/UBXGPS/UBXGPSSerial.h> #include <utils/AeroUtils/AeroUtils.h> #include <utils/SkyQuaternion/SkyQuaternion.h> @@ -48,8 +48,8 @@ Vector2f startPos = Vector2f(45.501141, 9.156281); NAS* nas; SPIBus spi1(SPI1); -MPU9250* imu = nullptr; -UbloxGPS* gps = nullptr; +MPU9250* imu = nullptr; +UBXGPSSerial* gps = nullptr; int main() { @@ -110,7 +110,7 @@ void init() imu = new MPU9250(spi1, sensors::mpu9250::cs::getPin()); imu->init(); - gps = new UbloxGPS(38400, 10, 2, "gps", 38400); + gps = new UBXGPSSerial(38400, 10, 2, "gps", 38400); gps->init(); gps->start(); diff --git a/src/tests/algorithms/NAS/test-nas-stack.cpp b/src/tests/algorithms/NAS/test-nas-stack.cpp index e72a1c9830b63682cffff7968cbc27106b85a61f..31980dd9195f45c444cba38d8a0bd1e927f22268 100644 --- a/src/tests/algorithms/NAS/test-nas-stack.cpp +++ b/src/tests/algorithms/NAS/test-nas-stack.cpp @@ -27,7 +27,7 @@ #include <sensors/BMX160/BMX160.h> #include <sensors/MS5803/MS5803.h> #include <sensors/SensorManager.h> -#include <sensors/UbloxGPS/UbloxGPS.h> +#include <sensors/UBXGPS/UBXGPSSerial.h> #include <utils/AeroUtils/AeroUtils.h> #include <utils/Constants.h> #include <utils/SkyQuaternion/SkyQuaternion.h> @@ -50,9 +50,9 @@ Vector2f startPos = Vector2f(45.501141, 9.156281); NAS* nas; SPIBus spi1(SPI1); -BMX160* imu = nullptr; -UbloxGPS* gps = nullptr; -MS5803* baro = nullptr; +BMX160* imu = nullptr; +UBXGPSSerial* gps = nullptr; +MS5803* baro = nullptr; int main() { @@ -134,7 +134,7 @@ void init() new BMX160(spi1, sensors::bmx160::cs::getPin(), bmx_config, spiConfig); imu->init(); - gps = new UbloxGPS(921600, 10, 2, "gps", 38400); + gps = new UBXGPSSerial(921600, 10, 2, "gps", 38400); gps->init(); gps->start(); diff --git a/src/tests/sensors/test-ubloxgps.cpp b/src/tests/sensors/test-ubxgps-serial.cpp similarity index 95% rename from src/tests/sensors/test-ubloxgps.cpp rename to src/tests/sensors/test-ubxgps-serial.cpp index 24b6cc092a73e531765fbbe4897a29133a827014..5518137419f3e03ea55e72011efdab7dbae65111 100644 --- a/src/tests/sensors/test-ubloxgps.cpp +++ b/src/tests/sensors/test-ubxgps-serial.cpp @@ -22,7 +22,7 @@ #include <drivers/timer/TimestampTimer.h> #include <miosix.h> -#include <sensors/UbloxGPS/UbloxGPS.h> +#include <sensors/UBXGPS/UBXGPSSerial.h> #include <utils/Debug.h> #include <cstdio> @@ -39,8 +39,8 @@ int main() printf("Welcome to the ublox test\n"); // Keep GPS baud rate at default for easier testing - UbloxGPS gps(921600, RATE, 2, "gps", 38400); - UbloxGPSData dataGPS; + UBXGPSSerial gps(921600, RATE, 2, "gps", 38400); + UBXGPSData dataGPS; printf("Gps allocated\n"); // Init the gps diff --git a/src/tests/sensors/test-ubxgps.cpp b/src/tests/sensors/test-ubxgps-spi.cpp similarity index 96% rename from src/tests/sensors/test-ubxgps.cpp rename to src/tests/sensors/test-ubxgps-spi.cpp index f5ec6e4194e8d6ff006a691be49cf89819246f75..3fcecde01e161e98c8e01a1aa2021d8e4e4775dc 100644 --- a/src/tests/sensors/test-ubxgps.cpp +++ b/src/tests/sensors/test-ubxgps-spi.cpp @@ -20,7 +20,7 @@ * THE SOFTWARE. */ -#include <sensors/UBXGPS/UBXGPS.h> +#include <sensors/UBXGPS/UBXGPSSpi.h> #include <utils/Debug.h> using namespace miosix; @@ -51,9 +51,9 @@ int main() spiMosi.mode(Mode::ALTERNATE); spiMosi.alternateFunction(5); - UBXGPS gps{spiBus, spiCs}; + UBXGPSSpi gps{spiBus, spiCs}; - TRACE("Initializing UBXGPS...\n"); + TRACE("Initializing UBXGPSSpi...\n"); while (!gps.init()) {