UNPKG

botnanajs

Version:

Botnana Control API for Javascript

567 lines (498 loc) 12.5 kB
"use strict"; var botnana = { sender: null, debug_level: 1, _: {} }; // Events API botnana.do_nothing = function() {}; botnana.do_nothing.nothing = true; botnana.handlers = {}; botnana.handler_counters = {}; botnana.times = function(event, handler, count) { let handlers = botnana.handlers; let handler_counters = botnana.handler_counters; if (!handlers[event]) { handlers[event] = [handler]; handler_counters[event] = [count]; } else { let found = handlers[event].length; for (let h in handlers[event]) { if (handlers[event][h] === botnana.do_nothing) { found = h; handlers[event][h] = handler; handler_counters[event][h] = count; break; } } if (found === handlers[event].length) { handlers[event].push(handler); handler_counters[event].push(count); } } }; botnana.on = function(event, handler) { botnana.times(event, handler, 0); }; botnana.once = function(event, handler) { botnana.times(event, handler, 1); }; botnana.handle_response = function(resp) { let lines = resp.split("\n"); for (let j = 0; j < lines.length; j = j + 1) { if (botnana.debug_level > 0 && lines[j].length) { console.log(lines[j]); } let r = lines[j].split("|"); for (let i = 0; i < r.length; i = i + 2) { let event = r[i]; let handlers = botnana.handlers[event]; let handler_counters = botnana.handler_counters[event]; if (handlers) { let data = r[i + 1]; for (let h in handlers) { handlers[h](data); if (handler_counters[h] >= 1) { --handler_counters[h]; if (handler_counters[h] === 0) { handlers[h] = botnana.do_nothing; } } } } } } }; botnana.poll = function() { var json = { jsonrpc: "2.0", method: "motion.poll" }; botnana.sender.send(JSON.stringify(json)); }; // Version API botnana.version = { get: function() { var json = { jsonrpc: "2.0", method: "version.get" }; botnana.sender.send(JSON.stringify(json)); } }; // Real-time scripting API botnana.motion = {}; botnana.motion.evaluate = function(script) { var json = { jsonrpc: "2.0", method: "motion.evaluate", params: { script: script } }; botnana.sender.send(JSON.stringify(json)); }; botnana.programs = []; botnana.empty = function() { botnana.motion.evaluate("empty"); }; const WAITING_NONE = 0; const WAITING_REQUESTS = 1; const WAITING_TARGET_REACHED = 2; class ProgrammedEtherCATSlave { constructor(program, i) { this.program = program; this.position = i; this.state = WAITING_NONE; } hm() { if (this.state == WAITING_TARGET_REACHED) { this.until_target_reached(); } this.program.lines.push("hm " + this.position + " op-mode!"); this.state = WAITING_REQUESTS; } pp() { if (this.state == WAITING_TARGET_REACHED) { this.until_target_reached(); } this.program.lines.push("pp " + this.position + " op-mode!"); this.state = WAITING_REQUESTS; } move_to(target) { this.program.lines.push(target + " " + this.position + " jog"); } go() { if (this.state == WAITING_REQUESTS) { this.until_no_requests(); } this.program.lines.push(this.position + " go"); this.state = WAITING_TARGET_REACHED; } until_target_reached() { this.program.lines.push(this.position + " until-target-reached"); this.state = WAITING_NONE; } until_no_requests() { this.program.lines.push("until-no-requests"); this.state = WAITING_NONE; } disable_aout(channel) { this.program.lines.push(channel + " " + this.position + " -ec-aout"); this.state = WAITING_REQUEST; } disable_ain(channel) { this.program.lines.push(channel + " " + this.position + " -ec-ain"); this.state = WAITING_REQUEST; } enable_aout(channel) { this.program.lines.push(channel + " " + this.position + " +ec-aout"); this.state = WAITING_REQUEST; } enable_ain(channel) { this.program.lines.push(channel + " " + this.position + " +ec-ain"); this.state = WAITING_REQUEST; } set_aout(channel, value) { this.program.lines.push( value + " " + channel + " " + this.position + " ec-aout!" ); this.state = WAITING_NONE; } set_dout(channel, t) { this.program.lines.push( t + " " + channel + " " + this.position + " ec-dout!" ); this.state = WAITING_NONE; } aout(channel) { this.program.line.push(channel + " " + this.position + " ec-aout@"); this.state = WAITING_NONE; return this; } dout(channel) { this.program.lines.push(channel + " " + this.position + " ec-dout@"); this.state = WAITING_NONE; return this; } ain(channel) { this.program.lines.push(channel + " " + this.position + " ec-ain@"); this.state = WAITING_NONE; return this; } din(channel) { this.program.lines.push(channel + " " + this.position + " ec-din@"); this.state = WAITING_NONE; return this; } IF() { this.program.lines.push(" if"); this.state = WAITING_NONE; } ELSE() { this.program.lines.push(" else"); this.state = WAITING_NONE; } THEN() { this.program.lines.push(" then"); this.state = WAITING_NONE; } BEGIN() { this.program.lines.push(" begin"); this.state = WAITING_NONE; } WHILE() { this.program.lines.push(" while"); this.state = WAITING_NONE; } REPEAT() { this.program.lines.push(" pause repeat"); this.state = WAITING_NONE; } /*UNTIL() { this.program.lines.push(" until"); this.state = WAITING_NONE; } DO() { this.program.lines.push(" do"); this.state = WAITING_NONE; } LOOP() { this.program.lines.push(" loop"); this.state = WAITING_NONE; } AGAIN() { this.program.lines.push(" again"); this.state = WAITING_NONE; }*/ GT(value) { this.program.lines.push(value + " >"); this.state = WAITING_NONE; } GE(value) { this.program.lines.push(value + " 2dup > >R = R> or"); this.state = WAITING_NONE; } LT(value) { this.program.lines.push(value + " <"); this.state = WAITING_NONE; } LE(value) { this.program.lines.push(value + " 2dup < >R = R> or"); this.state = WAITING_NONE; } EQ(value) { this.program.lines.push(value + " ="); this.state = WAITING_NONE; } NE(value) { this.program.lines.push(value + " = not"); this.state = WAITING_NONE; } } class Program { constructor(name) { var that = this; this.name = name; botnana.programs.push(this); this.lines = [": " + "user$" + name]; this.ethercat = {}; this.ethercat._slaves = []; for (var i = 1; i <= botnana.ethercat.slave_count; i = i + 1) { this.ethercat._slaves[i] = new ProgrammedEtherCATSlave(this, i); } this.ethercat.slave = function(n) { return that.ethercat._slaves[n]; }; } deploy() { for (var i = 1; i <= botnana.ethercat.slave_count; i = i + 1) { let slave = this.ethercat._slaves[i]; if (slave.state === WAITING_REQUESTS) { slave.until_no_requests(); } if (slave.state === WAITING_TARGET_REACHED) { slave.until_target_reached(); } slave.state = WAITING_NONE; } this.lines.push("end-of-program ;"); var params = { script: this.lines.join("\n") }; var json = { jsonrpc: "2.0", method: "script.deploy", params: params }; if (botnana.debug_level > 0) { console.log("Generated program for " + this.name + ":"); console.log(params.script); } botnana.sender.send(JSON.stringify(json)); } run() { botnana.motion.evaluate("deploy user$" + this.name + " ;deploy"); } ms(value) { this.program.lines.push(value + " ms"); } abort_program() { botnana.motion.evaluate("kill-task0"); } println(str) { this.program.lines.push(str); } } botnana.Program = Program; /// Hidden API botnana._.get_slaves = function() { var json = { jsonrpc: "2.0", method: "_.get_slaves" }; botnana.sender.send(JSON.stringify(json)); }; // Slave API class Slave { constructor(p, i, c, o) { this.position = p; this.vendor_id = i; this.product_code = c; this.old_pds_state = o; //vendor id & product code // is_drive // pds_state // old_pds_state } set(tag, value) { var json = { jsonrpc: "2.0", method: "ethercat.slave.set", params: { position: this.position, tag: tag, value: value } }; botnana.sender.send(JSON.stringify(json)); } get() { var json = { jsonrpc: "2.0", method: "ethercat.slave.get", params: { position: this.position } }; botnana.sender.send(JSON.stringify(json)); } get_diff() { var json = { jsonrpc: "2.0", method: "ethercat.slave.get_diff", params: { position: this.position } }; botnana.sender.send(JSON.stringify(json)); } reset_fault() { var json = { jsonrpc: "2.0", method: "ethercat.slave.reset_fault", params: { position: this.position } }; botnana.sender.send(JSON.stringify(json)); } set_dout(channel, value) { var json = { jsonrpc: "2.0", method: "ethercat.slave.set_dout", params: { position: this.position, channel: channel, value: value } }; botnana.sender.send(JSON.stringify(json)); } disable_aout(channel) { var json = { jsonrpc: "2.0", method: "ethercat.slave.disable_aout", params: { position: this.position, channel: channel } }; botnana.sender.send(JSON.stringify(json)); } enable_aout(channel) { var json = { jsonrpc: "2.0", method: "ethercat.slave.enable_aout", params: { position: this.position, channel: channel } }; botnana.sender.send(JSON.stringify(json)); } set_aout(channel, value) { var json = { jsonrpc: "2.0", method: "ethercat.slave.set_aout", params: { position: this.position, channel: channel, value: value } }; botnana.sender.send(JSON.stringify(json)); } disable_ain(channel) { var json = { jsonrpc: "2.0", method: "ethercat.slave.disable_ain", params: { position: this.position, channel: channel } }; botnana.sender.send(JSON.stringify(json)); } enable_ain(channel) { var json = { jsonrpc: "2.0", method: "ethercat.slave.enable_ain", params: { position: this.position, channel: channel } }; botnana.sender.send(JSON.stringify(json)); } } botnana.ethercat = {}; botnana.ethercat._slaves = []; botnana.ethercat.slave = function(n) { if (1 <= n && n <= botnana.ethercat._slaves.length) { return botnana.ethercat._slaves[n - 1]; } else { console.log("Invalid slave index " + n + "."); } }; // Configuration API botnana.config = { save: function() { var json = { jsonrpc: "2.0", method: "config.save" }; botnana.sender.send(JSON.stringify(json)); }, set_slave: function(args) { var json = { jsonrpc: "2.0", method: "config.set_slave", params: args }; botnana.sender.send(JSON.stringify(json)); } }; // Start API botnana.start = function(ip, period) { period = period | 100; var WebSocket = require("ws"); var ws = new WebSocket(ip); console.log("opening websocket..."); ws.on("open", function() { console.log("websocket opened."); botnana.sender = ws; botnana._.get_slaves(); console.log("polling for every " + period + "ms."); setInterval(botnana.poll, period); ws.on("message", function(data, flags) { if (data) { // if (botnana.debug_level > 0) { // console.log(data); // } botnana.handle_response(data); } }); botnana.once("slaves", function(slaves) { let s = slaves.split(","); let slave_count = s.length / 2; // console.log("slave count: " + slave_count); botnana.ethercat.slave_count = slave_count; for (var i = 0; i < slave_count; i = i + 1) { botnana.ethercat._slaves[i] = new Slave(i + 1); } botnana.handle_response("ready|ok"); }); }); }; module.exports = botnana;