Line data Source code
1 : // Copyright 2024 Accenture. 2 : 3 : #pragma once 4 : 5 : #include <platform/estdint.h> 6 : 7 : namespace docan 8 : { 9 : /** 10 : * Enumeration defining state of the message. 11 : */ 12 : enum class ReceiveState : uint8_t 13 : { 14 : /// A transport message should be allocated. 15 : ALLOCATE, 16 : /// Waiting for receiving a frame or next try for message allocation. 17 : WAIT, 18 : /// A flow control frame should be sent. 19 : SEND, 20 : /// The received message should be processed. 21 : PROCESSING, 22 : /// The reception of the message has ended. 23 : DONE 24 : }; 25 : 26 : /** 27 : * Enumeration defining timeouts to be set. 28 : */ 29 : enum class ReceiveTimeout : uint8_t 30 : { 31 : /// No timeout is needed. 32 : NONE, 33 : /// Timeout for reception of a frame is needed. 34 : RX, 35 : /// Timeout until next allocation of message is needed. 36 : ALLOCATE 37 : }; 38 : 39 : /** 40 : * Message state emitted by the receiver. 41 : */ 42 : enum class ReceiveMessage : uint8_t 43 : { 44 : /// No message. 45 : NONE, 46 : /// An event has occurred in an unexpected state. 47 : ILLEGAL_STATE, 48 : /// The maximum number of allocation retries has exceeded. 49 : ALLOCATION_RETRY_COUNT_EXCEEDED, 50 : /// The timeout for frame reception has expired. 51 : RX_TIMEOUT_EXPIRED, 52 : /// A frame with an unexpected sequence number has been received. 53 : BAD_SEQUENCE_NUMBER, 54 : /// The processing of the message was not successful. 55 : PROCESSING_FAILED 56 : }; 57 : 58 : /** 59 : * Helper class that holds the result of event handling. Most important 60 : * is the hasTransition() method that indicates whether a state transition 61 : * to a new state has been performed. 62 : */ 63 : class ReceiveResult 64 : { 65 : public: 66 : /** 67 : * constructor. No message and no parameter is set. 68 : * \param transition flag whether a transition has been performed 69 : */ 70 : explicit ReceiveResult(bool transition); 71 : 72 : /** 73 : * Set a message without parameter. 74 : * \param message message to emit 75 : * \return reference to this object 76 : */ 77 : ReceiveResult& setMessage(ReceiveMessage message); 78 : 79 : /** 80 : * Set a message with parameter. 81 : * \param message message to emit 82 : * \param param additional parameter value 83 : * \return reference to this object 84 : */ 85 : ReceiveResult& setMessage(ReceiveMessage message, uint8_t param); 86 : 87 : /** 88 : * Test whether a transition has occurred. A state transition indicates that 89 : * timeouts should be reset. 90 : * \return true if a transition has occurred. 91 : */ 92 5597 : bool hasTransition() const { return _transition; } 93 : 94 : /** 95 : * Get the message that is connected with the result. 96 : * \return message value 97 : */ 98 1899 : ReceiveMessage getMessage() const { return _message; } 99 : 100 : /** 101 : * Get the parameter to a message. 102 : * \return parameter value 103 : */ 104 3 : uint8_t getParam() const { return _param; } 105 : 106 : /** 107 : * Check result for equality. Results are equal if all fields are identical. 108 : * \param other result to compare with 109 : * \return true if result is equal to other 110 : */ 111 : bool operator==(ReceiveResult const& other) const; 112 : 113 : private: 114 : bool _transition; 115 : ReceiveMessage _message; 116 : uint8_t _param; 117 : }; 118 : 119 : /** 120 : * Class encapsulating the protocol handling for reception of a single message. 121 : */ 122 : template<typename FrameIndexType> 123 : class DoCanMessageReceiveProtocolHandler 124 : { 125 : public: 126 : /** 127 : * Constructor. 128 : * \param frameCount number of expected frames 129 : */ 130 : explicit DoCanMessageReceiveProtocolHandler(FrameIndexType frameCount); 131 : 132 : /** 133 : * Get the current state of the message. 134 : * \return state 135 : */ 136 5700 : ReceiveState getState() const { return _state; } 137 : 138 : /** 139 : * Get the timeout to be set for this state. 140 : * \return timeout 141 : */ 142 1961 : ReceiveTimeout getTimeout() const { return _timeout; } 143 : 144 : /** 145 : * Get the index of the next expected frame. 146 : * \return frame index 147 : */ 148 12 : FrameIndexType getFrameIndex() const { return _frameIndex; } 149 : 150 : /** 151 : * Get the number of expected frames for the message. 152 : * \return frame count 153 : */ 154 18 : FrameIndexType getFrameCount() const { return _frameCount; } 155 : 156 : /** 157 : * Test whether the a wait flow control frame should be sent. 158 : * This flag is only valid if state is STATE_SEND. 159 : * \return true if the next flow control frame should be a wait frame 160 : */ 161 89 : bool isFlowControlWait() const { return (_allocateRetryCount > 0U) && (_frameCount > 1U); } 162 : 163 : /** 164 : * Test whether message allocation is required. This "allocation" state 165 : * can be present in more than one state. 166 : * \return true if allocation of a message is required 167 : */ 168 131 : bool isAllocating() const { return _isAllocating; } 169 : 170 : /** 171 : * Cancel the reception process and set to state done. 172 : * \param message message to emit 173 : * \return result indicating state transition (and given message) 174 : */ 175 13 : ReceiveResult cancel(ReceiveMessage const message = ReceiveMessage::NONE) 176 : { 177 13 : return setDone(message); 178 : } 179 : 180 : /** 181 : * Handles a shutdown request during message reception. 182 : * \return result indicating state transition 183 : */ 184 7 : ReceiveResult shutdown() 185 : { 186 7 : return (_state == ReceiveState::PROCESSING) ? ReceiveResult(false) : cancel(); 187 : } 188 : 189 : /** 190 : * Called to indicate the result of a message allocation try. 191 : * \param success true if a message has been allocated successfully 192 : * \param maxRetryCount maximum number of retries 193 : * \return result indicating state transition 194 : */ 195 : ReceiveResult allocated(bool success, uint8_t maxRetryCount); 196 : 197 : /** 198 : * Called to indicate that the CAN frame has been sent. 199 : * \param success true if the CAN frame has been sent successfully 200 : * \return result indicating state transition 201 : */ 202 : ReceiveResult frameSent(bool success); 203 : 204 : /** 205 : * Called to indicate that a consecutive frame has been received. 206 : * \param frameIndex sequence number of the received frame 207 : * \param maxBlockSize maximum block size for message reception 208 : * \return result indicating state transition 209 : */ 210 : ReceiveResult consecutiveFrameReceived(uint8_t frameIndex, uint8_t maxBlockSize); 211 : 212 : /** 213 : * Called to indicate the result of message processing. 214 : * \param success true if message processing was successful 215 : * \return result indicating state transition 216 : */ 217 31 : ReceiveResult processed(bool const success) 218 : { 219 31 : return setDone(success ? ReceiveMessage::NONE : ReceiveMessage::PROCESSING_FAILED); 220 : } 221 : 222 : /** 223 : * Called to indicate that the current timeout has expired 224 : * \return result indicating state transition 225 : */ 226 23 : ReceiveResult expired() 227 : { 228 23 : switch (_timeout) 229 : { 230 9 : case ReceiveTimeout::RX: 231 : { 232 9 : return setDone(ReceiveMessage::RX_TIMEOUT_EXPIRED); 233 : } 234 13 : case ReceiveTimeout::ALLOCATE: 235 : { 236 13 : return setState(ReceiveState::ALLOCATE); 237 : } 238 1 : default: 239 : { 240 1 : return ReceiveResult(false); 241 : } 242 : } 243 : } 244 : 245 : private: 246 : inline ReceiveResult 247 : setState(ReceiveState state, ReceiveTimeout timeout = ReceiveTimeout::NONE); 248 : inline ReceiveResult setDone(ReceiveMessage message = ReceiveMessage::NONE, uint8_t param = 0U); 249 : 250 : FrameIndexType _frameIndex; 251 : FrameIndexType const _frameCount; 252 : ReceiveState _state; 253 : ReceiveTimeout _timeout; 254 : uint8_t _blockFrameIndex; 255 : uint8_t _allocateRetryCount; 256 : bool _isAllocating; 257 : }; 258 : 259 : /** 260 : * Inline implementation. 261 : */ 262 : 263 : template<typename FrameIndexType> 264 76 : inline DoCanMessageReceiveProtocolHandler<FrameIndexType>::DoCanMessageReceiveProtocolHandler( 265 : FrameIndexType const frameCount) 266 76 : : _frameIndex(1U) 267 76 : , _frameCount(frameCount) 268 76 : , _state(ReceiveState::ALLOCATE) 269 76 : , _timeout(ReceiveTimeout::NONE) 270 76 : , _blockFrameIndex(0U) 271 76 : , _allocateRetryCount(0U) 272 76 : , _isAllocating(true) 273 76 : {} 274 : 275 : template<typename FrameIndexType> 276 84 : inline ReceiveResult DoCanMessageReceiveProtocolHandler<FrameIndexType>::allocated( 277 : bool const success, uint8_t const maxRetryCount) 278 : { 279 84 : if (!_isAllocating) 280 : { 281 1 : return ReceiveResult(true).setMessage( 282 1 : ReceiveMessage::ILLEGAL_STATE, static_cast<uint8_t>(_state)); 283 : } 284 : 285 83 : if (success) 286 : { 287 56 : _isAllocating = false; 288 56 : _allocateRetryCount = 0U; 289 56 : return setState((_frameCount == 1U) ? ReceiveState::PROCESSING : ReceiveState::SEND); 290 : } 291 : 292 27 : if (_frameCount == 1U) 293 : { 294 13 : ++_allocateRetryCount; 295 13 : if (_allocateRetryCount > 1U) 296 : { 297 2 : return setDone(ReceiveMessage::ALLOCATION_RETRY_COUNT_EXCEEDED); 298 : } 299 : 300 11 : return setState(ReceiveState::WAIT, ReceiveTimeout::ALLOCATE); 301 : } 302 : 303 14 : ++_allocateRetryCount; 304 14 : if (_allocateRetryCount > maxRetryCount) 305 : { 306 2 : return setDone(ReceiveMessage::ALLOCATION_RETRY_COUNT_EXCEEDED); 307 : } 308 : 309 12 : return setState(ReceiveState::SEND); 310 : } 311 : 312 : template<typename FrameIndexType> 313 : inline ReceiveResult 314 50 : DoCanMessageReceiveProtocolHandler<FrameIndexType>::frameSent(bool const success) 315 : { 316 50 : if (_state != ReceiveState::SEND) 317 : { 318 1 : return ReceiveResult(true).setMessage( 319 1 : ReceiveMessage::ILLEGAL_STATE, static_cast<uint8_t>(_state)); 320 : } 321 49 : if (success) 322 : { 323 46 : return setState( 324 : ReceiveState::WAIT, 325 92 : isFlowControlWait() ? ReceiveTimeout::ALLOCATE : ReceiveTimeout::RX); 326 : } 327 3 : return ReceiveResult(false); 328 : } 329 : 330 : template<typename FrameIndexType> 331 1768 : inline ReceiveResult DoCanMessageReceiveProtocolHandler<FrameIndexType>::consecutiveFrameReceived( 332 : uint8_t const frameIndex, uint8_t const maxBlockSize) 333 : { 334 1768 : if ((_state != ReceiveState::WAIT) || (_timeout != ReceiveTimeout::RX)) 335 : { 336 2 : return ReceiveResult(false); 337 : } 338 : 339 1766 : if ((_frameIndex & 0xFU) != frameIndex) 340 : { 341 3 : return setDone(ReceiveMessage::BAD_SEQUENCE_NUMBER, frameIndex); 342 : } 343 : 344 1763 : ++_frameIndex; 345 1763 : if (_frameIndex == _frameCount) 346 : { 347 18 : return setState(ReceiveState::PROCESSING); 348 : } 349 1745 : if (maxBlockSize > 0U) 350 : { 351 6 : ++_blockFrameIndex; 352 6 : if (_blockFrameIndex == maxBlockSize) 353 : { 354 3 : _blockFrameIndex = 0U; 355 3 : return setState(ReceiveState::SEND); 356 : } 357 : } 358 : // set state to wait for timeout as in the default case 359 1742 : return setState(ReceiveState::WAIT, ReceiveTimeout::RX); 360 : } 361 : 362 : template<typename FrameIndexType> 363 1901 : inline ReceiveResult DoCanMessageReceiveProtocolHandler<FrameIndexType>::setState( 364 : ReceiveState const state, ReceiveTimeout const timeout) 365 : { 366 1901 : _state = state; 367 1901 : _timeout = timeout; 368 1901 : return ReceiveResult(true); 369 : } 370 : 371 : template<typename FrameIndexType> 372 60 : inline ReceiveResult DoCanMessageReceiveProtocolHandler<FrameIndexType>::setDone( 373 : ReceiveMessage const message, uint8_t const param) 374 : { 375 60 : _state = ReceiveState::DONE; 376 60 : _timeout = ReceiveTimeout::NONE; 377 60 : _isAllocating = false; 378 60 : return ReceiveResult(true).setMessage(message, param); 379 : } 380 : 381 3883 : inline ReceiveResult::ReceiveResult(bool const transition) 382 3883 : : _transition(transition), _message(ReceiveMessage::NONE), _param() 383 3883 : {} 384 : 385 7 : inline ReceiveResult& ReceiveResult::setMessage(ReceiveMessage const message) 386 : { 387 7 : _message = message; 388 7 : _param = 0U; 389 7 : return *this; 390 : } 391 : 392 75 : inline ReceiveResult& ReceiveResult::setMessage(ReceiveMessage const message, uint8_t const param) 393 : { 394 75 : _message = message; 395 75 : _param = param; 396 75 : return *this; 397 : } 398 : 399 86 : inline bool ReceiveResult::operator==(ReceiveResult const& other) const 400 : { 401 85 : return (_transition == other._transition) && (_message == other._message) 402 171 : && (_param == other._param); 403 : } 404 : 405 : } // namespace docan