Skip to content

Commit 4598bbe

Browse files
committed
Add SSD1306 compatability
1 parent 59c8a73 commit 4598bbe

File tree

8 files changed

+193
-5
lines changed

8 files changed

+193
-5
lines changed

platformio.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ lib_deps =
9191
https://github.com/Sensirion/arduino-i2c-scd4x.git
9292
https://github.com/adafruit/Adafruit_LED_Backpack.git
9393
https://github.com/adafruit/Adafruit_LiquidCrystal.git
94+
https://github.com/adafruit/Adafruit_SSD1306.git
9495

9596
; Common build environment for ESP32 platform
9697
[common:esp32]

src/components/i2c/controller.cpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,11 @@ static const std::map<std::string, FnCreateI2cOutputDrv> I2cFactoryOutput = {
375375
[](TwoWire *i2c, uint16_t addr, uint32_t mux_channel,
376376
const char *driver_name) -> drvOutputBase * {
377377
return new drvOutCharLcd(i2c, addr, mux_channel, driver_name);
378+
}},
379+
{"ssd1306",
380+
[](TwoWire *i2c, uint16_t addr, uint32_t mux_channel,
381+
const char *driver_name) -> drvOutputBase * {
382+
return new drvOutSsd1306(i2c, addr, mux_channel, driver_name);
378383
}}}; ///< I2C output driver factory
379384

