source: remote_control/puzzlebox_brainstorms_server_thinkgear.py @ 55

Last change on this file since 55 was 55, checked in by sc, 11 years ago

client_thinkgear:

  • default response cleanup
  • comment cleanup

configuration:

  • Special socket handling for Flash applications

server_thinkgear:

  • Special socket handling for Flash applications
File size: 8.2 KB
Line 
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3#
4# Puzzlebox - Brainstorms - Server - ThinkGear Emulator
5#
6# Copyright Puzzlebox Productions, LLC (2010)
7#
8# This code is released under the GNU Pulic License (GPL) version 2
9# For more information please refer to http://www.gnu.org/copyleft/gpl.html
10#
11# Last Update: 2010.06.21
12#
13#####################################################################
14
15import os, signal, sys, time
16import simplejson as json
17
18from twisted.internet import reactor, protocol, defer, task
19from twisted.protocols import basic
20
21import puzzlebox_brainstorms_configuration as configuration
22#import puzzlebox_logger
23
24#####################################################################
25# Globals
26#####################################################################
27
28DEBUG = 1
29
30SERVER_INTERFACE = configuration.SERVER_INTERFACE
31SERVER_PORT = configuration.THINKGEAR_SERVER_PORT
32
33FLASH_POLICY_FILE_REQUEST = configuration.FLASH_POLICY_FILE_REQUEST
34FLASH_SOCKET_POLICY_FILE = configuration.FLASH_SOCKET_POLICY_FILE
35
36THINKGEAR_DELIMITER = '\r'
37
38MESSAGE_FREQUENCY_TIMER = 1 # 1 Hz
39BLINK_FREQUENCY_TIMER = 10 # 10 seconds
40
41DEFAULT_SIGNAL_LEVEL_MESSAGE = \
42        {"poorSignalLevel": 0}
43                # A quantifier of the quality of the brainwave signal.
44                # This is an integer value that is generally in the
45                # range of 0 to 200, with 0 indicating a
46                # good signal and 200 indicating an off-head state.
47
48DEFAULT_EEG_POWER_MESSAGE = \
49        {'eegPower': { \
50                'lowGamma': 0, \
51                'highGamma': 0, \
52                'highAlpha': 0, \
53                'delta': 0, \
54                'highBeta': 0, \
55                'lowAlpha': 0, \
56                'lowBeta': 0, \
57                'theta': 0, \
58                }, \
59         } # A container for the EEG powers. These may
60           # be either integer or floating-point values.
61
62DEFAULT_ESENSE_MESSAGE = \
63        {'eSense': { \
64                'meditation': 0, \
65                'attention': 0, \
66                }, \
67        } # A container for the eSense™ attributes.
68          # These are integer values between 0 and 100,
69          # where 0 is perceived as a lack of that attribute
70          # and 100 is an excess of that attribute.
71               
72DEFAULT_BLINK_MESSAGE = {"blinkStrength": 100}
73        # The strength of a detected blink. This is
74        # an integer in the range of 0-255.
75
76DEFAULT_RAWEEG_MESSAGE = {"rawEeg": 255}
77        # The raw data reading off the forehead sensor.
78        # This may be either an integer or a floating-point value.
79
80DEFAULT_PACKET = {}
81DEFAULT_PACKET.update(DEFAULT_EEG_POWER_MESSAGE)
82DEFAULT_PACKET.update(DEFAULT_SIGNAL_LEVEL_MESSAGE)
83DEFAULT_PACKET.update(DEFAULT_ESENSE_MESSAGE)
84
85DEFAULT_RESPONSE_MESSAGE = DEFAULT_SIGNAL_LEVEL_MESSAGE
86
87#####################################################################
88# Classes
89#####################################################################
90
91class puzzlebox_brainstorms_server_thinkgear(protocol.ServerFactory):
92       
93        def __init__(self, log, DEBUG=DEBUG):
94               
95                self.log = log
96                self.DEBUG = DEBUG
97               
98                self.protocol = puzzlebox_brainstorms_server_protocol
99
100                self.status_packet = DEFAULT_PACKET
101                self.client_connected = False
102       
103       
104        ##################################################################
105       
106        def process_data(self, data):
107               
108                d = defer.Deferred()
109
110
111                # Special socket handling for Flash applications
112                if (data.startswith(FLASH_POLICY_FILE_REQUEST)):
113                        response = FLASH_SOCKET_POLICY_FILE
114
115                else:
116                        response = DEFAULT_RESPONSE_MESSAGE
117
118               
119                if self.DEBUG:
120                        print "--> [ThinkGear Emulator] Received:",
121                        print data
122               
123                if response:
124                        d.callback(response)
125               
126                return d
127       
128       
129        ##################################################################
130       
131        def process_connection_lost(self):
132               
133                print "--> [ThinkGear Emulator] Connection lost"
134                self.client_connected = False
135
136
137        ##################################################################
138
139        def update_status(self):
140
141                if self.DEBUG > 1:
142                        print "status:",
143                        print self.status_packet
144               
145
146        ##################################################################
147
148        def start_updating(self):
149
150                self.client_connected = True
151                self.looping_timer = task.LoopingCall(self.update_status)
152                self.looping_timer.start(MESSAGE_FREQUENCY_TIMER)
153
154
155#####################################################################
156# Protocol
157#####################################################################
158
159class puzzlebox_brainstorms_server_protocol(basic.LineReceiver):
160
161        delimiter='\r'
162       
163        def __init__(self):
164               
165                self.DEBUG = DEBUG
166                self.data_chunk = ""
167
168       
169        ##################################################################
170       
171        def connectionMade(self):
172               
173                if self.DEBUG:
174                        print "--> [ThinkGear Emulator] Client connected"
175                       
176                self.factory.start_updating()
177
178
179        ##################################################################
180       
181        def noReply(self):
182               
183                try:
184                        self.factory.replyDefer.callback('NO_REPLY')
185                except:
186                        if self.DEBUG:
187                                print "noReply failed to call callback"
188               
189                self.transport.loseConnection()
190       
191       
192        ##################################################################
193
194        def lineReceived(self, line):
195
196                # Ignore blank lines
197                if not line:
198                        return
199               
200                data = json.loads(line)
201
202                if self.DEBUG:
203                        print "line received:",
204                        print data
205
206                d = self.factory.process_data("%s" % data)
207                d.addCallback(self.send_response)
208
209       
210        ##################################################################
211       
212        def dataReceived(self, data_received):
213
214                data_to_process = None
215               
216                self.data_chunk += data_received
217               
218                try:
219                        data_to_process = json.loads(self.data_chunk)
220               
221                except Exception, e:
222
223                        # Special socket handling for Flash applications
224                        if (data_received.startswith( \
225                                FLASH_POLICY_FILE_REQUEST)):
226                               
227                                if self.DEBUG:
228                                        print "Flash policy file requested"
229                                       
230                                data_to_process = data_received
231                               
232                               
233                        else:
234                                if self.DEBUG:
235                                        print "Partial data received (or error:",
236                                        print e
237                                        print ")."
238
239                                        print "data_chunk:",
240                                        print self.data_chunk
241
242
243                if (data_to_process != None):
244
245                        self.data_chunk = ""
246
247                        d = self.factory.process_data("%s" % data_to_process)
248                        d.addCallback(self.send_response)
249       
250       
251        ##################################################################
252       
253        def send_response(self, response):
254
255                # Special socket handling for Flash applications
256                if (response == FLASH_SOCKET_POLICY_FILE):
257##                        self.sendLine(response)
258                        self.transport.write(response)
259                else:
260                        response = json.dumps(response)
261                        self.sendLine(response)
262
263                if self.factory.client_connected:
264                        if self.DEBUG:
265                                print "--> [ThinkGear Emulator] Sending:",
266                                print response
267
268                reactor.callLater(MESSAGE_FREQUENCY_TIMER, \
269                                  self.send_response, \
270                                  self.factory.status_packet)
271
272       
273        ##################################################################
274       
275        def connectionLost(self, reason):
276               
277                self.factory.process_connection_lost()
278
279
280#####################################################################
281# Main
282#####################################################################
283
284if __name__ == '__main__':
285       
286        #log = puzzlebox_logger.puzzlebox_logger(logfile='master_control')
287        log = None
288       
289        # Collect default settings and command line parameters
290        server_interface = SERVER_INTERFACE
291        server_port = SERVER_PORT
292       
293        for each in sys.argv:
294               
295                if each.startswith("--interface="):
296                        server_interface = each[ len("--interface="): ]
297                if each.startswith("--port="):
298                        server_port = each[ len("--port="): ]
299       
300       
301        thinkgear_server = puzzlebox_brainstorms_server_thinkgear(log, DEBUG=DEBUG)
302       
303        if DEBUG:
304                print "--> [ThinkGear Emulator] Initializing server on %s:%i" % \
305                        (server_interface, server_port)
306       
307        reactor.listenTCP(interface=server_interface, \
308                          port=server_port, \
309                          factory=thinkgear_server)
310        reactor.run()
311
Note: See TracBrowser for help on using the repository browser.