Skip to content

Commit 2d394f6

Browse files
The initial commit of the code.
git-svn-id: https://macquarie-observatory-automation.googlecode.com/svn/trunk@5 ba3ad000-c725-3ee3-f0a2-a6f435c0371d
1 parent 13393e5 commit 2d394f6

File tree

7 files changed

+310
-0
lines changed

7 files changed

+310
-0
lines changed

README

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
First run:
2+
./make_command_list labjack_server.py
3+
Then run:
4+
./labjack_main
5+
NB Make sure that /usr/bin/python is the correct version of python, or
6+
alternatively change labjack_main.

command_list.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Given a list of functions and a list of strings, this program
2+
# is designed to find the function matching a given string.
3+
# As this has to be done in principle when "compiling", the C way
4+
# to do this is to have a list of functions and a list of strings.
5+
#
6+
# Function lists may have to be imported from many places, but
7+
# within the same global scope. With the "simple server" mentality,
8+
# this can be passed a single object that contains the function
9+
# definitions, as a single object should be enough to contain all
10+
# pieces of hardware (which should be 1).
11+
#
12+
# The idea is that a single call to:
13+
# execute_command(command)
14+
# ... returns a string for successful execution, or a useful string
15+
#
16+
# Try:
17+
# ./make_command_list dummy_functions.py
18+
# import dummy_functions as d
19+
# import command_list as cl
20+
# print cl.execute_command("one",d)
21+
# print cl.execute_command("help",d)
22+
# print cl.execute_command("oops",d)
23+
24+
import string
25+
import pydoc
26+
27+
def execute_command(the_command, m):
28+
'''Find the_command amongst the list of commands like cmd_one in module m
29+
30+
This returns a string containing the response, or a -1 if a quit is commanded.'''
31+
the_functions = dict(humidity=m.cmd_humidity,temperature=m.cmd_temperature,ljtemp=m.cmd_ljtemp,status=m.cmd_status,wheel=m.cmd_wheel)
32+
commands = string.split(the_command)
33+
if len(commands) == 0:
34+
return ""
35+
if commands[0] == "help":
36+
if (len(commands) == 1):
37+
return 'humidity\ntemperature\nljtemp\nstatus\nwheel'
38+
elif commands[1] in the_functions:
39+
td=pydoc.TextDoc()
40+
return td.docroutine(the_functions[commands[1]])
41+
else:
42+
return "ERROR: "+commands[1]+" is not a valid command."
43+
elif commands[0] == 'exit' or commands[0] == 'bye' or commands[0] == 'quit':
44+
return -1
45+
elif commands[0] in the_functions:
46+
return the_functions[commands[0]](the_command)
47+
else:
48+
return "ERROR: Command not found."
49+

dummy_functions.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
''' This is a module with dummy functions'''
2+
3+
# The first dummy function
4+
def cmd_one(the_command):
5+
'''The first dummy function.
6+
Some extra text about it.'''
7+
return "This is function 1"
8+
9+
# The second dummy function
10+
def cmd_two(the_command):
11+
'''The second dummy function. A really long line with some extra text about it.'''
12+
return "This is function 2"
13+

