lib/standard/: Removed bin_and/or/xor/not from math
[nit.git] / lib / bcm2835 / bcm2835.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2013 Alexis Laferrière <alexis.laf@xymus.net>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # Services to control the bcm2835 chipset as used in the Raspberry Pi
18 # model B revision 1 Uses the C library by Mike McCauley from
19 # http://www.airspayce.com/mikem/bcm2835/
20 module bcm2835
21
22 import gpio
23
24 in "C Header" `{
25 #include <bcm2835.h>
26 `}
27
28 redef class Object
29 protected fun bcm2835_init: Bool `{ return bcm2835_init(); `}
30 protected fun bcm2835_close `{ bcm2835_close(); `}
31 protected fun bcm2835_debug=(v: Bool) `{ bcm2835_set_debug(v); `}
32 end
33
34 extern class RPiPin `{ RPiGPIOPin `}
35 super Pin
36
37 new p1_03 `{ return RPI_GPIO_P1_03; `}
38
39 new p1_05 `{ return RPI_GPIO_P1_05; `}
40 new p1_07 `{ return RPI_GPIO_P1_07; `}
41
42 new p1_11 `{ return RPI_GPIO_P1_11; `}
43 new p1_12 `{ return RPI_GPIO_P1_12; `}
44 new p1_13 `{ return RPI_GPIO_P1_13; `}
45
46 new p1_15 `{ return RPI_GPIO_P1_15; `}
47 new p1_16 `{ return RPI_GPIO_P1_16; `}
48
49 new p1_18 `{ return RPI_GPIO_P1_18; `}
50 new p1_19 `{ return RPI_GPIO_P1_19; `}
51
52 new p1_21 `{ return RPI_GPIO_P1_21; `}
53 new p1_22 `{ return RPI_GPIO_P1_22; `}
54 new p1_23 `{ return RPI_GPIO_P1_23; `}
55 new p1_24 `{ return RPI_GPIO_P1_24; `}
56
57 new p1_26 `{ return RPI_GPIO_P1_26; `}
58
59 # Select mode: input, output or alts
60 fun fsel=(mode: FunctionSelect) `{ bcm2835_gpio_fsel(self, mode); `}
61
62 # Set output
63 redef fun write(high) `{ bcm2835_gpio_write(self, high? HIGH: LOW); `}
64
65 # Set pull up mode
66 fun pud=(pud: PUDControl) `{ bcm2835_gpio_set_pud(self, pud); `}
67
68 # Falling edge detect
69 # Do not use on raspbian, it is bugged!
70 fun fen `{ bcm2835_gpio_fen(self); `}
71 fun clr_fen `{ bcm2835_gpio_clr_fen(self); `}
72
73 # Raising edge detect
74 # Do not use on raspbian, it is bugged!
75 fun ren `{ bcm2835_gpio_ren(self); `}
76 fun clr_ren `{ bcm2835_gpio_clr_ren(self); `}
77
78 # High edge detect
79 # Do not use on raspbian, it is bugged!
80 fun hen `{ bcm2835_gpio_hen(self); `}
81 fun clr_hen `{ bcm2835_gpio_clr_hen(self); `}
82
83 # Low edge detect
84 # Do not use on raspbian, it is bugged!
85 fun len `{ bcm2835_gpio_len(self); `}
86 fun clr_len `{ bcm2835_gpio_clr_len(self); `}
87
88 fun set_eds `{ bcm2835_gpio_set_eds(self); `}
89 fun eds: Bool `{ return bcm2835_gpio_eds(self); `}
90
91 # Return input on pin, true for high and false for low
92 fun lev: Bool `{ return bcm2835_gpio_lev(self); `}
93 end
94
95 extern class FunctionSelect `{ bcm2835FunctionSelect `}
96 # Input function
97 new inpt `{ return BCM2835_GPIO_FSEL_INPT; `}
98
99 # Output function
100 new outp `{ return BCM2835_GPIO_FSEL_OUTP; `}
101
102 new alt0 `{ return BCM2835_GPIO_FSEL_ALT0; `}
103 new alt1 `{ return BCM2835_GPIO_FSEL_ALT1; `}
104 new alt2 `{ return BCM2835_GPIO_FSEL_ALT2; `}
105 new alt3 `{ return BCM2835_GPIO_FSEL_ALT3; `}
106 new alt4 `{ return BCM2835_GPIO_FSEL_ALT4; `}
107 new alt5 `{ return BCM2835_GPIO_FSEL_ALT5; `}
108 new mask `{ return BCM2835_GPIO_FSEL_MASK; `}
109 end
110
111 extern class PUDControl `{ bcm2835PUDControl `}
112 new off `{ return BCM2835_GPIO_PUD_OFF; `}
113 new down `{ return BCM2835_GPIO_PUD_DOWN; `}
114 new up `{ return BCM2835_GPIO_PUD_UP; `}
115 end
116
117 redef universal Int
118 fun bcm2835_delay `{ bcm2835_delay(self); `}
119 fun bcm2835_delay_micros `{ bcm2835_delayMicroseconds(self); `}
120 end
121
122 class RotaryEncoder
123 var pin_a: RPiPin
124 var pin_b: RPiPin
125 var old_a= false
126 var old_b= false
127
128 # returns '<', '>' or null accoring to rotation or lack thereof
129 fun update: nullable Char
130 do
131 var new_a = pin_a.lev
132 var new_b = pin_b.lev
133 var res = null
134
135 if new_a != old_a or new_b != old_b then
136 if not old_a and not old_b then
137 # everything was on
138 if not new_a and new_b then
139 res = '<'
140 else if new_a and not new_b then
141 res = '>'
142 end
143 else if old_a and old_b then
144 # everything was off
145 if not new_a and new_b then
146 res = '>'
147 else if new_a and not new_b then
148 res = '<'
149 end
150 end
151
152 old_a = new_a
153 old_b = new_b
154 end
155
156 return res
157 end
158 end
159
160 # Hitachi HD44780 or similar 2-4 lines LCD displays
161 class HD44780
162 var rs: RPiPin
163 var en: RPiPin
164 var d4: RPiPin
165 var d5: RPiPin
166 var d6: RPiPin
167 var d7: RPiPin
168
169 var ds = new Array[RPiPin]
170
171 # commands
172 fun flag_clear_display: Int do return 1
173 fun flag_return_home: Int do return 2
174 fun flag_entry_mode_set: Int do return 4
175 fun flag_display_control: Int do return 8
176 fun flag_cursor_shift: Int do return 16
177 fun flag_function_set: Int do return 32
178 fun flag_set_cgram_addr: Int do return 64
179 fun flag_set_ggram_addr: Int do return 128
180
181 # entry mode
182 fun flag_entry_right: Int do return 0
183 fun flag_entry_left: Int do return 2
184 fun flag_entry_shift_increment: Int do return 1
185 fun flag_entry_shift_decrement: Int do return 0
186
187 # display flags
188 fun flag_display_on: Int do return 4
189 fun flag_display_off: Int do return 0
190 fun flag_cursor_on: Int do return 2
191 fun flag_cursor_off: Int do return 0
192 fun flag_blink_on: Int do return 1
193 fun flag_blink_off: Int do return 0
194
195 # display/cursor shift
196 fun flag_display_move: Int do return 8
197 fun flag_cursor_move: Int do return 0
198 fun flag_move_right: Int do return 4
199 fun flag_move_left: Int do return 0
200
201 # function set
202 fun flag_8bit_mode: Int do return 16
203 fun flag_4bit_mode: Int do return 0
204 fun flag_2_lines: Int do return 8
205 fun flag_1_line: Int do return 0
206 fun flag_5x10_dots: Int do return 4
207 fun flag_5x8_dots: Int do return 0
208
209 # last text displayed
210 private var last_text: nullable String = null
211
212 fun function_set(bits, lines, dots_wide: Int)
213 do
214 var fs = flag_function_set
215 if bits == 8 then
216 fs = fs | 16
217 else if bits != 4 then abort
218
219 if lines == 2 then
220 fs = fs | 8
221 else if lines != 1 then abort
222
223 if dots_wide == 10 then
224 fs = fs | 4
225 else if dots_wide != 8 then abort
226
227 write(true, fs)
228 end
229
230 fun display_control(on, cursor, blink: Bool)
231 do
232 var fs = flag_display_control
233
234 fs |= if on then flag_display_on else flag_display_off
235
236 fs |= if cursor then flag_cursor_on else flag_cursor_off
237
238 fs |= if blink then flag_blink_on else flag_blink_off
239
240 write(true, fs)
241 end
242
243 fun entry_mode(left, incr: Bool)
244 do
245 var fs = flag_entry_mode_set
246
247 fs |= if left then flag_entry_left else flag_entry_right
248
249 fs |= if incr then flag_entry_shift_increment else flag_entry_shift_decrement
250
251 write(true, fs)
252 end
253
254 fun setup_alt
255 do
256 ds = [d4,d5,d6,d7]
257
258 rs.fsel = new FunctionSelect.outp
259 en.fsel = new FunctionSelect.outp
260 d4.fsel = new FunctionSelect.outp
261 d5.fsel = new FunctionSelect.outp
262 d6.fsel = new FunctionSelect.outp
263 d7.fsel = new FunctionSelect.outp
264
265 rs.write(false)
266 en.write(false)
267
268 # wait 20ms for power up
269 50.bcm2835_delay
270
271 write_4bits(true,true,false,false)
272 write_4_bits(3)
273
274 5.bcm2835_delay
275
276 write_4bits(true,true,false,false)
277 write_4_bits(3)
278
279 5.bcm2835_delay
280
281 write_4bits(true,true,false,false)
282 write_4_bits(3)
283
284 200.bcm2835_delay_micros
285
286 write_4bits(false,true,false,false)
287 write_4_bits(2)
288
289 # wait 5ms
290 5.bcm2835_delay
291
292 # set interface
293 # 4bits, 2 lines
294 function_set(4, 2, 8)
295
296 # cursor
297 # don't shift & hide
298 display_control(true, true, true)
299
300 # clear & home
301 clear
302
303 # set cursor move direction
304 # move right
305 write(true, 6)
306
307 # turn on display
308 write(true, 4)
309
310 # set entry mode
311 entry_mode(true, true)
312 end
313
314 fun setup
315 do
316 ds = [d4,d5,d6,d7]
317
318 rs.fsel = new FunctionSelect.outp
319 en.fsel = new FunctionSelect.outp
320 d4.fsel = new FunctionSelect.outp
321 d5.fsel = new FunctionSelect.outp
322 d6.fsel = new FunctionSelect.outp
323 d7.fsel = new FunctionSelect.outp
324
325 rs.write(false)
326 en.write(false)
327
328 write(true, "33".to_hex) # init
329 write(true, "32".to_hex) # init
330 write(true, "28".to_hex) # 2 lines, 5x7
331 write(true, "0C".to_hex) # hide cursor
332 write(true, "06".to_hex) # cursor move right
333 write(true, "04".to_hex) # turn on display
334 write(true, "01".to_hex) # clear display
335 end
336
337 fun write_4_bits(v: Int)
338 do
339 var lb = once [1,2,4,8]
340 for i in [0..4[ do
341 var b = lb[i]
342 var r = b & v != 0
343 var d = ds[i]
344 d.write(r)
345 end
346 pulse_enable
347 end
348
349 fun write_4bits(a,b,c,d:Bool)
350 do
351 d4.write(a)
352 d5.write(b)
353 d6.write(c)
354 d7.write(d)
355 pulse_enable
356 end
357
358 fun pulse_enable
359 do
360 en.write(false)
361 1.bcm2835_delay_micros
362 en.write(true)
363 100.bcm2835_delay_micros
364 en.write(false)
365 1.bcm2835_delay_micros
366 end
367
368 fun write(is_cmd: Bool, cmd: Int)
369 do
370 en.write(false)
371 rs.write(not is_cmd)
372
373 # high byte
374 var hb = once [16,32,64,128]
375 for i in [0..4[ do
376 var b = hb[i]
377 var r = b & cmd != 0
378 var d = ds[i]
379 d.write(r)
380 end
381
382 pulse_enable
383
384 if is_cmd then
385 # wait 5ms
386 5.bcm2835_delay
387 else
388 # wait 200us
389 200.bcm2835_delay_micros
390 end
391
392 # low byte
393 var lb = once [1,2,4,8]
394 for i in [0..4[ do
395 var b = lb[i]
396 var r = b & cmd != 0
397 var d = ds[i]
398 d.write(r)
399 end
400
401 pulse_enable
402
403 if is_cmd then
404 # wait 5ms
405 5.bcm2835_delay
406 else
407 # wait 200us
408 200.bcm2835_delay_micros
409 end
410 end
411
412 fun clear
413 do
414 write(true,1)
415 2.bcm2835_delay
416 end
417
418 fun return_home
419 do
420 write(true,2)
421 2.bcm2835_delay
422 end
423
424 fun text=(v: String)
425 do
426 # do not redraw the samething
427 var last_text = last_text
428 if last_text != null and last_text == v then return
429
430 clear
431 return_home
432 var count = 0
433 for c in v.chars do
434 if c == '\n' then
435 # FIXME, this should work
436 #write(true, "C0".to_hex)
437 # instead we use the following which may not be portable
438
439 for s in [count..40[ do write(false, ' '.ascii)
440 count = 0
441 else
442 write(false, c.ascii)
443 count += 1
444 end
445 end
446
447 self.last_text = v
448 end
449 end
450
451 # Component for any kind of buttons or switches
452 class Switch
453 var pin: RPiPin
454
455 init (pin: RPiPin, pud: PUDControl)
456 do
457 self.pin = pin
458 pin.fsel = new FunctionSelect.inpt
459 pin.pud = pud
460 end
461
462 fun is_down: Bool do return pin.lev
463
464 var last_down: nullable Bool = null
465
466 # Returns true is state (is_down) changed since last call to `changed`
467 fun changed: Bool
468 do
469 var now = is_down
470 var last_down = last_down
471 if last_down == null then
472 self.last_down = now
473 return false
474 else if last_down != now then
475 self.last_down = now
476 return true
477 else return false
478 end
479 end
480
481 class StepperMotor
482 var pins: Sequence[RPiPin]
483 var delay: Int
484
485 init (delay: Int, a, b, c, d: RPiPin)
486 do
487 pins = [a, b, c, d]
488 self.delay = delay
489
490 for p in pins do p.fsel = new FunctionSelect.outp
491 end
492
493 fun forward(steps: Int)
494 do
495 for s in [0..steps[ do
496 set(true, false, false, false)
497 delay.bcm2835_delay
498 set(true, true, false, false)
499 delay.bcm2835_delay
500 set(false, true, false, false)
501 delay.bcm2835_delay
502 set(false, true, true, false)
503 delay.bcm2835_delay
504 set(false, false, true, false)
505 delay.bcm2835_delay
506 set(false, false, true, true)
507 delay.bcm2835_delay
508 set(false, false, false, true)
509 delay.bcm2835_delay
510 set(true, false, false, true)
511 delay.bcm2835_delay
512 end
513 end
514
515 fun backwards(steps: Int)
516 do
517 for s in [0..steps[ do
518 set(true, false, false, true)
519 delay.bcm2835_delay
520 set(false, false, false, true)
521 delay.bcm2835_delay
522 set(false, false, true, true)
523 delay.bcm2835_delay
524 set(false, false, true, false)
525 delay.bcm2835_delay
526 set(false, true, true, false)
527 delay.bcm2835_delay
528 set(false, true, false, false)
529 delay.bcm2835_delay
530 set(true, true, false, false)
531 delay.bcm2835_delay
532 set(true, false, false, false)
533 delay.bcm2835_delay
534 end
535 end
536
537 fun release do set(false, false, false, false)
538
539 protected fun set(a, b, c, d: Bool)
540 do
541 var bits = new Array[Bool].with_items(a, b, c, d)
542
543 for i in [0..4[ do pins[i].write(bits[i])
544 end
545 end
546
547 class Buzzer
548 var pin: RPiPin
549
550 fun buzz(delay: Float, times: Int)
551 do
552 assert times > 0
553 assert delay > 0.0
554 var delay_i = (delay*1000.0).to_i
555 for i in [0..times[ do
556 pin.write(true)
557 delay_i.bcm2835_delay_micros
558 pin.write(false)
559 delay_i.bcm2835_delay_micros
560 end
561 end
562 end