forked from jthlim/javelin-steno-rp2040
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathssd1306.h
187 lines (151 loc) · 5.51 KB
/
ssd1306.h
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
//---------------------------------------------------------------------------
#pragma once
#include "javelin/font/text_alignment.h"
#include "javelin/split/split.h"
#include "javelin/stroke.h"
//---------------------------------------------------------------------------
struct Font;
enum FontId : int;
//---------------------------------------------------------------------------
#if JAVELIN_OLED_DRIVER == 1306
class Ssd1306 {
public:
static void Initialize() { GetInstance().Initialize(); }
static void PrintInfo();
static void Update() { GetInstance().Update(); }
static void DrawPaperTape(int displayId, const StenoStroke *strokes,
size_t length) {
instances[displayId].DrawPaperTape(strokes, length);
}
static void DrawStenoLayout(int displayId, StenoStroke stroke) {
instances[displayId].DrawStenoLayout(stroke);
}
static void DrawText(int displayId, int x, int y, const Font *font,
TextAlignment alignment, const char *text) {
instances[displayId].DrawText(x, y, font, alignment, text);
}
#if JAVELIN_SPLIT
static void RegisterMasterHandlers() {
Split::RegisterRxHandler(SplitHandlerId::DISPLAY_AVAILABLE,
&instances[1].available);
Split::RegisterTxHandler(&instances[1]);
Split::RegisterTxHandler(&instances[1].control);
}
static void RegisterSlaveHandlers() {
Split::RegisterTxHandler(&instances[1].available);
Split::RegisterRxHandler(SplitHandlerId::DISPLAY_DATA, &instances[1]);
Split::RegisterRxHandler(SplitHandlerId::DISPLAY_CONTROL,
&instances[1].control);
}
#else
static void RegisterMasterHandlers() {}
static void RegisterSlaveHandlers() {}
#endif
private:
class Ssd1306Availability : public SplitTxHandler, public SplitRxHandler {
public:
void operator=(bool value) { available = value; }
bool operator!() const { return !available; }
operator bool() const { return available; }
private:
bool available = true; // During startup scripts, the frame buffer may
// need to be written.
// Setting this to available will permit
// the slave OLED to be updated until the first
// availability packet comes in.
bool dirty = true;
virtual void UpdateBuffer(TxBuffer &buffer);
virtual void OnDataReceived(const void *data, size_t length);
virtual void OnReceiveConnectionReset() { available = false; }
virtual void OnTransmitConnectionReset() { dirty = true; }
};
class Ssd1306Control : public SplitTxHandler, public SplitRxHandler {
public:
void Update();
void SetScreenOn(bool on) {
if (on != data.screenOn) {
data.screenOn = on;
dirtyFlag |= DIRTY_FLAG_SCREEN_ON;
}
}
void SetContrast(uint8_t value) {
if (value != data.contrast) {
data.contrast = value;
dirtyFlag |= DIRTY_FLAG_CONTRAST;
}
}
private:
struct Ssd1306ControlTxRxData {
bool screenOn;
uint8_t contrast;
};
uint8_t dirtyFlag;
Ssd1306ControlTxRxData data;
static const int DIRTY_FLAG_SCREEN_ON = 1;
static const int DIRTY_FLAG_CONTRAST = 2;
virtual void UpdateBuffer(TxBuffer &buffer);
virtual void OnDataReceived(const void *data, size_t length);
virtual void OnTransmitConnectionReset();
};
class Ssd1306Data : public SplitTxHandler, public SplitRxHandler {
public:
Ssd1306Availability available;
Ssd1306Control control;
bool dirty;
bool drawColor = true;
void Initialize();
// None of these will take effect until Update() is called.
void Clear();
void DrawLine(int x0, int y0, int x1, int y1);
void DrawRect(int left, int top, int right, int bottom);
void DrawImage(int x, int y, int width, int height, const uint8_t *data);
void DrawText(int x, int y, const Font *font, TextAlignment alignment,
const char *text);
void SetPixel(uint32_t x, uint32_t y);
void DrawPaperTape(const StenoStroke *strokes, size_t length);
void DrawStenoLayout(StenoStroke stroke);
void Update();
private:
union {
uint8_t buffer8[JAVELIN_OLED_WIDTH * JAVELIN_OLED_HEIGHT / 8];
uint32_t buffer32[JAVELIN_OLED_WIDTH * JAVELIN_OLED_HEIGHT / 32];
};
bool InitializeSsd1306();
virtual void UpdateBuffer(TxBuffer &buffer);
virtual void OnTransmitConnectionReset() { dirty = true; }
virtual void OnDataReceived(const void *data, size_t length);
};
static uint16_t dmaBuffer[JAVELIN_OLED_WIDTH * JAVELIN_OLED_HEIGHT / 8 + 1];
static bool IsI2cTxReady();
static void WaitForI2cTxReady();
static void SendCommandListDma(const uint8_t *commands, size_t length);
static bool SendCommandList(const uint8_t *commands, size_t length);
static bool SendCommand(uint8_t command);
static void SendDmaBuffer(size_t count);
#if JAVELIN_SPLIT
static Ssd1306Data &GetInstance() {
if (Split::IsMaster()) {
return instances[0];
} else {
return instances[1];
}
}
static Ssd1306Data instances[2];
#else
static Ssd1306Data &GetInstance() { return instance[0]; }
static Ssd1306Data instances[1];
#endif
friend class Display;
};
#else
class Ssd1306 {
public:
static void Initialize() {}
static void PrintInfo() {}
static void DrawPaperTape() {}
static void Update() {}
static void RegisterMasterHandlers() {}
static void RegisterSlaveHandlers() {}
};
#endif
//---------------------------------------------------------------------------