import {Logger} from './../function/log-helper.js';
import {ErrorCode, ExceptionIdMap} from '../exception/exceptionDesc.js';
import {InfoType, WarningType} from '../information/informationCode.js';
import {isChromiumBased, isInAppStudio} from '../utils/utils.js';
/**
* API Namespace
* @namespace API
*/
const API = {};
// @ts-expect-error TODO: fix this
const factoryApiBase = function (es) {
es.verbose = false;
const logModule = 'ecosystem-base';
/**
* @alias init - called when window 'load' event occurs
* @memberof API
* @private
*/
es.init = async () => {
// await API.CONTROLLER._init()
window.addEventListener('error', (e) => {
Logger.e(logModule, ErrorCode.WindowErrorEvent, e);
});
window.addEventListener('unhandledrejection', (evt) => {
Logger.e(logModule, ErrorCode.WindowUnhandledRejectionEvent, 'undandledrejection!!!!', evt, evt.reason);
});
window.addEventListener('uncaughtException', (error) => {
Logger.e(logModule, ErrorCode.WindowUnCaughtExceptionEvent, 'uncaughtException', error);
});
};
window.addEventListener('load', es.init, false);
es.__unload = false;
/**
* Clean up when the web page is closed
*/
window.addEventListener(
'beforeunload',
() => {
es.__unload = true;
return null;
},
false,
);
/**
* Modifies an Error so it can be used with JSON.strigify
* @alias replaceErrors
* @memberof API
* @private
* @param {any} key
* @param {any} value
* @returns {object}
*/
const replaceErrors = function (key, value) {
if (value instanceof Error) {
var error = {};
Object.getOwnPropertyNames(value).forEach(function (propName) {
error[propName] = value[propName];
});
return error;
}
return value;
};
/**
* Builds an status object.
* @alias createStatusObject
* @memberof API
* @private
* @param {string} message
* @param {Error | object | string} item
*/
function createStatusObject(message, item = {}) {
let r = {};
try {
let msg = '';
if (typeof message === 'string') msg = message;
r.message = msg;
if (item instanceof Error) {
if (r.message.length <= 0) r.message = `Exception: ${item.message}`;
else r.message += ` >>> Exception: ${item.message}`;
} else if (typeof item === 'string') {
if (r.message.length <= 0) r.message = item;
else r.message += ` >>> ${item}`;
} else if (Object.prototype.hasOwnProperty.call(item, 'message')) {
r = JSON.parse(JSON.stringify(item));
r.message = msg;
if (typeof item.message === 'string' && item.message.length > 0) r.message += ` >>> ${item.message}`;
}
} catch (error) {
r = {};
r.message = `Failed to create status object. >>> Exception: ${error.message}`;
}
return r;
}
/**
* Checks if input is a non empty string
* @alias isNonEmptyString
* @memberof API
* @private
* @param {any} x - String to be evaluated
* @returns {boolean}
*/
const isNonEmptyString = (x) => {
if (x === null) return false;
if (typeof x !== 'string') return false;
if (x === '') return false;
if (x === 'undefined') return false;
return true;
};
/**
* Disable monitor and variable subscriptions.
* @param {} value
*/
es.blockSubscription = (value = true) => {
es.isSubscriptionBlocked = value;
};
/**
* Disable fetch controller requests.
* @param {} value
*/
es.blockFetchController = (value = true) => {
es.isFetchControllerBlocked = value;
};
/**
* Rejects with status object.
* @alias rejectWithStatus
* @memberof API
* @private
* @param {string} message
* @param {any} item
* case 1: a custom Error instance without valid ErrorCode: new Error('Incorrect dimension number')
* case 2: the result returned by API.rejectWithStatus with valid ErrorCode
* case 3: a custom Error instance with valid ErrorCode
* @param {object | string} errInfo
* @param {string} errInfo.errorCode - The API error code. (legacy: can be passed directly as a string)
* @param {object} errInfo.msgParams - Translation parameters for the message, which can be used in i18n message templates
* @param {string} errInfo.severity - The severity of the error
* @returns {Promise<never>} A rejected Promise with an Error instance
*
* Behavior notes:
* - If `item` is an `Error` and `item.message` is a known `ErrorCode`, it will be rejected directly without wrapping.
* This is used to pass through Errors that already come from `rejectWithStatus` (or any Error created with an `ErrorCode` message).
* - Otherwise, a new `Error(errInfo.errorCode, {cause: statusObject})` is created and rejected.
*/
es.rejectWithStatus = function (
message,
item = {},
errInfo = {errorCode: ErrorCode.APIRejectedWithStatus, msgParams: {}, severity: 'warning'},
) {
const isKnownErrorCode = (maybeCode) => {
if (!isNonEmptyString(maybeCode)) return false;
return Object.prototype.hasOwnProperty.call(ErrorCode, maybeCode);
};
const normalizedErrInfo = typeof errInfo === 'string' ? {errorCode: errInfo} : errInfo || {};
const errorCode = isNonEmptyString(normalizedErrInfo.errorCode)
? normalizedErrInfo.errorCode
: ErrorCode.APIRejectedWithStatus;
const msgParams =
normalizedErrInfo.msgParams && typeof normalizedErrInfo.msgParams === 'object' ? normalizedErrInfo.msgParams : {};
const severity = isNonEmptyString(normalizedErrInfo.severity) ? normalizedErrInfo.severity : 'warning';
if (es.verbose) {
Logger.i(logModule, message);
Logger.e(logModule, item);
}
if (item instanceof Error) {
if (isKnownErrorCode(item.message)) {
return Promise.reject(item);
} else {
const r = createStatusObject(message, item);
item.message = errorCode;
item.cause = r;
return Promise.reject(item);
}
}
let r = createStatusObject(message, item);
const errInst = new Error(errorCode);
errInst.cause = r; // to be compatibile with standard mode
errInst.msgParams = msgParams;
errInst.severity = severity;
return Promise.reject(errInst);
};
/**
* Displays warning popup with specified exception ID.
* @alias showWarning
* @memberof API
* @private
* @param {string} exceptionId - The exception ID from ExceptionIdMap
* @example
* API.showWarning(ExceptionIdMap.MissPermissionsToJog);
*/
es.showWarning = function (exceptionId) {
TComponents.Popup_A.warning(
`${exceptionId}-${TComponents.Component_A.t(`framework:${exceptionId}.title`)}`,
TComponents.Component_A.t(`framework:${exceptionId}.description`),
);
};
/**
* Returns true if running in TPU environment
* @alias isTPU
* @memberof API
* @returns {boolean}
* @example
* let bInTPU = API.isTPU()
*/
es.isTPU = function () {
return RWS.isTPUWebView();
};
/**
* Returns true if running in a webview environment
* @alias isWebView
* @memberof API
* @returns {boolean}
* @example
* let bInWebView = API.isWebView()
*/
es.isWebView = function () {
return (
('chrome' in window && 'webview' in window.chrome && 'postMessage' in window.chrome.webview) ||
('external' in window && 'notify' in window.external) ||
'_omnipanel_type_1' in window ||
('hybridWebViewHost' in window && 'sendMessage' in window.hybridWebViewHost)
);
};
/**
* Generates a UUIDs (Universally Unique Identifier)
* @alias generateUUID
* @memberof API
* @returns {string} UUID
* @example
* let uuid = API.generateUUID()
*/
// https://stackoverflow.com/questions/105034/how-do-i-create-a-guid-uuid/
es.generateUUID = () => {
// Public Domain/MIT
var d = new Date().getTime(); //Timestamp
var d2 = (typeof performance !== 'undefined' && performance.now && performance.now() * 1000) || 0; //Time in microseconds since page-load or 0 if unsupported
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = Math.random() * 16; //random number between 0 and 16
if (d > 0) {
//Use timestamp until depleted
r = (d + r) % 16 | 0;
d = Math.floor(d / 16);
} else {
//Use microseconds since page-load if supported
r = (d2 + r) % 16 | 0;
d2 = Math.floor(d2 / 16);
}
return (c === 'x' ? r : (r & 0x3) | 0x8).toString(16);
});
};
/**
* Asynchronous sleep function
* @alias sleep
* @memberof API
* @param {number} ms - Time in miliseconds
* @returns {Promise}
* @example
* await API.sleep(1000);
*/
es.sleep = (ms) => {
return new Promise((resolve) => setTimeout(resolve, ms));
};
/**
* Asynchronous formatValue function
* @alias formatValue
* @memberof API
* @param {any} value The value to be formatted.
* @returns {any}
* @example
* API.formatValue("\"666\"");
*/
es.formatValue = (value) => {
if (typeof value == 'string' && value.startsWith('"') && value.endsWith('"')) {
return value.slice(1, -1);
}
return value;
};
/**
* Timeout function - this can be used with Promise.race to escape another asynchronous function which takes longer than the timeout
* @alias timeout
* @memberof API
* @param {number} ms - Time in miliseconds
* @private
*/
es.timeout = function (ms) {
return new Promise(function (_, reject) {
setTimeout(function () {
reject(new Error(`Request took too long! Timeout after ${ms} milisecond`));
}, ms);
});
};
/**
* Wait for a condition to be true. It can be used together with Promise.race and API.timeout to wait for a condition with timeout
* @alias waitForCondition
* @memberof API
* @param {function} func - Function containing the condition
* @param {API.waitForConditionOptions} interval_ms - Interval in miliseconds
* @param {API.waitForConditionOptions} timeout_ms - Timeout in miliseconds
*
* @returns {Promise}
* @example
await API.waitForCondition(async ()=>{
const state= await API.CONTROLLER.getControllerState() === API.CONTROLLER.STATE.MotorsOn;
console.log(state);
return state;
}, {interval_ms: 100, timeout_ms: 10000});
*/
es.waitForCondition = async function (func, {interval_ms = 100, timeout_ms = 10000} = {}) {
return new Promise((resolve, reject) => {
const startTime = Date.now();
const interval = setInterval(async () => {
try {
const res = await func();
if (res) {
clearInterval(interval);
resolve(true);
} else if (Date.now() - startTime >= timeout_ms) {
clearInterval(interval);
resolve(false);
}
} catch (error) {
clearInterval(interval);
reject();
}
}, interval_ms);
});
};
/**
* @class API.Events
* @memberof API
*/
es.Events = class Events {
constructor() {
this.events = {};
}
/**
* removes all the subscriptions with a given event name.
* @alias cleanEvents
* @memberof API.Events
* @param {string} eventName Optional Name of the event
*/
cleanEvents(eventName) {
if (eventName && this.events[eventName]) {
delete this.events[eventName];
} else {
this.events = {};
}
}
/**
* Subscribes to controller resource with a given event name
* @alias on
* @memberof API.Events
* @param {string} eventName Name of the event
* @param {function} callback Function to be called when event is triggered
*/
on(eventName, callback) {
if (typeof callback !== 'function') throw new Error('callback is not a valid function');
const handlers = this.events[eventName] || [];
if (handlers.some((h) => h === callback || (h && h._original && h._original === callback))) return;
handlers.push(callback);
this.events[eventName] = handlers;
}
/**
* @description Subscribe to an event, but the callback is called only once
* @alias once
* @memberof API.Events
* @method
* @param {string} eventName - Name of the triggering event
* @param {Function} callback - Function to be called when the event is triggered
* @returns {boolean} - True if the callback was added, false if it was already added
*/
once(eventName, callback) {
if (typeof callback !== 'function') throw new Error('callback is not a valid function');
const handlers = this.events[eventName] || [];
if (handlers.some((h) => h === callback || (h && h._original && h._original === callback))) return false;
const onceCallback = (...data) => {
try {
callback(...data);
} finally {
this.off(eventName, onceCallback);
}
};
// keep reference to original so off() can remove by original function
onceCallback._original = callback;
handlers.push(onceCallback);
this.events[eventName] = handlers;
return true;
}
/**
* Removes the subscriptions with a given event name.
* @alias off
* @memberof API.Events
* @param {string} eventName Name of the event.
* @param {Function} [callback] - Optional Function to be removed from the event's callbacks
* @returns {boolean} - True if the callback was removed, false if it was not found
*/
off(eventName, callback) {
const handlers = this.events[eventName];
if (!handlers || handlers.length === 0) {
return false;
}
if (callback) {
const index = handlers.findIndex((h) => h === callback || (h && h._original && h._original === callback));
if (index > -1) {
handlers.splice(index, 1);
return true;
}
return false;
} else {
this.events[eventName] = [];
return true;
}
}
/**
* Triggers all the callback functions that have subscribed to an event.
* @alias trigger
* @memberof API.Events
* @param {string} eventName - Name of the event to be triggered
* @param {any} data - Data passed to the callback as input parameter
*/
trigger(eventName, data = null) {
const handlers = this.events[eventName];
if (!handlers || handlers.length === 0) {
return;
}
const toCall = handlers.slice();
toCall.forEach((handler) => {
try {
handler(data);
} catch (e) {
Logger.e(logModule, ErrorCode.EventHandlerError, `Error in event handler for ${eventName}:`, e);
// swallow listener errors to avoid breaking other listeners
}
});
}
};
es._events = new es.Events();
/**
* The API.CONTROLLER class provides a set of interfaces for managing and monitoring the robot controller's motor status, operation modes,and other.
* It includes methods for subscribing to motor status, retrieving the current state or operation mode, and performing actions such as setting motor states or restarting the controller.
* This class serves as a high-level abstraction for interacting with the robot controller.
* @alias API.CONTROLLER
* @namespace
*/
es.CONTROLLER = new (function () {
/**
* @alias STATE
* @memberof API.CONTROLLER
* @readonly
* @enum {string}
* @property {enum} Init The controller is starting up.
* @property {enum} MotorsOn Motor on state.
* @property {enum} MotorsOff Motor off state.
* @property {enum} GuardStopS Stopped due to safety reasons.
* @property {enum} EStop Emergency stop state.
* @property {enum} EStopR Emergency stop state resetting.
* @property {enum} SysFailure System failure.
*/
this.STATE = {
/*the controller is starting up*/
Init: 'initializing',
/*motors on state*/
MotorsOn: 'motors_on',
/*motors off state*/
MotorsOff: 'motors_off',
/*stopped due to safety*/
GuardStop: 'guard_stop',
/*emergency stop state*/
EStop: 'emergency_stop',
/*emergency stop state resetting*/
EStopR: 'emergency_stop_resetting',
/*system failure state*/
SysFailure: 'system_failure',
};
/**
* @alias OPMODE
* @memberof API.CONTROLLER
* @readonly
* @enum {string}
* @property {enum} Auto Auto mode
* @property {enum} Manual Manual mode
* @property {enum} ManualR Manual reduce speed mode
* @property {enum} ManualFull Manual full speed mode
*/
this.OPMODE = {
Auto: 'automatic',
Manual: 'manual',
ManualR: 'manual_reduced',
ManualFull: 'manual_full',
};
/**
* @alias STATE
* @memberof API.CONTROLLER
* @readonly
* @enum {string}
*/
this.ROBOTTYPES = {
IRB14050: /IRB 14050/,
IRB1100: /IRB 1100/,
IRB910: /IRB 910/,
CRB1100: /CRB 1100/,
CRB15000: /CRB 15000/,
IRB1300: /IRB 1300/,
CRB1300: /CRB 1300/,
};
/**
* Gets the robot type. For example, CRB 15000-5/0.95.
* @alias getRobotType
* @memberof API.CONTROLLER
* @returns {Promise<string>} A promise object with a string presenting the robot type.
* @example
* let robotType = await API.CONTROLLER.getRobotType()
*/
this.getRobotType = async function () {
if (typeof this.robotType == 'undefined') {
this.robotType = await API.RWS.CONTROLLER.getRobotType();
}
return this.robotType;
};
/**
* Check whether the connected robot is IRB 14050
* @alias isSAY
* @memberof API.CONTROLLER
* @returns {Promise<boolean>} A promise object with a boolean value indicating whether the robot is IRB 14050.
* @example
* let isSAY = await API.CONTROLLER.isSAY()
*/
this.isSAY = async function () {
let robotType = await this.getRobotType();
return API.CONTROLLER.ROBOTTYPES.IRB14050.test(robotType);
};
/**
* @memberof API.CONTROLLER
* @param {RWS.Controller.MonitorResources} res
* @param {Function} func
* @returns {Promise<{}>}
* @private
*/
const subscribeRes = async function (res, func) {
if (es.isSubscriptionBlocked) {
Logger.w(WarningType.RWSSubscriptionBlocked, 'API.CONTROLLER: Subscription disabled.');
return;
}
const monitor = RWS.Controller.getMonitor(res);
monitor.addCallbackOnChanged(func);
await monitor.subscribe();
};
/**
* Subscribes to 'operation-mode'. Current state is stored in
* {@link opMode}. Additionally, {@link isManReduced}
* is updated with the corresponding value.
* @alias monitorOperationMode
* @memberof API.CONTROLLER
* @param {function} [callback] - Callback function is called when operation mode changes
* @example
* // The callback will be executed when operation mode is changed
* const opMode = (value)=>{console.log("operation mode is:",value);}
* await API.CONTROLLER.monitorOperationMode(opMode);
*/
this.monitorOperationMode = async function (callback = null) {
Logger.i(InfoType.RobotOperation, 'Trying to monitor operation mode');
if (this.opMode === undefined) {
try {
/**
* @alias opMode
* @memberof API.CONTROLLER
* @property {boolean} opMode Stores the operation mode.
* This property is available only after calling API.CONTROLLER.monitorController()
*/
this.opMode = await RWS.Controller.getOperationMode();
/**
* @alias isManual
* @memberof API.CONTROLLER
* @property {boolean} isManual true if operation mode is manual reduced speed mode, false otherwiseValue "true" indicates that the operation mode is manual reduce. In other cases, the value is "false".
* This property is available only after calling API.CONTROLLER.monitorController()
*/
this.isManual = this.opMode === API.CONTROLLER.OPMODE.ManualR ? true : false;
/**
* @alias isAuto
* @memberof API.CONTROLLER
* @property {boolean} isAuto Value "true" indicates that the operation mode is Auto mode. In other cases, the value is "false".
* This property is available only after calling API.CONTROLLER.monitorController()
*/
this.isAuto = this.opMode === API.CONTROLLER.OPMODE.Auto ? true : false;
const cbOpMode = function (data) {
this.opMode = data;
data === API.CONTROLLER.OPMODE.ManualR ? (this.isManual = true) : (this.isManual = false);
data === API.CONTROLLER.OPMODE.Auto ? (this.isAuto = true) : (this.isAuto = false);
es._events.trigger('op-mode', data);
Logger.i(InfoType.RobotOperation, `Switch operation mode to: ${this.opMode}`);
};
subscribeRes(RWS.Controller.MonitorResources.operationMode, cbOpMode.bind(this));
callback(this.opMode);
} catch (e) {
TComponents.Popup_A.warning(
`${ExceptionIdMap.RWSSubscriptionFailed}-${TComponents.Component_A.t(
`framework:${ExceptionIdMap.RWSSubscriptionFailed}.title`,
{resourceName: RWS.Controller.MonitorResources.operationMode},
)}`,
TComponents.Component_A.t(`framework:${ExceptionIdMap.RWSSubscriptionFailed}.causes`),
);
Logger.e(logModule, ErrorCode.RWSSubscriptionFailed, 'ailed to subscribe controller operation mode.');
}
}
es._events.on('op-mode', callback);
};
/**
* Subscribes to 'controller-state' and 'operation-mode'. Current state is stored in
* {@link ctrlState}. Additionally, {@link isMotOn}
* is updated with the corresponding value.
* @alias monitorControllerState
* @memberof API.CONTROLLER
* @param {function} [callback] - Callback function is called when controller state changes
* @example
* // The callback will be executed when motor status is changed
* const motorStatus = (value)=>{console.log("motor status is:",value);}
* await API.CONTROLLER.monitorControllerState(motorStatus);
*/
this.monitorControllerState = async function (callback) {
Logger.i(InfoType.RobotOperation, 'Trying to monitor controller motor status');
if (this.ctrlState === undefined) {
try {
/**
* @alias ctrlState
* @memberof API.CONTROLLER
* @property {string} ctrlState The current state of the controller.
* This property is available only after calling API.CONTROLLER.monitorController().
*/
this.ctrlState = await RWS.Controller.getControllerState();
/**
* @alias isMotOn
* @memberof API.CONTROLLER
* @property {boolean} isMotOn Value "true" indicates that motors are on. In other cases, the value is "false".
* This property is available only after calling API.CONTROLLER.monitorController().
*/
this.isMotOn = this.ctrlState === API.CONTROLLER.STATE.MotorsOn ? true : false;
const cbControllerState = function (data) {
this.ctrlState = data;
data === API.CONTROLLER.STATE.MotorsOn ? (this.isMotOn = true) : (this.isMotOn = false);
es._events.trigger('controller-state', data);
Logger.i(InfoType.RobotOperation, `Controller motor state is turning to ${this.ctrlState}`);
};
subscribeRes(RWS.Controller.MonitorResources.controllerState, cbControllerState.bind(this));
callback(this.ctrlState);
} catch (e) {
TComponents.Popup_A.warning(
`${ExceptionIdMap.RWSSubscriptionFailed}-${TComponents.Component_A.t(
`framework:${ExceptionIdMap.RWSSubscriptionFailed}.title`,
{resourceName: RWS.Controller.MonitorResources.controllerState},
)}`,
TComponents.Component_A.t(`framework:${ExceptionIdMap.RWSSubscriptionFailed}.causes`),
);
Logger.e(logModule, ErrorCode.RWSSubscriptionFailed, 'Failed to subscribe controller motor state');
}
}
es._events.on('controller-state', callback);
};
// this.monitorMechUnit = async function (callback) {
// try {
// if (typeof callback !== 'function' && callback !== null)
// throw new Error('callback is not a valid function');
// const cbMechUnit = function (data) {
// this.mechUnit = data;
// callback && callback(data);
// API.verbose && console.log(this.mechUnit);
// };
// subscribeRes('mechunit', cbMechUnit.bind(this));
// } catch (e) {
// return API.rejectWithStatus('Failed to subscribe controller state', e);
// }
// };
/**
* Set operation mode to a specific mode.
* @alias setOpMode
* @note SPOC systems (e.g., RobotWare 8): Write access must be held before switching operation mode. Use {@link API.RWS.CONTROLSTATION.requestWriteAccess} to acquire write access explicitly.
* @note Non-SPOC systems (e.g., RobotWare 7): Use this interface directly as edit mastership is not required.
* @memberof API.CONTROLLER
* @param {API.CONTROLLER.OPMODE} mode - The operation mode to be set
* @example
* // Set the operation mode to Auto mode
* await API.CONTROLLER.setOpMode(API.CONTROLLER.OPMODE.Auto)
*/
this.setOpMode = async function (mode) {
if (mode === API.CONTROLLER.OPMODE.Manual) await this.setOpModeManual();
else if (mode === API.CONTROLLER.OPMODE.Auto) await this.setOpModeAutomatic();
};
/**
* Sets the operation mode to Manual mode
* @note SPOC systems (e.g., RobotWare 8): Write access must be held before switching operation mode. Use {@link API.RWS.CONTROLSTATION.requestWriteAccess} to acquire write access explicitly.
* @note Non-SPOC systems (e.g., RobotWare 7): Use this interface directly as edit mastership is not required.
* @alias setOpModeManual
* @memberof API.CONTROLLER
* @example
* await API.CONTROLLER.setOpModeManual()
*/
this.setOpModeManual = async function () {
try {
// check write access status if SPOC system
const isSpocSystem = await API.RWS.CONTROLSTATION.isSpocSystem();
if (isSpocSystem) {
await API.RWS.CONTROLSTATION.checkIfHeldWriteAccess();
}
await RWS.Controller.setOperationMode(API.CONTROLLER.OPMODE.Manual);
} catch (e) {
return API.rejectWithStatus('Failed to set operation mode to Manual mode', e, {
errorCode: ErrorCode.FailedToSetOperationMode,
});
}
};
/**
* Sets the operation mode to Auto mode
* @note SPOC systems (e.g., RobotWare 8): Write access must be held before switching operation mode. Use {@link API.RWS.CONTROLSTATION.requestWriteAccess} to acquire write access explicitly.
* @note Non-SPOC systems (e.g., RobotWare 7): Use this interface directly as edit mastership is not required.
* @alias setOpModeAutomatic
* @memberof API.CONTROLLER
* @example
* await API.CONTROLLER.setOpModeAutomatic()
*/
this.setOpModeAutomatic = async function () {
try {
const isSpocSystem = await API.RWS.CONTROLSTATION.isSpocSystem();
if (isSpocSystem) {
await API.RWS.CONTROLSTATION.checkIfHeldWriteAccess();
}
await RWS.Controller.setOperationMode(API.CONTROLLER.OPMODE.Auto);
} catch (e) {
return API.rejectWithStatus('Failed to set operation mode to Auto mode', e, {
errorCode: ErrorCode.FailedToSetOperationMode,
});
}
};
/**
* Gets the operation mode. Possible modes are:
* <br> 'initializing' controller is starting up, but not yet ready
* <br> 'automatic_changing' automatic mode requested
* <br> 'manual_full_changing' manual full speed mode requested
* <br> 'manual_reduced' manual reduced speed mode
* <br> 'manual_full' manual full speed mode
* <br> 'automatic' automatic mode
* <br> 'undefined' undefined
* @alias getOperationMode
* @memberof API.CONTROLLER
* @returns {Promise<RWS.Controller.OperationModes>} A promise with a string containing the operation mode.
* @example
* let opMode = await API.CONTROLLER.getOperationMode()
*/
this.getOperationMode = function () {
return (async () => {
return await RWS.Controller.getOperationMode();
})();
};
/**
* Gets the controller state. Possible states are:
* <br> 'initializing' the controller is starting up
* <br> 'motors_on' motors on state
* <br> 'motors_off' motors off state
* <br> 'guard_stop' stopped due to safety
* <br> 'emergency_stop' emergency stop state
* <br> 'emergency_stop_resetting' emergency stop state resetting
* <br> 'system_failure' system failure state
* @alias getControllerState
* @memberof API.CONTROLLER
* @returns {Promise<RWS.Controller.ControllerStates>} A promise with a string containing the controller state.
* @example
* let controllerState = await API.CONTROLLER.getControllerState()
*/
this.getControllerState = function () {
return (async () => {
return await RWS.Controller.getControllerState();
})();
};
/**
* Check whether motor is on
* @alias checkIfMotorIsOn
* @memberof API.CONTROLLER
* @returns {Promise<boolean>} A promise with a boolean containing if motor is in on status.
* @example
* let motorStatus = await API.CONTROLLER.checkIfMotorIsOn()
*/
this.checkIfMotorIsOn = async function () {
try {
let motorState = await API.CONTROLLER.getControllerState();
return motorState == API.CONTROLLER.STATE.MotorsOn;
} catch (e) {
return API.rejectWithStatus('Failed to get controller motor status', e, {
errorCode: ErrorCode.FailedToCheckMotorStatus,
});
}
};
/**
* Sets motor status to on/off
* This interface is not valid for SPOC system, e.g., RobotWare 8.
* With SPOC system,
* Manual mode: press enable device to set motor on
* Auto mode: long press physical thumb button on FlexPendant, or trigger specific Safety input.
* @alias setMotorsState
* @memberof API.CONTROLLER
* @param {API.CONTROLLER.STATE} state - The motor status to be set
* @example
* // Set motor on
* await API.CONTROLLER.setMotorsState(API.CONTROLLER.STATE.MotorsOn)
*/
this.setMotorsState = async function (state) {
const isSpocSystem = await API.RWS.CONTROLSTATION.isSpocSystem();
if (isSpocSystem) {
return API.rejectWithStatus(
'Motor control is not supported in SPOC system.',
{},
{errorCode: ErrorCode.MotorControlInSpoc},
);
}
// return if wrong command
if (![API.CONTROLLER.STATE.MotorsOn, API.CONTROLLER.STATE.MotorsOff].includes(state)) return;
// return if already in expected state
let motorState = await this.getControllerState();
if (motorState == state) return;
// return if in manual mode and the robot is not IRB 14050
let opMode = await this.getOperationMode();
let isSAY = await this.isSAY();
if (!(isSAY || opMode == API.CONTROLLER.OPMODE.Auto) && state == API.CONTROLLER.STATE.MotorsOn) {
throw new Error(ErrorCode.FailedToSetMotorStatus, {
cause: 'Motor cannot be enabled in the current operation mode.',
});
}
try {
await RWS.Controller.setMotorsState(state);
if (state == API.CONTROLLER.STATE.MotorsOn) {
await API.waitForCondition(this.checkIfMotorIsOn, {interval_ms: 100, timeout_ms: 2000});
}
} catch (e) {
return API.rejectWithStatus(`Failed to set motor to ${state} status`, e, {
errorCode: ErrorCode.FailedToSetMotorStatus,
});
}
};
/**
* Gets the current language
* @alias getLanguage
* @memberof API.CONTROLLER
* @returns {Promise<string>}
* @example
* await API.CONTROLLER.getLanguage()
*/
this.getLanguage = async function () {
try {
return await RWS.Controller.getEnvironmentVariable('$LANGUAGE');
} catch (e) {
return API.rejectWithStatus('Failed to get controller language', e, {
errorCode: ErrorCode.FailedToGetControllerLanguage,
});
}
};
/**
* Restarts the controller. Possible modes are:
* <br> 'restart' normal warm start
* <br> 'shutdown' shut down the controller
* <br> 'boot_application' start boot application
* <br> 'reset_system' reset system
* <br> 'reset_rapid' reset Rapid
* <br> 'revert_to_auto' revert to last auto-save
* <br> NOTE! An enum ‘RWS.Controller.RestartModes’ with the valid values is provided for ease of use.
* @alias restart
* @note SPOC systems (e.g., RobotWare 8): Write access must be held before restarting controller. Use {@link API.RWS.CONTROLSTATION.requestWriteAccess} to acquire write access explicitly.
* @note Non-SPOC systems (e.g., RobotWare 7): Use this interface directly as edit mastership is handled internally.
* @memberof API.CONTROLLER
* @param [mode] - The parameter 'mode" indicates the type of the restart that is requested.
* @returns {Promise<{}>}
* @example
* await API.CONTROLLER.restart()
*/
this.restart = async function (mode = RWS.Controller.RestartModes.restart) {
try {
Logger.i(InfoType.RobotOperation, 'API.CONTROLLER.restart is used to restart controller');
await API.sleep(1000);
RWS.Subscriptions.unsubscribeToAll();
await RWS.Controller.restartController(mode);
} catch (e) {
return API.rejectWithStatus('Failed to restart controller', e, {
errorCode: ErrorCode.FailedToRestartController,
});
}
};
})();
es.constructedBase = true;
};
// const API = {};
factoryApiBase(API);
export default API;