lib/bcm2835: move components support from contrib to lib
[nit.git] / contrib / physical_interface_for_mpd_on_rpi / physical_interface_for_mpd_on_rpi.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 # This programs interprets the input of a physical interface thought the
18 # GPIO pins of a Raspberry Pi to control an MPD server.
19 #
20 # It suppot two inputs: a play/pause button and a rotary encoder to adjust
21 # the volume.
22 #
23 # The each data output of the volume control are connected to the board
24 # pins #3 and #5.
25 module physical_interface_for_mpd_on_rpi
26
27 import bcm2835
28 import mpd
29 import privileges
30
31 redef class Object
32 fun mpd: MPDConnection do return once new MPDConnection("localhost", 6600, "password")
33 end
34
35 fun hit_play_stop
36 do
37 # get current status
38 var status = mpd.status
39 var playing = false
40 if status != null then
41 playing = status.playing
42 else
43 print "Cannot get state"
44 return
45 end
46
47 if playing then
48 # stop
49 print "playing -> stop"
50 mpd.pause
51 else
52 print "stopped -> play"
53 mpd.play
54 end
55 end
56
57 # commandline options for privileges drop
58 var opts = new OptionContext
59 var opt_ug = new OptionDropPrivileges
60 #opt_ug.mandatory = true
61 opts.add_option(opt_ug)
62
63 # parse and check command line options
64 opts.parse(args)
65 if not opts.errors.is_empty then
66 print opts.errors
67 print "Usage: {program_name} [options]"
68 opts.usage
69 exit 1
70 end
71
72 assert bcm2835_init else print "Failed to init"
73
74 # drop privileges!
75 var user_group = opt_ug.value
76 if user_group != null then user_group.drop_privileges
77
78 # Debug LED
79 var out = new RPiPin.p1_11
80 out.fsel = new FunctionSelect.outp
81 out.write(false)
82
83 # Play button
84 var inp = new RPiPin.p1_13
85 inp.fsel = new FunctionSelect.inpt
86 inp.pud = new PUDControl.down
87
88 # Vol +
89 var vol3 = new RPiPin.p1_03
90 vol3.fsel = new FunctionSelect.inpt
91 vol3.pud = new PUDControl.up
92
93 # Vol -
94 var vol5 = new RPiPin.p1_05
95 vol5.fsel = new FunctionSelect.inpt
96 vol5.pud = new PUDControl.up
97
98 var vol = new RotaryEncoder(vol3,vol5)
99 var vol_step = 2
100
101 # LCD
102 var lcd_rs = new RPiPin.p1_23
103 var lcd_en = new RPiPin.p1_21
104 var lcd_d4 = new RPiPin.p1_19
105 var lcd_d5 = new RPiPin.p1_26
106 var lcd_d6 = new RPiPin.p1_24
107 var lcd_d7 = new RPiPin.p1_22
108 var lcd = new HD44780(lcd_rs, lcd_en, lcd_d4, lcd_d5, lcd_d6, lcd_d7)
109 lcd.setup
110 lcd.clear
111
112 var last_in = false
113 var led_on = false
114 var tick = 0
115 loop
116 var force_lcd_update = false
117
118 # play button
119 var lev = inp.lev
120 if lev != last_in then
121 last_in = lev
122 if lev then hit_play_stop
123 force_lcd_update = true
124 end
125
126 # volume
127 var s = vol.update
128 if s != null then
129 if s == '<' then
130 print "vol down"
131 mpd.relative_volume = -vol_step
132 else # >
133 print "vol up"
134 mpd.relative_volume = vol_step
135 end
136 force_lcd_update = true
137 end
138
139 # update lcd
140 if tick % 100 == 0 or force_lcd_update then
141 var status = mpd.status
142 var song = mpd.current_song
143
144 var status_char
145 if status == null then
146 lcd.text = "Unknown status"
147 else if song == null then
148 lcd.text = "No song playing"
149 else
150 if status.playing then
151 status_char = ">"
152 else status_char = "#"
153
154 var tr = status.time_ratio
155 var pos = "-"
156 if tr != null then pos = (status.time_ratio*10.0).to_i.to_s
157
158 lcd.text = "{status_char} {song.artist}\n{pos} {song.title}"
159 end
160 end
161
162 10.bcm2835_delay
163 tick += 1
164 end