labjack_server.py

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
#*********************************************************************#
2+
# Code for the labjack server #
3+
#*********************************************************************#
4+
5+
#*********************************************************************#
6+
#Code the runs on module import starts here.
7+
#1) Import all modules that we need. NB ei1050 isn't installed by default,
8+
# but is in the "examples" directory of the labjack code.
9+
import string
10+
import u3
11+
import ei1050
12+
13+
#***********************************************************************#
14+
#2) Set up the labjack. As the LJ and LJPROBE are declared in the global
15+
# module scope, lets give them capitals. These are initialized, byt
16+
# not written to within our module. Two instances of the LabjackServer
17+
# would then write to the *same* labjack hardware, but could e.g.
18+
# do different parts of the job. You's almost certainly *not* want to do
19+
# this.
20+
LJ=u3.U3()
21+
LJPROBE=ei1050.EI1050(LJ, enablePinNum=0, dataPinNum=1, clockPinNum=2)
22+
LJ.configIO(NumberOfTimersEnabled = 2)
23+
LJ.getFeedback(u3.Timer0Config(8), u3.Timer1Config(8))
24+
25+
#***********************************************************************#
26+
#2) Now define our main class, the LabjackServer.
27+
class LabjackServer:
28+
29+
#Variables not used yet...
30+
dome_status = 'HOME'
31+
slit_status = 'closed'
32+
weather_status = 'NULL' #Needs to come from connection to weather server. Who is the client?
33+
34+
#Some properties relating to the relative encoder.
35+
wheel_pos = 0.0
36+
wheel_command = 0
37+
wheel_moving = False
38+
current_pos = 0 #MJI Doesn't understand the difference between WHEEL_POS, WHEEL_COMMAND and this... Needs comments
39+
40+
#*************************************************************************#
41+
#All the definitions used are listed here
42+
43+
#definition for weather checking
44+
def cmd_humidity(self,the_command):
45+
''' Get the humidity from the E1050 probe '''
46+
humidity = LJPROBE.getHumidity()
47+
return str(humidity)
48+
49+
def cmd_temperature(self,the_command):
50+
''' Get the temperature from the E1050 probe '''
51+
temperature = LJPROBE.getTemperature()
52+
return str(temperature)
53+
54+
def cmd_ljtemp(self,the_command):
55+
''' Get the temperature of the labjack in Kelvin'''
56+
temperature = LJ.getTemperature()
57+
return str(temperature)
58+
59+
def cmd_status(self,the_command):
60+
'''Return the status of the entire system.'''
61+
return(str(self.wheel_pos))
62+
63+
def cmd_wheel(self,the_command):
64+
'''Move the wheel'''
65+
commands=string.split(the_command)
66+
if self.wheel_moving == True:
67+
return "Wheel already moving"
68+
elif len(commands) ==1:
69+
return "Wheel\'s current position: "+str(self.wheel_pos)+". Wheel NOT moving."
70+
else:
71+
self.wheel_command = commands[1]
72+
self.wheel_moving = True
73+
return "Wheel''s current position: "+str(self.wheel_pos)+". Moving Wheel."
74+
75+
#****** End of user commands *******
76+
77+
#This is the background job that defines if the wheel is moving.
78+
def dome_rotate(self,command):
79+
command = float(command)
80+
command = command*48 #turns number of turns into number of counts
81+
temp = LJ.getFeedback(u3.QuadratureInputTimer())
82+
temp2 = temp[-1]
83+
temp2 = temp2 - (self.wheel_pos*48)
84+
destination = command + self.wheel_pos
85+
if command >= 0:
86+
if temp2 < command:
87+
self.wheel_moving = True
88+
temp = LJ.getFeedback(u3.QuadratureInputTimer())
89+
self.current_pos = float(temp[-1])
90+
else: self.wheel_moving = False
91+
elif command < 0:
92+
if temp2 > command:
93+
self.wheel_moving = True
94+
temp = LJ.getFeedback(u3.QuadratureInputTimer())
95+
self.current_pos = float(temp[-1])
96+
else: self.wheel_moving = False
97+
else:
98+
return "ERROR"
99+
100+
if self.wheel_moving == False:
101+
turns = (self.current_pos/48.0) - self.wheel_pos
102+
pos = self.wheel_pos
103+
pos = pos + turns
104+
self.wheel_pos = pos
105+
return turns
106+
else: return
107+
108+
#This will 'move' the wheel if there has been a command which has not yet completed
109+
#obviously at the moment the wheel is moved manually
110+
def wheel_move(self):
111+
if self.wheel_moving == True:
112+
self.dome_rotate(self.wheel_command)
113+
114+
115+

