#ifndef MISSION_DEVICES_DEVICEDEFINITIONS_RWHELPERS_H_ #define MISSION_DEVICES_DEVICEDEFINITIONS_RWHELPERS_H_ #include #include #include #include #include "eive/resultClassIds.h" #include "events/subsystemIdRanges.h" #include "objects/systemObjectList.h" namespace rws { void encodeHdlc(const uint8_t* sourceBuf, size_t sourceLen, uint8_t* encodedBuffer, size_t& encodedLen); size_t idToPacketLen(DeviceCommandId_t id); static const size_t SIZE_GET_RESET_STATUS = 5; static const size_t SIZE_CLEAR_RESET_STATUS = 4; static const size_t SIZE_INIT_RW = 4; static const size_t SIZE_GET_RW_STATUS = 14; static const size_t SIZE_SET_SPEED_REPLY = 4; static const size_t SIZE_GET_TEMPERATURE_REPLY = 8; /** Max size when requesting telemetry */ static const size_t SIZE_GET_TELEMETRY_REPLY = 91; //! This is the end and start marker of the frame datalinklayer. Also called frame delimiter //! in the NanoAvionics datasheet. static constexpr uint8_t FRAME_DELIMITER = 0x7E; enum class SpecialRwRequest : uint8_t { REQUEST_NONE = 0, RESET_MCU = 1, INIT_RW_CONTROLLER = 2, GET_TM = 3, NUM_REQUESTS }; struct RwRequest { acs::SimpleSensorMode mode = acs::SimpleSensorMode::OFF; bool setSpeed = true; int32_t currentRwSpeed = 0; uint16_t currentRampTime = 0; rws::SpecialRwRequest specialRequest = rws::SpecialRwRequest::REQUEST_NONE; uint8_t rwIdx = 0; }; static const uint8_t INTERFACE_ID = CLASS_ID::RW_HANDLER; static const ReturnValue_t SPI_WRITE_FAILURE = MAKE_RETURN_CODE(0xB0); //! [EXPORT] : [COMMENT] Used by the spi send function to tell a failing read call static const ReturnValue_t SPI_READ_FAILURE = MAKE_RETURN_CODE(0xB1); //! [EXPORT] : [COMMENT] Can be used by the HDLC decoding mechanism to inform about a missing //! start sign 0x7E static const ReturnValue_t MISSING_START_SIGN = MAKE_RETURN_CODE(0xB2); //! [EXPORT] : [COMMENT] Can be used by the HDLC decoding mechanism to inform about an invalid //! substitution combination static const ReturnValue_t INVALID_SUBSTITUTE = MAKE_RETURN_CODE(0xB3); //! [EXPORT] : [COMMENT] HDLC decoding mechanism never receives the end sign 0x7E static const ReturnValue_t MISSING_END_SIGN = MAKE_RETURN_CODE(0xB4); //! [EXPORT] : [COMMENT] Reaction wheel only responds with empty frames. static const ReturnValue_t NO_REPLY = MAKE_RETURN_CODE(0xB5); //! [EXPORT] : [COMMENT] Expected a start marker as first byte static const ReturnValue_t NO_START_MARKER = MAKE_RETURN_CODE(0xB6); //! [EXPORT] : [COMMENT] Timeout when reading reply static const ReturnValue_t SPI_READ_TIMEOUT = MAKE_RETURN_CODE(0xB7); static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::RW_HANDLER; //! [EXPORT] : [COMMENT] Reaction wheel signals an error state static constexpr Event ERROR_STATE = MAKE_EVENT(1, severity::HIGH); static constexpr Event RESET_OCCURED = event::makeEvent(SUBSYSTEM_ID, 2, severity::LOW); //! Minimal delay as specified by the datasheet. static const uint32_t SPI_REPLY_DELAY = 20000; // us enum PoolIds : lp_id_t { TEMPERATURE_C, CURR_SPEED, REFERENCE_SPEED, STATE, CLC_MODE, LAST_RESET_STATUS, CURRRENT_RESET_STATUS, TM_LAST_RESET_STATUS, TM_MCU_TEMPERATURE, PRESSURE_SENSOR_TEMPERATURE, PRESSURE, TM_RW_STATE, TM_CLC_MODE, TM_RW_CURR_SPEED, TM_RW_REF_SPEED, INVALID_CRC_PACKETS, INVALID_LEN_PACKETS, INVALID_CMD_PACKETS, EXECUTED_REPLIES, COMMAND_REPLIES, UART_BYTES_WRITTEN, UART_BYTES_READ, UART_PARITY_ERRORS, UART_NOISE_ERRORS, UART_FRAME_ERRORS, UART_REG_OVERRUN_ERRORS, UART_TOTAL_ERRORS, TOTAL_ERRORS, SPI_BYTES_WRITTEN, SPI_BYTES_READ, SPI_REG_OVERRUN_ERRORS, SPI_TOTAL_ERRORS, RW_SPEED, RAMP_TIME, }; enum States : uint8_t { STATE_ERROR, IDLE, COASTING, RUNNING_SPEED_STABLE, RUNNING_SPEED_CHANGING }; enum LastResetStatusBitPos : uint8_t { PIN_RESET = 0, POR_PDR_BOR_RESET = 1, SOFTWARE_RESET = 2, INDEPENDENT_WATCHDOG_RESET = 3, WINDOW_WATCHDOG_RESET = 4, LOW_POWER_RESET = 5 }; enum DeviceCommandId : DeviceCommandId_t { RESET_MCU = 1, GET_LAST_RESET_STATUS = 2, CLEAR_LAST_RESET_STATUS = 3, GET_RW_STATUS = 4, INIT_RW_CONTROLLER = 5, SET_SPEED = 6, GET_TEMPERATURE = 8, GET_TM = 9 }; static constexpr DeviceCommandId_t REQUEST_ID = 0x77; static constexpr DeviceCommandId_t REPLY_ID = 0x78; enum SetIds : uint32_t { TEMPERATURE_SET_ID = DeviceCommandId::GET_TEMPERATURE, STATUS_SET_ID = DeviceCommandId::GET_RW_STATUS, LAST_RESET_ID = DeviceCommandId::GET_LAST_RESET_STATUS, TM_SET_ID = DeviceCommandId::GET_TM, SPEED_CMD_SET = 10, }; /** Set speed command has maximum size */ static const size_t MAX_CMD_SIZE = 9; /** * Max reply is reached when each byte is replaced by its substitude which should normally never * happen. */ static const size_t MAX_REPLY_SIZE = 2 * SIZE_GET_TELEMETRY_REPLY; static const uint8_t LAST_RESET_ENTRIES = 2; static const uint8_t STATUS_SET_ENTRIES = 5; static const uint8_t TM_SET_ENTRIES = 24; /** * @brief This dataset can be used to store the data periodically polled from the RW */ class StatusSet : public StaticLocalDataSet { public: StatusSet(HasLocalDataPoolIF* owner) : StaticLocalDataSet(owner, rws::SetIds::STATUS_SET_ID) {} StatusSet(object_id_t objectId) : StaticLocalDataSet(sid_t(objectId, rws::SetIds::STATUS_SET_ID)) {} lp_var_t temperatureCelcius = lp_var_t(sid.objectId, PoolIds::TEMPERATURE_C, this); lp_var_t currSpeed = lp_var_t(sid.objectId, PoolIds::CURR_SPEED, this); lp_var_t referenceSpeed = lp_var_t(sid.objectId, PoolIds::REFERENCE_SPEED, this); lp_var_t state = lp_var_t(sid.objectId, PoolIds::STATE, this); lp_var_t clcMode = lp_var_t(sid.objectId, PoolIds::CLC_MODE, this); }; /** * @brief This dataset stores the last reset status. */ class LastResetSatus : public StaticLocalDataSet { public: LastResetSatus(HasLocalDataPoolIF* owner) : StaticLocalDataSet(owner, rws::SetIds::LAST_RESET_ID) {} LastResetSatus(object_id_t objectId) : StaticLocalDataSet(sid_t(objectId, rws::SetIds::LAST_RESET_ID)) {} // If a reset occurs, the status code will be cached into this variable lp_var_t lastNonClearedResetStatus = lp_var_t(sid.objectId, PoolIds::LAST_RESET_STATUS, this); // This will always contain the last polled reset status lp_var_t currentResetStatus = lp_var_t(sid.objectId, PoolIds::CURRRENT_RESET_STATUS, this); }; /** * @brief This dataset stores telemetry data as specified in the datasheet of the nano avionics * reaction wheels. https://eive-cloud.irs.uni-stuttgart.de/index.php/apps/files/?dir=/ * EIVE_IRS/Arbeitsdaten/08_Used%20Components/Nanoavionics_Reactionwheels&fileid=181622 */ class TmDataset : public StaticLocalDataSet { public: TmDataset(HasLocalDataPoolIF* owner) : StaticLocalDataSet(owner, rws::SetIds::TM_SET_ID) {} TmDataset(object_id_t objectId) : StaticLocalDataSet(sid_t(objectId, rws::SetIds::TM_SET_ID)) {} lp_var_t lastResetStatus = lp_var_t(sid.objectId, PoolIds::TM_LAST_RESET_STATUS, this); lp_var_t mcuTemperature = lp_var_t(sid.objectId, PoolIds::TM_MCU_TEMPERATURE, this); lp_var_t pressureSensorTemperature = lp_var_t(sid.objectId, PoolIds::PRESSURE_SENSOR_TEMPERATURE, this); lp_var_t pressure = lp_var_t(sid.objectId, PoolIds::PRESSURE, this); lp_var_t rwState = lp_var_t(sid.objectId, PoolIds::TM_RW_STATE, this); lp_var_t rwClcMode = lp_var_t(sid.objectId, PoolIds::TM_CLC_MODE, this); lp_var_t rwCurrSpeed = lp_var_t(sid.objectId, PoolIds::TM_RW_CURR_SPEED, this); lp_var_t rwRefSpeed = lp_var_t(sid.objectId, PoolIds::TM_RW_REF_SPEED, this); lp_var_t numOfInvalidCrcPackets = lp_var_t(sid.objectId, PoolIds::INVALID_CRC_PACKETS, this); lp_var_t numOfInvalidLenPackets = lp_var_t(sid.objectId, PoolIds::INVALID_LEN_PACKETS, this); lp_var_t numOfInvalidCmdPackets = lp_var_t(sid.objectId, PoolIds::INVALID_CMD_PACKETS, this); lp_var_t numOfCmdExecutedReplies = lp_var_t(sid.objectId, PoolIds::EXECUTED_REPLIES, this); lp_var_t numOfCmdReplies = lp_var_t(sid.objectId, PoolIds::COMMAND_REPLIES, this); lp_var_t uartNumOfBytesWritten = lp_var_t(sid.objectId, PoolIds::UART_BYTES_WRITTEN, this); lp_var_t uartNumOfBytesRead = lp_var_t(sid.objectId, PoolIds::UART_BYTES_READ, this); lp_var_t uartNumOfParityErrors = lp_var_t(sid.objectId, PoolIds::UART_PARITY_ERRORS, this); lp_var_t uartNumOfNoiseErrors = lp_var_t(sid.objectId, PoolIds::UART_NOISE_ERRORS, this); lp_var_t uartNumOfFrameErrors = lp_var_t(sid.objectId, PoolIds::UART_FRAME_ERRORS, this); lp_var_t uartNumOfRegisterOverrunErrors = lp_var_t(sid.objectId, PoolIds::UART_REG_OVERRUN_ERRORS, this); lp_var_t uartTotalNumOfErrors = lp_var_t(sid.objectId, PoolIds::UART_TOTAL_ERRORS, this); lp_var_t spiNumOfBytesWritten = lp_var_t(sid.objectId, PoolIds::SPI_BYTES_WRITTEN, this); lp_var_t spiNumOfBytesRead = lp_var_t(sid.objectId, PoolIds::SPI_BYTES_READ, this); lp_var_t spiNumOfRegisterOverrunErrors = lp_var_t(sid.objectId, PoolIds::SPI_REG_OVERRUN_ERRORS, this); lp_var_t spiTotalNumOfErrors = lp_var_t(sid.objectId, PoolIds::SPI_TOTAL_ERRORS, this); }; class RwSpeedActuationSet : public StaticLocalDataSet<2> { friend class RwHandler; public: RwSpeedActuationSet(HasLocalDataPoolIF& owner) : StaticLocalDataSet(&owner, rws::SetIds::SPEED_CMD_SET) {} RwSpeedActuationSet(object_id_t objectId) : StaticLocalDataSet(sid_t(objectId, rws::SetIds::SPEED_CMD_SET)) {} void setRwSpeed(int32_t rwSpeed_, uint16_t rampTime_) { if (rwSpeed.value != rwSpeed_) { rwSpeed = rwSpeed_; } if (rampTime.value != rampTime_) { rampTime = rampTime_; } } void getRwSpeed(int32_t& rwSpeed_, uint16_t& rampTime_) { rwSpeed_ = rwSpeed.value; rampTime_ = rampTime.value; } private: lp_var_t rwSpeed = lp_var_t(sid.objectId, rws::PoolIds::RW_SPEED, this); lp_var_t rampTime = lp_var_t(sid.objectId, rws::PoolIds::RAMP_TIME, this); }; } // namespace rws /** * Raw pointer overlay to hold the different frames received from the reaction * wheel in a raw buffer and send them to the device handler. */ struct RwReplies { friend class RwPollingTask; public: RwReplies(const uint8_t* rawData) : rawData(const_cast(rawData)) { initPointers(); } const uint8_t* getClearLastResetStatusReply() const { return clearLastResetStatusReply + 1; } bool wasClearLastRsetStatusReplyRead() const { return clearLastResetStatusReply[0]; } const uint8_t* getGetLastResetStatusReply() const { return getLastResetStatusReply + 1; } bool wasGetLastStatusReplyRead() const { return getLastResetStatusReply[0]; } const uint8_t* getHkDataReply() const { return hkDataReply + 1; } bool wasHkDataReplyRead() const { return hkDataReply[0]; } const uint8_t* getInitRwControllerReply() const { return initRwControllerReply + 1; } bool wasInitRwControllerReplyRead() const { return initRwControllerReply[0]; } const uint8_t* getRawData() const { return rawData; } const uint8_t* getReadTemperatureReply() const { return readTemperatureReply + 1; } bool wasReadTemperatureReplySet() const { return readTemperatureReply[0]; } const uint8_t* getRwStatusReply() const { return rwStatusReply + 1; } bool wasRwStatusRead() const { return rwStatusReply[0]; } const uint8_t* getSetSpeedReply() const { return setSpeedReply + 1; } bool wasSetSpeedReplyRead() const { return setSpeedReply[0]; } private: RwReplies(uint8_t* rwData) : rawData(rwData) { initPointers(); } /** * The first byte of the reply buffers contains a flag which shows whether that * frame was read from the reaction wheel at least once. */ void initPointers() { rwStatusReply = rawData; setSpeedReply = rawData + rws::SIZE_GET_RW_STATUS + 1; getLastResetStatusReply = setSpeedReply + rws::SIZE_SET_SPEED_REPLY + 1; clearLastResetStatusReply = getLastResetStatusReply + rws::SIZE_GET_RESET_STATUS + 1; readTemperatureReply = clearLastResetStatusReply + rws::SIZE_CLEAR_RESET_STATUS + 1; hkDataReply = readTemperatureReply + rws::SIZE_GET_TEMPERATURE_REPLY + 1; initRwControllerReply = hkDataReply + rws::SIZE_GET_TELEMETRY_REPLY + 1; dummyPointer = initRwControllerReply + rws::SIZE_INIT_RW + 1; } uint8_t* rawData; uint8_t* rwStatusReply; uint8_t* setSpeedReply; uint8_t* getLastResetStatusReply; uint8_t* clearLastResetStatusReply; uint8_t* readTemperatureReply; uint8_t* hkDataReply; uint8_t* initRwControllerReply; uint8_t* dummyPointer; }; #endif /* MISSION_DEVICES_DEVICEDEFINITIONS_RWHELPERS_H_ */