238 lines
7.8 KiB
Python
Executable File
238 lines
7.8 KiB
Python
Executable File
#!/usr/bin/env python
|
|
|
|
# ------------------------------------------------------------------------
|
|
# ecamonitor: Ecasound monitor client implemented using NetECI
|
|
# Copyright (C) 2002-2003,2009 Kai Vehmanen
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 2 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
# ------------------------------------------------------------------------
|
|
|
|
import curses
|
|
import re
|
|
import socket
|
|
import string
|
|
import sys
|
|
import time
|
|
|
|
ecamonitor_remote_host = "localhost"
|
|
ecamonitor_remote_port = 2868
|
|
ecamonitor_version = "v20090419-7"
|
|
|
|
# TODO:
|
|
# - nothing at the moment
|
|
|
|
# References:
|
|
# - http://www.python.org/doc/essays/styleguide.html
|
|
# - http://py-howto.sourceforge.net/curses/curses.html
|
|
# - http://www.python.org/doc/2.2.2/lib/module-curses.html
|
|
# - http://py-howto.sourceforge.net/regex/regex.html
|
|
# - http://www.python.org/doc/2.2.2/lib/module-re.html
|
|
# - http://py-howto.sourceforge.net/sockets/sockets.html
|
|
# - http://www.python.org/doc/2.2.2/lib/module-string.html
|
|
|
|
def connect_to_server(remote_host, remote_port):
|
|
"""Connects to the ecasound server.
|
|
|
|
@return Socket object for the connection.
|
|
"""
|
|
|
|
while 1:
|
|
try:
|
|
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
s.connect((remote_host, remote_port))
|
|
s.setblocking(1)
|
|
return(s)
|
|
|
|
except Exception, e:
|
|
if e[0] == 111: # 111 = connection refused
|
|
time.sleep(1)
|
|
pass
|
|
else:
|
|
raise
|
|
|
|
def issue_eiam_command(s, cmd):
|
|
"""Sends a command to ecasound and waits for an response.
|
|
|
|
@param s socket for an active connection
|
|
@param cmd EIAM command to send
|
|
|
|
@return tuple of return value type and value
|
|
"""
|
|
|
|
tm = ''
|
|
counter = 0
|
|
s.send(cmd + '\r\n')
|
|
while counter < 16:
|
|
count = counter + 1
|
|
newdata = s.recv(4096)
|
|
if len(newdata) == 0:
|
|
return ('e','')
|
|
|
|
tm = tm + newdata
|
|
|
|
# lets test whether we have received a valid
|
|
# EIAM command
|
|
try:
|
|
m = expand_eiam_response(tm)
|
|
return parse_eiam_response(m, tm)
|
|
|
|
except Exception, e:
|
|
pass
|
|
|
|
return ('e','')
|
|
|
|
def expand_eiam_response(str):
|
|
"""Checks wheter 'str' is a valid EIAM response.
|
|
|
|
@return Regex match object.
|
|
"""
|
|
|
|
m = re.match('256 ([0-9]{1,5}) (.+)\r\n(.*)\r\n\r\n.*', str, re.MULTILINE | re.S)
|
|
return m
|
|
|
|
def parse_eiam_response(m, str):
|
|
"""Parses a valid EIAM response.
|
|
|
|
@param m Valid regex match object.
|
|
@param str The whole EIAM response.
|
|
|
|
@return tuple of return value type and value
|
|
"""
|
|
|
|
if not m:
|
|
m = re.match('256 ([0-9]{1,5}) (.+)\r\n(.*)', str, re.MULTILINE | re.S)
|
|
if not m:
|
|
raise Exception, 'Regexp failed!'
|
|
|
|
if m and len(m.groups()) == 0:
|
|
print "(ecamonitor) Matching groups failed: ", m.groups()
|
|
|
|
if m and len(m.groups()) == 3:
|
|
#print 'received=', len(m.group(3)), ', expected=', m.group(1)
|
|
if int(m.group(1)) != len(m.group(3)):
|
|
print "(ecamonitor) Response length error."
|
|
|
|
if m:
|
|
return (m.group(2), m.group(3))
|
|
|
|
return ('e','')
|
|
|
|
def main():
|
|
|
|
s = None
|
|
|
|
remote_host = ecamonitor_remote_host
|
|
remote_port = ecamonitor_remote_port
|
|
|
|
if not hasattr(sys, 'version_info') or (hasattr(sys, 'version_info') and sys.version_info[1] <2):
|
|
print 'Error! Ecamonitor requires python-2.0 or newer to run!'
|
|
return 1
|
|
|
|
if len(sys.argv) > 1:
|
|
destination = sys.argv[1]
|
|
address = string.split(destination, ':')
|
|
remote_host = address[0]
|
|
if len(address) > 1:
|
|
remote_port = int(address[1])
|
|
|
|
try:
|
|
stdscr = curses.initscr()
|
|
pad = curses.newpad(255, 80)
|
|
pad.nodelay(1) # to make getch() nonblocking
|
|
|
|
while 1:
|
|
try:
|
|
pad.erase()
|
|
pad.addstr(0, 0, "ecamonitor " + ecamonitor_version, curses.A_BOLD)
|
|
|
|
if s == None:
|
|
pad.addstr(2, 0, "No connection. Trying to connect to " + remote_host + ":" + str(remote_port) + ".\n")
|
|
pad.refresh(0, 0, 0, 0, stdscr.getmaxyx()[0]-1, stdscr.getmaxyx()[1]-1)
|
|
#time.sleep(3)
|
|
s = connect_to_server(remote_host, remote_port)
|
|
pad.addstr(3, 0, "Connection established.\n")
|
|
pad.refresh(0, 0, 0, 0, stdscr.getmaxyx()[0]-1, stdscr.getmaxyx()[1]-1)
|
|
pad.addstr(1, 0, "")
|
|
else:
|
|
pad.addstr("\n")
|
|
|
|
pad.addstr("\n------------------------------------------------------------")
|
|
pad.addstr("\nEngine status: ")
|
|
pad.addstr((issue_eiam_command(s, 'engine-status')[1]), curses.A_BOLD)
|
|
pad.addstr("\nConnected chainsetup: ")
|
|
pad.addstr(issue_eiam_command(s, 'cs-connected')[1], curses.A_BOLD)
|
|
pad.addstr("\nSelected chainsetup: ")
|
|
pad.addstr(issue_eiam_command(s, 'cs-selected')[1], curses.A_BOLD)
|
|
|
|
#pad.addstr("\nSelected chainsetup status:: ")
|
|
#pad.addstr(issue_eiam_command(s, 'cs-status')[1])
|
|
|
|
pad.addstr("\n\nPosition: ")
|
|
pad.addstr(issue_eiam_command(s, 'cs-get-position')[1] + "s", curses.A_BOLD)
|
|
pad.addstr(" / Length: ")
|
|
pad.addstr(issue_eiam_command(s, 'cs-get-length')[1] + "s", curses.A_BOLD)
|
|
pad.addstr("\nChains: ")
|
|
pad.addstr(str(len(string.split(issue_eiam_command(s, 'c-list')[1],','))), curses.A_BOLD)
|
|
pad.addstr(" / Inputs: ")
|
|
pad.addstr(str(len(string.split(issue_eiam_command(s, 'ai-list')[1],','))), curses.A_BOLD)
|
|
pad.addstr(" / Outputs: ")
|
|
pad.addstr(str(len(string.split(issue_eiam_command(s, 'ao-list')[1],','))), curses.A_BOLD)
|
|
|
|
pad.addstr("\n\n------------------------------------------------------------\n")
|
|
res = issue_eiam_command(s, 'aio-status')
|
|
pad.addstr(res[1])
|
|
|
|
pad.addstr("\n\n------------------------------------------------------------\n")
|
|
res = issue_eiam_command(s, 'cop-status')
|
|
pad.addstr(res[1])
|
|
|
|
pad.addstr("\n\n------------------------------------------------------------\n")
|
|
res = issue_eiam_command(s, 'ctrl-status')
|
|
pad.addstr(res[1])
|
|
|
|
pad.addstr("\n\n------------------------------------------------------------\n")
|
|
|
|
pad.refresh(0, 0, 0, 0, stdscr.getmaxyx()[0]-1, stdscr.getmaxyx()[1]-1)
|
|
|
|
time.sleep(1.0)
|
|
|
|
ch=pad.getch()
|
|
if ch == ord('q'):
|
|
break
|
|
|
|
except curses.error:
|
|
raise
|
|
|
|
except socket.error, e:
|
|
if e[0] == 32 or e[0] == 104 or e[0] == 111:
|
|
s = None
|
|
pass
|
|
else:
|
|
curses.endwin()
|
|
print "Exception!" , e
|
|
raise
|
|
|
|
except KeyboardInterrupt:
|
|
break
|
|
|
|
|
|
finally:
|
|
if s != None:
|
|
s.close()
|
|
curses.endwin()
|
|
|
|
if __name__ == '__main__':
|
|
main()
|