Skip to content

Commit 63de020

Browse files
authored
Merge pull request #682 from pimoroni/feature/inky73c++
Inky 7.3: C++ library and JPEG example compatibility.
2 parents 1317f2e + bea90df commit 63de020

File tree

12 files changed

+426
-17
lines changed

12 files changed

+426
-17
lines changed
Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,30 @@
1-
set(OUTPUT_NAME inky_frame_day_planner)
1+
# Inky Frame 5.7"
2+
add_executable(
3+
inky_frame_day_planner
4+
inky_frame_day_planner.cpp
5+
)
6+
7+
# Pull in pico libraries that we need
8+
target_link_libraries(inky_frame_day_planner pico_stdlib inky_frame hardware_pwm hardware_spi hardware_i2c hardware_rtc fatfs sdcard pico_graphics)
29

10+
pico_enable_stdio_usb(inky_frame_day_planner 1)
11+
12+
# create map/bin/hex file etc.
13+
pico_add_extra_outputs(inky_frame_day_planner)
14+
15+
# Inky Frame 7.3"
316
add_executable(
4-
${OUTPUT_NAME}
17+
inky_frame_7_day_planner
518
inky_frame_day_planner.cpp
619
)
720

821
# Pull in pico libraries that we need
9-
target_link_libraries(${OUTPUT_NAME} pico_stdlib inky_frame hardware_pwm hardware_spi hardware_i2c hardware_rtc fatfs sdcard pico_graphics)
22+
target_link_libraries(inky_frame_7_day_planner pico_stdlib inky_frame_7 hardware_pwm hardware_spi hardware_i2c hardware_rtc fatfs sdcard pico_graphics)
1023

11-
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
24+
pico_enable_stdio_usb(inky_frame_7_day_planner 1)
1225

1326
# create map/bin/hex file etc.
14-
pico_add_extra_outputs(${OUTPUT_NAME})
27+
pico_add_extra_outputs(inky_frame_7_day_planner)
28+
29+
target_compile_definitions(inky_frame_7_day_planner PUBLIC INKY_FRAME_7)
30+

examples/inky_frame/inky_frame_day_planner.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@
44
#include <stdio.h>
55
#include "pico/stdlib.h"
66

7+
#ifdef INKY_FRAME_7
8+
#include "libraries/inky_frame_7/inky_frame_7.hpp"
9+
#else
710
#include "libraries/inky_frame/inky_frame.hpp"
11+
#endif
812

913
using namespace pimoroni;
1014

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,28 @@
1-
set(OUTPUT_NAME inky_frame_jpeg_image)
1+
add_executable(
2+
inky_frame_jpeg_image
3+
inky_frame_jpeg_image.cpp
4+
)
5+
6+
# Pull in pico libraries that we need
7+
target_link_libraries(inky_frame_jpeg_image pico_stdlib jpegdec inky_frame fatfs hardware_pwm hardware_spi hardware_i2c hardware_rtc fatfs sdcard pico_graphics)
8+
9+
pico_enable_stdio_usb(inky_frame_jpeg_image 1)
10+
11+
# create map/bin/hex file etc.
12+
pico_add_extra_outputs(inky_frame_jpeg_image)
13+
214

315
add_executable(
4-
${OUTPUT_NAME}
16+
inky_frame_7_jpeg_image
517
inky_frame_jpeg_image.cpp
618
)
719

820
# Pull in pico libraries that we need
9-
target_link_libraries(${OUTPUT_NAME} pico_stdlib jpegdec inky_frame fatfs hardware_pwm hardware_spi hardware_i2c hardware_rtc fatfs sdcard pico_graphics)
21+
target_link_libraries(inky_frame_7_jpeg_image pico_stdlib jpegdec inky_frame_7 fatfs hardware_pwm hardware_spi hardware_i2c hardware_rtc fatfs sdcard pico_graphics)
1022

11-
pico_enable_stdio_usb(${OUTPUT_NAME} 1)
23+
pico_enable_stdio_usb(inky_frame_7_jpeg_image 1)
1224

