Source: equipment/shaker-Tecan1.js

/**
 * Roboliq: Automation for liquid-handling robots
 * @copyright 2017, ETH Zurich, Ellis Whitehead
 * @license GPL-3.0
 */

/**
 * Module for a 1-site Tecan shaker.
 * @module
 */
const _ = require('lodash');
const assert = require('assert');
const math = require('mathjs');
const commandHelper = require('roboliq-processor/dist/commandHelper.js');
const expect = require('roboliq-processor/dist/expect.js');

/**
 * @typedef ShakerTecan1Params
 * @type {object}
 * @property {!string} evowareId - the Evoware ID of this equipment
 * @property {?string} evowareGrid - the grid that the equipment is on
 * @param {!string} site - the equipment's site name (just the base part, without namespace)
 * ```
 * evowareId: "HPShaker",
 * site: "P3"
 * ```
 */
/**
 * Configure the Tecan 1-site shaker
 * @param {ShakerTecan1Params} params - parameters for the configuration
 * @return {EquipmentConfig}
 */
function configure(config, equipmentName, params) {
	const agent = config.getAgentName();
	const equipment = config.getEquipmentName(equipmentName);
	const siteName = config.getSiteName(params.site);

	const objects = {};
	_.set(objects, equipment, {
		type: "Shaker",
		evowareId: params.evowareId
	});

	const predicates = [
		{
			"shaker.canAgentEquipmentSite": {
				agent,
				equipment,
				site: siteName
			}
		},
	];
	// console.log("shaker.predicates: "+JSON.stringify(predicates, null, '\t'));

	const schemas = {
		[`shaker.run|${agent}|${equipment}`]: {
			properties: {
				agent: {description: "Agent identifier", type: "Agent"},
				equipment: {description: "Equipment identifier", type: "Equipment"},
				program: {
					description: "Program for shaking",
					properties: {
						rpm: {description: "Rotations per minute (RPM)", type: "number"},
						duration: {description: "Duration of shaking", type: "Duration"}
					},
					required: ["duration"]
				},
				object: {description: "Plate identifier (optional)", type: "Plate"}
			},
			required: ["agent", "equipment", "program"]
		}
	};

	const commandHandlers = {
		[`shaker.run|${agent}|${equipment}`]: function(params, parsed, data) {
			//console.log("equipment.run|ourlab.mario.evoware|ourlab.mario.shaker: "+JSON.stringify(parsed, null, '\t'))
			const equipmentId = commandHelper.getParsedValue(parsed, data, "equipment", "evowareId");
			const rpm = parsed.value.program.rpm || 750;

			// Construct the shaker program data
			const shakerNo = 1;
			// FIXME: Let the user specify mode1, steps1, mode2, steps2, power
			const mode1 = 2;
			const steps1 = 0;
			const mode2 = 1;
			const steps2 = 0;
			const freq = (60000000/rpm).toFixed(0);
			const cycles = Math.floor(rpm * parsed.value.program.duration.toNumber("minute")).toFixed(0);
			const powerPerc = 50;
			const power = Math.floor(255 * powerPerc / 100).toFixed(0);
			const s0 = `*27${shakerNo}|${freq}|${mode1}|${steps1}|${mode2}|${steps2}|${cycles}|${power}*27`;
			// Replace all occurences of '0' with "*30"
			const s1 = s0.replace(/0/g, "*30");
			// Finally, split string into 32 char parts, then rebind them, separated by commas
			const s2 = _(s1).chunk(32).map(s => s.join("")).join(",");

			return {
				expansion: [
					{
						command: "evoware._facts",
						agent: parsed.objectName.agent,
						factsEquipment: equipmentId,
						factsVariable: equipmentId+"_HP__Start",
						factsValue: s2
					},
					{
						command: "timer.sleep",
						agent: parsed.objectName.agent,
						duration: parsed.orig.program.duration
					},
					{
						command: "evoware._facts",
						agent: parsed.objectName.agent,
						factsEquipment: equipmentId,
						factsVariable: equipmentId+"_HP__Stop",
						factsValue: "1"
					},
				]
			};
		},
	};

	const protocol = {
		objects,
		predicates,
		schemas,
		commandHandlers
	};
	return protocol;
}

module.exports = {
	configure
};