380385
/*!
@@ -844,6 +849,14 @@ bool I2cController::Handle_I2cDeviceOutputWrite(pb_istream_t *stream) {
844849
WS_DEBUG_PRINTLN("[i2c] ERROR: Unable to write to char LCD!");
845850
return false;
846851
}
852+
} else if (_i2c_model->GetI2cDeviceOutputWriteMsg()->which_output_msg ==
853+
wippersnapper_i2c_I2cDeviceOutputWrite_write_oled_tag) {
854+
WS_DEBUG_PRINTLN("[i2c] Writing to SSD1306 OLED...");
855+
// Note: In the future, we can expand this to support other OLEDs by
856+
// creating and checking a tag within the write oled msg (e.g. SSD1327,
857+
// etc.)
858+
driver->WriteMessageSSD1306(_i2c_model->GetI2cDeviceOutputWriteMsg()
859+
->output_msg.write_oled.message);
847860
} else {
848861
WS_DEBUG_PRINTLN("[i2c] ERROR: Unable to determine I2C Output Write type!");
849862
return false;
@@ -1036,6 +1049,15 @@ bool I2cController::Handle_I2cDeviceAddOrReplace(pb_istream_t *stream) {
10361049
} else if (config ==
10371050
wippersnapper_i2c_output_I2cOutputAdd_char_lcd_config_tag) {
10381051
WS_DEBUG_PRINTLN("[i2c] Configuring char LCD...");
1052+
} else if (config ==
1053+
wippersnapper_i2c_output_I2cOutputAdd_oled_config_tag) {
1054+
WS_DEBUG_PRINTLN("[i2c] Configuring OLED...");
1055+
wippersnapper_i2c_output_OledConfig cfg =
1056+
_i2c_model->GetI2cDeviceAddOrReplaceMsg()
1057+
->i2c_output_add.config.oled_config;
1058+
WS_DEBUG_PRINT("[i2c] Got cfg, calling ConfigureOLED...");
1059+
drv_out->ConfigureSSD1306(cfg.width, cfg.height, cfg.font_size);
1060+
WS_DEBUG_PRINTLN("OK!");
10391061
} else {
10401062
WS_DEBUG_PRINTLN(
10411063
"[i2c] ERROR: Unknown config specified for output driver!");

src/components/i2c/controller.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#include "drivers/drvOut7Seg.h"
4949
#include "drivers/drvOutCharLcd.h"
5050
#include "drivers/drvOutQuadAlphaNum.h"
51+
#include "drivers/drvOutSsd1306.h"
5152
#include "drivers/drvOutputBase.h" ///< Base i2c output driver class
5253
#include "drivers/drvPct2075.h"
5354
#include "drivers/drvPm25.h"
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
/*!
2+
* @file drvOutSsd1306.h
3+
*
4+
* Device driver for OLED displays with a SSD1306 driver
5+
*
6+
* Adafruit invests time and resources providing this open source code,
7+
* please support Adafruit and open-source hardware by purchasing
8+
* products from Adafruit!
9+
*
10+
* Copyright (c) Brent Rubell for Adafruit Industries 2025
11+
*
12+
* MIT license, all text here must be included in any redistribution.
13+
*
14+
*/
15+
16+
#ifndef DRV_OUT_SSD1306_H
17+
#define DRV_OUT_SSD1306_H
18+
19+
#include "drvOutputBase.h"
20+
#include <Adafruit_SSD1306.h>
21+
#include <Arduino.h>
22+
23+
/*!
24+
@brief Class that provides a driver interface for a SSD1306 OLED display.
25+
This class is a wrapper around the Adafruit_SSD1306 library.
26+
*/
27+
class drvOutSsd1306 : public drvOutputBase {
28+
public:
29+
/*!
30+
@brief Constructor for a lcd character display.
31+
@param i2c
32+
The I2C interface.
33+
@param sensorAddress
34+
7-bit device address.
35+
@param mux_channel
36+
The I2C multiplexer channel.
37+
@param driver_name
38+
The name of the driver.
39+
*/
40+
drvOutSsd1306(TwoWire *i2c, uint16_t sensorAddress, uint32_t mux_channel,
41+
const char *driver_name)
42+
: drvOutputBase(i2c, sensorAddress, mux_channel, driver_name) {
43+
// Initialization handled by drvOutPutBase constructor
44+
}
45+
46+
/*!
47+
@brief Destructor for a quad alphanumeric display.
48+
*/
49+
~drvOutSsd1306() {
50+
if (_display != nullptr) {
51+
_display->ssd1306_command(SSD1306_DISPLAYOFF);
52+
delete _display;
53+
_display = nullptr;
54+
}
55+
}
56+
57+
/*!
58+
@brief Initializes the SSD1306 display and begins I2C.
59+
@returns True if initialized successfully, False otherwise.
60+
*/
61+
bool begin() {
62+
// Attempt to create and allocate a SSD1306 obj.
63+
_display = new Adafruit_SSD1306(_width, _height, _i2c);
64+
if (!_display->begin(SSD1306_SWITCHCAPVCC, _address))
65+
return false;
66+
// Clear the buffer
67+
_display->clearDisplay();
68+
// Configure the text size and color
69+
_display->setTextSize(_text_sz);
70+
_display->setTextColor(SSD1306_WHITE);
71+
// Reset the cursor position
72+
_display->setCursor(0, 0);
73+
_display->display();
74+
return true;
75+
}
76+
77+
/*!
78+
@brief Configures a SSD1306 OLED display. Must be called before driver
79+
begin()
80+
@param width
81+
The width of the display in pixels.
82+
@param height
83+
The height of the display in pixels.
84+
@param text_size
85+
The magnification factor for the text size.
86+
*/
87+
void ConfigureSSD1306(uint8_t width, uint8_t height, uint8_t text_size) {
88+
_width = width;
89+
_height = height;
90+
_text_sz = text_size;
91+
}
92+
93+
/*!
94+
@brief Writes a message to the SSD1306 display.
95+
@param message
96+
The message to be displayed.
97+
*/
98+
void WriteMessageSSD1306(const char *message) {
99+
if (_display == nullptr)
100+
return;
101+
102+
// Start with a fresh display buffer
103+
// and settings
104+
int16_t y_idx = 0;
105+
_display->clearDisplay();
106+
_display->setTextSize(_text_sz);
107+
_display->setTextColor(SSD1306_WHITE);
108+
_display->setCursor(0, y_idx);
109+
_display->display();
110+
111+
// Calculate the line height based on the text size (NOTE: base height is
112+
// 8px)
113+
int16_t line_height = 8 * _text_sz;
114+
uint16_t c_idx = 0;
115+
size_t msg_size = strlen(message);
116+
for (size_t i = 0; i < msg_size && c_idx < msg_size; i++) {
117+
if (message[i] == '\\' && i + 1 < msg_size && message[i + 1] == 'n') {
118+
// detected a newline char sequence (\n)
119+
i++;
120+
// Skip to the next possible line
121+
y_idx += line_height;
122+
_display->setCursor(0, y_idx);
123+
} else {
124+
_display->print(message[i]);
125+
_display->display();
126+
}
127+
}
128+
}
129+
130+
protected:
131+
Adafruit_SSD1306 *_display =
132+
nullptr; ///< Pointer to the Adafruit_SSD1306 object
133+
uint8_t _width; ///< Width of the display in pixels
134+
uint8_t _height; ///< Height of the display in pixels
135+
uint8_t _text_sz; ///< Text size of the display
136+
};
137+
138+
#endif // DRV_OUT_SSD1306_H

