Skip to content

Commit

Permalink
create button gui for percival powerup
Browse files Browse the repository at this point in the history
  • Loading branch information
William Nichols committed Sep 18, 2020
1 parent aa14b53 commit c70e5a8
Show file tree
Hide file tree
Showing 7 changed files with 427 additions and 11 deletions.
17 changes: 14 additions & 3 deletions percival_test.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,22 @@ debug_mode = 1
http_port = 8888
http_addr = 0.0.0.0
static_path = ./static
adapters = percival
adapters = percival, fr, fp

[tornado]
logging = debug
logging = error

[adapter.percival]
module = percival.detector.adapter.PercivalAdapter
config_file = config/percival.ini
config_file = DESY/W3C3/config/percival.ini

[adapter.fr]
module = odin_data.frame_processor_adapter.OdinDataAdapter
endpoints = 172.23.98.130:5000,172.23.98.131:5010
update_interval = 0.5

[adapter.fp]
module = odin_data.frame_processor_adapter.FrameProcessorAdapter
endpoints = 172.23.98.130:5004,172.23.98.131:5014
update_interval = 0.5

4 changes: 2 additions & 2 deletions static/js/odin-data.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,8 @@ function process_fp_error(response)

$(document).ready(function()
{
setInterval(read_fr_status, 500);
setInterval(read_fp_status, 500);
setInterval(read_fr_status, 5000);
setInterval(read_fp_status, 5000);
$('#fp-start-cmd').on('click', function(event){
start_fp_writing();
});
Expand Down
93 changes: 93 additions & 0 deletions user_scripts/buttons.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
#!/usr/bin/env python

import json;
import socket;
import sys;
from Tkinter import *
import socketfns;

if len(sys.argv)==2 and sys.argv[1]=="--shutdown-server":
print "sending shutdown message to server";
socketfns.sendMsg("shutdown", None);
exit(0);

master = Tk();
master.geometry("400x300+200+200");
master.title("Percival Operation");

def btnCallback(buttxt):
actions = socketfns.getActions();
# this button callback should also disable the button so it doesn't
# get pressed twice; we may as well disable all the buttons then.
for i in range(0,len(actions)):
but = f.grid_slaves(column=1,row=i)[0];
but.configure(state=DISABLED);

if buttxt in actions:
print "toggling action ", actions.index(buttxt);
socketfns.togTask(buttxt);


def updateCanvas(status):
for i in range(0,len(actions)):
cv = f.grid_slaves(column=2, row=i)[0];
state = status[actions[i]];
if state=="done":
cv.configure(bg="green");
elif state=="not done":
cv.configure(bg="red");
else:
cv.configure(bg="orange");

def updateButtons(status):
for i in range(0,len(actions)):
but = f.grid_slaves(column=1,row=i)[0];
canChange = True;
if 0<i:
canChange &= (status[actions[i-1]]=="done");
if i+1<len(actions):
canChange &= (status[actions[i+1]]=="not done");

taskStatus = status[actions[i]];

if canChange and (taskStatus=="done" or taskStatus=="not done"):
but.configure(state=NORMAL);
else:
but.configure(state=DISABLED);

def updateStatus():
# updateStatus and button callbacks won't be called simultaneously;
# master seems to be single-threaded, but it will queue functions to call
print "update status";
status = socketfns.getStatus();
updateCanvas(status);
updateButtons(status);
master.after(1000, updateStatus);

# borderwidth is internal border
f = Frame(master, height=320, width=400, borderwidth=10, highlightbackground="red", highlightthickness=0);
f.pack_propagate(0); # don't shrink
f.pack();

actions = socketfns.getActions();
row = 0;

for ac in actions:
t0 = Label(f, height=1, width=30, text=ac);
t0.grid(row=row, column=0);
# t0.insert(END, "task1");

c0 = Canvas(f,
width=20,
height=10,
bg="grey");
c0.grid(row=row, column=2);

b0 = Button(f, text="on/off", state=DISABLED, command=lambda bac=ac: btnCallback(bac));
b0.grid(row=row, column=1);
row = row + 1;

master.after(1000, updateStatus);
mainloop();


227 changes: 227 additions & 0 deletions user_scripts/server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
#!/usr/bin/env python

import threading;
import socket;
import time;
import json;
import os;
import os.path;
import requests;
import subprocess;

AtDesy = False;
HOST = '' # all nics
PORT = 8889; # Port to listen on (non-privileged ports are > 1023)

# Thread;
# The Protocol:
# the sender transmits a json dictionary which has
# "cmd:" ->
# gettasks
# querystatus
# start
# stop
#
# The server sends back the same json dictionary with some things appended:
# "tasks:" - an array of tasks available
# "taskstatus:" - a dictionary of tasks to status
# you can add your own task: add a unique name in the list of tasks, and specify the
# getOnScript, getOffScript. The script should return an exit-code: 0 means success.
tasks = ["turn on wiener", "power to PwB", "check voltages1", "power to head", "check voltages2", "head operational", "check voltages3", "digtest1", "check voltages4"];
# task states can be not done, done, doing and undoing.
if AtDesy:
tasks[0] = "check voltages0";

def getOnScript(task):
if task == "turn on wiener":
return "./user_scripts/wiener/mainswitchON.sh";
if task == "power to PwB":
return "./user_scripts/wiener/pwb_UP.sh";
if task == "power to head":
return "./DESY/W3C3/user_scripts/DLS_POWERUP_000_unix.sh";
if task == "head operational":
return "./DESY/W3C3/user_scripts/DLS_FSI07_FromSysPowON_ToSeq_3T_PGAB_10Img_12ms_0802g_PLL120MHz_ADC25MHz.sh";
if task == "digtest1":
return "./DESY/W3C3/user_scripts/DLS_digTest1_RESET_DATA_SYNCH_STATUS_unix.sh";
if task == "check voltages0":
return "./user_scripts/wiener/checkcurrents.py -voltageszero";
if task == "check voltages1":
return "./user_scripts/wiener/checkcurrents.py -voltages -pwbon";
if task == "check voltages2" or task == "check voltages3" or task == "check voltages4":
return "./user_scripts/wiener/checkcurrents.py -voltages -headon";
return "errorunknowntask";

def getOffScript(task):
if task == "turn on wiener":
return "./user_scripts/wiener/mainswitchOFF.sh";
if task == "power to PwB":
return "./user_scripts/wiener/pwb_DOWN.sh";
if task == "power to head":
return "./DESY/W3C3/user_scripts/DLS_POWERDOWN_000_unix.sh";
if task == "head operational":
return "./DESY/W3C3/user_scripts/DLS_FSI07_FromSeq0802g_ToSysPowON_unix.sh";
if task == "digtest1":
return "pwd";
if task == "check voltages0":
return "./user_scripts/wiener/checkcurrents.py -voltageszero";
if task == "check voltages1":
return "./user_scripts/wiener/checkcurrents.py -voltages -pwbon";
if task == "check voltages2" or task == "check voltages3" or task == "check voltages4":
return "./user_scripts/wiener/checkcurrents.py -voltages -headon";
return "errorUnknownTask";

Go = True;

class myServer:
def __init__(self):
self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM);
self._sock.bind((HOST, PORT));
self._sock.listen(1);
self._sock.settimeout(0.2);
# nb the socket prevents two servers running on the same system
self._taskstates = {};
self._mythread = threading.Thread();
for task in tasks:
self._taskstates[task] = "not done";

def __del__(self):
print "closing server";
if self._mythread and self._mythread.isAlive():
self._mythread.join();
self._sock.close();

def doTask(self, task):
print "DOING TASK ", task;
script = getOnScript(task);
if 0<=len(script):
print "running ", script;
rc = os.system(script);
if rc:
print "task failed", task;
self._taskstates[task] = "not done";
else:
print "done task: ", task;
self._taskstates[task] = "done";

def undoTask(self, task):
print "UNDOING TASK ", task;
script = getOffScript(task);
if 0<=len(script):
print "running ", script;
rc = os.system(script);
if rc:
print "script failed", task;
self._taskstates[task] = "done";
else:
print "undone task: ", task;
self._taskstates[task] = "not done";

def doOnce(self):
global Go;
# what is crucial is that only one client can connect at any time, and that client
# can not alter the state in an unsafe manner. Safe movements are moving from one
# state to the next/previous only.
try:
conn, addr = self._sock.accept();
except:
return;

try:
# print('Connected by', addr);
data = conn.recv(1024);
# print "got data from " , conn;
# print data;

di = json.loads(data);
if di.has_key("cmd:"):
cmd = di["cmd:"];
if cmd=="gettasks":
# print "GETTING TASKS";
di["tasklist:"] = tasks;
elif cmd=="querystatus":
di["status:"] = self._taskstates;
elif cmd=="start" or cmd=="stop" or cmd=="toggle":
if di.has_key("task:") and di["task:"] in tasks:
task = di["task:"];
tidx = tasks.index(task);
tstatus = self._taskstates[task];

if(cmd=="toggle" and self._taskstates[task]=="done"):
cmd = "stop";
if(cmd=="toggle" and self._taskstates[task]=="not done"):
cmd = "start";

print "TASK ", tidx, task, cmd;
# to do a task, two checks are made:
# firstly that the task itself is in state done/notdone
# secondly that the prev task is done, and the next task is not done.
# The tasks form a chain and you can only alter the one at the end of the done chain.
canDoTask = (tstatus == "not done");
canUndoTask = (tstatus == "done");

if 0 < tidx:
prevtask = tasks[tidx-1];
canUndoTask &= (self._taskstates[prevtask] == "done");
canDoTask &= (self._taskstates[prevtask] == "done");
if tidx+1 < len(tasks):
nexttask = tasks[tidx+1];
canUndoTask &= (self._taskstates[nexttask] == "not done");
canDoTask &= (self._taskstates[nexttask] == "not done");

if cmd=="start" and canDoTask:
self._taskstates[task] = "doing";
self._mythread = threading.Thread(target=self.doTask, args=(task,));
self._mythread.daemon = True; # thread dies when prog exits
self._mythread.start();
if cmd=="stop" and canUndoTask:
self._taskstates[task] = "undoing";
self._mythread = threading.Thread(target=self.undoTask, args=(task,));
self._mythread.daemon = True; # thread dies when prog exits
self._mythread.start();
elif cmd=="shutdown":
Go = False;

ji = json.dumps(di);
conn.send(ji);
except:
pass;

conn.close();

print "hello.\nchecking odin_server is started";
# need to check that odin_server is available. This is usually on localhost:8888
response = requests.get("http://localhost:8888");
if response.status_code != 200:
exit(1);

print "check cur dir is percivalui";
if os.path.basename(os.getcwd())!="percivalui":
print "fail";
exit(2);

wnr = subprocess.check_output("user_scripts/wiener/querymainswitch.sh");
if AtDesy:
print "check wiener is ON";
if "on" not in wnr:
print "error: wiener is off; you need to load the carrier board firmware";
exit(4);
else:
print "check wiener is OFF";
if "off" not in wnr:
print "error: wiener is on";
exit(3);

print "check venv contains percivalui";
rc = os.system("pip show percivalui");
if rc!=0:
print "error can't find percivalui in python venv";
exit(4);

print "checks passed";
serv = myServer();
while Go:
serv.doOnce();

print "SHUTTING DOWN";


0 comments on commit c70e5a8

Please sign in to comment.