1 /*
2  * Author: Yevgeniy Kiveisha <yevgeniy.kiveisha@intel.com>
3  * Copyright (c) 2014 Intel Corporation.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining
6  * a copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sublicense, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24 
25 #include <stdexcept>
26 #include <string>
27 #include <unistd.h>
28 
29 #include "hd44780_bits.h"
30 #include "ssd1308.h"
31 
32 using namespace upm;
33 
SSD1308(int bus_in,int addr_in)34 SSD1308::SSD1308(int bus_in, int addr_in) : m_i2c_lcd_control(bus_in)
35 {
36     m_lcd_control_address = addr_in;
37     m_name = "SSD1308";
38 
39     mraa::Result error = m_i2c_lcd_control.address(m_lcd_control_address);
40     if (error != mraa::SUCCESS) {
41         throw std::invalid_argument(std::string(__FUNCTION__) +
42                                     ": I2c.address() failed");
43         return;
44     }
45 
46     m_i2c_lcd_control.writeReg(LCD_CMD, DISPLAY_CMD_OFF); // display off
47     usleep(4500);
48     m_i2c_lcd_control.writeReg(LCD_CMD, DISPLAY_CMD_ON); // display on
49     usleep(4500);
50     setNormalDisplay(); // set to normal display '1' is ON
51 
52     clear();
53     setAddressingMode(PAGE);
54 }
55 
~SSD1308()56 SSD1308::~SSD1308()
57 {
58 }
59 
60 mraa::Result
draw(uint8_t * data,int bytes)61 SSD1308::draw(uint8_t* data, int bytes)
62 {
63     mraa::Result error = mraa::SUCCESS;
64 
65     setAddressingMode(HORIZONTAL);
66     for (int idx = 0; idx < bytes; idx++) {
67         m_i2c_lcd_control.writeReg(LCD_DATA, data[idx]);
68     }
69 
70     return error;
71 }
72 
73 /*
74  * **************
75  *  virtual area
76  * **************
77  */
78 mraa::Result
write(std::string msg)79 SSD1308::write(std::string msg)
80 {
81     mraa::Result error = mraa::SUCCESS;
82     uint8_t data[2] = { 0x40, 0 };
83 
84     setAddressingMode(PAGE);
85     for (std::string::size_type i = 0; i < msg.size(); ++i) {
86         writeChar(msg[i]);
87     }
88 
89     return error;
90 }
91 
92 mraa::Result
setCursor(int row,int column)93 SSD1308::setCursor(int row, int column)
94 {
95     mraa::Result error = mraa::SUCCESS;
96 
97     error = m_i2c_lcd_control.writeReg(LCD_CMD, BASE_PAGE_START_ADDR + row); // set page address
98     error = m_i2c_lcd_control.writeReg(LCD_CMD,
99                                        BASE_LOW_COLUMN_ADDR + (8 * column & 0x0F)); // set column
100                                                                                     // lower address
101     error = m_i2c_lcd_control.writeReg(LCD_CMD,
102                                        BASE_HIGH_COLUMN_ADDR +
103                                        ((8 * column >> 4) & 0x0F)); // set column higher address
104 
105     return error;
106 }
107 
108 mraa::Result
clear()109 SSD1308::clear()
110 {
111     mraa::Result error = mraa::SUCCESS;
112     uint8_t columnIdx, rowIdx;
113 
114     m_i2c_lcd_control.writeReg(LCD_CMD, DISPLAY_CMD_OFF); // display off
115     for (rowIdx = 0; rowIdx < 8; rowIdx++) {
116         setCursor(rowIdx, 0);
117 
118         // clear all columns
119         for (columnIdx = 0; columnIdx < 16; columnIdx++) {
120             writeChar(' ');
121         }
122     }
123     m_i2c_lcd_control.writeReg(LCD_CMD, DISPLAY_CMD_ON); // display on
124     home();
125 
126     return mraa::SUCCESS;
127 }
128 
129 mraa::Result
home()130 SSD1308::home()
131 {
132     return setCursor(0, 0);
133 }
134 
135 /*
136  * **************
137  *  private area
138  * **************
139  */
140 mraa::Result
writeChar(uint8_t value)141 SSD1308::writeChar(uint8_t value)
142 {
143     mraa::Result rv;
144     if (value < 0x20 || value > 0x7F) {
145         value = 0x20; // space
146     }
147 
148     for (uint8_t idx = 0; idx < 8; idx++) {
149         rv = m_i2c_lcd_control.writeReg(LCD_DATA, BasicFont[value - 32][idx]);
150     }
151 
152     return rv;
153 }
154 
155 mraa::Result
setNormalDisplay()156 SSD1308::setNormalDisplay()
157 {
158     return m_i2c_lcd_control.writeReg(LCD_CMD,
159                                       DISPLAY_CMD_SET_NORMAL_1308); // set to normal display '1' is
160                                                                     // ON
161 }
162 
163 mraa::Result
setAddressingMode(displayAddressingMode mode)164 SSD1308::setAddressingMode(displayAddressingMode mode)
165 {
166     mraa::Result rv;
167     rv =m_i2c_lcd_control.writeReg(LCD_CMD, DISPLAY_CMD_MEM_ADDR_MODE); // set addressing mode
168     rv =m_i2c_lcd_control.writeReg(LCD_CMD, mode);                      // set page addressing mode
169     return rv;
170 }
171