| 
						
						
							
								
							
						
						
					 | 
					 | 
					@ -36,27 +36,27 @@ class GpioExpander { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  // Port A:
 | 
					 | 
					 | 
					 | 
					  // Port A:
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  // 0 - audio power enable
 | 
					 | 
					 | 
					 | 
					  // 0 - audio power enable
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  // 1 - usb interface power enable
 | 
					 | 
					 | 
					 | 
					  // 1 - usb interface power enable (active low)
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  // 2 - display power enable
 | 
					 | 
					 | 
					 | 
					  // 2 - display power enable
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  // 3 - sd card power enable
 | 
					 | 
					 | 
					 | 
					  // 3 - touchpad power enable
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  // 4 - charge power ok (active low)
 | 
					 | 
					 | 
					 | 
					  // 4 - sd card power enable
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  // 5 - sd mux switch
 | 
					 | 
					 | 
					 | 
					  // 5 - sd mux switch
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  // 6 - sd chip select
 | 
					 | 
					 | 
					 | 
					  // 6 - LDO enable
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  // 7 - display chip select
 | 
					 | 
					 | 
					 | 
					  // 7 - charge power ok (active low)
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  // All power switches low, chip selects high, active-low charge power high
 | 
					 | 
					 | 
					 | 
					  // All power switches low, sd mux pointing away from us, inputs high.
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  static const uint8_t kPortADefault = 0b11010001; | 
					 | 
					 | 
					 | 
					  static const uint8_t kPortADefault = 0b10000010; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  // Port B:
 | 
					 | 
					 | 
					 | 
					  // Port B:
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  // 0 - 3.5mm jack detect (active low)
 | 
					 | 
					 | 
					 | 
					  // 0 - 3.5mm jack detect (active low)
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  // 1 - dac soft mute switch
 | 
					 | 
					 | 
					 | 
					  // 1 - unused
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  // 2 - GPIO
 | 
					 | 
					 | 
					 | 
					  // 2 - volume up
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  // 3 - GPIO
 | 
					 | 
					 | 
					 | 
					  // 3 - volume down
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  // 4 - GPIO
 | 
					 | 
					 | 
					 | 
					  // 4 - lock switch
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  // 5 - GPIO
 | 
					 | 
					 | 
					 | 
					  // 5 - touchpad interupt
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  // 6 - GPIO
 | 
					 | 
					 | 
					 | 
					  // 6 - display DR
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  // 7 - GPIO
 | 
					 | 
					 | 
					 | 
					  // 7 - display LED
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  // DAC mute output low, everything else is active-low inputs.
 | 
					 | 
					 | 
					 | 
					  // Inputs all high, all others low.
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  static const uint8_t kPortBDefault = 0b11111111; | 
					 | 
					 | 
					 | 
					  static const uint8_t kPortBDefault = 0b00111101; | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  /*
 | 
					 | 
					 | 
					 | 
					  /*
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					   * Convenience mehod for packing the port a and b bytes into a single 16 bit | 
					 | 
					 | 
					 | 
					   * Convenience mehod for packing the port a and b bytes into a single 16 bit | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					 | 
					@ -102,33 +102,27 @@ class GpioExpander { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    AUDIO_POWER_ENABLE = 0, | 
					 | 
					 | 
					 | 
					    AUDIO_POWER_ENABLE = 0, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    USB_INTERFACE_POWER_ENABLE = 1, | 
					 | 
					 | 
					 | 
					    USB_INTERFACE_POWER_ENABLE = 1, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    DISPLAY_POWER_ENABLE = 2, | 
					 | 
					 | 
					 | 
					    DISPLAY_POWER_ENABLE = 2, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    SD_CARD_POWER_ENABLE = 3, | 
					 | 
					 | 
					 | 
					    TOUCHPAD_POWER_ENABLE = 3, | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    CHARGE_POWER_OK = 4,  // Active-low input
 | 
					 | 
					 | 
					 | 
					    SD_CARD_POWER_ENABLE = 4, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    SD_MUX_SWITCH = 5, | 
					 | 
					 | 
					 | 
					    SD_MUX_SWITCH = 5, | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    SD_CHIP_SELECT = 6, | 
					 | 
					 | 
					 | 
					    LDO_ENABLE = 6, | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    DISPLAY_CHIP_SELECT = 7, | 
					 | 
					 | 
					 | 
					    CHARGE_POWER_OK = 7,  // Active-low input
 | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    // Port B
 | 
					 | 
					 | 
					 | 
					    // Port B
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    PHONE_DETECT = 8,  // Active-high input
 | 
					 | 
					 | 
					 | 
					    PHONE_DETECT = 8,  // Active-high input
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    DAC_MUTE = 9, | 
					 | 
					 | 
					 | 
					    //UNUSED = 9,
 | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    GPIO_1 = 10, | 
					 | 
					 | 
					 | 
					    VOL_UP = 10, | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    GPIO_2 = 11, | 
					 | 
					 | 
					 | 
					    VOL_DOWN = 11, | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    GPIO_3 = 12, | 
					 | 
					 | 
					 | 
					    LOCK = 12, | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    GPIO_4 = 13, | 
					 | 
					 | 
					 | 
					    TOUCHPAD_INT = 13, | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    GPIO_5 = 14, | 
					 | 
					 | 
					 | 
					    DISPLAY_DR = 14, | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    GPIO_6 = 15, | 
					 | 
					 | 
					 | 
					    DISPLAY_LED = 15, | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  }; | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  /* Pins whose access should be guarded by `cs_lock`. */ | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  enum ChipSelect { | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    SD_CARD = SD_CHIP_SELECT, | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    DISPLAY = DISPLAY_CHIP_SELECT, | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  }; | 
					 | 
					 | 
					 | 
					  }; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  /* Nicer value names for use with the SD_MUX_SWITCH pin. */ | 
					 | 
					 | 
					 | 
					  /* Nicer value names for use with the SD_MUX_SWITCH pin. */ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  enum SdController { | 
					 | 
					 | 
					 | 
					  enum SdController { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    SD_MUX_ESP = 0, | 
					 | 
					 | 
					 | 
					    SD_MUX_ESP = 1, | 
				
			
			
				
				
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    SD_MUX_USB = 1, | 
					 | 
					 | 
					 | 
					    SD_MUX_USB = 0, | 
				
			
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  }; | 
					 | 
					 | 
					 | 
					  }; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  /**
 | 
					 | 
					 | 
					 | 
					  /**
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -145,7 +139,6 @@ class GpioExpander { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					   * is made. | 
					 | 
					 | 
					 | 
					   * is made. | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					   */ | 
					 | 
					 | 
					 | 
					   */ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  void set_pin(Pin pin, bool value); | 
					 | 
					 | 
					 | 
					  void set_pin(Pin pin, bool value); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  void set_pin(ChipSelect cs, bool value); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  /**
 | 
					 | 
					 | 
					 | 
					  /**
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					   * Returns the input status of each of the ports. The first byte is port a, | 
					 | 
					 | 
					 | 
					   * Returns the input status of each of the ports. The first byte is port a, | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					 | 
					@ -159,49 +152,12 @@ class GpioExpander { | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					   */ | 
					 | 
					 | 
					 | 
					   */ | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  bool get_input(Pin pin) const; | 
					 | 
					 | 
					 | 
					  bool get_input(Pin pin) const; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  /* Returns the mutex that must be held whilst pulling a CS pin low. */ | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  std::mutex& cs_mutex() { return cs_mutex_; } | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  /*
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					   * Helper class containing an active `cs_mutex` lock. When an instance of | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					   * this class is destroyed (usually by falling out of scope), the associated | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					   * CS pin will be driven high before the lock is released. | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					   */ | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  class SpiLock { | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					   public: | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    SpiLock(GpioExpander& gpio, ChipSelect cs); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    ~SpiLock(); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    SpiLock(const SpiLock&) = delete; | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					   private: | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    std::scoped_lock<std::mutex> lock_; | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    GpioExpander& gpio_; | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					    ChipSelect cs_; | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  }; | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  /*
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					   * Pulls the given CS pin low to signal that we are about to communicate | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					   * with a particular device, after acquiring a lock on `cs_mutex`. The | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					   * recommended way to safely interact with devices on the SPI bus is to have | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					   * a self-contained block like so: | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					   * | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					   * ``` | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					   * { | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					   *	auto lock = AcquireSpiBus(WHATEVER); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					   *  // Do some cool things here.
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					   * } | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					   * ``` | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					   */ | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  SpiLock AcquireSpiBus(ChipSelect cs); | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  // Not copyable or movable. There should usually only ever be once instance
 | 
					 | 
					 | 
					 | 
					  // Not copyable or movable. There should usually only ever be once instance
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  // of this class, and that instance will likely have a static lifetime.
 | 
					 | 
					 | 
					 | 
					  // of this class, and that instance will likely have a static lifetime.
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  GpioExpander(const GpioExpander&) = delete; | 
					 | 
					 | 
					 | 
					  GpioExpander(const GpioExpander&) = delete; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  GpioExpander& operator=(const GpioExpander&) = delete; | 
					 | 
					 | 
					 | 
					  GpioExpander& operator=(const GpioExpander&) = delete; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					 private: | 
					 | 
					 | 
					 | 
					 private: | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  std::mutex cs_mutex_; | 
					 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  std::atomic<uint16_t> ports_; | 
					 | 
					 | 
					 | 
					  std::atomic<uint16_t> ports_; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					  std::atomic<uint16_t> inputs_; | 
					 | 
					 | 
					 | 
					  std::atomic<uint16_t> inputs_; | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					 | 
					}; | 
					 | 
					 | 
					 | 
					}; | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
					 | 
					
  |