kopia lustrzana https://github.com/pimoroni/pimoroni-pico
				
				
				
			
		
			
				
	
	
		
			167 wiersze
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C++
		
	
	
			
		
		
	
	
			167 wiersze
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C++
		
	
	
| #include <string.h>
 | |
| #include <math.h>
 | |
| #include <functional>
 | |
| 
 | |
| #include "hardware/pwm.h"
 | |
| #include "hardware/watchdog.h"
 | |
| 
 | |
| #include "inky_frame_7.hpp"
 | |
| 
 | |
| namespace pimoroni {
 | |
|   void gpio_configure(uint gpio, bool dir, bool value = false) {
 | |
|     gpio_set_function(gpio, GPIO_FUNC_SIO); gpio_set_dir(gpio, dir); gpio_put(gpio, value);
 | |
|   }
 | |
| 
 | |
|   void gpio_configure_pwm(uint gpio) {
 | |
|     pwm_config cfg = pwm_get_default_config();
 | |
|     pwm_set_wrap(pwm_gpio_to_slice_num(gpio), 65535);
 | |
|     pwm_init(pwm_gpio_to_slice_num(gpio), &cfg, true);
 | |
|     gpio_set_function(gpio, GPIO_FUNC_PWM);
 | |
|   }
 | |
| 
 | |
|   void InkyFrame::init() {
 | |
|     // keep the pico awake by holding vsys_en high
 | |
|     gpio_set_function(HOLD_VSYS_EN, GPIO_FUNC_SIO);
 | |
|     gpio_set_dir(HOLD_VSYS_EN, GPIO_OUT);
 | |
|     gpio_put(HOLD_VSYS_EN, true);
 | |
| 
 | |
|     // setup the shift register
 | |
|     gpio_configure(SR_CLOCK, GPIO_OUT, true);
 | |
|     gpio_configure(SR_LATCH, GPIO_OUT, true);
 | |
|     gpio_configure(SR_OUT, GPIO_IN);
 | |
| 
 | |
|     // determine wake up event
 | |
|     if(read_shift_register_bit(BUTTON_A)) {_wake_up_event = BUTTON_A_EVENT;}
 | |
|     if(read_shift_register_bit(BUTTON_B)) {_wake_up_event = BUTTON_B_EVENT;}
 | |
|     if(read_shift_register_bit(BUTTON_C)) {_wake_up_event = BUTTON_C_EVENT;}
 | |
|     if(read_shift_register_bit(BUTTON_D)) {_wake_up_event = BUTTON_D_EVENT;}
 | |
|     if(read_shift_register_bit(BUTTON_E)) {_wake_up_event = BUTTON_E_EVENT;}
 | |
|     if(read_shift_register_bit(RTC_ALARM)) {_wake_up_event = RTC_ALARM_EVENT;}
 | |
|     if(read_shift_register_bit(EXTERNAL_TRIGGER)) {_wake_up_event = EXTERNAL_TRIGGER_EVENT;}
 | |
|     // there are other reasons a wake event can occur: connect power via usb,
 | |
|     // connect a battery, or press the reset button. these cannot be
 | |
|     // disambiguated so we don't attempt to report them
 | |
| 
 | |
|     // Disable display update busy wait, we'll handle it ourselves
 | |
|     inky73.set_blocking(false);
 | |
| 
 | |
|     // initialise the rtc
 | |
|     rtc.init();
 | |
| 
 | |
|     // setup led pwm
 | |
|     gpio_configure_pwm(LED_A);
 | |
|     gpio_configure_pwm(LED_B);
 | |
|     gpio_configure_pwm(LED_C);
 | |
|     gpio_configure_pwm(LED_D);
 | |
|     gpio_configure_pwm(LED_E);
 | |
|     gpio_configure_pwm(LED_ACTIVITY);
 | |
|     gpio_configure_pwm(LED_CONNECTION);
 | |
|   }
 | |
| 
 | |
|   bool InkyFrame::is_busy() {
 | |
|     // check busy flag on shift register
 | |
|     bool busy = !read_shift_register_bit(Flags::EINK_BUSY);
 | |
|     return busy;
 | |
|   }
 | |
| 
 | |
|   void InkyFrame::update(bool blocking) {
 | |
|     while(is_busy()) {
 | |
|       tight_loop_contents();
 | |
|     }
 | |
|     inky73.update((PicoGraphics_PenInky7 *)this);
 | |
|     while(is_busy()) {
 | |
|       tight_loop_contents();
 | |
|     }
 | |
|     inky73.power_off();
 | |
|   }
 | |
| 
 | |
|   bool InkyFrame::pressed(Button button) {
 | |
|     return read_shift_register_bit(button);
 | |
|   }
 | |
| 
 | |
|   // set the LED brightness by generating a gamma corrected target value for
 | |
|   // the 16-bit pwm channel. brightness values are from 0 to 100.
 | |
|   void InkyFrame::led(LED led, uint8_t brightness) {
 | |
|     uint16_t value =
 | |
|       (uint16_t)(pow((float)(brightness) / 100.0f, 2.8) * 65535.0f + 0.5f);
 | |
|     pwm_set_gpio_level(led, value);
 | |
|   }
 | |
| 
 | |
|   uint8_t InkyFrame::read_shift_register() {
 | |
|     gpio_put(SR_LATCH, false); sleep_us(1);
 | |
|     gpio_put(SR_LATCH, true); sleep_us(1);
 | |
| 
 | |
|     uint8_t result = 0;
 | |
|     uint8_t bits = 8;
 | |
|     while(bits--) {
 | |
|       result <<= 1;
 | |
|       result |= gpio_get(SR_OUT) ? 1 : 0;
 | |
| 
 | |
|       gpio_put(SR_CLOCK, false); sleep_us(1);
 | |
|       gpio_put(SR_CLOCK, true); sleep_us(1);
 | |
|     }
 | |
| 
 | |
|     return result;
 | |
|   }
 | |
| 
 | |
|   bool InkyFrame::read_shift_register_bit(uint8_t index) {
 | |
|     return read_shift_register() & (1U << index);
 | |
|   }
 | |
| 
 | |
|   void InkyFrame::sleep(int wake_in_minutes) {
 | |
|     if(wake_in_minutes != -1) {
 | |
|       // set an alarm to wake inky up in wake_in_minutes - the maximum sleep
 | |
|       // is 255 minutes or around 4.5 hours which is the longest timer the RTC
 | |
|       // supports, to sleep any longer we need to specify a date and time to
 | |
|       // wake up
 | |
|       rtc.set_timer(wake_in_minutes, PCF85063A::TIMER_TICK_1_OVER_60HZ);
 | |
|       rtc.enable_timer_interrupt(true, false);
 | |
|     }
 | |
| 
 | |
|     // release the vsys hold pin so that inky can go to sleep
 | |
|     gpio_put(HOLD_VSYS_EN, false);
 | |
|     while(true){};
 | |
|   }
 | |
| 
 | |
|   void InkyFrame::sleep_until(int second, int minute, int hour, int day) {
 | |
|     if(second != -1 || minute != -1 || hour != -1 || day != -1) {
 | |
|       // set an alarm to wake inky up at the specified time and day
 | |
|       rtc.set_alarm(second, minute, hour, day);
 | |
|       rtc.enable_alarm_interrupt(true);
 | |
|     }
 | |
| 
 | |
|     // release the vsys hold pin so that inky can go to sleep
 | |
|     gpio_put(HOLD_VSYS_EN, false);
 | |
|   }
 | |
| 
 | |
|   // Display a portion of an image (icon sheet) at dx, dy
 | |
|   void InkyFrame::icon(const uint8_t *data, int sheet_width, int icon_size, int index, int dx, int dy) {
 | |
|     image(data, sheet_width, icon_size * index, 0, icon_size, icon_size, dx, dy);
 | |
|   }
 | |
| 
 | |
|   // Display an image that fills the screen (286*128)
 | |
|   void InkyFrame::image(const uint8_t* data) {
 | |
|     image(data, width, 0, 0, width, height, 0, 0);
 | |
|   }
 | |
| 
 | |
|   // Display an image smaller than the screen (sw*sh) at dx, dy
 | |
|   void InkyFrame::image(const uint8_t *data, int w, int h, int x, int y) {
 | |
|     image(data, w, 0, 0, w, h, x, y);
 | |
|   }
 | |
| 
 | |
|   void InkyFrame::image(const uint8_t *data, int stride, int sx, int sy, int dw, int dh, int dx, int dy) {
 | |
|     for(auto y = 0; y < dh; y++) {
 | |
|       for(auto x = 0; x < dw; x++) {
 | |
| 
 | |
|         uint32_t o = ((y + sy) * (stride / 2)) + ((x + sx) / 2);
 | |
|         uint8_t  d = ((x + sx) & 0b1) ? data[o] >> 4 : data[o] & 0xf;
 | |
| 
 | |
|         // draw the pixel
 | |
|         set_pen(d);
 | |
|         pixel({dx + x, dy + y});
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
| }
 |