Send a request to an expansion board and append the response to 'reply'. The response may either be a standard reply or 'replyType'.
| 791 | |
| 792 | // Send a request to an expansion board and append the response to 'reply'. The response may either be a standard reply or 'replyType'. |
| 793 | GCodeResult CanInterface::SendRequestAndGetCustomReply(CanMessageBuffer *buf, CanRequestId rid, const StringRef& reply, uint8_t *extra, CanMessageType replyType, function_ref_noexcept<void(const CanMessageBuffer*) noexcept> callback) noexcept |
| 794 | { |
| 795 | if (can0dev == nullptr) |
| 796 | { |
| 797 | // Transactions sometimes get requested after we have shut down CAN, e.g. when we destroy filament monitors |
| 798 | CanMessageBuffer::Free(buf); |
| 799 | return GCodeResult::error; |
| 800 | } |
| 801 | |
| 802 | const CanAddress dest = buf->id.Dst(); |
| 803 | const CanMessageType msgType = buf->id.MsgType(); // save for possible error message |
| 804 | |
| 805 | { |
| 806 | // This code isn't re-entrant and it can get called from a task other than Main to shut the system down, so we need to use a mutex |
| 807 | MutexLocker lock(transactionMutex); |
| 808 | |
| 809 | SendCanMessage(TxBufferIndexRequest, MaxRequestSendWait, buf); |
| 810 | reprap.GetPlatform().OnProcessingCanMessage(); |
| 811 | |
| 812 | const uint32_t whenStartedWaiting = millis(); |
| 813 | uint32_t timeWaiting = 0; |
| 814 | unsigned int fragmentsReceived = 0; |
| 815 | for (;;) |
| 816 | { |
| 817 | const uint32_t timeout = (timeWaiting < UsualResponseTimeout) ? UsualResponseTimeout - timeWaiting : 1; |
| 818 | if (!can0dev->ReceiveMessage(RxBufferIndexResponse, timeout, buf)) |
| 819 | { |
| 820 | break; |
| 821 | } |
| 822 | |
| 823 | if (reprap.Debug(Module::CAN)) |
| 824 | { |
| 825 | buf->DebugPrint("Rx1:"); |
| 826 | } |
| 827 | |
| 828 | // The following code allows for the possibility of receiving a StandardReply (e.g. because an error occurred) when we were expecting a different reply. |
| 829 | // It assumes that any custom reply we may want has the requestId in the same place as a StandardReply. |
| 830 | const bool matchesRequest = buf->id.Src() == dest |
| 831 | && (buf->msg.standardReply.requestId == rid || buf->msg.standardReply.requestId == CanRequestIdAcceptAlways); |
| 832 | if (matchesRequest && buf->id.MsgType() == CanMessageType::standardReply && buf->msg.standardReply.fragmentNumber == fragmentsReceived) |
| 833 | { |
| 834 | if (fragmentsReceived == 0) |
| 835 | { |
| 836 | const size_t textLength = buf->msg.standardReply.GetTextLength(buf->dataLength); |
| 837 | if (textLength != 0) // avoid concatenating blank lines to existing output |
| 838 | { |
| 839 | reply.lcatn(buf->msg.standardReply.text, textLength); |
| 840 | } |
| 841 | if (extra != nullptr) |
| 842 | { |
| 843 | *extra = buf->msg.standardReply.extra; |
| 844 | } |
| 845 | uint32_t waitedFor = millis() - whenStartedWaiting; |
| 846 | if (waitedFor > longestWaitTime) |
| 847 | { |
| 848 | longestWaitTime = waitedFor; |
| 849 | longestWaitMessageType = (uint16_t)msgType; |
| 850 | } |
nothing calls this directly
no test coverage detected