xref: /aosp_15_r20/external/pigweed/pw_stream_shmem_mcuxpresso/stream.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include "pw_stream_shmem_mcuxpresso/stream.h"
16 
17 #include <atomic>
18 #include <cstdint>
19 
20 namespace pw::stream {
21 namespace {
22 
23 constexpr uint32_t kMuRegDataSize = 0;
24 constexpr uint32_t kMuRegDataCopied = 1;
25 
26 }  // namespace
27 
~ShmemMcuxpressoStream()28 ShmemMcuxpressoStream::~ShmemMcuxpressoStream() { Disable(); }
29 
Enable()30 void ShmemMcuxpressoStream::Enable() {
31   MU_Init(base_);
32   MU_EnableInterrupts(base_,
33                       kMU_Tx0EmptyInterruptEnable | kMU_Rx0FullInterruptEnable |
34                           kMU_Rx1FullInterruptEnable);
35 }
36 
Disable()37 void ShmemMcuxpressoStream::Disable() {
38   MU_DisableInterrupts(base_,
39                        kMU_Tx0EmptyInterruptEnable |
40                            kMU_Rx0FullInterruptEnable |
41                            kMU_Rx1FullInterruptEnable);
42   MU_Deinit(base_);
43 }
44 
DoRead(ByteSpan data)45 StatusWithSize ShmemMcuxpressoStream::DoRead(ByteSpan data) {
46   read_semaphore_.acquire();
47 
48   const uint32_t msg_len = MU_ReceiveMsgNonBlocking(base_, kMuRegDataSize);
49   StatusWithSize result(msg_len);
50 
51   if (msg_len > shared_read_buffer_.size()) {
52     result = StatusWithSize::Internal();
53   } else if (msg_len > data.size()) {
54     result = StatusWithSize::InvalidArgument();
55   } else {
56     std::copy(shared_read_buffer_.begin(),
57               shared_read_buffer_.begin() + msg_len,
58               data.begin());
59     // Ensure all data is read before MU message is written.
60     std::atomic_thread_fence(std::memory_order_release);
61   }
62 
63   // Ack we're done with our copy. Use blocking send as the other side will
64   // process the message directly in ISR.
65   MU_SendMsg(base_, kMuRegDataCopied, msg_len);
66 
67   // Turn back on Rx0 interrupt, which will unblock next read.
68   MU_EnableInterrupts(base_, kMU_Rx0FullInterruptEnable);
69 
70   return result;
71 }
72 
DoWrite(ConstByteSpan data)73 Status ShmemMcuxpressoStream::DoWrite(ConstByteSpan data) {
74   if (data.size() > shared_write_buffer_.size()) {
75     return Status::InvalidArgument();
76   }
77   write_semaphore_.acquire();
78 
79   std::copy(data.begin(), data.end(), shared_write_buffer_.begin());
80 
81   // Ensure MU message is written after shared buffer is populated.
82   std::atomic_thread_fence(std::memory_order_release);
83 
84   MU_SendMsgNonBlocking(base_, kMuRegDataSize, data.size());
85 
86   write_done_semaphore_.acquire();
87 
88   MU_EnableInterrupts(base_, kMU_Tx0EmptyInterruptEnable);
89 
90   return OkStatus();
91 }
92 
HandleInterrupt()93 void ShmemMcuxpressoStream::HandleInterrupt() {
94   const uint32_t flags = MU_GetInterruptsPending(base_);
95   if (flags & kMU_Tx0EmptyFlag) {
96     write_semaphore_.release();
97     MU_DisableInterrupts(base_, kMU_Tx0EmptyInterruptEnable);
98   }
99   if (flags & kMU_Rx0FullFlag) {
100     read_semaphore_.release();
101     MU_DisableInterrupts(base_, kMU_Rx0FullInterruptEnable);
102   }
103   if (flags & kMU_Rx1FullFlag) {
104     write_done_semaphore_.release();
105     MU_ReceiveMsgNonBlocking(base_, kMuRegDataCopied);
106   }
107 }
108 
109 }  // namespace pw::stream
110