src/components/i2c/drivers/drvOutputBase.h

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,28 @@ class drvOutputBase : public drvBase {
133133
// noop
134134
}
135135

136-
protected:
136+
/*!
137+
@brief Configures a SSD1306 OLED display. Must be called before driver
138+
begin()
139+
@param width
140+
The width of the display in pixels.
141+
@param height
142+
The height of the display in pixels.
143+
@param text_size
144+
The magnification factor for the text size.
145+
*/
146+
virtual void ConfigureSSD1306(uint8_t width, uint8_t height,
147+
uint8_t text_size) {
148+
// noop
149+
}
150+
151+
/*!
152+
@brief Writes a message to the SSD1306 display.
153+
@param message
154+
The message to be displayed.
155+
*/
156+
virtual void WriteMessageSSD1306(const char *message) {
157+
// noop
158+
}
137159
};
138160
#endif // DRV_OUTPUT_BASE_H

src/protos/i2c.pb.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ PB_BIND(wippersnapper_i2c_I2cDeviceRemoved, wippersnapper_i2c_I2cDeviceRemoved,
3333
PB_BIND(wippersnapper_i2c_I2cDeviceEvent, wippersnapper_i2c_I2cDeviceEvent, 2)
3434

3535

36-
PB_BIND(wippersnapper_i2c_I2cDeviceOutputWrite, wippersnapper_i2c_I2cDeviceOutputWrite, AUTO)
36+
PB_BIND(wippersnapper_i2c_I2cDeviceOutputWrite, wippersnapper_i2c_I2cDeviceOutputWrite, 2)
3737

3838

3939

src/protos/i2c.pb.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ typedef struct _wippersnapper_i2c_I2cDeviceOutputWrite {
133133
union {
134134
wippersnapper_i2c_output_LedBackpackWrite write_led_backpack; /* * Optional - If the I2C device is a LED backpack, fill this field. * */
135135
wippersnapper_i2c_output_CharLCDWrite write_char_lcd; /* * Optional - If the I2C device is a character LCD, fill this field. * */
136+
wippersnapper_i2c_output_OLEDWrite write_oled; /* * Optional - If the I2C device is an OLED display, fill this field. * */
136137
} output_msg;
137138
} wippersnapper_i2c_I2cDeviceOutputWrite;
138139

@@ -221,6 +222,7 @@ extern "C" {
221222
#define wippersnapper_i2c_I2cDeviceOutputWrite_i2c_device_description_tag 1
222223
#define wippersnapper_i2c_I2cDeviceOutputWrite_write_led_backpack_tag 2
223224
#define wippersnapper_i2c_I2cDeviceOutputWrite_write_char_lcd_tag 3
225+
#define wippersnapper_i2c_I2cDeviceOutputWrite_write_oled_tag 4
224226

225227
/* Struct field encoding specification for nanopb */
226228
#define wippersnapper_i2c_I2cDeviceDescriptor_FIELDLIST(X, a) \
@@ -301,12 +303,14 @@ X(a, STATIC, REPEATED, MESSAGE, i2c_device_events, 2)
301303
#define wippersnapper_i2c_I2cDeviceOutputWrite_FIELDLIST(X, a) \
302304
X(a, STATIC, OPTIONAL, MESSAGE, i2c_device_description, 1) \
303305
X(a, STATIC, ONEOF, MESSAGE, (output_msg,write_led_backpack,output_msg.write_led_backpack), 2) \
304-
X(a, STATIC, ONEOF, MESSAGE, (output_msg,write_char_lcd,output_msg.write_char_lcd), 3)
306+
X(a, STATIC, ONEOF, MESSAGE, (output_msg,write_char_lcd,output_msg.write_char_lcd), 3) \
307+
X(a, STATIC, ONEOF, MESSAGE, (output_msg,write_oled,output_msg.write_oled), 4)
305308
#define wippersnapper_i2c_I2cDeviceOutputWrite_CALLBACK NULL
306309
#define wippersnapper_i2c_I2cDeviceOutputWrite_DEFAULT NULL
307310
#define wippersnapper_i2c_I2cDeviceOutputWrite_i2c_device_description_MSGTYPE wippersnapper_i2c_I2cDeviceDescriptor
308311
#define wippersnapper_i2c_I2cDeviceOutputWrite_output_msg_write_led_backpack_MSGTYPE wippersnapper_i2c_output_LedBackpackWrite
309312
#define wippersnapper_i2c_I2cDeviceOutputWrite_output_msg_write_char_lcd_MSGTYPE wippersnapper_i2c_output_CharLCDWrite
313+
#define wippersnapper_i2c_I2cDeviceOutputWrite_output_msg_write_oled_MSGTYPE wippersnapper_i2c_output_OLEDWrite
310314

311315
extern const pb_msgdesc_t wippersnapper_i2c_I2cDeviceDescriptor_msg;
312316
extern const pb_msgdesc_t wippersnapper_i2c_I2cBusDescriptor_msg;
@@ -339,7 +343,7 @@ extern const pb_msgdesc_t wippersnapper_i2c_I2cDeviceOutputWrite_msg;
339343
#define wippersnapper_i2c_I2cDeviceAddOrReplace_size 125
340344
#define wippersnapper_i2c_I2cDeviceAddedOrReplaced_size 56
341345
#define wippersnapper_i2c_I2cDeviceDescriptor_size 50
342-
#define wippersnapper_i2c_I2cDeviceOutputWrite_size 157
346+
#define wippersnapper_i2c_I2cDeviceOutputWrite_size 569
343347
#define wippersnapper_i2c_I2cDeviceRemove_size 54
344348
#define wippersnapper_i2c_I2cDeviceRemoved_size 54
345349
#if defined(wippersnapper_sensor_SensorEvent_size)

src/protos/signal.pb.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,7 +257,7 @@ extern const pb_msgdesc_t wippersnapper_signal_DeviceToBroker_msg;
257257

258258
/* Maximum encoded size of messages (where known) */
259259
#if defined(wippersnapper_digitalio_DigitalIOEvent_size) && defined(wippersnapper_digitalio_DigitalIOWrite_size) && defined(wippersnapper_uart_UARTAdd_size) && defined(wippersnapper_uart_UARTRemove_size)
260-
union wippersnapper_signal_BrokerToDevice_payload_size_union {char f12[(6 + wippersnapper_digitalio_DigitalIOEvent_size)]; char f13[(6 + wippersnapper_digitalio_DigitalIOWrite_size)]; char f80[(7 + wippersnapper_uart_UARTAdd_size)]; char f81[(7 + wippersnapper_uart_UARTRemove_size)]; char f0[161];};
260+
union wippersnapper_signal_BrokerToDevice_payload_size_union {char f12[(6 + wippersnapper_digitalio_DigitalIOEvent_size)]; char f13[(6 + wippersnapper_digitalio_DigitalIOWrite_size)]; char f80[(7 + wippersnapper_uart_UARTAdd_size)]; char f81[(7 + wippersnapper_uart_UARTRemove_size)]; char f0[573];};
261261
#endif
262262
#if defined(wippersnapper_digitalio_DigitalIOEvent_size) && defined(wippersnapper_analogio_AnalogIOEvent_size) && defined(wippersnapper_ds18x20_Ds18x20Event_size) && defined(wippersnapper_uart_UARTAdded_size) && defined(wippersnapper_uart_UARTEvent_size) && defined(wippersnapper_i2c_I2cDeviceEvent_size)
263263
union wippersnapper_signal_DeviceToBroker_payload_size_union {char f10[(6 + wippersnapper_digitalio_DigitalIOEvent_size)]; char f20[(7 + wippersnapper_analogio_AnalogIOEvent_size)]; char f80[(7 + wippersnapper_ds18x20_Ds18x20Event_size)]; char f90[(7 + wippersnapper_uart_UARTAdded_size)]; char f100[(7 + wippersnapper_uart_UARTEvent_size)]; char f113[(7 + wippersnapper_i2c_I2cDeviceEvent_size)]; char f0[6246];};

0 commit comments

Comments
 (0)