1325
# create map/bin/hex file etc.
14-
pico_add_extra_outputs(${OUTPUT_NAME})
26+
pico_add_extra_outputs(inky_frame_7_jpeg_image)
27+
28+
target_compile_definitions(inky_frame_7_jpeg_image PUBLIC INKY_FRAME_7)

examples/inky_frame/inky_frame_jpeg_image.cpp

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@
77

88
#include "JPEGDEC.h"
99

10+
#ifdef INKY_FRAME_7
11+
#include "libraries/inky_frame_7/inky_frame_7.hpp"
12+
#else
1013
#include "libraries/inky_frame/inky_frame.hpp"
14+
#endif
1115

1216
using namespace pimoroni;
1317

@@ -65,6 +69,36 @@ int jpegdec_draw_callback(JPEGDRAW *draw) {
6569
return 1; // continue drawing
6670
}
6771

72+
// Draw to the nearest colour instead of dithering
73+
int jpegdec_draw_posterize_callback(JPEGDRAW *draw) {
74+
uint16_t *p = draw->pPixels;
75+
76+
int xo = jpeg_decode_options.x;
77+
int yo = jpeg_decode_options.y;
78+
79+
for(int y = 0; y < draw->iHeight; y++) {
80+
for(int x = 0; x < draw->iWidth; x++) {
81+
int sx = ((draw->x + x + xo) * jpeg_decode_options.w) / jpeg.getWidth();
82+
int sy = ((draw->y + y + yo) * jpeg_decode_options.h) / jpeg.getHeight();
83+
84+
if(xo + sx > 0 && xo + sx < inky.bounds.w && yo + sy > 0 && yo + sy < inky.bounds.h) {
85+
int closest = RGB(RGB565(*p)).closest(inky.palette, inky.palette_size);
86+
if (closest != -1) {
87+
inky.set_pen(closest);
88+
inky.set_pixel({xo + sx, yo + sy});
89+
} else {
90+
inky.set_pen(0);
91+
inky.set_pixel({xo + sx, yo + sy});
92+
}
93+
}
94+
95+
p++;
96+
}
97+
}
98+
99+
return 1; // continue drawing
100+
}
101+
68102
void draw_jpeg(std::string filename, int x, int y, int w, int h) {
69103

70104
// TODO: this is a horrible way to do it but we need to pass some parameters
@@ -81,7 +115,8 @@ void draw_jpeg(std::string filename, int x, int y, int w, int h) {
81115
jpegdec_close_callback,
82116
jpegdec_read_callback,
83117
jpegdec_seek_callback,
84-
jpegdec_draw_callback);
118+
jpegdec_draw_callback // Try jpegdec_draw_posterize_callback
119+
);
85120

86121
jpeg.setPixelType(RGB565_BIG_ENDIAN);
87122

@@ -130,7 +165,7 @@ int main() {
130165
}; // Wait for debugger
131166
}
132167

133-
filename = "butterfly-600x448.jpg";
168+
filename = "shutterstock_172537049.jpg";
134169

