1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2013 Alexis Laferrière <alexis.laf@xymus.net>
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
9 # http://www.apache.org/licenses/LICENSE-2.0
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.
17 # This programs interprets the input of a physical interface thought the
18 # GPIO pins of a Raspberry Pi to control an MPD server.
20 # It suppot two inputs: a play/pause button and a rotary encoder to adjust
23 # The each data output of the volume control are connected to the board
25 module physical_interface_for_mpd_on_rpi
32 fun mpd
: MPDConnection do return once
new MPDConnection("localhost", 6600, "password")
41 # returns '<', '>' or null accoring to rotation or lack thereof
42 fun update
: nullable Char
48 if new_a
!= old_a
or new_b
!= old_b
then
49 if not old_a
and not old_b
then
51 if not new_a
and new_b
then
53 else if new_a
and not new_b
then
56 else if old_a
and old_b
then
58 if not new_a
and new_b
then
60 else if new_a
and not new_b
then
81 var ds
= new Array[RPiPin]
84 fun flag_clear_display
: Int do return 1
85 fun flag_return_home
: Int do return 2
86 fun flag_entry_mode_set
: Int do return 4
87 fun flag_display_control
: Int do return 8
88 fun flag_cursor_shift
: Int do return 16
89 fun flag_function_set
: Int do return 32
90 fun flag_set_cgram_addr
: Int do return 64
91 fun flag_set_ggram_addr
: Int do return 128
94 fun flag_entry_right
: Int do return 0
95 fun flag_entry_left
: Int do return 2
96 fun flag_entry_shift_increment
: Int do return 1
97 fun flag_entry_shift_decrement
: Int do return 0
100 fun flag_display_on
: Int do return 4
101 fun flag_display_off
: Int do return 0
102 fun flag_cursor_on
: Int do return 2
103 fun flag_cursor_off
: Int do return 0
104 fun flag_blink_on
: Int do return 1
105 fun flag_blink_off
: Int do return 0
107 # display/cursor shift
108 fun flag_display_move
: Int do return 8
109 fun flag_cursor_move
: Int do return 0
110 fun flag_move_right
: Int do return 4
111 fun flag_move_left
: Int do return 0
114 fun flag_8bit_mode
: Int do return 16
115 fun flag_4bit_mode
: Int do return 0
116 fun flag_2_lines
: Int do return 8
117 fun flag_1_line
: Int do return 0
118 fun flag_5x10_dots
: Int do return 4
119 fun flag_5x8_dots
: Int do return 0
121 fun function_set
(bits
, lines
, dots_wide
: Int)
123 var fs
= flag_function_set
126 else if bits
!= 4 then abort
130 else if lines
!= 1 then abort
132 if dots_wide
== 10 then
134 else if dots_wide
!= 8 then abort
139 fun display_control
(on
, cursor
, blink
: Bool)
141 var fs
= flag_display_control
144 fs
= fs
.bin_or
(flag_display_on
)
145 else fs
= fs
.bin_or
(flag_display_off
)
148 fs
= fs
.bin_or
(flag_cursor_on
)
149 else fs
= fs
.bin_or
(flag_cursor_off
)
152 fs
= fs
.bin_or
(flag_blink_on
)
153 else fs
= fs
.bin_or
(flag_blink_off
)
158 fun entry_mode
(left
, incr
: Bool)
160 var fs
= flag_entry_mode_set
163 fs
= fs
.bin_or
(flag_entry_left
)
164 else fs
= fs
.bin_or
(flag_entry_right
)
167 fs
= fs
.bin_or
(flag_entry_shift_increment
)
168 else fs
= fs
.bin_or
(flag_entry_shift_decrement
)
177 rs
.fsel
= new FunctionSelect.outp
178 en
.fsel
= new FunctionSelect.outp
179 d4
.fsel
= new FunctionSelect.outp
180 d5
.fsel
= new FunctionSelect.outp
181 d6
.fsel
= new FunctionSelect.outp
182 d7
.fsel
= new FunctionSelect.outp
187 # wait 20ms for power up
190 #write_4bits(true,true,false,false)
195 #write_4bits(true,true,false,false)
200 #write_4bits(true,true,false,false)
203 #200.bcm2835_delay_micros
205 #write_4bits(false,true,false,false)
214 #function_set(4, 2, 8)
218 #display_control(true, true, true)
224 # set cursor move direction
232 #entry_mode(true, true)
234 write
(true, "33".to_hex
)
235 write
(true, "32".to_hex
)
236 write
(true, "28".to_hex
)
237 write
(true, "0C".to_hex
)
238 write
(true, "01".to_hex
)
241 fun write_4_bits
(v
: Int)
243 var lb
= once
[1,2,4,8]
246 var r
= b
.bin_and
(v
) != 0
253 fun write_4bits
(a
,b
,c
,d
:Bool)
265 1.bcm2835_delay_micros
267 100.bcm2835_delay_micros
271 fun write
(is_cmd
: Bool, cmd
: Int)
277 var hb
= once
[16,32,64,128]
280 var r
= b
.bin_and
(cmd
) != 0
288 1.bcm2835_delay_micros
297 200.bcm2835_delay_micros
301 var lb
= once
[1,2,4,8]
304 var r
= b
.bin_and
(cmd
) != 0
312 1.bcm2835_delay_micros
321 200.bcm2835_delay_micros
341 for c
in v
do write
(false, c
.ascii
)
348 var status
= mpd
.status
350 if status
!= null then
351 playing
= status
.playing
353 print
"Cannot get state"
359 print
"playing -> stop"
362 print
"stopped -> play"
367 # commandline options for privileges drop
368 var opts
= new OptionContext
369 var opt_ug
= new OptionDropPrivileges
370 #opt_ug.mandatory = true
371 opts
.add_option
(opt_ug
)
373 # parse and check command line options
375 if not opts
.errors
.is_empty
then
377 print
"Usage: {program_name} [options]"
382 assert bcm2835_init
else print
"Failed to init"
385 var user_group
= opt_ug
.value
386 if user_group
!= null then user_group
.drop_privileges
389 var out
= new RPiPin.p1_11
390 out
.fsel
= new FunctionSelect.outp
394 var inp
= new RPiPin.p1_13
395 inp
.fsel
= new FunctionSelect.inpt
396 inp
.pud
= new PUDControl.down
399 var vol3
= new RPiPin.p1_03
400 vol3
.fsel
= new FunctionSelect.inpt
401 vol3
.pud
= new PUDControl.up
404 var vol5
= new RPiPin.p1_05
405 vol5
.fsel
= new FunctionSelect.inpt
406 vol5
.pud
= new PUDControl.up
408 var vol
= new RotaryEncoder(vol3
,vol5
)
412 var lcd_rs
= new RPiPin.p1_23
413 var lcd_en
= new RPiPin.p1_21
414 var lcd_d4
= new RPiPin.p1_19
415 var lcd_d5
= new RPiPin.p1_26
416 var lcd_d6
= new RPiPin.p1_24
417 var lcd_d7
= new RPiPin.p1_22
418 var lcd
= new LCD(lcd_rs
, lcd_en
, lcd_d4
, lcd_d5
, lcd_d6
, lcd_d7
)
420 #lcd.write(false, 'a'.to_i.to_ascii)
422 lcd
.write
(false, 'a'.ascii
)
423 lcd
.write
(false, 'C'.ascii
)
431 if lev
!= last_in
then
444 mpd
.relative_volume
= -vol_step
447 mpd
.relative_volume
= vol_step
451 if tick
% 100 == 0 then
453 #var now_playing = mpd.status("")
454 #lcd.text = tick.to_s