diff --git a/GUI/server/odrive_server.py b/GUI/server/odrive_server.py index 717c5f40..9f8b15d1 100644 --- a/GUI/server/odrive_server.py +++ b/GUI/server/odrive_server.py @@ -24,21 +24,21 @@ CORS(app, support_credentials=True) Payload.max_decode_packets = 100 socketio = SocketIO(app, cors_allowed_origins="*", async_mode = "threading") -def get_all_odrives(): +def get_odrive(): globals()['odrives'] = [] globals()['odrives'].append(odrive.find_any()) globals()['odrives'][0].__channel__._channel_broken.subscribe(lambda: handle_disconnect()) + print("odrives found") + socketio.emit('odrive-found') def handle_disconnect(): - print("lost odrive, attempting to reconnect") - # synchronizing flag for connect/disconnect - globals()['inUse'] = True - globals()['odrives'] = [] - while len(globals()['odrives']) == 0: - get_all_odrives() - time.sleep(0.1) - globals()['inUse'] = False - print("reconnected!") + print("lost odrive, emitting disconnect event to client") + socketio.emit('odrive-disconnected') + +@socketio.on('findODrives') +def getODrives(message): + print("looking for odrive") + get_odrive() @socketio.on('enableSampling') def enableSampling(message): @@ -193,8 +193,6 @@ def callFunc(odrives, keyList): print("fcn call failed") if __name__ == "__main__": - # sleep to allow time for background.js to register event callbacks for stdout,stderr - time.sleep(3) print("args from python: " + str(sys.argv[1:0])) #print(sys.argv[1:]) # try to import based on command line arguments or config file @@ -212,11 +210,11 @@ if __name__ == "__main__": globals()['inUse'] = False # busy wait for connection - while len(globals()['odrives']) == 0: - print("looking for odrives...") - get_all_odrives() + #while len(globals()['odrives']) == 0: + # print("looking for odrives...") + # get_odrive() - print("found odrives!") - globals()['connected'] = True + #print("found odrives!") + #globals()['connected'] = True socketio.run(app, host='0.0.0.0', port=5000) diff --git a/GUI/src/App.vue b/GUI/src/App.vue index b0de8945..3e5eaf3f 100644 --- a/GUI/src/App.vue +++ b/GUI/src/App.vue @@ -46,6 +46,8 @@ style="display: none" /> + + @@ -63,6 +65,9 @@ :axis="axis.name" :odrives="odrives" > +
+ ODrive:{{ODriveConnected}} +
@@ -133,6 +138,22 @@ export default { currentDash: function () { return this.$store.state.currentDash; }, + ODriveConnected: function () { + // if server and odrive disconnected, disconnected + // if server connected and odrive disco, connecting + // if server and odrive connected, connected + let ret; + if (this.$store.state.serverConnected && this.$store.state.ODriveConnected) { + ret = "connected"; + } + else if (this.$store.state.serverConnected && !this.$store.state.ODriveConnected) { + ret = "connecting..."; + } + else { + ret = "disconnected"; + } + return ret; + } }, methods: { changeDash(dashName) { @@ -234,6 +255,19 @@ export default { // send stop command to odrives // behavior on reset? }, + emitFindODrives() { + socketio.sendEvent({ + type: "findODrives", + data: {}, + }); + }, + killServer() { + window.ipcRenderer.send('kill-server'); + }, + startServer() { + window.ipcRenderer.send('start-server'); + this.$store.dispatch("setServerAddress", "http://127.0.0.1:5000"); + } }, created() { // on app creation, set the address to the default @@ -247,6 +281,7 @@ export default { window.ipcRenderer.on('server-stderr', (event, arg) => { this.$store.commit('logServerMessage', arg); }); + window.ipcRenderer.send('start-server'); } }, }; @@ -356,4 +391,10 @@ button { margin-left: auto; } +.odrive-status { + margin-left: auto; + font-family: "Roboto Mono", monospace; + padding: 5px 10px; +} + diff --git a/GUI/src/background.js b/GUI/src/background.js index 5fde0c34..368b01ef 100644 --- a/GUI/src/background.js +++ b/GUI/src/background.js @@ -104,7 +104,7 @@ app.on('ready', async () => { } } createWindow() - // Spawn the python server + // Figure out correct path and arguments to launch python server let scriptFilename = path.join(app.getAppPath(), '../server', 'odrive_server.py'); const args = process.argv; let effectiveCommand = []; @@ -119,15 +119,22 @@ app.on('ready', async () => { effectiveCommand.push(arg); } } - var python = spawn(getPyCmd(), effectiveCommand); - python.stdout.on('data',function(data) { - console.log(data.toString('utf8')); - win.webContents.send('server-stdout', String(data.toString('utf8'))); - }); - python.stderr.on('data',function(data) { - console.log(data.toString('utf8')); - win.webContents.send('server-stderr', String(data.toString('utf8'))); - }); + var python; + // launch python server on event from renderer process (gui) and pipe stdout/stderr to it + ipcMain.on('start-server', () => { + python = spawn(getPyCmd(), effectiveCommand); + python.stdout.on('data',function(data) { + console.log(data.toString('utf8')); + win.webContents.send('server-stdout', String(data.toString('utf8'))); + }); + python.stderr.on('data',function(data) { + console.log(data.toString('utf8')); + win.webContents.send('server-stderr', String(data.toString('utf8'))); + }); + }) + ipcMain.on('kill-server', () => { + python.kill('SIGINT'); + }) }) // Exit cleanly on request from parent process in development mode. diff --git a/GUI/src/lib/odrive_utils.js b/GUI/src/lib/odrive_utils.js index 20eb82c4..9d64d91d 100644 --- a/GUI/src/lib/odrive_utils.js +++ b/GUI/src/lib/odrive_utils.js @@ -24,10 +24,12 @@ export function getReadonly(path) { } export function fetchParam(path) { - socketio.sendEvent({ - type: "getProperty", - data: {path: path}, - }); + if (store.state.serverConnected){ + socketio.sendEvent({ + type: "getProperty", + data: {path: path}, + }); + } } export function putVal(path, value) { diff --git a/GUI/src/store.js b/GUI/src/store.js index 33721655..2bd55814 100644 --- a/GUI/src/store.js +++ b/GUI/src/store.js @@ -21,6 +21,7 @@ export default new Vuex.Store({ axes: Array, odriveServerAddress: String, serverConnected: Boolean, + ODriveConnected: false, serverOutput: [], dashboards: [ { @@ -157,6 +158,9 @@ export default new Vuex.Store({ setServerStatus(state, val) { state.serverConnected = val; }, + setODriveConnected(state, val) { + state.ODriveConnected = val; + }, removeCtrlFromDash(state, obj) { // obj is {dash: dashID, path: control path} for (const dash of state.dashboards) { @@ -306,9 +310,20 @@ export default new Vuex.Store({ callback: () => { context.commit("setServerStatus", true); console.log('connected to server'); - context.dispatch("getOdrives"); + //context.dispatch("getOdrives"); + socketio.sendEvent({ + type: "findODrives", + }); } }); + socketio.addEventListener({ + type: "odrive-found", + callback: () => { + console.log("odrive-found recieved from server"); + context.commit("setODriveConnected", true); + context.dispatch("getOdrives"); + } + }) socketio.addEventListener({ type: "disconnect", callback: () => { @@ -348,6 +363,17 @@ export default new Vuex.Store({ context.commit('updateOdriveProp', JSON.parse(retmsg)); } }); + socketio.addEventListener({ + type: "odrive-disconnected", + callback: () => { + console.log("odrive disconnected"); + context.commit("setODriveConnected", false); + console.log("restarting server..."); + window.ipcRenderer.send('kill-server'); + window.ipcRenderer.send('start-server'); + context.dispatch('setServerAddress', context.state.odriveServerAddress); + } + }) } } }) \ No newline at end of file