You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
128 lines
3.0 KiB
128 lines
3.0 KiB
/*
|
|
* Copyright 2023 jacqueline <me@jacqueline.id.au>
|
|
*
|
|
* SPDX-License-Identifier: GPL-3.0-only
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <stdint.h>
|
|
|
|
#include <atomic>
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <mutex>
|
|
#include <optional>
|
|
#include <tuple>
|
|
#include <utility>
|
|
|
|
#include "driver/i2c.h"
|
|
#include "esp_check.h"
|
|
#include "esp_err.h"
|
|
#include "esp_log.h"
|
|
#include "freertos/FreeRTOS.h"
|
|
|
|
namespace drivers {
|
|
|
|
/**
|
|
* Wrapper for interfacing with the PCA8575 GPIO expander. Includes basic
|
|
* low-level pin setting methods, as well as higher level convenience functions
|
|
* for reading, writing, and atomically interacting with the SPI chip select
|
|
* pins.
|
|
*
|
|
* Each method of this class can be called safely from any thread, and all
|
|
* updates are guaranteed to be atomic. Any access to chip select related pins
|
|
* should be done whilst holding `cs_lock` (preferably via the helper methods).
|
|
*/
|
|
class IGpios {
|
|
public:
|
|
virtual ~IGpios() {}
|
|
|
|
/* Maps each pin of the expander to its number in a `pack`ed uint16. */
|
|
enum class Pin {
|
|
// Port A
|
|
kSdMuxSwitch = 0,
|
|
kSdMuxDisable = 1,
|
|
kKeyUp = 2,
|
|
kKeyDown = 3,
|
|
kKeyLock = 4,
|
|
kDisplayEnable = 5,
|
|
// 6 is unused
|
|
kSdPowerDisable = 7,
|
|
|
|
// Port B
|
|
kPhoneDetect = 8,
|
|
kAmplifierEnable = 9,
|
|
kSdCardDetect = 10,
|
|
// 11 through 15 are unused
|
|
};
|
|
|
|
/* Nicer value names for use with kSdMuxSwitch. */
|
|
enum SdController {
|
|
SD_MUX_ESP = 0,
|
|
SD_MUX_SAMD = 1,
|
|
};
|
|
|
|
/*
|
|
* Sets a single specific pin to the given value. `true` corresponds to
|
|
* HIGH, and `false` corresponds to LOW.
|
|
*
|
|
* This function will block until the pin has changed level.
|
|
*/
|
|
virtual auto WriteSync(Pin, bool) -> bool = 0;
|
|
|
|
/*
|
|
* Returns the most recently cached value of the given pin.
|
|
*/
|
|
virtual auto Get(Pin) const -> bool = 0;
|
|
};
|
|
|
|
class Gpios : public IGpios {
|
|
public:
|
|
static auto Create() -> Gpios*;
|
|
~Gpios();
|
|
|
|
/*
|
|
* Sets a single specific pin to the given value. `true` corresponds to
|
|
* HIGH, and `false` corresponds to LOW.
|
|
*
|
|
* Calls to this method will be buffered in memory until a call to `Write()`
|
|
* is made.
|
|
*/
|
|
auto WriteSync(Pin, bool) -> bool override;
|
|
|
|
virtual auto WriteBuffered(Pin, bool) -> void;
|
|
|
|
/**
|
|
* Sets the ports on the GPIO expander to the values currently represented
|
|
* in `ports`.
|
|
*/
|
|
auto Flush(void) -> bool;
|
|
|
|
auto Get(Pin) const -> bool override;
|
|
|
|
/**
|
|
* Reads from the GPIO expander, populating `inputs` with the most recent
|
|
* values.
|
|
*/
|
|
auto Read(void) -> bool;
|
|
|
|
auto listener() -> std::function<void(void)>* { return listener_; }
|
|
|
|
auto set_listener(std::function<void(void)>* l) -> void { listener_ = l; }
|
|
|
|
// Not copyable or movable. There should usually only ever be once instance
|
|
// of this class, and that instance will likely have a static lifetime.
|
|
Gpios(const Gpios&) = delete;
|
|
Gpios& operator=(const Gpios&) = delete;
|
|
|
|
private:
|
|
Gpios();
|
|
|
|
std::atomic<uint16_t> ports_;
|
|
std::atomic<uint16_t> inputs_;
|
|
|
|
std::function<void(void)>* listener_;
|
|
};
|
|
|
|
} // namespace drivers
|
|
|