135170
//inky.led(InkyFrame::LED_E, 255);
136171
//sleep_ms(1000);
@@ -169,7 +204,7 @@ int main() {
169204
printf("done!\n");
170205

171206
printf("Displaying file: %s\n", filename.c_str());
172-
draw_jpeg(filename, 0, 0, 600, 448);
207+
draw_jpeg(filename, 0, 0, inky.width, inky.height);
173208
printf("done!\n");
174209

175210
inky.update();

libraries/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ add_subdirectory(inventor2040w)
3636
add_subdirectory(adcfft)
3737
add_subdirectory(jpegdec)
3838
add_subdirectory(inky_frame)
39+
add_subdirectory(inky_frame_7)
3940
add_subdirectory(galactic_unicorn)
4041
add_subdirectory(gfx_pack)
4142
add_subdirectory(interstate75)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
include(inky_frame_7.cmake)
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
set(LIB_NAME inky_frame_7)
2+
add_library(${LIB_NAME} INTERFACE)
3+
4+
target_sources(${LIB_NAME} INTERFACE
5+
${CMAKE_CURRENT_LIST_DIR}/${LIB_NAME}.cpp
6+
)
7+
8+
target_include_directories(${LIB_NAME} INTERFACE ${CMAKE_CURRENT_LIST_DIR})
9+
10+
# Pull in pico libraries that we need
11+
target_link_libraries(${LIB_NAME} INTERFACE hardware_i2c pico_graphics hardware_spi hardware_pwm bitmap_fonts hershey_fonts pico_stdlib sdcard fatfs pcf85063a psram_display inky73 jpegdec)
12+
13+
target_compile_options(${LIB_NAME} INTERFACE -Wno-error=reorder)
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
#include <string.h>
2+
#include <math.h>
3+
#include <functional>
4+
5+
#include "hardware/pwm.h"
6+
#include "hardware/watchdog.h"
7+
8+
#include "inky_frame_7.hpp"
9+
10+
namespace pimoroni {
11+
void gpio_configure(uint gpio, bool dir, bool value = false) {
12+
gpio_set_function(gpio, GPIO_FUNC_SIO); gpio_set_dir(gpio, dir); gpio_put(gpio, value);
13+
}
14+
15+
void gpio_configure_pwm(uint gpio) {
16+
pwm_config cfg = pwm_get_default_config();
17+
pwm_set_wrap(pwm_gpio_to_slice_num(gpio), 65535);
18+
pwm_init(pwm_gpio_to_slice_num(gpio), &cfg, true);
19+
gpio_set_function(gpio, GPIO_FUNC_PWM);
20+
}
21+
22+
void InkyFrame::init() {
23+
// keep the pico awake by holding vsys_en high
24+
gpio_set_function(HOLD_VSYS_EN, GPIO_FUNC_SIO);
25+
gpio_set_dir(HOLD_VSYS_EN, GPIO_OUT);
26+
gpio_put(HOLD_VSYS_EN, true);
27+
28+
// setup the shift register
29+
gpio_configure(SR_CLOCK, GPIO_OUT, true);
30+
gpio_configure(SR_LATCH, GPIO_OUT, true);
31+
gpio_configure(SR_OUT, GPIO_IN);
32+
33+
// determine wake up event
34+
if(read_shift_register_bit(BUTTON_A)) {_wake_up_event = BUTTON_A_EVENT;}
35+
if(read_shift_register_bit(BUTTON_B)) {_wake_up_event = BUTTON_B_EVENT;}
36+
if(read_shift_register_bit(BUTTON_C)) {_wake_up_event = BUTTON_C_EVENT;}
37+
if(read_shift_register_bit(BUTTON_D)) {_wake_up_event = BUTTON_D_EVENT;}
38+
if(read_shift_register_bit(BUTTON_E)) {_wake_up_event = BUTTON_E_EVENT;}
39+
if(read_shift_register_bit(RTC_ALARM)) {_wake_up_event = RTC_ALARM_EVENT;}
40+
if(read_shift_register_bit(EXTERNAL_TRIGGER)) {_wake_up_event = EXTERNAL_TRIGGER_EVENT;}
41+
// there are other reasons a wake event can occur: connect power via usb,
42+
// connect a battery, or press the reset button. these cannot be
43+
// disambiguated so we don't attempt to report them
44+
45+
// Disable display update busy wait, we'll handle it ourselves
46+
inky73.set_blocking(false);
47+
48+
// initialise the rtc
49+
rtc.init();
50+
51+
// setup led pwm
52+
gpio_configure_pwm(LED_A);
53+
gpio_configure_pwm(LED_B);
54+
gpio_configure_pwm(LED_C);
55+
gpio_configure_pwm(LED_D);
56+
gpio_configure_pwm(LED_E);
57+
gpio_configure_pwm(LED_ACTIVITY);
58+
gpio_configure_pwm(LED_CONNECTION);
59+
}
60+
61+
bool InkyFrame::is_busy() {
62+
// check busy flag on shift register
63+
bool busy = !read_shift_register_bit(Flags::EINK_BUSY);
64+
return busy;
65+
}
66+
67+
void InkyFrame::update(bool blocking) {
68+
while(is_busy()) {
69+
tight_loop_contents();
70+
}
71+
inky73.update((PicoGraphics_PenInky7 *)this);
72+
while(is_busy()) {
73+
tight_loop_contents();
74+
}
75+
inky73.power_off();
76+
}
77+
78+
bool InkyFrame::pressed(Button button) {
79+
return read_shift_register_bit(button);
80+
}
81+
82+
// set the LED brightness by generating a gamma corrected target value for
83+
// the 16-bit pwm channel. brightness values are from 0 to 100.
84+
void InkyFrame::led(LED led, uint8_t brightness) {
85+
uint16_t value =
86+
(uint16_t)(pow((float)(brightness) / 100.0f, 2.8) * 65535.0f + 0.5f);
87+
pwm_set_gpio_level(led, value);
88+
}
89+
90+
uint8_t InkyFrame::read_shift_register() {
91+
gpio_put(SR_LATCH, false); sleep_us(1);
92+
gpio_put(SR_LATCH, true); sleep_us(1);
93+
94+
uint8_t result = 0;
95+
uint8_t bits = 8;
96+
while(bits--) {
97+
result <<= 1;
98+
result |= gpio_get(SR_OUT) ? 1 : 0;
99+
100+
gpio_put(SR_CLOCK, false); sleep_us(1);
101+
gpio_put(SR_CLOCK, true); sleep_us(1);
102+
}
103+
104+
return result;
105+
}
106+
107+
bool InkyFrame::read_shift_register_bit(uint8_t index) {
108+
return read_shift_register() & (1U << index);
109+
}
110+
111+
void InkyFrame::sleep(int wake_in_minutes) {
112+
if(wake_in_minutes != -1) {
113+
// set an alarm to wake inky up in wake_in_minutes - the maximum sleep
114+
// is 255 minutes or around 4.5 hours which is the longest timer the RTC
115+
// supports, to sleep any longer we need to specify a date and time to
116+
// wake up
117+
rtc.set_timer(wake_in_minutes, PCF85063A::TIMER_TICK_1_OVER_60HZ);
118+
rtc.enable_timer_interrupt(true, false);
119+
}
120+
121+
// release the vsys hold pin so that inky can go to sleep
122+
gpio_put(HOLD_VSYS_EN, false);
123+
while(true){};
124+
}
125+
126+
void InkyFrame::sleep_until(int second, int minute, int hour, int day) {
127+
if(second != -1 || minute != -1 || hour != -1 || day != -1) {
128+
// set an alarm to wake inky up at the specified time and day
129+
rtc.set_alarm(second, minute, hour, day);
130+
rtc.enable_alarm_interrupt(true);
131+
}
132+
133+
// release the vsys hold pin so that inky can go to sleep
134+
gpio_put(HOLD_VSYS_EN, false);
135+
}
136+
137+
// Display a portion of an image (icon sheet) at dx, dy
138+
void InkyFrame::icon(const uint8_t *data, int sheet_width, int icon_size, int index, int dx, int dy) {
139+
image(data, sheet_width, icon_size * index, 0, icon_size, icon_size, dx, dy);
140+
}
141+
142+
// Display an image that fills the screen (286*128)
143+
void InkyFrame::image(const uint8_t* data) {
144+
image(data, width, 0, 0, width, height, 0, 0);
145+
}
146+
147+
// Display an image smaller than the screen (sw*sh) at dx, dy
148+
void InkyFrame::image(const uint8_t *data, int w, int h, int x, int y) {
149+
image(data, w, 0, 0, w, h, x, y);
150+
}
151+
152+
void InkyFrame::image(const uint8_t *data, int stride, int sx, int sy, int dw, int dh, int dx, int dy) {
153+
for(auto y = 0; y < dh; y++) {
154+
for(auto x = 0; x < dw; x++) {
155+
156+
uint32_t o = ((y + sy) * (stride / 2)) + ((x + sx) / 2);
157+
uint8_t d = ((x + sx) & 0b1) ? data[o] >> 4 : data[o] & 0xf;
158+
159+
// draw the pixel
160+
set_pen(d);
161+
pixel({dx + x, dy + y});
162+
}
163+
}
164+
}
165+
166+
}

0 commit comments

Comments
 (0)