├── .gitignore
├── Framebuffer.cpp
├── Framebuffer.h
├── I2C.cpp
├── I2C.h
├── README.md
├── SSD1306.cpp
├── SSD1306.h
├── examples
├── example1
│ ├── Makefile
│ ├── example1.cpp
│ └── example1.h
└── example2
│ ├── Makefile
│ ├── example2
│ ├── example2.cpp
│ └── example2.h
├── img
└── simulator1.png
└── simulator
├── I2C.cpp
├── I2C.h
├── Makefile
├── SDLMain.h
├── SDLMain.m
├── main.c
└── main.h
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | *.o
3 | examples/example1/example1
4 | examples/example1/example1.hex
5 | examples/example2/example2
6 | examples/example2/example2.hex
7 | simulator/simulator
--------------------------------------------------------------------------------
/Framebuffer.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | This is free and unencumbered software released into the public domain.
3 |
4 | Anyone is free to copy, modify, publish, use, compile, sell, or
5 | distribute this software, either in source code form or as a compiled
6 | binary, for any purpose, commercial or non-commercial, and by any
7 | means.
8 |
9 | In jurisdictions that recognize copyright laws, the author or authors
10 | of this software dedicate any and all copyright interest in the
11 | software to the public domain. We make this dedication for the benefit
12 | of the public at large and to the detriment of our heirs and
13 | successors. We intend this dedication to be an overt act of
14 | relinquishment in perpetuity of all present and future rights to this
15 | software under copyright law.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 | OTHER DEALINGS IN THE SOFTWARE.
24 |
25 | For more information, please refer to
26 | */
27 |
28 | #include "Framebuffer.h"
29 |
30 | Framebuffer::Framebuffer() {
31 | this->clear();
32 | }
33 |
34 | #ifndef SIMULATOR
35 | void Framebuffer::drawBitmap(const uint8_t *progmem_bitmap, uint8_t height, uint8_t width, uint8_t pos_x, uint8_t pos_y) {
36 | uint8_t current_byte;
37 | uint8_t byte_width = (width + 7)/8;
38 |
39 | for (uint8_t current_y = 0; current_y < height; current_y++) {
40 | for (uint8_t current_x = 0; current_x < width; current_x++) {
41 | current_byte = pgm_read_byte(progmem_bitmap + current_y*byte_width + current_x/8);
42 | if (current_byte & (128 >> (current_x&7))) {
43 | this->drawPixel(current_x+pos_x,current_y+pos_y,1);
44 | } else {
45 | this->drawPixel(current_x+pos_x,current_y+pos_y,0);
46 | }
47 | }
48 | }
49 | }
50 |
51 | void Framebuffer::drawBuffer(const uint8_t *progmem_buffer) {
52 | uint8_t current_byte;
53 |
54 | for (uint8_t y_pos = 0; y_pos < 64; y_pos++) {
55 | for (uint8_t x_pos = 0; x_pos < 128; x_pos++) {
56 | current_byte = pgm_read_byte(progmem_buffer + y_pos*16 + x_pos/8);
57 | if (current_byte & (128 >> (x_pos&7))) {
58 | this->drawPixel(x_pos,y_pos,1);
59 | } else {
60 | this->drawPixel(x_pos,y_pos,0);
61 | }
62 | }
63 | }
64 | }
65 | #endif
66 |
67 | void Framebuffer::drawPixel(uint8_t pos_x, uint8_t pos_y, uint8_t pixel_status) {
68 | if (pos_x >= SSD1306_WIDTH || pos_y >= SSD1306_HEIGHT) {
69 | return;
70 | }
71 |
72 | if (pixel_status) {
73 | this->buffer[pos_x+(pos_y/8)*SSD1306_WIDTH] |= (1 << (pos_y&7));
74 | } else {
75 | this->buffer[pos_x+(pos_y/8)*SSD1306_WIDTH] &= ~(1 << (pos_y&7));
76 | }
77 | }
78 |
79 | void Framebuffer::drawPixel(uint8_t pos_x, uint8_t pos_y) {
80 | if (pos_x >= SSD1306_WIDTH || pos_y >= SSD1306_HEIGHT) {
81 | return;
82 | }
83 |
84 | this->buffer[pos_x+(pos_y/8)*SSD1306_WIDTH] |= (1 << (pos_y&7));
85 | }
86 |
87 | void Framebuffer::drawVLine(uint8_t x, uint8_t y, uint8_t length) {
88 | for (uint8_t i = 0; i < length; ++i) {
89 | this->drawPixel(x,i+y);
90 | }
91 | }
92 |
93 | void Framebuffer::drawHLine(uint8_t x, uint8_t y, uint8_t length) {
94 | for (uint8_t i = 0; i < length; ++i) {
95 | this->drawPixel(i+x,y);
96 | }
97 | }
98 |
99 | void Framebuffer::drawRectangle(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2) {
100 | uint8_t length = x2 - x1 + 1;
101 | uint8_t height = y2 - y1;
102 |
103 | this->drawHLine(x1,y1,length);
104 | this->drawHLine(x1,y2,length);
105 | this->drawVLine(x1,y1,height);
106 | this->drawVLine(x2,y1,height);
107 | }
108 |
109 | void Framebuffer::drawRectangle(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint8_t fill) {
110 | if (!fill) {
111 | this->drawRectangle(x1,y1,x2,y2);
112 | } else {
113 | uint8_t length = x2 - x1 + 1;
114 | uint8_t height = y2 - y1;
115 |
116 | for (int x = 0; x < length; ++x) {
117 | for (int y = 0; y <= height; ++y) {
118 | this->drawPixel(x1+x,y+y1);
119 | }
120 | }
121 | }
122 | }
123 |
124 | void Framebuffer::clear() {
125 | for (uint16_t buffer_location = 0; buffer_location < SSD1306_BUFFERSIZE; buffer_location++) {
126 | this->buffer[buffer_location] = 0x00;
127 | }
128 | }
129 |
130 | void Framebuffer::invert(uint8_t status) {
131 | this->oled.invert(status);
132 | }
133 |
134 | void Framebuffer::show() {
135 | this->oled.sendFramebuffer(this->buffer);
136 | }
--------------------------------------------------------------------------------
/Framebuffer.h:
--------------------------------------------------------------------------------
1 | /*
2 | This is free and unencumbered software released into the public domain.
3 |
4 | Anyone is free to copy, modify, publish, use, compile, sell, or
5 | distribute this software, either in source code form or as a compiled
6 | binary, for any purpose, commercial or non-commercial, and by any
7 | means.
8 |
9 | In jurisdictions that recognize copyright laws, the author or authors
10 | of this software dedicate any and all copyright interest in the
11 | software to the public domain. We make this dedication for the benefit
12 | of the public at large and to the detriment of our heirs and
13 | successors. We intend this dedication to be an overt act of
14 | relinquishment in perpetuity of all present and future rights to this
15 | software under copyright law.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 | OTHER DEALINGS IN THE SOFTWARE.
24 |
25 | For more information, please refer to
26 | */
27 |
28 | #include
29 | #ifndef SIMULATOR
30 | #include
31 | #endif
32 | #include "SSD1306.h"
33 |
34 | class Framebuffer {
35 | public:
36 | Framebuffer();
37 | void drawBitmap(const uint8_t *bitmap, uint8_t height, uint8_t width, uint8_t pos_x, uint8_t pos_y);
38 | void drawBuffer(const uint8_t *buffer);
39 | void drawPixel(uint8_t pos_x, uint8_t pos_y, uint8_t pixel_status);
40 | void drawPixel(uint8_t pos_x, uint8_t pos_y);
41 | void drawVLine(uint8_t x, uint8_t y, uint8_t length);
42 | void drawHLine(uint8_t pos_y, uint8_t start, uint8_t length);
43 | void drawRectangle(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2);
44 | void drawRectangle(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2, uint8_t fill);
45 | void invert(uint8_t status);
46 | void clear();
47 | void show();
48 | private:
49 | uint8_t buffer[1024];
50 | SSD1306 oled;
51 | };
--------------------------------------------------------------------------------
/I2C.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | This is free and unencumbered software released into the public domain.
3 |
4 | Anyone is free to copy, modify, publish, use, compile, sell, or
5 | distribute this software, either in source code form or as a compiled
6 | binary, for any purpose, commercial or non-commercial, and by any
7 | means.
8 |
9 | In jurisdictions that recognize copyright laws, the author or authors
10 | of this software dedicate any and all copyright interest in the
11 | software to the public domain. We make this dedication for the benefit
12 | of the public at large and to the detriment of our heirs and
13 | successors. We intend this dedication to be an overt act of
14 | relinquishment in perpetuity of all present and future rights to this
15 | software under copyright law.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 | OTHER DEALINGS IN THE SOFTWARE.
24 |
25 | For more information, please refer to
26 | */
27 |
28 | #include "I2C.h"
29 |
30 | I2C::I2C() {}
31 |
32 | void I2C::init(uint8_t address) {
33 | this->address = address;
34 | TWSR = 0;
35 | TWBR = ((F_CPU/SCL_CLOCK)-16)/2;
36 | }
37 |
38 | uint8_t I2C::start() {
39 | TWCR = (1<twi_status_register != TW_START) && (this->twi_status_register != TW_REP_START)) {
44 | return 1;
45 | }
46 |
47 | TWDR = address;
48 | TWCR = (1<twi_status_register = TW_STATUS & 0xF8;
53 | if ((this->twi_status_register != TW_MT_SLA_ACK) && (this->twi_status_register != TW_MR_SLA_ACK)) {
54 | return 1;
55 | }
56 |
57 | return 0;
58 | }
59 |
60 | uint8_t I2C::write(uint8_t data) {
61 | TWDR = data;
62 | TWCR = (1<twi_status_register = TW_STATUS & 0xF8;
67 | if (this->twi_status_register != TW_MT_DATA_ACK) {
68 | return 1;
69 | } else {
70 | return 0;
71 | }
72 | }
73 |
74 | void I2C::stop(void) {
75 | TWCR = (1<
26 | */
27 |
28 | #ifndef _I2C_H_
29 | #define _I2C_H_
30 |
31 | #include
32 | #include
33 |
34 | #define SCL_CLOCK 100000L
35 |
36 | class I2C {
37 | public:
38 | I2C();
39 | void init(uint8_t address);
40 | uint8_t start();
41 | uint8_t write(uint8_t data);
42 | void stop(void);
43 | private:
44 | uint8_t address;
45 | uint8_t twi_status_register;
46 | };
47 |
48 | #endif
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SSD1306-AVR
2 |
3 | SSD1306-AVR is a C++ library for using SSD1306, 128x64, monochrome OLED displays. Currently only the I2C version of the display is supported.
4 |
5 | The I2C address of the display is set up in SSD1306.h :
6 | ```C
7 | #define SSD1306_DEFAULT_ADDRESS 0x78
8 | ```
9 |
10 | The library is written in pure C++. You'll only need avr-libc, Arduino framework is not needed.
11 |
12 | This library is released under a VERY permissive license. Do anything with it, but if something goes wrong, it is YOUR problem (= NO WARRANTY AT ALL).
13 |
14 | ## Example code (no framebuffer used)
15 |
16 | ```C++
17 | #include
18 | #include "SSD1306.h"
19 |
20 | int main(void) {
21 | // This is our buffer
22 | // Each byte = 8 pixels on the screen
23 | uint8_t buffer[1024];
24 |
25 | // Only two lines of code to initiate the driver
26 | // and to send our framebuffer
27 | SSD1306 myDisplay;
28 | myDisplay.sendFramebuffer(buffer);
29 |
30 | // Hardware function to reverse the pixels
31 | // (swap black and white pixel)
32 | myDisplay.invert(1);
33 | // Revert back to normal display
34 | myDisplay.invert(0);
35 |
36 | return 0;
37 | }
38 | ```
39 |
40 | ## Another example code (using the framebuffer)
41 |
42 | ```C++
43 | #include
44 | #include "Framebuffer.h"
45 |
46 | int main(void) {
47 | Framebuffer fb;
48 |
49 | fb.drawRectangle(1,1,126,62);
50 | fb.drawRectangle(3,3,124,60);
51 | fb.drawRectangle(5,5,122,58);
52 | fb.drawRectangle(7,7,120,56);
53 | fb.drawRectangle(9,9,118,54);
54 | fb.drawRectangle(11,11,116,52);
55 | fb.drawRectangle(13,13,114,50);
56 |
57 | fb.show();
58 |
59 | return 0;
60 | }
61 | ```
62 |
63 | As you can see the framebuffer API is quite easy to understand.
64 |
65 | ## Images !
66 |
67 | You can display images using the Framebuffer, though you will need to convert those images using [Esther](https://github.com/tibounise/Esther).
68 |
69 | ```C++
70 | #include
71 | #include
72 | #include "Framebuffer.h"
73 |
74 | const uint8_t image[] PROGMEM = {
75 | ...
76 | };
77 |
78 | int main(void) {
79 |
80 | Framebuffer fb;
81 |
82 | fb.drawBitmap(image,64,128,0,0);
83 |
84 | fb.show();
85 |
86 | return 0;
87 | }
88 | ```
89 |
90 | ## SSD1306 simulator
91 |
92 | It is very experimental, maybe not usefull.
93 |
94 | 
95 |
96 | There are some example programs using the simulator, in `/examples/`. Compile the simulator (requires SDL2) and the example program, then run your example program like this :
97 |
98 | ```shell
99 | ./examples/example1/example1 | ./simulator/simulator
100 | ```
101 |
102 | ## Looking for your support
103 |
104 | If you would like to see 128x32 displays (or any other I2C SSD1306-based displays) supported by my library, please do a donation, so that I could buy one of those displays to improve my library.
105 |
106 | I currently accept [PayPal](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=K65LZXQXASC8E) and [Bitcoin](https://blockchain.info/address/13XFkvDBm8iqbwVC1egYZ8sCSu72eebJ7N) donations.
107 |
--------------------------------------------------------------------------------
/SSD1306.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | This is free and unencumbered software released into the public domain.
3 |
4 | Anyone is free to copy, modify, publish, use, compile, sell, or
5 | distribute this software, either in source code form or as a compiled
6 | binary, for any purpose, commercial or non-commercial, and by any
7 | means.
8 |
9 | In jurisdictions that recognize copyright laws, the author or authors
10 | of this software dedicate any and all copyright interest in the
11 | software to the public domain. We make this dedication for the benefit
12 | of the public at large and to the detriment of our heirs and
13 | successors. We intend this dedication to be an overt act of
14 | relinquishment in perpetuity of all present and future rights to this
15 | software under copyright law.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 | OTHER DEALINGS IN THE SOFTWARE.
24 |
25 | For more information, please refer to
26 | */
27 |
28 | #include
29 | #include "SSD1306.h"
30 |
31 | #ifdef SIMULATOR
32 | #include "simulator/I2C.h"
33 | #else
34 | #include "I2C.h"
35 | #endif
36 |
37 | SSD1306::SSD1306() {
38 | i2c.init(SSD1306_DEFAULT_ADDRESS);
39 |
40 | // Turn display off
41 | sendCommand(SSD1306_DISPLAYOFF);
42 |
43 | sendCommand(SSD1306_SETDISPLAYCLOCKDIV);
44 | sendCommand(0x80);
45 |
46 | sendCommand(SSD1306_SETMULTIPLEX);
47 | sendCommand(0x3F);
48 |
49 | sendCommand(SSD1306_SETDISPLAYOFFSET);
50 | sendCommand(0x00);
51 |
52 | sendCommand(SSD1306_SETSTARTLINE | 0x00);
53 |
54 | // We use internal charge pump
55 | sendCommand(SSD1306_CHARGEPUMP);
56 | sendCommand(0x14);
57 |
58 | // Horizontal memory mode
59 | sendCommand(SSD1306_MEMORYMODE);
60 | sendCommand(0x00);
61 |
62 | sendCommand(SSD1306_SEGREMAP | 0x1);
63 |
64 | sendCommand(SSD1306_COMSCANDEC);
65 |
66 | sendCommand(SSD1306_SETCOMPINS);
67 | sendCommand(0x12);
68 |
69 | // Max contrast
70 | sendCommand(SSD1306_SETCONTRAST);
71 | sendCommand(0xCF);
72 |
73 | sendCommand(SSD1306_SETPRECHARGE);
74 | sendCommand(0xF1);
75 |
76 | sendCommand(SSD1306_SETVCOMDETECT);
77 | sendCommand(0x40);
78 |
79 | sendCommand(SSD1306_DISPLAYALLON_RESUME);
80 |
81 | // Non-inverted display
82 | sendCommand(SSD1306_NORMALDISPLAY);
83 |
84 | // Turn display back on
85 | sendCommand(SSD1306_DISPLAYON);
86 | }
87 |
88 | void SSD1306::sendCommand(uint8_t command) {
89 | i2c.start();
90 | i2c.write(0x00);
91 | i2c.write(command);
92 | i2c.stop();
93 | }
94 |
95 | void SSD1306::invert(uint8_t inverted) {
96 | if (inverted) {
97 | sendCommand(SSD1306_INVERTDISPLAY);
98 | } else {
99 | sendCommand(SSD1306_NORMALDISPLAY);
100 | }
101 | }
102 |
103 | void SSD1306::sendFramebuffer(uint8_t *buffer) {
104 | sendCommand(SSD1306_COLUMNADDR);
105 | sendCommand(0x00);
106 | sendCommand(0x7F);
107 |
108 | sendCommand(SSD1306_PAGEADDR);
109 | sendCommand(0x00);
110 | sendCommand(0x07);
111 |
112 | // We have to send the buffer as 16 bytes packets
113 | // Our buffer is 1024 bytes long, 1024/16 = 64
114 | // We have to send 64 packets
115 | for (uint8_t packet = 0; packet < 64; packet++) {
116 | i2c.start();
117 | i2c.write(0x40);
118 | for (uint8_t packet_byte = 0; packet_byte < 16; ++packet_byte) {
119 | i2c.write(buffer[packet*16+packet_byte]);
120 | }
121 | i2c.stop();
122 | }
123 | }
--------------------------------------------------------------------------------
/SSD1306.h:
--------------------------------------------------------------------------------
1 | /*
2 | This is free and unencumbered software released into the public domain.
3 |
4 | Anyone is free to copy, modify, publish, use, compile, sell, or
5 | distribute this software, either in source code form or as a compiled
6 | binary, for any purpose, commercial or non-commercial, and by any
7 | means.
8 |
9 | In jurisdictions that recognize copyright laws, the author or authors
10 | of this software dedicate any and all copyright interest in the
11 | software to the public domain. We make this dedication for the benefit
12 | of the public at large and to the detriment of our heirs and
13 | successors. We intend this dedication to be an overt act of
14 | relinquishment in perpetuity of all present and future rights to this
15 | software under copyright law.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 | OTHER DEALINGS IN THE SOFTWARE.
24 |
25 | For more information, please refer to
26 | */
27 |
28 | #ifdef SIMULATOR
29 | #include "simulator/I2C.h"
30 | #else
31 | #include "I2C.h"
32 | #endif
33 |
34 | #define SSD1306_DEFAULT_ADDRESS 0x78
35 | #define SSD1306_SETCONTRAST 0x81
36 | #define SSD1306_DISPLAYALLON_RESUME 0xA4
37 | #define SSD1306_DISPLAYALLON 0xA5
38 | #define SSD1306_NORMALDISPLAY 0xA6
39 | #define SSD1306_INVERTDISPLAY 0xA7
40 | #define SSD1306_DISPLAYOFF 0xAE
41 | #define SSD1306_DISPLAYON 0xAF
42 | #define SSD1306_SETDISPLAYOFFSET 0xD3
43 | #define SSD1306_SETCOMPINS 0xDA
44 | #define SSD1306_SETVCOMDETECT 0xDB
45 | #define SSD1306_SETDISPLAYCLOCKDIV 0xD5
46 | #define SSD1306_SETPRECHARGE 0xD9
47 | #define SSD1306_SETMULTIPLEX 0xA8
48 | #define SSD1306_SETLOWCOLUMN 0x00
49 | #define SSD1306_SETHIGHCOLUMN 0x10
50 | #define SSD1306_SETSTARTLINE 0x40
51 | #define SSD1306_MEMORYMODE 0x20
52 | #define SSD1306_COLUMNADDR 0x21
53 | #define SSD1306_PAGEADDR 0x22
54 | #define SSD1306_COMSCANINC 0xC0
55 | #define SSD1306_COMSCANDEC 0xC8
56 | #define SSD1306_SEGREMAP 0xA0
57 | #define SSD1306_CHARGEPUMP 0x8D
58 | #define SSD1306_SWITCHCAPVCC 0x2
59 | #define SSD1306_NOP 0xE3
60 |
61 | #define SSD1306_WIDTH 128
62 | #define SSD1306_HEIGHT 64
63 | #define SSD1306_BUFFERSIZE (SSD1306_WIDTH*SSD1306_HEIGHT)/8
64 |
65 | class SSD1306{
66 | private:
67 | I2C i2c;
68 |
69 | public:
70 | SSD1306();
71 | void sendFramebuffer(uint8_t *buffer);
72 | void invert(uint8_t inverted);
73 | private:
74 | void sendCommand(uint8_t command);
75 | void sendData(uint8_t data);
76 | };
--------------------------------------------------------------------------------
/examples/example1/Makefile:
--------------------------------------------------------------------------------
1 | ARCH = SIMULATOR
2 |
3 | # MCU specific
4 | MCU = atmega328p
5 | F_CPU = 16000000
6 |
7 | CXX_SIMULATOR = g++
8 | CXX_AVR = avr-g++
9 | CXX = $(CXX_$(ARCH))
10 |
11 | CXXFLAGS_SIMULATOR = -O2 -Wall -D SIMULATOR
12 | CXXFLAGS_AVR = -Os -Wall -mmcu=$(MCU) -DF_CPU=$(F_CPU) -I./include -I/usr/lib/avr/include -fno-exceptions
13 | CXXFLAGS = $(CXXFLAGS_$(ARCH))
14 |
15 | OBJS_SIMULATOR = ../../simulator/I2C.o ../../SSD1306.o ../../Framebuffer.o example1.o
16 | OBJS_AVR = ../../I2C.o ../../SSD1306.o ../../Framebuffer.o example1.o
17 | OBJS = $(OBJS_$(ARCH))
18 |
19 | TARGET_SIMULATOR = example1
20 | TARGET_AVR = example1.hex
21 | TARGET = $(TARGET_$(ARCH))
22 |
23 | all: $(TARGET)
24 |
25 | %.hex: %.obj
26 | avr-objcopy -R .eeprom -O ihex $< $@
27 |
28 | %.obj: $(OBJS)
29 | $(CXX) $(CXXFLAGS) $(OBJS) $(LDFLAGS) -o $@
30 |
31 | ifeq ($(ARCH),SIMULATOR)
32 | $(TARGET): $(OBJS)
33 | $(CC) $(LDFLAGS) $(OBJS) -o $(TARGET) -D SIMULATOR
34 | endif
35 |
36 | clean:
37 | rm -f $(TARGET) $(OBJS)
38 |
39 | .PHONY: all example1 clean
--------------------------------------------------------------------------------
/examples/example1/example1.cpp:
--------------------------------------------------------------------------------
1 | #include "example1.h"
2 |
3 | int main(void) {
4 | Framebuffer fb;
5 |
6 | fb.drawRectangle(2,2,125,61);
7 | fb.drawRectangle(6,6,12,12,1);
8 |
9 | fb.show();
10 |
11 | // Invert uses direct hardware commands
12 | // So no need to send the framebuffer again
13 | // => no need to fb.show();
14 | fb.invert(1);
15 |
16 | return 0;
17 | }
--------------------------------------------------------------------------------
/examples/example1/example1.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include "../../Framebuffer.h"
--------------------------------------------------------------------------------
/examples/example2/Makefile:
--------------------------------------------------------------------------------
1 | ARCH = SIMULATOR
2 |
3 | # MCU specific
4 | MCU = atmega328p
5 | F_CPU = 16000000
6 |
7 | CXX_SIMULATOR = g++
8 | CXX_AVR = avr-g++
9 | CXX = $(CXX_$(ARCH))
10 |
11 | CXXFLAGS_SIMULATOR = -O2 -Wall -D SIMULATOR
12 | CXXFLAGS_AVR = -Os -Wall -mmcu=$(MCU) -DF_CPU=$(F_CPU) -I./include -I/usr/lib/avr/include -fno-exceptions
13 | CXXFLAGS = $(CXXFLAGS_$(ARCH))
14 |
15 | OBJS_SIMULATOR = ../../simulator/I2C.o ../../SSD1306.o ../../Framebuffer.o example2.o
16 | OBJS_AVR = ../../I2C.o ../../SSD1306.o ../../Framebuffer.o example2.o
17 | OBJS = $(OBJS_$(ARCH))
18 |
19 | TARGET_SIMULATOR = example2
20 | TARGET_AVR = example2.hex
21 | TARGET = $(TARGET_$(ARCH))
22 |
23 | all: $(TARGET)
24 |
25 | %.hex: %.obj
26 | avr-objcopy -R .eeprom -O ihex $< $@
27 |
28 | %.obj: $(OBJS)
29 | $(CXX) $(CXXFLAGS) $(OBJS) $(LDFLAGS) -o $@
30 |
31 | ifeq ($(ARCH),SIMULATOR)
32 | $(TARGET): $(OBJS)
33 | $(CC) $(LDFLAGS) $(OBJS) -o $(TARGET) -D SIMULATOR
34 | endif
35 |
36 | clean:
37 | rm -f $(TARGET) $(OBJS)
38 |
39 | .PHONY: all $(TARGET) clean
--------------------------------------------------------------------------------
/examples/example2/example2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tibounise/SSD1306-AVR/a658894d38be7a67299eeb810b15dcbbe910838f/examples/example2/example2
--------------------------------------------------------------------------------
/examples/example2/example2.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | In this example, we are going to draw bitmaps.
3 | The code is quite straight forward.
4 | */
5 |
6 | #include "example2.h"
7 |
8 | int main(void) {
9 | Framebuffer fb;
10 |
11 | uint8_t bitmap1[8] = {
12 | 0b00100100,
13 | 0b00100100,
14 | 0b00100100,
15 | 0b00000000,
16 | 0b10000001,
17 | 0b01000010,
18 | 0b00100100,
19 | 0b00011000
20 | };
21 |
22 | uint8_t bitmap2[8] = {
23 | 0b11111110,
24 | 0b00010000,
25 | 0b00010000,
26 | 0b00010000,
27 | 0b00010000,
28 | 0b00010000,
29 | 0b00010000,
30 | 0b00000000
31 | };
32 |
33 | uint8_t bitmap3[8] = {
34 | 0b00000000,
35 | 0b00010000,
36 | 0b00000000,
37 | 0b00010000,
38 | 0b00010000,
39 | 0b00010000,
40 | 0b00010000,
41 | 0b00000000
42 | };
43 |
44 | uint8_t bitmap4[8] = {
45 | 0b00000000,
46 | 0b10000000,
47 | 0b10000000,
48 | 0b11111100,
49 | 0b10000010,
50 | 0b10000010,
51 | 0b11111100,
52 | 0b00000000
53 | };
54 |
55 | uint8_t bitmap5[8] = {
56 | 0b00000000,
57 | 0b00000000,
58 | 0b01111110,
59 | 0b10000001,
60 | 0b10000001,
61 | 0b10000001,
62 | 0b01111110,
63 | 0b00000000
64 | };
65 |
66 | uint8_t bitmap6[8] = {
67 | 0b00000000,
68 | 0b00000000,
69 | 0b10000010,
70 | 0b10000010,
71 | 0b10000010,
72 | 0b10000010,
73 | 0b01111100,
74 | 0b00000000
75 | };
76 |
77 | // Drawing the smiley stored in bitmap1[]
78 | for (int i = 0; i < sizeof(bitmap1); ++i) {
79 | for (int p = 0; p < 8; ++p) {
80 | if ((bitmap1[i] >> p) & 0x1) {
81 | fb.drawPixel(p+32,i+32);
82 | }
83 | }
84 | }
85 |
86 | for (int i = 0; i < sizeof(bitmap2); ++i) {
87 | for (int p = 0; p < 8; ++p) {
88 | if ((bitmap2[i] >> p) & 0x1) {
89 | fb.drawPixel(p+10,i+5);
90 | }
91 | }
92 | }
93 | for (int i = 0; i < sizeof(bitmap3); ++i) {
94 | for (int p = 0; p < 8; ++p) {
95 | if ((bitmap3[i] >> p) & 0x1) {
96 | fb.drawPixel(p+18,i+5);
97 | }
98 | }
99 | }
100 | for (int i = 0; i < sizeof(bitmap4); ++i) {
101 | for (int p = 0; p < 8; ++p) {
102 | if ((bitmap4[i] >> p) & 0x1) {
103 | fb.drawPixel((7-p)+26,i+5);
104 | }
105 | }
106 | }
107 | for (int i = 0; i < sizeof(bitmap5); ++i) {
108 | for (int p = 0; p < 8; ++p) {
109 | if ((bitmap5[i] >> p) & 0x1) {
110 | fb.drawPixel(p+34,i+5);
111 | }
112 | }
113 | }
114 | for (int i = 0; i < sizeof(bitmap6); ++i) {
115 | for (int p = 0; p < 8; ++p) {
116 | if ((bitmap6[i] >> p) & 0x1) {
117 | fb.drawPixel(p+42,i+5);
118 | }
119 | }
120 | }
121 |
122 | fb.show();
123 |
124 | return 0;
125 | }
--------------------------------------------------------------------------------
/examples/example2/example2.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include "../../Framebuffer.h"
--------------------------------------------------------------------------------
/img/simulator1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tibounise/SSD1306-AVR/a658894d38be7a67299eeb810b15dcbbe910838f/img/simulator1.png
--------------------------------------------------------------------------------
/simulator/I2C.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | This is free and unencumbered software released into the public domain.
3 |
4 | Anyone is free to copy, modify, publish, use, compile, sell, or
5 | distribute this software, either in source code form or as a compiled
6 | binary, for any purpose, commercial or non-commercial, and by any
7 | means.
8 |
9 | In jurisdictions that recognize copyright laws, the author or authors
10 | of this software dedicate any and all copyright interest in the
11 | software to the public domain. We make this dedication for the benefit
12 | of the public at large and to the detriment of our heirs and
13 | successors. We intend this dedication to be an overt act of
14 | relinquishment in perpetuity of all present and future rights to this
15 | software under copyright law.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 | OTHER DEALINGS IN THE SOFTWARE.
24 |
25 | For more information, please refer to
26 | */
27 |
28 | #include
29 | #include "I2C.h"
30 |
31 | I2C::I2C() {}
32 |
33 | void I2C::init(uint8_t address) {
34 | }
35 |
36 | uint8_t I2C::start() {
37 | return 0;
38 | }
39 |
40 | uint8_t I2C::write(uint8_t data) {
41 | putchar(data);
42 | return 0;
43 | }
44 |
45 | void I2C::stop(void) {
46 | }
--------------------------------------------------------------------------------
/simulator/I2C.h:
--------------------------------------------------------------------------------
1 | /*
2 | This is free and unencumbered software released into the public domain.
3 |
4 | Anyone is free to copy, modify, publish, use, compile, sell, or
5 | distribute this software, either in source code form or as a compiled
6 | binary, for any purpose, commercial or non-commercial, and by any
7 | means.
8 |
9 | In jurisdictions that recognize copyright laws, the author or authors
10 | of this software dedicate any and all copyright interest in the
11 | software to the public domain. We make this dedication for the benefit
12 | of the public at large and to the detriment of our heirs and
13 | successors. We intend this dedication to be an overt act of
14 | relinquishment in perpetuity of all present and future rights to this
15 | software under copyright law.
16 |
17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20 | IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
21 | OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 | OTHER DEALINGS IN THE SOFTWARE.
24 |
25 | For more information, please refer to
26 | */
27 |
28 | #ifndef _I2C_H_
29 | #define _I2C_H_
30 |
31 | #include
32 |
33 | class I2C {
34 | public:
35 | I2C();
36 | void init(uint8_t address);
37 | uint8_t start();
38 | uint8_t write(uint8_t data);
39 | void stop(void);
40 | };
41 | #endif
--------------------------------------------------------------------------------
/simulator/Makefile:
--------------------------------------------------------------------------------
1 | all: simulator
2 |
3 | simulator: main.c
4 | g++ main.c -o simulator `sdl2-config --cflags` -lSDL2main -lSDL2 -framework Cocoa -D SIMULATOR
5 |
6 | clean:
7 | rm simulator
8 |
9 | .PHONY: all fb-sim clean
--------------------------------------------------------------------------------
/simulator/SDLMain.h:
--------------------------------------------------------------------------------
1 | /* SDLMain.m - main entry point for our Cocoa-ized SDL app
2 | Initial Version: Darrell Walisser
3 | Non-NIB-Code & other changes: Max Horn
4 | Feel free to customize this file to suit your needs
5 | */
6 |
7 | #import
8 |
9 | @interface SDLMain : NSObject
10 | @end
--------------------------------------------------------------------------------
/simulator/SDLMain.m:
--------------------------------------------------------------------------------
1 | /* SDLMain.m - main entry point for our Cocoa-ized SDL app
2 | Initial Version: Darrell Walisser
3 | Non-NIB-Code & other changes: Max Horn
4 | Feel free to customize this file to suit your needs
5 | */
6 |
7 | #import
8 | #import "SDLMain.h"
9 | #import /* for MAXPATHLEN */
10 | #import
11 |
12 | /* For some reaon, Apple removed setAppleMenu from the headers in 10.4,
13 | but the method still is there and works. To avoid warnings, we declare
14 | it ourselves here. */
15 | @interface NSApplication(SDL_Missing_Methods)
16 | - (void)setAppleMenu:(NSMenu *)menu;
17 | @end
18 |
19 | /* Use this flag to determine whether we use SDLMain.nib or not */
20 | #define SDL_USE_NIB_FILE 0
21 |
22 | /* Use this flag to determine whether we use CPS (docking) or not */
23 | #define SDL_USE_CPS 1
24 | #ifdef SDL_USE_CPS
25 | /* Portions of CPS.h */
26 | typedef struct CPSProcessSerNum
27 | {
28 | UInt32 lo;
29 | UInt32 hi;
30 | } CPSProcessSerNum;
31 |
32 | extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn);
33 | extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5);
34 | extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn);
35 |
36 | #endif /* SDL_USE_CPS */
37 |
38 | static int gArgc;
39 | static char **gArgv;
40 | static BOOL gFinderLaunch;
41 | static BOOL gCalledAppMainline = FALSE;
42 |
43 | static NSString *getApplicationName(void)
44 | {
45 | NSDictionary *dict;
46 | NSString *appName = 0;
47 |
48 | /* Determine the application name */
49 | dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle());
50 | if (dict)
51 | appName = [dict objectForKey: @"CFBundleName"];
52 |
53 | if (![appName length])
54 | appName = [[NSProcessInfo processInfo] processName];
55 |
56 | return appName;
57 | }
58 |
59 | #if SDL_USE_NIB_FILE
60 | /* A helper category for NSString */
61 | @interface NSString (ReplaceSubString)
62 | - (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString;
63 | @end
64 | #endif
65 |
66 | @interface SDLApplication : NSApplication
67 | @end
68 |
69 | @implementation SDLApplication
70 | /* Invoked from the Quit menu item */
71 | - (void)terminate:(id)sender
72 | {
73 | /* Post a SDL_QUIT event */
74 | SDL_Event event;
75 | event.type = SDL_QUIT;
76 | SDL_PushEvent(&event);
77 | }
78 | @end
79 |
80 | /* The main class of the application, the application's delegate */
81 | @implementation SDLMain
82 |
83 | /* Set the working directory to the .app's parent directory */
84 | - (void) setupWorkingDirectory:(BOOL)shouldChdir
85 | {
86 | if (shouldChdir)
87 | {
88 | char appdir[MAXPATHLEN];
89 | CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle());
90 | if (CFURLGetFileSystemRepresentation(url, true, (UInt8 *)appdir, MAXPATHLEN)) {
91 | assert ( chdir (appdir) == 0 ); /* chdir to the binary app */
92 | }
93 | CFRelease(url);
94 | }
95 |
96 | }
97 |
98 | #if SDL_USE_NIB_FILE
99 |
100 | /* Fix menu to contain the real app name instead of "SDL App" */
101 | - (void)fixMenu:(NSMenu *)aMenu withAppName:(NSString *)appName
102 | {
103 | NSRange aRange;
104 | NSEnumerator *enumerator;
105 | NSMenuItem *menuItem;
106 |
107 | aRange = [[aMenu title] rangeOfString:@"SDL App"];
108 | if (aRange.length != 0)
109 | [aMenu setTitle: [[aMenu title] stringByReplacingRange:aRange with:appName]];
110 |
111 | enumerator = [[aMenu itemArray] objectEnumerator];
112 | while ((menuItem = [enumerator nextObject]))
113 | {
114 | aRange = [[menuItem title] rangeOfString:@"SDL App"];
115 | if (aRange.length != 0)
116 | [menuItem setTitle: [[menuItem title] stringByReplacingRange:aRange with:appName]];
117 | if ([menuItem hasSubmenu])
118 | [self fixMenu:[menuItem submenu] withAppName:appName];
119 | }
120 | [ aMenu sizeToFit ];
121 | }
122 |
123 | #else
124 |
125 | static void setApplicationMenu(void)
126 | {
127 | /* warning: this code is very odd */
128 | NSMenu *appleMenu;
129 | NSMenuItem *menuItem;
130 | NSString *title;
131 | NSString *appName;
132 |
133 | appName = getApplicationName();
134 | appleMenu = [[NSMenu alloc] initWithTitle:@""];
135 |
136 | /* Add menu items */
137 | title = [@"About " stringByAppendingString:appName];
138 | [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
139 |
140 | [appleMenu addItem:[NSMenuItem separatorItem]];
141 |
142 | title = [@"Hide " stringByAppendingString:appName];
143 | [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
144 |
145 | menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
146 | [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];
147 |
148 | [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
149 |
150 | [appleMenu addItem:[NSMenuItem separatorItem]];
151 |
152 | title = [@"Quit " stringByAppendingString:appName];
153 | [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
154 |
155 |
156 | /* Put menu into the menubar */
157 | menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
158 | [menuItem setSubmenu:appleMenu];
159 | [[NSApp mainMenu] addItem:menuItem];
160 |
161 | /* Tell the application object that this is now the application menu */
162 | [NSApp setAppleMenu:appleMenu];
163 |
164 | /* Finally give up our references to the objects */
165 | [appleMenu release];
166 | [menuItem release];
167 | }
168 |
169 | /* Create a window menu */
170 | static void setupWindowMenu(void)
171 | {
172 | NSMenu *windowMenu;
173 | NSMenuItem *windowMenuItem;
174 | NSMenuItem *menuItem;
175 |
176 | windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];
177 |
178 | /* "Minimize" item */
179 | menuItem = [[NSMenuItem alloc] initWithTitle:@"Minimize" action:@selector(performMiniaturize:) keyEquivalent:@"m"];
180 | [windowMenu addItem:menuItem];
181 | [menuItem release];
182 |
183 | /* Put menu into the menubar */
184 | windowMenuItem = [[NSMenuItem alloc] initWithTitle:@"Window" action:nil keyEquivalent:@""];
185 | [windowMenuItem setSubmenu:windowMenu];
186 | [[NSApp mainMenu] addItem:windowMenuItem];
187 |
188 | /* Tell the application object that this is now the window menu */
189 | [NSApp setWindowsMenu:windowMenu];
190 |
191 | /* Finally give up our references to the objects */
192 | [windowMenu release];
193 | [windowMenuItem release];
194 | }
195 |
196 | /* Replacement for NSApplicationMain */
197 | static void CustomApplicationMain (int argc, char **argv)
198 | {
199 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
200 | SDLMain *sdlMain;
201 |
202 | /* Ensure the application object is initialised */
203 | [SDLApplication sharedApplication];
204 |
205 | #ifdef SDL_USE_CPS
206 | {
207 | CPSProcessSerNum PSN;
208 | /* Tell the dock about us */
209 | if (!CPSGetCurrentProcess(&PSN))
210 | if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103))
211 | if (!CPSSetFrontProcess(&PSN))
212 | [SDLApplication sharedApplication];
213 | }
214 | #endif /* SDL_USE_CPS */
215 |
216 | /* Set up the menubar */
217 | [NSApp setMainMenu:[[NSMenu alloc] init]];
218 | setApplicationMenu();
219 | setupWindowMenu();
220 |
221 | /* Create SDLMain and make it the app delegate */
222 | sdlMain = [[SDLMain alloc] init];
223 | [NSApp setDelegate:sdlMain];
224 |
225 | /* Start the main event loop */
226 | [NSApp run];
227 |
228 | [sdlMain release];
229 | [pool release];
230 | }
231 |
232 | #endif
233 |
234 |
235 | /*
236 | * Catch document open requests...this lets us notice files when the app
237 | * was launched by double-clicking a document, or when a document was
238 | * dragged/dropped on the app's icon. You need to have a
239 | * CFBundleDocumentsType section in your Info.plist to get this message,
240 | * apparently.
241 | *
242 | * Files are added to gArgv, so to the app, they'll look like command line
243 | * arguments. Previously, apps launched from the finder had nothing but
244 | * an argv[0].
245 | *
246 | * This message may be received multiple times to open several docs on launch.
247 | *
248 | * This message is ignored once the app's mainline has been called.
249 | */
250 | - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename
251 | {
252 | const char *temparg;
253 | size_t arglen;
254 | char *arg;
255 | char **newargv;
256 |
257 | if (!gFinderLaunch) /* MacOS is passing command line args. */
258 | return FALSE;
259 |
260 | if (gCalledAppMainline) /* app has started, ignore this document. */
261 | return FALSE;
262 |
263 | temparg = [filename UTF8String];
264 | arglen = SDL_strlen(temparg) + 1;
265 | arg = (char *) SDL_malloc(arglen);
266 | if (arg == NULL)
267 | return FALSE;
268 |
269 | newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2));
270 | if (newargv == NULL)
271 | {
272 | SDL_free(arg);
273 | return FALSE;
274 | }
275 | gArgv = newargv;
276 |
277 | SDL_strlcpy(arg, temparg, arglen);
278 | gArgv[gArgc++] = arg;
279 | gArgv[gArgc] = NULL;
280 | return TRUE;
281 | }
282 |
283 |
284 | /* Called when the internal event loop has just started running */
285 | - (void) applicationDidFinishLaunching: (NSNotification *) note
286 | {
287 | int status;
288 |
289 | /* Set the working directory to the .app's parent directory */
290 | [self setupWorkingDirectory:gFinderLaunch];
291 |
292 | #if SDL_USE_NIB_FILE
293 | /* Set the main menu to contain the real app name instead of "SDL App" */
294 | [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()];
295 | #endif
296 |
297 | /* Hand off to main application code */
298 | gCalledAppMainline = TRUE;
299 | status = SDL_main (gArgc, gArgv);
300 |
301 | /* We're done, thank you for playing */
302 | exit(status);
303 | }
304 | @end
305 |
306 |
307 | @implementation NSString (ReplaceSubString)
308 |
309 | - (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString
310 | {
311 | unsigned int bufferSize;
312 | unsigned int selfLen = [self length];
313 | unsigned int aStringLen = [aString length];
314 | unichar *buffer;
315 | NSRange localRange;
316 | NSString *result;
317 |
318 | bufferSize = selfLen + aStringLen - aRange.length;
319 | buffer = NSAllocateMemoryPages(bufferSize*sizeof(unichar));
320 |
321 | /* Get first part into buffer */
322 | localRange.location = 0;
323 | localRange.length = aRange.location;
324 | [self getCharacters:buffer range:localRange];
325 |
326 | /* Get middle part into buffer */
327 | localRange.location = 0;
328 | localRange.length = aStringLen;
329 | [aString getCharacters:(buffer+aRange.location) range:localRange];
330 |
331 | /* Get last part into buffer */
332 | localRange.location = aRange.location + aRange.length;
333 | localRange.length = selfLen - localRange.location;
334 | [self getCharacters:(buffer+aRange.location+aStringLen) range:localRange];
335 |
336 | /* Build output string */
337 | result = [NSString stringWithCharacters:buffer length:bufferSize];
338 |
339 | NSDeallocateMemoryPages(buffer, bufferSize);
340 |
341 | return result;
342 | }
343 |
344 | @end
345 |
346 |
347 |
348 | #ifdef main
349 | # undef main
350 | #endif
351 |
352 |
353 | /* Main entry point to executable - should *not* be SDL_main! */
354 | int main (int argc, char **argv)
355 | {
356 | /* Copy the arguments into a global variable */
357 | /* This is passed if we are launched by double-clicking */
358 | if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) {
359 | gArgv = (char **) SDL_malloc(sizeof (char *) * 2);
360 | gArgv[0] = argv[0];
361 | gArgv[1] = NULL;
362 | gArgc = 1;
363 | gFinderLaunch = YES;
364 | } else {
365 | int i;
366 | gArgc = argc;
367 | gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1));
368 | for (i = 0; i <= argc; i++)
369 | gArgv[i] = argv[i];
370 | gFinderLaunch = NO;
371 | }
372 |
373 | #if SDL_USE_NIB_FILE
374 | [SDLApplication poseAsClass:[NSApplication class]];
375 | NSApplicationMain (argc, argv);
376 | #else
377 | CustomApplicationMain (argc, argv);
378 | #endif
379 | return 0;
380 | }
--------------------------------------------------------------------------------
/simulator/main.c:
--------------------------------------------------------------------------------
1 | #include "main.h"
2 |
3 | int main(int argc, char *argv[]) {
4 | if (SDL_Init(SDL_INIT_VIDEO) == -1) {
5 | fprintf(stderr, "SDL error : %s\n", SDL_GetError());
6 | exit(EXIT_FAILURE);
7 | }
8 |
9 | SDL_Window *window = NULL;
10 | window = SDL_CreateWindow("Simulator",SDL_WINDOWPOS_UNDEFINED,SDL_WINDOWPOS_UNDEFINED,SCREEN_WIDTH,SCREEN_HEIGHT,SDL_WINDOW_SHOWN);
11 |
12 | SDL_Renderer *renderer = NULL;
13 | renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
14 |
15 | ssd1306_register display_register;
16 | display_register = initDisplayRegister();
17 |
18 | uint8_t buffer_segment = 0;
19 | uint8_t current_byte;
20 |
21 | bool running = true;
22 | bool rerender = true;
23 |
24 | SDL_Event event;
25 |
26 | while (running) {
27 | while (SDL_PollEvent(&event)){
28 | if (event.type == SDL_QUIT){
29 | running = false;
30 | printf("LOG : Closing simulator\n");
31 | }
32 | }
33 |
34 | current_byte = getchar();
35 |
36 | switch (current_byte) {
37 | case 0x00: // Command
38 | current_byte = getchar();
39 |
40 | switch (current_byte) {
41 | case SSD1306_DISPLAYOFF:
42 | printf("LOG : Turning display off\n");
43 | display_register.status = false;
44 | rerender = true;
45 | break;
46 | case SSD1306_DISPLAYON:
47 | printf("LOG : Turning display on\n");
48 | display_register.status = true;
49 | rerender = true;
50 | break;
51 | case SSD1306_NORMALDISPLAY:
52 | printf("LOG : Non-inverted colors\n");
53 | display_register.inverted = false;
54 | rerender = true;
55 | break;
56 | case SSD1306_INVERTDISPLAY:
57 | printf("LOG : Inverted colors\n");
58 | display_register.inverted = true;
59 | rerender = true;
60 | break;
61 | case SSD1306_NOP:
62 | printf("LOG : NOP command received\n");
63 | break;
64 | default:
65 | printf("LOG : Received unknown command : 0x%x\n",current_byte);
66 | break;
67 | }
68 |
69 | break;
70 | case 0x40: // Buffer incomming !
71 | printf("LOG : Receiving buffer segment %d/%d\n",buffer_segment+1,BUFFER_SIZE/16);
72 | for (int i = 0; i < 16; ++i) {
73 | current_byte = getchar();
74 | display_register.buffer[buffer_segment*16+i] = current_byte;
75 | }
76 |
77 | buffer_segment++;
78 | break;
79 | }
80 |
81 | if (buffer_segment == (BUFFER_SIZE/16)) {
82 | buffer_segment = 0;
83 | rerender = true;
84 | }
85 |
86 | if (rerender) {
87 | rerender = false;
88 |
89 | fillScreen(renderer,0);
90 |
91 | if (display_register.status) {
92 | drawBuffer(display_register,renderer,display_register.buffer);
93 | }
94 | }
95 | }
96 |
97 | SDL_DestroyRenderer(renderer);
98 | SDL_DestroyWindow(window);
99 | SDL_Quit();
100 |
101 | return EXIT_SUCCESS;
102 | }
103 |
104 | ssd1306_register initDisplayRegister() {
105 | ssd1306_register display_register;
106 |
107 | // Filling the buffer with zeroes
108 | for (int i = 0; i < BUFFER_SIZE; ++i) {
109 | display_register.buffer[i] = 0x00;
110 | }
111 |
112 | // Display turned off
113 | display_register.status = false;
114 |
115 | // Vertical addressing mode
116 | display_register.addressing_mode = 0x00;
117 |
118 | // Display not inverted
119 | display_register.inverted = false;
120 |
121 | return display_register;
122 | }
123 |
124 | void fillScreen(SDL_Renderer *renderer,int color) {
125 | SDL_Rect blackrect;
126 | blackrect.x = 0;
127 | blackrect.y = 0;
128 | blackrect.w = SCREEN_WIDTH;
129 | blackrect.h = SCREEN_HEIGHT;
130 |
131 | if (color == 0) {
132 | SDL_SetRenderDrawColor(renderer,0x00,0x00,0x00,128);
133 | } else if (color == 1) {
134 | SDL_SetRenderDrawColor(renderer,0xFF,0xFF,0xFF,128);
135 | }
136 |
137 | SDL_RenderFillRect(renderer,&blackrect);
138 | SDL_RenderPresent(renderer);
139 | }
140 |
141 | void drawBuffer(ssd1306_register display_register,SDL_Renderer *renderer,uint8_t *buffer) {
142 | SDL_RenderClear(renderer);
143 |
144 | int x_pos = 0;
145 | int y_byte = 0;
146 |
147 | for (int i = 0; i < BUFFER_SIZE; ++i) {
148 | if (x_pos == SSD1306_WIDTH) {
149 | x_pos = 0;
150 | y_byte++;
151 | }
152 |
153 | // One byte = 8 pixels (vertical)
154 | for (int y = 7; y >= 0; --y) {
155 | if ((buffer[i] >> y) & 0x01 && display_register.status && !display_register.inverted) {
156 | drawPixel(renderer,x_pos,y_byte*8+y);
157 | }
158 | if (!((buffer[i] >> y) & 0x01) && display_register.status && display_register.inverted) {
159 | drawPixel(renderer,x_pos,y_byte*8+y);
160 | }
161 | }
162 |
163 | x_pos++;
164 | }
165 |
166 | SDL_RenderPresent(renderer);
167 | }
168 |
169 | void drawPixel(SDL_Renderer* renderer, int x, int y) {
170 | SDL_Rect pixel;
171 | pixel.x = x;
172 | pixel.y = y;
173 | pixel.w = 1;
174 | pixel.h = 1;
175 |
176 | switch (SCREEN_TYPE) {
177 | case SCREEN_BLUE:
178 | SDL_SetRenderDrawColor(renderer,0x10,0xF0,0xFF,128);
179 | break;
180 | case SCREEN_BLUE_YELLOW:
181 | if (y <= 16) {
182 | SDL_SetRenderDrawColor(renderer,0xFF,0xFD,0x7F,128);
183 | } else if (y > 17) {
184 | SDL_SetRenderDrawColor(renderer,0x10,0xF0,0xFF,128);
185 | } else if (y == 17) {
186 | SDL_SetRenderDrawColor(renderer,0x00,0x00,0x00,128);
187 | }
188 | break;
189 | default:
190 | SDL_SetRenderDrawColor(renderer,0xFF,0xFF,0xFF,128);
191 | break;
192 | }
193 |
194 | SDL_RenderFillRect(renderer,&pixel);
195 | }
--------------------------------------------------------------------------------
/simulator/main.h:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include "../SSD1306.h"
5 |
6 | #define SCREEN_WHITE 0
7 | #define SCREEN_BLUE 1
8 | #define SCREEN_BLUE_YELLOW 2
9 |
10 | #define SCREEN_WIDTH 128
11 | #define SCREEN_HEIGHT 64
12 | #define SCREEN_TYPE SCREEN_BLUE_YELLOW
13 | #define BUFFER_SIZE 1024
14 |
15 | struct ssd1306_register {
16 | // Display buffer
17 | uint8_t buffer[BUFFER_SIZE];
18 |
19 | // True => display on, false => display off
20 | bool status;
21 |
22 | // True => inverted, false => normal
23 | bool inverted;
24 |
25 | // Addressing mode
26 | // 0x00 => Horizontal, 0x01 => Vertical
27 | uint8_t addressing_mode;
28 | };
29 |
30 | ssd1306_register initDisplayRegister();
31 | void fillScreen(SDL_Renderer *renderer,int color);
32 | void drawPixel(SDL_Renderer* renderer, int x, int y);
33 | void drawBuffer(ssd1306_register display_register,SDL_Renderer *renderer,uint8_t *buffer);
34 | int handleExit(void *running, SDL_Event* event);
--------------------------------------------------------------------------------