make_command_dict

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/bin/bash
2+
THESTRINGS=$1=m.cmd_$1
3+
shift
4+
while [ $# -gt 0 ]
5+
do
6+
THESTRINGS=${THESTRINGS}','$1=m.cmd_$1
7+
shift
8+
done
9+
echo ${THESTRINGS}

make_command_list

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#!/bin/bash
2+
#Make a list of commands from the python file.
3+
grep 'def cmd_' $1 | sed 's/def cmd_//g' | sed 's/^[ \t]*//' |cut -d '(' -f1 > command_list.txt
4+
#Now turn newlines into \n
5+
sed '{:q;N;s/\n/\\\\n/g;t q}' command_list.txt > temp.txt
6+
sed 's/INSERT_COMMAND_LIST/'`cat temp.txt`'/g' command_list.template > temp.txt
7+
SED_COMMAND='./make_command_dict '`cat command_list.txt`
8+
sed 's/INSERT_COMMAND_DICT/'`${SED_COMMAND}`'/' temp.txt > command_list.py
9+
rm temp.txt

server_socket.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
# This python object is designed to take as inputs a socket number, a server name
2+
# and a hardware object, and to do all communication in the same way for all servers.
3+
4+
#*********************************************************************#
5+
#Code the runs on module import starts here.
6+
#1) Import all modules that we need.
7+
8+
import sys
9+
import string
10+
import select
11+
import socket
12+
from datetime import datetime
13+
#imports that we wrote
14+
import command_list as cl
15+
16+
#*************************************************************************#
17+
#2) Now define our main class, the ServerSocket
18+
class ServerSocket:
19+
#Some properties needed by multiple methods.
20+
clients=[]
21+
jobs=[]
22+
def __init__(self, port, hardware_name, hardware_object):
23+
#Set up the class properties "server", "input", "hardware_name" and "hardware_object"
24+
self.hardware_object=hardware_object
25+
self.hardware_name=hardware_name
26+
IP = ''
27+
ADS = (IP, port)
28+
self.server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
29+
#See /usr/include/sus/socket.h
30+
#SOL_SOCK and SO_REUSE_ADDR. This stops the port from blocking after a crash etc.
31+
self.server.setsockopt(0xffff, 0x0004, 1)
32+
#See /usr/include/netinet/in.h
33+
#IPPROTO_TCP, TCP_NODELAY. This makes the packet get sent straight away (instead of waiting for extra data
34+
#that might arrive).
35+
self.server.setsockopt(6, 1, 1)
36+
self.server.bind(ADS)
37+
self.server.setblocking(0)
38+
self.server.listen(5) #will allow 5 clients to connect with server
39+
self.input = [self.server, sys.stdin]
40+
41+
#This method deals with the various inputs from stdin and connected clients
42+
def socket_funct(self, s):
43+
if s == self.server:
44+
#handle server socket
45+
client, address = self.server.accept()
46+
client.setblocking(0)
47+
self.input.append(client)
48+
self.clients.append(client)
49+
self.input[-1].send("Welcome to "+self.hardware_name+"! There are "+str(len(self.clients))+" people connected\n> ")
50+
self.log("A client has joined, number of clients connected: "+str(len(self.clients)))
51+
return 0
52+
elif s == sys.stdin:
53+
#handle standard input
54+
data = sys.stdin.readline()
55+
return data
56+
else:
57+
#handle all other sockets
58+
data = str(s.recv(1024))
59+
if data:
60+
return data
61+
else:
62+
s.close()
63+
self.input.remove(s)
64+
self.clients.remove(s)
65+
return 0
66+
67+
#We will use this to log what is happening in a file with a timestamp, but for now, print to screen
68+
#I should also add something to document which client sent which command
69+
def log(self, message):
70+
print str(datetime.now())+" "+str(message)
71+
72+
#This closes the connections to the cliente neatly.
73+
def close(self):
74+
self.server.close
75+
76+
#This medhod adds a new job to the queue.
77+
def add_job(self, new_job):
78+
self.jobs.append(new_job)
79+
80+
#This method runs the jobs and waits for new input
81+
def run(self):
82+
self.log("Waiting for connection, number of clients connected: "+str(len(self.clients)))
83+
running=True
84+
while running:
85+
inputready,outputready,exceptready = select.select(self.input,[],[],0)
86+
87+
for s in inputready: #loop through our array of sockets/inputs
88+
data = self.socket_funct(s)
89+
if data == -1:
90+
running=False
91+
elif data != 0:
92+
response = cl.execute_command(data,self.hardware_object)
93+
if response == -1:
94+
running=False
95+
if s == sys.stdin:
96+
self.log("Manually shut down. Goodbye.")
97+
else:
98+
self.log("Shut down by remote connection. Goodbye.")
99+
else:
100+
if s==sys.stdin:
101+
print response
102+
else:
103+
s.send(response + '\n> ')
104+
for the_job in self.jobs:
105+
message=the_job()
106+
if message:
107+
for i in self.clients:
108+
i.send(message)
109+

0 commit comments

Comments
 (0)