├── .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 | ![The simulator in action](img/simulator1.png) 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); --------------------------------------------------------------------------------