Modifications after testing on RPi
[miniband.git] / release / miniband.py
1 # This code is copyright ...... under the GPL v2.
2 # This code is derived from scratch_gpio_handler by Simon Walters, which
3 # is derived from scratch_handler by Thomas Preston
4 # Version 0.1: It's kind of working.
5
6 from array import *
7 import threading
8 import socket
9 import time
10 import sys
11 import struct
12 import serial
13 import io
14 import logging
15
16 PORT = 42001
17 DEFAULT_HOST = '127.0.0.1'
18 BUFFER_SIZE = 240 #used to be 100
19 SOCKET_TIMEOUT = 1
20 DEVICES = ['/dev/ttyACM0', '/dev/ttyACM1','/dev/ttyACM3']
21 ARDUINO_BAUD_RATE = 9600
22
23 BROADCAST_NAMES = {'guitar': 'guitar',
24 'drum': {0: 'cymbal',
25 1: 'hihat',
26 2: 'slowdrum',
27 3: 'snare',
28 4: 'tomtom'},
29 'maracas': 'maracas'}
30
31 SENSOR_NAMES = {'guitar': 'guitar_pitch'}
32
33 logging.basicConfig(level = logging.INFO)
34 #logging.basicConfig(level = logging.DEBUG)
35
36 class MyError(Exception):
37 def __init__(self, value):
38 self.value = value
39
40 def __str__(self):
41 return repr(self.value)
42
43 class ScratchSender(threading.Thread):
44 def __init__(self, socket):
45 threading.Thread.__init__(self)
46 self.scratch_socket = socket
47 self._stop = threading.Event()
48
49 def join(self,timeout=None):
50 self._stop.set()
51 threading.Thread.join(self, timeout)
52
53 def stopped(self):
54 return self._stop.isSet()
55
56 def run(self):
57 while not self.stopped():
58 time.sleep(0.01) # be kind to cpu - not certain why :)
59
60 def send_scratch_command(self, cmd):
61 n = len(cmd)
62 a = array('c')
63 a.append(chr((n >> 24) & 0xFF))
64 a.append(chr((n >> 16) & 0xFF))
65 a.append(chr((n >> 8) & 0xFF))
66 a.append(chr(n & 0xFF))
67 self.scratch_socket.send(a.tostring() + cmd)
68
69
70 class ArduinoListener(threading.Thread):
71 def __init__(self, device, speed, sender, instruments, values):
72 threading.Thread.__init__(self)
73 self.arduino_device = serial.Serial(device, speed, timeout=0.5)
74 self._stop = threading.Event()
75 self.scratch_sender = sender
76 self.instruments = instruments
77 self.values = values
78 logging.info("Started listener on port %s" % device)
79
80 def join(self,timeout=None):
81 self._stop.set()
82 threading.Thread.join(self, timeout)
83
84 def stopped(self):
85 return self._stop.isSet()
86
87 def run(self):
88 self.arduino_device.readline() # discard the first (partial) line
89 while not self.stopped():
90 logging.debug('Thread waiting for a signal')
91 try:
92 device_line = self.arduino_device.readline()
93 if device_line :
94 instrument, instrument_value_string = device_line.rstrip().split(',', 1)
95 instrument_value = int(instrument_value_string)
96 logging.info('Instrument: %s, Value: %d' % (instrument, instrument_value))
97 if instrument in self.values:
98 try:
99 logging.info("sensor-update %s %d" % (self.values[instrument], (instrument_value * 100) / 1024))
100 self.scratch_sender.send_scratch_command("sensor-update %s %d" % (self.values[instrument], (instrument_value * 100) / 1024))
101 except KeyError:
102 # Do nothing
103 pass
104 if instrument in self.instruments:
105 if isinstance(self.instruments[instrument], dict):
106 broadcast = self.instruments[instrument][instrument_value]
107 else:
108 broadcast = self.instruments[instrument]
109 try:
110 logging.info("broadcast %s" % broadcast)
111 self.scratch_sender.send_scratch_command('broadcast %s' % broadcast)
112 except KeyError:
113 # Do nothing
114 pass
115
116 except serial.SerialException:
117 logging.error('Serial exception')
118 logging.debug('Thread run() exiting')
119
120
121 def create_socket(host, port):
122 while True:
123 try:
124 logging.info('Connecting to Scratch')
125 scratch_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
126 scratch_sock.connect((host, port))
127 break
128 except socket.error:
129 logging.warning("There was an error connecting to Scratch!")
130 logging.warning("I couldn't find a Mesh session at host: %s, port: %s" % (host, port))
131 time.sleep(3)
132 return scratch_sock
133
134 def cleanup_threads(threads):
135 logging.debug("Stopping %d threads" % len(threads))
136 for thread in threads:
137 thread.join()
138 logging.debug("Threads joined")
139
140 if __name__ == '__main__':
141 if len(sys.argv) > 1:
142 host = sys.argv[1]
143 else:
144 host = DEFAULT_HOST
145
146 cycle_trace = 'start'
147 while True:
148 if (cycle_trace == 'disconnected'):
149 logging.info("Scratch disconnected")
150 cleanup_threads(listeners + sender)
151 time.sleep(1)
152 cycle_trace = 'start'
153
154 if (cycle_trace == 'start'):
155 # open the socket
156 logging.info('Connecting to Scratch...')
157 the_socket = create_socket(host, PORT)
158 logging.info('Connected to Scratch')
159 the_socket.settimeout(SOCKET_TIMEOUT)
160 sender = ScratchSender(the_socket)
161 listeners = [ArduinoListener(device, ARDUINO_BAUD_RATE, sender, BROADCAST_NAMES, SENSOR_NAMES) for device in DEVICES]
162 cycle_trace = 'running'
163 logging.info("Listeners running....")
164 sender.start()
165 for listener in listeners:
166 listener.start()
167
168 # wait for ctrl+c
169 try:
170 #just pause
171 time.sleep(0.1)
172 except KeyboardInterrupt:
173 logging.warning("Interrrupted")
174 cleanup_threads(listeners + [sender])
175 sys.exit()
176