Merge remote-tracking branch 'alexis/raspberry-pi'
authorJean Privat <jean@pryen.org>
Mon, 29 Jul 2013 19:42:49 +0000 (15:42 -0400)
committerJean Privat <jean@pryen.org>
Mon, 29 Jul 2013 19:42:49 +0000 (15:42 -0400)
contrib/physical_interface_for_mpd_on_rpi.nit [new file with mode: 0644]
examples/rpi/blink.nit [new file with mode: 0644]
examples/rpi/input.nit [new file with mode: 0644]
lib/bcm2835.nit [new file with mode: 0644]
lib/gpio.nit [new file with mode: 0644]
lib/mpd.nit [new file with mode: 0644]
lib/standard/collection/collection.nit
tests/sav/test_subarray.sav [new file with mode: 0644]
tests/test_subarray.nit [new file with mode: 0644]

diff --git a/contrib/physical_interface_for_mpd_on_rpi.nit b/contrib/physical_interface_for_mpd_on_rpi.nit
new file mode 100644 (file)
index 0000000..502db34
--- /dev/null
@@ -0,0 +1,435 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2013 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# This programs interprets the input of a physical interface thought the
+# GPIO pins of a Raspberry Pi to control an MPD server.
+#
+# It suppot two inputs: a play/pause button and a rotary encoder to adjust
+# the volume.
+#
+# The each data output of the volume control are connected to the board
+# pins #3 and #5.
+module physical_interface_for_mpd_on_rpi
+
+import bcm2835
+import mpd
+
+redef class Object
+       fun mpd: MPDConnection do return once new MPDConnection("localhost", 6600, "password")
+end
+
+class RotaryEncoder
+       var pin_a: RPiPin
+       var pin_b: RPiPin
+       var old_a= false
+       var old_b= false
+
+       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
+
+class LCD
+       var rs: RPiPin
+       var en: RPiPin
+       var d4: RPiPin
+       var d5: RPiPin
+       var d6: RPiPin
+       var d7: RPiPin
+
+       var ds = new Array[RPiPin]# = [d4,d5,d6,d7]
+
+       # 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
+
+       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
+       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
+               #write(true, flow)
+               #function_set(4, 2, 8)
+
+               # cursor
+               # don't shift & hide
+               #display_control(true, true, true)
+
+               # clear & home
+               #write(true, flag_)
+               #clear
+
+               # set cursor move direction
+               # move right
+               #write(true, 6)
+
+               # turn on display
+               #write(true, 4)
+
+               # set entry mode
+               #entry_mode(true, true)
+
+               write(true, "33".to_hex)
+               write(true, "32".to_hex)
+               write(true, "28".to_hex)
+               write(true, "0C".to_hex)
+               write(true, "01".to_hex)
+       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)
+       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
+
+               en.write(true)
+
+               # wait 450 ns
+               1.bcm2835_delay_micros
+
+               en.write(false)
+
+               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
+
+               en.write(true)
+
+               # wait 450ns
+               1.bcm2835_delay_micros
+
+               en.write(false)
+
+               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
+               clear
+               return_home
+               for c in v do write(false, c.ascii)
+       end
+end
+
+fun hit_play_stop
+do
+       # get current status
+       var status = mpd.status
+       var playing = false
+       if status != null then
+               playing = status.state == "play"
+       end
+
+       if playing then
+               # stop
+               print "playing -> stop"
+               mpd.pause
+       else
+               print "stopped -> play"
+               mpd.play
+       end
+end
+
+assert bcm2835_init else print "Failed to init"
+
+# Debug LED
+var out = new RPiPin.p1_11
+out.fsel = new FunctionSelect.outp
+out.write(false)
+
+# Play button
+var inp = new RPiPin.p1_13
+inp.fsel = new FunctionSelect.inpt
+inp.pud = new PUDControl.down
+
+# Vol +
+var vol3 = new RPiPin.p1_03
+vol3.fsel = new FunctionSelect.inpt
+vol3.pud = new PUDControl.up
+
+# Vol -
+var vol5 = new RPiPin.p1_05
+vol5.fsel = new FunctionSelect.inpt
+vol5.pud = new PUDControl.up
+
+var vol = new RotaryEncoder(vol3,vol5)
+var vol_step = 2
+
+# LCD
+var lcd_rs = new RPiPin.p1_23
+var lcd_en = new RPiPin.p1_21
+var lcd_d4 = new RPiPin.p1_19
+var lcd_d5 = new RPiPin.p1_26
+var lcd_d6 = new RPiPin.p1_24
+var lcd_d7 = new RPiPin.p1_22
+var lcd = new LCD(lcd_rs, lcd_en, lcd_d4, lcd_d5, lcd_d6, lcd_d7)
+lcd.setup
+#lcd.write(false, 'a'.to_i.to_ascii)
+lcd.clear
+lcd.write(false, 'a'.ascii)
+lcd.write(false, 'C'.ascii)
+
+var last_in = false
+var led_on = false
+var tick = 0
+loop
+       # play button
+       var lev = inp.lev
+       if lev != last_in then
+               last_in = lev
+               if lev then
+                       print "hps"
+                       hit_play_stop
+               end
+       end
+
+       # volume
+       var s = vol.update
+       if s != null then
+               if s == '<' then
+                       print "vol down"
+                       mpd.relative_volume = -vol_step
+               else # >
+                       print "vol up"
+                       mpd.relative_volume = vol_step
+               end
+       end
+
+       if tick % 100 == 0 then
+               print tick
+               #var now_playing = mpd.status("")
+               #lcd.text = tick.to_s
+       end
+
+       10.bcm2835_delay
+       tick += 1
+end
diff --git a/examples/rpi/blink.nit b/examples/rpi/blink.nit
new file mode 100644 (file)
index 0000000..60a59aa
--- /dev/null
@@ -0,0 +1,33 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2013 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+module blink
+
+import bcm2835
+
+assert bcm2835_init else print "Failed to init"
+
+var out = new RPiPin.p1_11
+out.fsel = new FunctionSelect.outp
+
+for i in [0..1000[ do
+       out.write(true)
+       500.bcm2835_delay
+       out.write(false)
+       500.bcm2835_delay
+end
+
+bcm2835_close
diff --git a/examples/rpi/input.nit b/examples/rpi/input.nit
new file mode 100644 (file)
index 0000000..8acff6b
--- /dev/null
@@ -0,0 +1,43 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2013 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+module input
+
+import bcm2835
+
+assert bcm2835_init else print "Failed to init"
+
+var out = new RPiPin.p1_11
+out.fsel = new FunctionSelect.outp
+out.write(false)
+
+var inp = new RPiPin.p1_22
+inp.fsel = new FunctionSelect.inpt
+inp.pud = new PUDControl.down
+
+var last_in = false
+loop
+       var lev = inp.lev
+       if lev != last_in then
+               last_in = lev
+               if lev then print "button pressed"
+       end
+
+       out.write(true)
+       100.bcm2835_delay
+       out.write(false)
+       100.bcm2835_delay
+end
diff --git a/lib/bcm2835.nit b/lib/bcm2835.nit
new file mode 100644 (file)
index 0000000..9de90ff
--- /dev/null
@@ -0,0 +1,120 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2013 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Services to control the bcm2835 chipset as used in the Raspberry Pi
+# model B revision 1 Uses the C library by Mike McCauley from
+# http://www.airspayce.com/mikem/bcm2835/
+module bcm2835
+
+import gpio
+
+in "C Header" `{
+       #include <bcm2835.h>
+`}
+
+redef class Object
+       protected fun bcm2835_init: Bool `{ return bcm2835_init(); `}
+       protected fun bcm2835_close `{ bcm2835_close(); `}
+       protected fun bcm2835_debug=(v: Bool) `{ bcm2835_set_debug(v); `}
+end
+
+extern class RPiPin `{ RPiGPIOPin `}
+       super Pin
+
+       new p1_03 `{ return RPI_GPIO_P1_03; `}
+
+       new p1_05 `{ return RPI_GPIO_P1_05; `}
+       new p1_07 `{ return RPI_GPIO_P1_07; `}
+
+       new p1_11 `{ return RPI_GPIO_P1_11; `}
+       new p1_12 `{ return RPI_GPIO_P1_12; `}
+       new p1_13 `{ return RPI_GPIO_P1_13; `}
+
+       new p1_15 `{ return RPI_GPIO_P1_15; `}
+       new p1_16 `{ return RPI_GPIO_P1_16; `}
+
+       new p1_18 `{ return RPI_GPIO_P1_18; `}
+       new p1_19 `{ return RPI_GPIO_P1_19; `}
+
+       new p1_21 `{ return RPI_GPIO_P1_21; `}
+       new p1_22 `{ return RPI_GPIO_P1_22; `}
+       new p1_23 `{ return RPI_GPIO_P1_23; `}
+       new p1_24 `{ return RPI_GPIO_P1_24; `}
+
+       new p1_26 `{ return RPI_GPIO_P1_26; `}
+
+       # Select mode: input, output or alts
+       fun fsel=(mode: FunctionSelect) `{ bcm2835_gpio_fsel(recv, mode); `}
+
+       # Set output
+       redef fun write(high) `{ bcm2835_gpio_write(recv, high? HIGH: LOW); `}
+
+       # Set pull up mode
+       fun pud=(pud: PUDControl) `{ bcm2835_gpio_set_pud(recv, pud); `}
+
+       # Falling edge detect
+       # Do not use on raspbian, it is bugged!
+       fun fen `{ bcm2835_gpio_fen(recv); `}
+       fun clr_fen `{ bcm2835_gpio_clr_fen(recv); `}
+
+       # Raising edge detect
+       # Do not use on raspbian, it is bugged!
+       fun ren `{ bcm2835_gpio_ren(recv); `}
+       fun clr_ren `{ bcm2835_gpio_clr_ren(recv); `}
+
+       # High edge detect
+       # Do not use on raspbian, it is bugged!
+       fun hen `{ bcm2835_gpio_hen(recv); `}
+       fun clr_hen `{ bcm2835_gpio_clr_hen(recv); `}
+
+       # Low edge detect
+       # Do not use on raspbian, it is bugged!
+       fun len `{ bcm2835_gpio_len(recv); `}
+       fun clr_len `{ bcm2835_gpio_clr_len(recv); `}
+
+       fun set_eds `{ bcm2835_gpio_set_eds(recv); `}
+       fun eds: Bool `{ return bcm2835_gpio_eds(recv); `}
+
+       # Return input on pin, true for high and false for low
+       fun lev: Bool `{ return bcm2835_gpio_lev(recv); `}
+end
+
+extern class FunctionSelect `{ bcm2835FunctionSelect `}
+       # Input function
+       new inpt `{ return BCM2835_GPIO_FSEL_INPT; `}
+
+       # Output function
+       new outp `{ return BCM2835_GPIO_FSEL_OUTP; `}
+
+       new alt0 `{ return BCM2835_GPIO_FSEL_ALT0; `}
+       new alt1 `{ return BCM2835_GPIO_FSEL_ALT1; `}
+       new alt2 `{ return BCM2835_GPIO_FSEL_ALT2; `}
+       new alt3 `{ return BCM2835_GPIO_FSEL_ALT3; `}
+       new alt4 `{ return BCM2835_GPIO_FSEL_ALT4; `}
+       new alt5 `{ return BCM2835_GPIO_FSEL_ALT5; `}
+       new mask `{ return BCM2835_GPIO_FSEL_MASK; `}
+end
+
+extern class PUDControl `{ bcm2835PUDControl `}
+       new off `{ return BCM2835_GPIO_PUD_OFF; `}
+       new down `{ return BCM2835_GPIO_PUD_DOWN; `}
+       new up `{ return BCM2835_GPIO_PUD_UP; `}
+end
+
+redef universal Int
+       fun bcm2835_delay `{ bcm2835_delay(recv); `}
+       fun bcm2835_delay_micros `{ bcm2835_delayMicroseconds(recv); `}
+end
diff --git a/lib/gpio.nit b/lib/gpio.nit
new file mode 100644 (file)
index 0000000..820f608
--- /dev/null
@@ -0,0 +1,22 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2013 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# GPIO related functionnalities
+module gpio
+
+interface Pin
+       fun write(high: Bool) is abstract
+end
diff --git a/lib/mpd.nit b/lib/mpd.nit
new file mode 100644 (file)
index 0000000..4c74554
--- /dev/null
@@ -0,0 +1,177 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2013 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Client for a MPD server
+module mpd
+
+import socket
+
+# Connection to a MPD server
+class MPDConnection
+       var socket: nullable Socket = null
+
+       var host: String
+       var port: Int
+       var password: nullable String
+
+       var error: nullable String = null
+
+       # Connect to the MPD server
+       fun connect
+       do
+               var p: nullable Socket = null
+
+               p = new Socket.stream_with_host(host, port)
+               p.connect
+
+               sys.nanosleep(0,5000)
+
+               var rep = p.read
+               assert not rep.is_empty
+               if not rep.has_prefix("OK") then
+                       print "MPD responded {rep}"
+                       abort
+               end
+
+               socket = p
+
+               var password = password
+               if password != null then
+                       write("password {password}\n")
+               end
+       end
+
+       # Write a command to the MPD server
+       protected fun write(msg: String)
+       do
+               if socket == null then connect
+
+               socket.write(msg)
+               sys.nanosleep(0,5000)
+               var rep = socket.read
+               assert rep.has_prefix("OK") else print "MPD responded {rep}"
+       end
+
+       # Get MPD server status
+       fun status: nullable ServerStatus
+       do
+               if socket == null then connect
+
+               var volume: nullable Int = null
+               var state: nullable String = null
+
+               # get current status
+               socket.write("status\n")
+               var rep = socket.read
+               for l in rep.split_with("\n") do
+                       var words = l.split_with(" ")
+                       if words.length > 1 then
+                               var key = words[0].to_lower
+                               var first_space = l.index_of(' ')
+                               var rest = l.substring_from(first_space+1)
+                               if  key == "volume:" then
+                                       volume = rest.to_i
+                                       if volume == -1 then volume = null
+                               else if  key == "volume:" then
+                                       state = rest
+                               end
+                       end
+               end
+
+               if state != null then
+                       return new ServerStatus(volume, state)
+               else
+                       return null
+               end
+       end
+
+       # Set the volume relatively
+       fun relative_volume=(diff: Int)
+       do
+               if socket == null then connect
+
+               var status = status
+               if status != null then
+                       var vol = status.volume
+                       if vol != null then
+                               var new_vol = vol + diff
+                               new_vol = new_vol.max(0).min(100)
+                               volume = new_vol
+                               return
+                       end
+               end
+
+               error = "Cannot get volume"
+       end
+
+       fun volume=(vol: Int) do write("setvol {vol}\n")
+
+       # Pause music playing on the MPD server
+       fun pause do write("pause\n")
+
+       # Stop music playing on the MPD server
+       fun stop do write("stop\n")
+
+       # Play music playing on the MPD server
+       fun play do write("play\n")
+
+       # Get information on the currently playing song on the MPD server
+       fun current_song: nullable SongInfo
+       do
+               if socket == null then connect
+
+               var album: nullable String = null
+               var artist: nullable String = null
+               var title: nullable String = null
+
+               socket.write("currentsong\n")
+               var rep = socket.read
+               for l in rep.split_with("\n") do
+                       var words = l.split_with(" ")
+                       if words.length > 1 then
+                               var key = words[0].to_lower
+                               var first_space = l.index_of(' ')
+                               var rest = l.substring_from(first_space+1)
+                               if key == "album:" then
+                                       album = rest
+                               else if key == "artist:" then
+                                       artist = rest
+                               else if key == "title:" then
+                                       title = rest
+                               end
+                       end
+               end
+
+               if album != null and artist != null and title != null then
+                       return new SongInfo(album, artist, title)
+               else
+                       return null
+               end
+       end
+end
+
+# MPD song info
+class SongInfo
+       var album: String
+       var artist: String
+       var title: String
+end
+
+# MPD server status
+class ServerStatus
+       var volume: nullable Int
+       var state: String
+end
index 781cd54..27ed996 100644 (file)
@@ -19,3 +19,12 @@ import list
 intrude import array # FIXME because of string.nit
 import sorter
 import hash_collection
+
+redef class Sequence[E]
+       fun subarray(start, len: Int): Array[E]
+       do
+               var a = new Array[E].with_capacity(len)
+               for i in [start .. start+len[ do a.add(self[i])
+               return a
+       end
+end
diff --git a/tests/sav/test_subarray.sav b/tests/sav/test_subarray.sav
new file mode 100644 (file)
index 0000000..e7e74aa
--- /dev/null
@@ -0,0 +1,5 @@
+123
+012345678
+456
+01234
+123L123truefalse
diff --git a/tests/test_subarray.nit b/tests/test_subarray.nit
new file mode 100644 (file)
index 0000000..460a11d
--- /dev/null
@@ -0,0 +1,23 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Copyright 2013 Alexis Laferrière <alexis.laf@xymus.net>
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+module test_subarray
+
+print( [0,1,2,3,4,5,6,7,8,9,10].subarray(1, 3) )
+print( [0,1,2,3,4,5,6,7,8,9,10].subarray(0, 9) )
+print( [0,1,2,3,4,5,6,7,8,9,10].subarray(4, 3) )
+print( [0,1,2,3,4].subarray(0, 5) )
+print( new Array[Object].with_items("a", 123, 'L', [1,2,3], true, false).subarray(1,5) )