common: Add the gps module.
[gps-watch.git] / src / common / display.rs
1 /*
2  * Copyright (c) 2019 Tilman Sauerbeck (tilman at code-monkey de)
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23
24 use core::ptr;
25 use screen;
26 use gpio;
27 use i2c;
28
29 pub struct Display {
30     reset_gpio: u32,
31     reset_gpio_pin: u32,
32     i2c_slave_address: u8,
33 }
34
35 fn delay(u: u32) {
36     let mut r = u;
37
38     unsafe {
39         loop {
40             let x = ptr::read_volatile(&r);
41             ptr::write_volatile(&mut r, x - 1);
42
43             if x == 0 {
44                 break
45             }
46
47             let mut a = 0;
48
49             loop {
50                 let x = ptr::read_volatile(&a);
51                 ptr::write_volatile(&mut a, x + 1);
52
53                 if x == 5000 {
54                     break
55                 }
56             }
57         }
58     }
59 }
60
61 fn delay2(u: u32) {
62     let mut r = u;
63
64     unsafe {
65         loop {
66             let x = ptr::read_volatile(&r);
67             ptr::write_volatile(&mut r, x - 1);
68
69             if x == 0 {
70                 break
71             }
72         }
73     }
74 }
75
76 impl Display {
77     pub fn new(reset_gpio: u32, reset_gpio_pin: u32, i2c_slave_address: u8) -> Display {
78         Display {
79             reset_gpio: reset_gpio,
80             reset_gpio_pin: reset_gpio_pin,
81             i2c_slave_address: i2c_slave_address,
82         }
83     }
84
85     pub fn init(&mut self) {
86         let init_sequence : [u8; 18] = [
87             0x3a,
88             0x88,
89             0x88,
90             0x88,
91             0x88,
92             0x60,
93             0xe3,
94             0x2f,
95             0x30,
96             0x96,
97             0xa4,
98             0xb1,
99             0x53,
100             0xb2,
101             0x78,
102             0x01,
103             0x60,
104             0x3d,
105         ];
106
107         gpio::clear(self.reset_gpio, self.reset_gpio_pin);
108         delay(100);
109         gpio::set(self.reset_gpio, self.reset_gpio_pin);
110         delay(100);
111
112         for &b in init_sequence.iter() {
113             self.write_command(b);
114         }
115     }
116
117     pub fn clear(&mut self) {
118         self.seek(0, 0);
119
120         for _ in 0..(32 * 128) {
121             self.write_data(0x00);
122         }
123     }
124
125     pub fn draw(&mut self, screen: &screen::Screen) {
126         let mut mask : u8 = 0x80;
127
128         for col in 0..screen::WIDTH_PX {
129             mask = mask.rotate_left(1);
130
131             // Rotate by 90 degrees.
132             //
133             // Also skip special columns 0..8 which we don't consider
134             // to be part of the screen (they hold the icon area).
135             self.seek(screen::WIDTH_PX - 1 - col, 9);
136
137             // We'll draw eight pixels at once.
138             for row in 0..(screen::HEIGHT_PX / 8) {
139                 let mut combined = 0;
140
141                 for sub in 0..8 {
142                     let index = ((row as usize * 8) + sub) * screen::WIDTH_BYTES
143                               + (col as usize / 8);
144                     let pixel = screen.pixel(index);
145
146                     combined <<= 1;
147
148                     if (pixel & mask) != 0 {
149                         combined |= 1;
150                     }
151                 }
152
153                 self.write_data(combined);
154             }
155         }
156     }
157
158     fn write_command(&self, c: u8) {
159         i2c::tx16(i2c::I2C0, self.i2c_slave_address, 0x80 | ((c as u16) << 8));
160         delay2(50);
161     }
162
163     fn write_data(&self, d: u8) {
164         i2c::tx16(i2c::I2C0, self.i2c_slave_address, 0xc0 | ((d as u16) << 8));
165         delay2(50);
166     }
167
168     fn seek(&self, row: usize, col: usize) {
169         self.write_command(0x00 | ((row >> 0) & 0x0f) as u8);
170         self.write_command(0x10 | ((row >> 4) & 0x07) as u8);
171         self.write_command(0xc0 | ((col >> 0) & 0x1f) as u8);
172     }
173 }