| /* |
| * Copyright (C) 2020 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #ifndef CHPP_PLATFORM_UART_LINK_MANAGER_H_ |
| #define CHPP_PLATFORM_UART_LINK_MANAGER_H_ |
| |
| #include "FreeRTOS.h" |
| #include "chpp/condition_variable.h" |
| #include "chpp/link.h" |
| #include "chpp/mutex.h" |
| #include "chpp/platform/chpp_task_util.h" |
| #include "chpp/transport.h" |
| #include "chre/platform/atomic.h" |
| #include "chre/util/non_copyable.h" |
| #include "chre/util/time.h" |
| #include "core_monitor.h" |
| #include "gpi_aoc.h" |
| #include "gpio_aoc.h" |
| #include "uart.h" |
| |
| namespace chpp { |
| |
| /** |
| * A class to manage a CHPP link to a remote CHPP endpoint using UART as the |
| * physical layer. Each physical link must instantiate its own instance of |
| * the UartLinkManager. |
| * |
| * This class implements the wake handshaking protocol as follows. Each endpoint |
| * is expected to have a wake_in and wake_out GPIO and a bidirectional UART |
| * link. |
| * |
| * 1) A transaction begins by a request to transmit a packet from either |
| * end of the link. If the local endpoint has data to transmit, it must notify |
| * the remote endpoint by asserting its wake_out GPIO. Consequently, a request |
| * from the remote endpoint is driven by an IRQ from the wake_in GPIO. |
| * |
| * 2) If a packet is pending, it can be transmitted once the remote end has |
| * asserted its wake_out GPIO. Otherwise, the wake_out GPIO pulse should be |
| * asserted for at least the duration to satisfy the pulse width requirements of |
| * the specification. |
| * |
| * 3) The wake_out GPIO can be deasserted once the transmission is complete (if |
| * any). No transaction can begin until the current one has completed, and both |
| * GPIOs have been deasserted. |
| */ |
| class UartLinkManager : public chre::NonCopyable { |
| public: |
| /** |
| * @param context The context pointer of the CHPP transport. |
| * @param uart The pointer to the UART instance. |
| * @param wakeOutPinNumber The pin number of the wake_out GPIO. |
| * @param wakeInGpiNumber The GPI number of the wake_in GPIO. |
| * @param mask The mask to use when preventing monitor mode. |
| * @param wakeHandshakeEnable true to enable wake handshaking. |
| */ |
| UartLinkManager(struct ChppTransportState *context, UART *uart, |
| uint8_t wakeOutPinNumber, uint8_t wakeInGpiNumber, |
| enum PreventCoreMonitorMask mask, |
| bool wakeHandshakeEnable = false); |
| |
| /** |
| * This method must be called before invoking the rest of the public methods |
| * in this class. |
| * |
| * @param handle The task handle that this manager will run in. |
| */ |
| void init(TaskHandle_t handle); |
| |
| /** |
| * Resets the state and disables the UartLinkManager. init() must be called |
| * after invoking this method to use this class again. |
| */ |
| void deinit(); |
| |
| /** |
| * @param buf The non-null pointer to the buffer. |
| * @param len The length of the above buffer. |
| * |
| * @return true if the packet was successfully prepared to be transmitted in |
| * the next transaction. |
| */ |
| bool prepareTxPacket(uint8_t *buf, size_t len); |
| |
| /** |
| * Starts a transaction to transmit any pending packets (if any, via a |
| * previous call to prepareTxPacket()), and handles the wake handshaking |
| * protocol. |
| * |
| * @return true if the transaction succeeded. |
| */ |
| bool startTransaction(); |
| |
| /** |
| * Pulls RX data from the UART peripheral. |
| */ |
| void pullRxSamples(); |
| |
| /** |
| * Same as pullRxSamples() but also sends the data to the CHPP transport. |
| */ |
| void processRxSamples(); |
| |
| struct ChppTransportState *getTransportContext() const { |
| return mTransportContext; |
| } |
| |
| UART *getUart() const { |
| return mUart; |
| } |
| |
| GPIAoC *getWakeInGpi() { |
| return &mWakeInGpi; |
| } |
| |
| /** |
| * Functions that should be called before/after a transaction, respectively. |
| * |
| * Note that prepareForTransaction() may be called by either a wake IRQ or |
| * from the CHPP thread indicating that TX data is ready. On the contrary, |
| * completeTransction() is always called from within the CHPP work thread, |
| * since the above two events are handled together if occurring |
| * simultaneously. |
| */ |
| void prepareForTransaction(); |
| void completeTransaction(); |
| |
| TaskHandle_t getTaskHandle() const { |
| return mTaskHandle; |
| } |
| |
| /** |
| * Waits for a wake handshaking IRQ to trigger, with a specified timeout. |
| * |
| * @param timeoutNs The timeout in nanoseconds. |
| * |
| * @return false if timed out |
| */ |
| bool waitForHandshakeIrq(uint64_t timeoutNs); |
| |
| bool isRxBufferFull() const { |
| return mRxBufIndex == kRxBufSize; |
| } |
| |
| /** |
| * Allow core monitor for this UART. |
| */ |
| void allowCoreMonitor(); |
| |
| /** |
| * This function should be used to trigger allowing core monitor at the end of |
| * a transaction. |
| */ |
| void onCoreMonitorAllowEvent(); |
| |
| /** |
| * GPIO pin numbers to be used in the argument of UartLinkManager, which |
| * defines the physical pin used for the wake_out GPIO. |
| */ |
| static constexpr uint8_t kWifiWakeOutGpioPinNumber = 43; |
| static constexpr uint8_t kGnssWakeOutGpioPinNumber = 86; |
| static constexpr uint8_t kWwanWakeOutGpioPinNumber = 84; |
| |
| /** |
| * GPI numbers to be used in the argument of UartLinkManager, which defines |
| * the GPI used to generate the wake_in interrupts. |
| */ |
| static constexpr uint8_t kWifiWakeInGpiNumber = 46; |
| static constexpr uint8_t kGnssWakeInGpiNumber = 44; |
| static constexpr uint8_t kWwanWakeInGpiNumber = 42; |
| |
| private: |
| TaskHandle_t mTaskHandle = nullptr; |
| |
| struct ChppTransportState *mTransportContext = nullptr; |
| |
| UART *mUart = nullptr; |
| |
| GPIOAoC mWakeOutGpio; |
| |
| GPIAoC mWakeInGpi; |
| |
| //! The pointer to the currently pending TX packet. |
| uint8_t *mCurrentBuffer = nullptr; |
| size_t mCurrentBufferLen = 0; |
| |
| //! The temporary buffer to store RX data. |
| //! NOTE: Access to these variables must be done when the RX interrupt is |
| //! disabled. |
| static constexpr size_t kRxBufSize = CHPP_PLATFORM_LINK_RX_MTU_BYTES; |
| volatile uint8_t mRxBuf[kRxBufSize]; |
| volatile size_t mRxBufIndex = 0; |
| |
| //! The timeout for waiting on the remote to indicate transaction readiness |
| //! (t_start per specifications). |
| static constexpr uint64_t kStartTimeoutNs = |
| 100 * chre::kOneMillisecondInNanoseconds; |
| |
| //! The timeout for waiting on the remote to indicate transaction ended |
| //! (t_end per specifications). |
| static constexpr uint64_t kEndTimeoutNs = chre::kOneSecondInNanoseconds; |
| |
| //! The minimum amount of time to assert the wake_out GPIO (t_pulse per |
| //! specifications). |
| static constexpr uint64_t kPulseTimeNs = |
| 100 * chre::kOneMicrosecondInNanoseconds; |
| |
| static constexpr uint64_t kSuspendTimeoutNs = |
| 100 * chre::kOneMillisecondInNanoseconds; |
| |
| chre::AtomicBool mTransactionPending{false}; |
| |
| TaskUtil mTaskUtil; |
| |
| //! The mask to use when allowing or preventing core monitor mode. This should |
| //! be used while wake handshaking is in progress to avoid the UART clock |
| //! from being turned off. |
| enum PreventCoreMonitorMask mCoreMonitorMask; |
| |
| //! true to enable wake handshake algorithm. |
| const bool mWakeHandshakeEnabled; |
| |
| //! The refcount to use when allowing core monitor mode. This value should |
| //! be incremented to "vote" to prevent, decremented to "vote" to allow. The |
| //! module should allow core monitor once the count has reached zero. The |
| //! refcount scheme may be helpful in avoiding allowing core monitor too |
| //! early. |
| chre::AtomicUint32 mCoreMonitorRefCount{0}; |
| |
| /** |
| * @return if a TX packet is pending transmission. |
| */ |
| bool hasTxPacket() const; |
| |
| /** |
| * Clears a pending TX packet. |
| */ |
| void clearTxPacket(); |
| }; |
| |
| } // namespace chpp |
| |
| #endif // CHPP_PLATFORM_UART_LINK_MANAGER_H_ |