X-Git-Url: http://nitlanguage.org diff --git a/lib/bcm2835.nit b/lib/bcm2835.nit index 9de90ff..aac7352 100644 --- a/lib/bcm2835.nit +++ b/lib/bcm2835.nit @@ -118,3 +118,455 @@ redef universal Int fun bcm2835_delay `{ bcm2835_delay(recv); `} fun bcm2835_delay_micros `{ bcm2835_delayMicroseconds(recv); `} end + +class RotaryEncoder + var pin_a: RPiPin + var pin_b: RPiPin + var old_a= false + var old_b= false + + # returns '<', '>' or null accoring to rotation or lack thereof + fun update: nullable Char + do + var new_a = pin_a.lev + var new_b = pin_b.lev + var res = null + + if new_a != old_a or new_b != old_b then + if not old_a and not old_b then + # everything was on + if not new_a and new_b then + res = '<' + else if new_a and not new_b then + res = '>' + end + else if old_a and old_b then + # everything was off + if not new_a and new_b then + res = '>' + else if new_a and not new_b then + res = '<' + end + end + + old_a = new_a + old_b = new_b + end + + return res + end +end + +# Hitachi HD44780 or similar 2-4 lines LCD displays +class HD44780 + var rs: RPiPin + var en: RPiPin + var d4: RPiPin + var d5: RPiPin + var d6: RPiPin + var d7: RPiPin + + var ds = new Array[RPiPin] + + # commands + fun flag_clear_display: Int do return 1 + fun flag_return_home: Int do return 2 + fun flag_entry_mode_set: Int do return 4 + fun flag_display_control: Int do return 8 + fun flag_cursor_shift: Int do return 16 + fun flag_function_set: Int do return 32 + fun flag_set_cgram_addr: Int do return 64 + fun flag_set_ggram_addr: Int do return 128 + + # entry mode + fun flag_entry_right: Int do return 0 + fun flag_entry_left: Int do return 2 + fun flag_entry_shift_increment: Int do return 1 + fun flag_entry_shift_decrement: Int do return 0 + + # display flags + fun flag_display_on: Int do return 4 + fun flag_display_off: Int do return 0 + fun flag_cursor_on: Int do return 2 + fun flag_cursor_off: Int do return 0 + fun flag_blink_on: Int do return 1 + fun flag_blink_off: Int do return 0 + + # display/cursor shift + fun flag_display_move: Int do return 8 + fun flag_cursor_move: Int do return 0 + fun flag_move_right: Int do return 4 + fun flag_move_left: Int do return 0 + + # function set + fun flag_8bit_mode: Int do return 16 + fun flag_4bit_mode: Int do return 0 + fun flag_2_lines: Int do return 8 + fun flag_1_line: Int do return 0 + fun flag_5x10_dots: Int do return 4 + fun flag_5x8_dots: Int do return 0 + + # last text displayed + private var last_text: nullable String = null + + fun function_set(bits, lines, dots_wide: Int) + do + var fs = flag_function_set + if bits == 8 then + fs = fs.bin_or(16) + else if bits != 4 then abort + + if lines == 2 then + fs = fs.bin_or(8) + else if lines != 1 then abort + + if dots_wide == 10 then + fs = fs.bin_or(4) + else if dots_wide != 8 then abort + + write(true, fs) + end + + fun display_control(on, cursor, blink: Bool) + do + var fs = flag_display_control + + if on then + fs = fs.bin_or(flag_display_on) + else fs = fs.bin_or(flag_display_off) + + if cursor then + fs = fs.bin_or(flag_cursor_on) + else fs = fs.bin_or(flag_cursor_off) + + if blink then + fs = fs.bin_or(flag_blink_on) + else fs = fs.bin_or(flag_blink_off) + + write(true, fs) + end + + fun entry_mode(left, incr: Bool) + do + var fs = flag_entry_mode_set + + if left then + fs = fs.bin_or(flag_entry_left) + else fs = fs.bin_or(flag_entry_right) + + if incr then + fs = fs.bin_or(flag_entry_shift_increment) + else fs = fs.bin_or(flag_entry_shift_decrement) + + write(true, fs) + end + + fun setup_alt + do + ds = [d4,d5,d6,d7] + + rs.fsel = new FunctionSelect.outp + en.fsel = new FunctionSelect.outp + d4.fsel = new FunctionSelect.outp + d5.fsel = new FunctionSelect.outp + d6.fsel = new FunctionSelect.outp + d7.fsel = new FunctionSelect.outp + + rs.write(false) + en.write(false) + + # wait 20ms for power up + 50.bcm2835_delay + + write_4bits(true,true,false,false) + write_4_bits(3) + + 5.bcm2835_delay + + write_4bits(true,true,false,false) + write_4_bits(3) + + 5.bcm2835_delay + + write_4bits(true,true,false,false) + write_4_bits(3) + + 200.bcm2835_delay_micros + + write_4bits(false,true,false,false) + write_4_bits(2) + + # wait 5ms + 5.bcm2835_delay + + # set interface + # 4bits, 2 lines + function_set(4, 2, 8) + + # cursor + # don't shift & hide + display_control(true, true, true) + + # clear & home + clear + + # set cursor move direction + # move right + write(true, 6) + + # turn on display + write(true, 4) + + # set entry mode + entry_mode(true, true) + end + + fun setup + do + ds = [d4,d5,d6,d7] + + rs.fsel = new FunctionSelect.outp + en.fsel = new FunctionSelect.outp + d4.fsel = new FunctionSelect.outp + d5.fsel = new FunctionSelect.outp + d6.fsel = new FunctionSelect.outp + d7.fsel = new FunctionSelect.outp + + rs.write(false) + en.write(false) + + write(true, "33".to_hex) # init + write(true, "32".to_hex) # init + write(true, "28".to_hex) # 2 lines, 5x7 + write(true, "0C".to_hex) # hide cursor + write(true, "06".to_hex) # cursor move right + write(true, "04".to_hex) # turn on display + write(true, "01".to_hex) # clear display + end + + fun write_4_bits(v: Int) + do + var lb = once [1,2,4,8] + for i in [0..4[ do + var b = lb[i] + var r = b.bin_and(v) != 0 + var d = ds[i] + d.write(r) + end + pulse_enable + end + + fun write_4bits(a,b,c,d:Bool) + do + d4.write(a) + d5.write(b) + d6.write(c) + d7.write(d) + pulse_enable + end + + fun pulse_enable + do + en.write(false) + 1.bcm2835_delay_micros + en.write(true) + 100.bcm2835_delay_micros + en.write(false) + 1.bcm2835_delay_micros + end + + fun write(is_cmd: Bool, cmd: Int) + do + en.write(false) + rs.write(not is_cmd) + + # high byte + var hb = once [16,32,64,128] + for i in [0..4[ do + var b = hb[i] + var r = b.bin_and(cmd) != 0 + var d = ds[i] + d.write(r) + end + + pulse_enable + + if is_cmd then + # wait 5ms + 5.bcm2835_delay + else + # wait 200us + 200.bcm2835_delay_micros + end + + # low byte + var lb = once [1,2,4,8] + for i in [0..4[ do + var b = lb[i] + var r = b.bin_and(cmd) != 0 + var d = ds[i] + d.write(r) + end + + pulse_enable + + if is_cmd then + # wait 5ms + 5.bcm2835_delay + else + # wait 200us + 200.bcm2835_delay_micros + end + end + + fun clear + do + write(true,1) + 2.bcm2835_delay + end + + fun return_home + do + write(true,2) + 2.bcm2835_delay + end + + fun text=(v: String) + do + # do not redraw the samething + var last_text = last_text + if last_text != null and last_text == v then return + + clear + return_home + var count = 0 + for c in v.chars do + if c == '\n' then + # FIXME, this should work + #write(true, "C0".to_hex) + # instead we use the following which may not be portable + + for s in [count..40[ do write(false, ' '.ascii) + count = 0 + else + write(false, c.ascii) + count += 1 + end + end + + self.last_text = v + end +end + +# Component for any kind of buttons or switches +class Switch + var pin: RPiPin + + init (pin: RPiPin, pud: PUDControl) + do + self.pin = pin + pin.fsel = new FunctionSelect.inpt + pin.pud = pud + end + + fun is_down: Bool do return pin.lev + + var last_down: nullable Bool = null + + # Returns true is state (is_down) changed since last call to `changed` + fun changed: Bool + do + var now = is_down + var last_down = last_down + if last_down == null then + self.last_down = now + return false + else if last_down != now then + self.last_down = now + return true + else return false + end +end + +class StepperMotor + var pins: Sequence[RPiPin] + var delay: Int + + init (delay: Int, a, b, c, d: RPiPin) + do + pins = [a, b, c, d] + self.delay = delay + + for p in pins do p.fsel = new FunctionSelect.outp + end + + fun forward(steps: Int) + do + for s in [0..steps[ do + set(true, false, false, false) + delay.bcm2835_delay + set(true, true, false, false) + delay.bcm2835_delay + set(false, true, false, false) + delay.bcm2835_delay + set(false, true, true, false) + delay.bcm2835_delay + set(false, false, true, false) + delay.bcm2835_delay + set(false, false, true, true) + delay.bcm2835_delay + set(false, false, false, true) + delay.bcm2835_delay + set(true, false, false, true) + delay.bcm2835_delay + end + end + + fun backwards(steps: Int) + do + for s in [0..steps[ do + set(true, false, false, true) + delay.bcm2835_delay + set(false, false, false, true) + delay.bcm2835_delay + set(false, false, true, true) + delay.bcm2835_delay + set(false, false, true, false) + delay.bcm2835_delay + set(false, true, true, false) + delay.bcm2835_delay + set(false, true, false, false) + delay.bcm2835_delay + set(true, true, false, false) + delay.bcm2835_delay + set(true, false, false, false) + delay.bcm2835_delay + end + end + + fun release do set(false, false, false, false) + + protected fun set(a, b, c, d: Bool) + do + var bits = new Array[Bool].with_items(a, b, c, d) + + for i in [0..4[ do pins[i].write(bits[i]) + end +end + +class Buzzer + var pin: RPiPin + + fun buzz(delay: Float, times: Int) + do + assert times > 0 + assert delay > 0.0 + var delay_i = (delay*1000.0).to_i + for i in [0..times[ do + pin.write(true) + delay_i.bcm2835_delay_micros + pin.write(false) + delay_i.bcm2835_delay_micros + end + end +end