#ifndef MISSION_DEVICES_SYRLINKSHANDLER_H_ #define MISSION_DEVICES_SYRLINKSHANDLER_H_ #include #include "devices/powerSwitcherList.h" #include "fsfw/devicehandlers/DeviceHandlerBase.h" #include "fsfw/timemanager/Countdown.h" #include "fsfw_hal/linux/gpio/Gpio.h" #include "mission/comDefs.h" #include "mission/devices/devicedefinitions/SyrlinksDefinitions.h" #include "returnvalues/classIds.h" /** * @brief This is the device handler for the syrlinks transceiver. It handles the command * transmission and reading of housekeeping data via the housekeeping interface. The * transmission of telemetry and the reception of telecommands is handled by an additional * class. * * @author J. Meier */ class SyrlinksHandler : public DeviceHandlerBase { public: SyrlinksHandler(object_id_t objectId, object_id_t comIF, CookieIF* comCookie, power::Switch_t powerSwitch, FailureIsolationBase* customFdir); virtual ~SyrlinksHandler(); /** * @brief Sets mode to MODE_NORMAL. Can be used for debugging. */ void setModeNormal(); void setDebugMode(bool enable); protected: void doStartUp() override; void doShutDown() override; void doTransition(Mode_t modeFrom, Submode_t subModeFrom) override; ReturnValue_t isModeCombinationValid(Mode_t mode, Submode_t submode) override; ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t* id) override; ReturnValue_t buildTransitionDeviceCommand(DeviceCommandId_t* id) override; ReturnValue_t buildCommandFromCommand(DeviceCommandId_t deviceCommand, const uint8_t* commandData, size_t commandDataLen) override; void fillCommandAndReplyMap() override; ReturnValue_t scanForReply(const uint8_t* start, size_t remainingSize, DeviceCommandId_t* foundId, size_t* foundLen) override; ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, const uint8_t* packet) override; ReturnValue_t getSwitches(const uint8_t** switches, uint8_t* numberOfSwitches) override; void setNormalDatapoolEntriesInvalid() override; uint32_t getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) override; ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap, LocalDataPoolManager& poolManager) override; LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override; // Parameter IF ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId, ParameterWrapper* parameterWrapper, const ParameterWrapper* newValues, uint16_t startAtIndex) override; private: static const uint8_t INTERFACE_ID = CLASS_ID::SYRLINKS_HANDLER; static const ReturnValue_t CRC_FAILURE = MAKE_RETURN_CODE(0xA0); static const ReturnValue_t UART_FRAMIN_OR_PARITY_ERROR_ACK = MAKE_RETURN_CODE(0xA1); static const ReturnValue_t BAD_CHARACTER_ACK = MAKE_RETURN_CODE(0xA2); static const ReturnValue_t BAD_PARAMETER_VALUE_ACK = MAKE_RETURN_CODE(0xA3); static const ReturnValue_t BAD_END_OF_FRAME_ACK = MAKE_RETURN_CODE(0xA4); static const ReturnValue_t UNKNOWN_COMMAND_ID_ACK = MAKE_RETURN_CODE(0xA5); static const ReturnValue_t BAD_CRC_ACK = MAKE_RETURN_CODE(0xA6); static const ReturnValue_t REPLY_WRONG_SIZE = MAKE_RETURN_CODE(0xA7); static const ReturnValue_t MISSING_START_FRAME_CHARACTER = MAKE_RETURN_CODE(0xA8); static const uint8_t CRC_INITIAL_VALUE = 0x0; // Uses CRC-16/XMODEM std::string resetCommand = ""; std::string readRxStatusRegCommand = ""; std::string setTxModeStandby = ""; /** W - write, 04 - 4 bytes in data field, 01 - value, 40 register to write value */ std::string setTxModeModulation = ""; std::string configBPSK = ""; std::string configOQPSK = ""; std::string setTxModeCw = ""; std::string writeLclConfig = ""; std::string setWaveformOQPSK = ""; std::string setWaveformBPSK = ""; std::string readTxStatus = ""; std::string readTxWaveform = ""; std::string readTxAgcValueHighByte = ""; std::string readTxAgcValueLowByte = ""; std::string readLclConfig = ""; std::string tempPowerAmpBoardHighByte = ""; std::string tempPowerAmpBoardLowByte = ""; std::string tempBasebandBoardHighByte = ""; std::string tempBasebandBoardLowByte = ""; /** * In some cases it is not possible to extract from the received reply the information about * the associated command. This variable is thus used to remember the command id. */ DeviceCommandId_t rememberCommandId = syrlinks::NONE; syrlinks::RxDataset rxDataset; syrlinks::TxDataset txDataset; syrlinks::TemperatureSet temperatureSet; const power::Switch_t powerSwitch = power::NO_SWITCH; bool debugMode = false; uint8_t agcValueHighByte = 0; uint16_t rawTempPowerAmplifier = 0; uint16_t rawTempBasebandBoard = 0; float tempPowerAmplifier = 0; float tempBasebandBoard = 0; bool commandExecuted = false; uint8_t commandBuffer[syrlinks::MAX_COMMAND_SIZE]; enum class InternalState { OFF, ENABLE_TEMPERATURE_PROTECTION, SELECT_MODULATION_BPSK, SELECT_MODULATION_0QPSK, SET_TX_MODULATION, SET_TX_CW, SET_TX_STANDBY, IDLE }; InternalState internalState = InternalState::OFF; /** * This object is used to store the id of the next command to execute. This controls the * read out of multiple registers which can not be fetched with one single command. */ DeviceCommandId_t nextCommand = syrlinks::READ_RX_STATUS_REGISTERS; /** * @brief This function converts an uint16_t into its hexadecimal string representation. * * @param intValue The value to convert. * * @return An std::string object containing the hex representation of intValue. */ std::string convertUint16ToHexString(uint16_t intValue); /** * @brief This function converts a hex number represented by to chars to an 8-bit integer. * * @param twoChars Pointer to the two characters representing the hex value. * * @details E.g. when twoChars points to an array with the two characters "A5" then the function * will return 0xA5. * @return The converted integer. */ uint8_t convertHexStringToUint8(const char* twoChars); /** * @brief This function converts a hex number represented by 4 chars to an uint16_t. * * @param Pointer to the fourCharacters representing the 16-bit integer. * * @return The uint16_t result. */ uint16_t convertHexStringToUint16(const char* fourChars); /** * @brief Function converts a hex number represented by 6 or 8 characters to an uint32_t or * int32_t, depending on the template parameter. * * @param characters Pointer to the hex characters array. * @param numberOfChars Number of characters representing the hex value. Must be 6 or 8. * * @return The value. */ template T convertHexStringTo32bit(const char* characters, uint8_t numberOfChars); /** * @brief This function parses the status reply * @param status Pointer to the status information. * * @details Some commands reply with a status message giving information about the preceding * command transmission and/or execution was successful. */ ReturnValue_t parseReplyStatus(const char* status); /** * @brief Function verifies the received reply from the syrlinks by recalculating and * comparing the crc. * * @param packet Pointer to the received reply. * @param size Size of the whole packet including the crc and the packet termination * character '>'. * * @return returnvalue::OK if successful, otherwise returnvalue::FAILED. */ ReturnValue_t verifyReply(const uint8_t* packet, uint8_t size); /** * @brief This function extracts the data from a rx status registers reply and writes the * information to the status registers dataset. * @param packet Pointer to the reply packet. */ void parseRxStatusRegistersReply(const uint8_t* packet); void parseLclConfigReply(const uint8_t* packet); /** * @brief This function writes the read tx status register to the txStatusDataset. * @param packet Pointer to the received packet. */ void parseTxStatusReply(const uint8_t* packet); /** * @brief This function writes the received waveform configuration to the txDataset. */ void parseTxWaveformReply(const uint8_t* packet); /** * @brief The agc value is split over two registers. The parse agc functions are used to get * the values from the received reply and write them into the txDataset. */ void parseAgcLowByte(const uint8_t* packet); void parseAgcHighByte(const uint8_t* packet); /** * @brief Calculates temperature in degree celcius form raw value */ float calcTempVal(uint16_t); ReturnValue_t handleAckReply(const uint8_t* packet); void prepareCommand(std::string command, DeviceCommandId_t commandId); }; template T SyrlinksHandler::convertHexStringTo32bit(const char* characters, uint8_t numberOfChars) { if (sizeof(T) < 4) { sif::error << "SyrlinksHkHandler::convertHexStringToRaw: Only works for 32-bit conversion" << std::endl; } T value = 0; switch (numberOfChars) { case 6: // The bitshift trickery required is necessary when creating an int32_t from a // 24 bit signed value. value = ((convertHexStringToUint8(characters) << 24) | (convertHexStringToUint8(characters + 2) << 16) | (convertHexStringToUint8(characters + 4) << 8)) >> 8; return value; case 8: value = convertHexStringToUint8(characters) << 24 | convertHexStringToUint8(characters + 2) << 16 | convertHexStringToUint8(characters + 4) << 8 | convertHexStringToUint8(characters + 4); return value; default: sif::debug << "SyrlinksHkHandler::convertHexStringToUint32: Invalid number of characters. " << "Must be either 6 or 8" << std::endl; return 0; } } #endif /* MISSION_DEVICES_SYRLINKSHANDLER_H_ */