pep8analysis: intro a variant main program for a web interface
[nit.git] / lib / bcm2835.nit
index 9de90ff..aac7352 100644 (file)
@@ -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