1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
|
#ifdef SDL2_BUILD
#include "display.hpp"
#include "../../buttons.hpp"
#include "pico/types.h"
#include <iostream>
#include <time.h>
#define SCREEN_HEIGHT 64
#define SCREEN_WIDTH 128
SDLDisplay::SDLDisplay() {
SDL_Init(SDL_INIT_VIDEO);
SDL_SetHint(SDL_HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0");
/* scale here to make the window larger than the surface itself.
Integer scalings only as set by function below. */
m_window = SDL_CreateWindow("SDL2 pico-watch build", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, 0);
if (m_window == nullptr) {
SDL_Log("Unable to create renderer: %s", SDL_GetError());
m_should_quit = true;
return;
}
m_renderer = SDL_CreateRenderer(m_window, -1, SDL_RENDERER_PRESENTVSYNC);
if (m_renderer == nullptr) {
SDL_Log("Unable to create renderer: %s", SDL_GetError());
m_should_quit = true;
return;
}
const int width = SCREEN_WIDTH;
const int height = SCREEN_HEIGHT;
/* Since we are going to display a low resolution buffer,
it's best to limit the window size so that it cannot be
smaller than our internal buffer size. */
SDL_SetWindowMinimumSize(m_window, width, height);
SDL_RenderSetLogicalSize(m_renderer, width, height);
SDL_RenderSetIntegerScale(m_renderer, SDL_bool(1));
/* A one-bit-per-pixel Surface, indexed to these colors */
m_surface = SDL_CreateRGBSurfaceWithFormat(SDL_SWSURFACE,
width, height, 1, SDL_PIXELFORMAT_INDEX1MSB);
SDL_Color colors[2] = {{0, 0, 0, 255}, {255, 255, 255, 255}};
SDL_SetPaletteColors(m_surface->format->palette, colors, 0, 2);
}
SDLDisplay::~SDLDisplay() {
SDL_DestroyTexture(m_texture);
SDL_DestroyRenderer(m_renderer);
SDL_DestroyWindow(m_window);
SDL_Quit();
}
bool SDLDisplay::process_input() {
SDL_Event e;
while (SDL_PollEvent(&e) != 0) {
switch (e.type) {
case SDL_QUIT:
m_should_quit = true;
break;
case SDL_KEYDOWN:
case SDL_KEYUP:
uint button = get_button(e.key.keysym.sym);
if (button)
gpio_interrupt_cb(button, e.type == SDL_KEYDOWN);
break;
}
}
return m_should_quit;
}
bool SDLDisplay::update_display(const uint8_t* oled_screen) {
// NOTE: hardcoded display size (might be fine, see todo.md and oledWriteDataBlock in ss_oled.c)
// memcpy(m_surface->pixels, oled_screen, (size_t)(128*8));
convert_display(oled_screen);
// render on screen
SDL_RenderClear(m_renderer);
SDL_Texture* screen_texture = SDL_CreateTextureFromSurface(m_renderer, m_surface);
SDL_RenderCopy(m_renderer, screen_texture, NULL, NULL);
SDL_RenderPresent(m_renderer);
SDL_DestroyTexture(screen_texture);
return m_should_quit;
}
bool SDLDisplay::get_datetime(datetime_t* t) {
// Get current date and time
time_t rawtime;
struct tm* timeinfo;
time(&rawtime);
timeinfo = localtime(&rawtime);
// Map ISO C tm struct to Pico's datetime_t
t->day = timeinfo->tm_mday;
t->dotw = timeinfo->tm_wday;
t->month = timeinfo->tm_mon;
t->year = timeinfo->tm_year + 1900;
t->hour = timeinfo->tm_hour;
t->min = timeinfo->tm_min;
t->sec = timeinfo->tm_sec;
return true;
}
unsigned char rorb(unsigned char x, unsigned char n) {
return __rorb(x,n);
}
unsigned char rolb(unsigned char x, unsigned char n) {
return __rolb(x,n);
}
void SDLDisplay::convert_display(const uint8_t* in) {
unsigned char* out = (unsigned char*)m_surface->pixels;
// clear screen
for (int i = 0; i < 8*128; ++i)
out[i] = 0x00;
// draw to screen
for (int i = 0; i < 8*128; ++i) {
int row = i / 128; // "super-row" consisting of 8 subrows
int col = i % 128;
// create a column of a subrow
// int subrow represents which bit of byte i
for (int subrow = 0; subrow < 8; ++subrow)
// OR instead of XOR seems to do exactly the same thing?
out[col/8 + (row*8 + subrow)*16] ^= rorb(
(bool)(in[i] & rolb(1, subrow)), (col % 8) + 1);
}
}
// Get the GPIO pin number corresponding to the button that has been pressed
uint SDLDisplay::get_button(SDL_Keycode key) {
switch (key) {
case SDLK_w:
case SDLK_UP:
return BUTTON_UP;
case SDLK_s:
case SDLK_DOWN:
return BUTTON_DOWN;
case SDLK_RETURN:
case SDLK_o:
return BUTTON_SELECT;
case SDLK_TAB:
case SDLK_m:
return BUTTON_MODE;
case SDLK_BACKSPACE:
case SDLK_h:
return BUTTON_HOME;
case SDLK_x:
m_testbool = !m_testbool;
default:
return 0;
}
}
#endif
|