src.dualinventive.com/dinet/libdi/common/ditest-php/equipment/psu_cpx400.php

555 lines
13 KiB
PHP

<?php
require_once(dirname(__FILE__) . "/../test_framework.php");
abstract class PsuCpx400LockStatus {
const Unknown = -2;
const Disabled = -1;
const Unlocked = 0;
const Locked = 1;
private static $enum = array(
-2 => "Unknown",
-1 => "Disabled",
0 => "Unlocked",
1 => "Locked"
);
public static function toInt($name) {
return array_search($name, self::$enum);
}
public static function str($int) {
return self::$enum[$int];
}
};
class PsuCpx400 {
private $__componentName = "PsuCpx400";
private $__requestDelayUs = 80000; // We need some delay after every request because else the PSU will choke
private $name = "psu_cpx400";
private $debug = false;
private $__fd = null;
/* Hardware capability */
private $__capabilities = array(
"channels" => 2,
"v_min" => 0.00,
"v_max" => 60.00,
"i_min" => 0.01,
"i_max" => 20.00
);
private $__info = array (
"host" => "",
"port" => "",
"lock" => PsuCpx400LockStatus::Unknown,
"name" => "",
"model" => "",
"serial" => "",
"version" => ""
);
private $__channelsInfo = array (
array(
"id" => 1, // Channel ID
"enabled" => false, // Output enabled
"v" => 0.0, // Voltage
"v_inc" => 0.0, // Voltage increment step
"v_umin" => 0.0, // Voltage min (user limit)
"v_umax" => 0.0, // Current max (user limit)
"i" => 0.0, // Current
"i_inc" => 0.0, // Current increment step
"i_umin" => 0.0, // Current min (user limit)
"i_umax" => 0.0, // Current max (user limit)
),
array(
"id" => 2, // Channel ID
"enabled" => false, // Output enabled
"v" => 0.0, // Voltage
"v_inc" => 0.0, // Voltage increment step
"v_umin" => 0.0, // Voltage min (user limit)
"v_umax" => 0.0, // Voltage max (user limit)
"i" => 0.0, // Current
"i_max" => 0.0, // Current max
"i_inc" => 0.0, // Current increment step
"i_umin" => 0.0, // Current min (user limit)
"i_umax" => 0.0, // Current max (user limit)
)
);
private function debug($msg) {
if ($this->debug) {
$msg = str_replace("\r", '\r', $msg);
$msg = str_replace("\n", '\n', $msg);
DiTestMsg::dbg(trim($msg), $this->__componentName);
}
}
private function err($msg) {
DiTestMsg::err(trim($msg), $this->__componentName);
}
private function warn($msg) {
DiTestMsg::warn(trim($msg), $this->__componentName);
}
private function fail($msg) {
DiTestMsg::fail(trim($msg), $this->__componentName);
}
private function pass($msg) {
DiTestMsg::pass(trim($msg), $this->__componentName);
}
function __construct($host = "psu", $port = 9221, $debug = false) {
$this->debug = $debug;
$this->__fd = fsockopen($host, $port, $errno, $errstr, 30);
if ($this->__fd === FALSE) {
$this->fail("$errstr ($errno)");
} else {
$this->setInfo("host", $host);
$this->setInfo("port", $port);
$this->requestInfo();
$this->requestLockStatus();
if ($this->getInfo("lock") != PsuCpx400LockStatus::Unlocked) {
$this->warn("PSU not unlocked, ignoring...");
}
$this->outputsOff();
$this->reset();
$this->resetLimits();
}
}
function __destruct() {
if ($this->__fd) {
$this->resetLimits();
$this->outputsOff();
$this->reset();
fclose($this->__fd);
$this->__fd = null;
}
}
function setInfo($key, $value) {
$this->__info[$key] = $value;
}
function getInfo($key) {
return $this->__info[$key];
}
function getCapability($id) {
return $this->__capabilities[$id];
}
function setChannelInfo($channel, $key, $value) {
$channel = (int)$channel - 1;
$this->__channelsInfo[$channel][$key] = $value;
$this->debug("[setChannelInfo] channel: $channel, \"$key\" => \"$value\"");
}
function getChannelInfo($channel, $key) {
$channel = (int)$channel - 1;
$value = $this->__channelsInfo[(int)$channel][$key];
if ($key == "enabled") {
if ($value == true)
$value = "ON";
else
$value = "OFF";
}
$this->debug("[getChannelInfo] channel: $channel, \"$key\" => \"$value\"");
return $value;
}
private function reply() {
if ($this->__fd) {
$reply = fgets($this->__fd);
$this->debug("[reply] \"$reply\"");
return $reply;
}
return "";
}
private function request($cmd) {
if ($this->__fd) {
$cmd .= "\n";
$this->debug("[request] cmd: \"$cmd\"");
fwrite($this->__fd, "$cmd");
}
}
private function requestInfo() {
$this->request("*IDN?");
$r = $this->reply();
if (!empty($r)) {
$info = explode(",", $r);
if (count($info) == 4) {
$this->setInfo("name", trim($info[0]));
$this->setInfo("model", trim($info[1]));
$this->setInfo("serial", trim($info[2]));
$this->setInfo("version", trim($info[3]));
} else {
// TODO something unexpected returned
}
}
}
private function requestLockStatus() {
$this->request("IFLOCK?");
$r = $this->reply();
if (!empty($r)) {
$this->setInfo("lock", (int)trim($r));
} else {
$this->setInfo("lock", PsuCpx400LockStatus::Unknown);
}
}
private function isValidChannel($channel) {
if ($channel > 0 && $channel <= 2)
return true;
$this->fail("Invalid channel $channel selected");
return false;
}
/**
* Verify if requested channel voltage is within user and hardware limits
*/
private function isValidVoltage($channel, $voltage) {
// Check channel number
if (!($this->isValidChannel($channel)))
return false;
// User limit
$min = $this->getChannelInfo($channel, "v_umin");
$max = $this->getChannelInfo($channel, "v_umax");
if ($voltage >= $min && $voltage <= $max) {
$this->debug("valid voltage for channel: $channel, $voltage");
return true;
}
/*
// Hardware limit
$min = $this->getCapability('v_min');
$max = $this->getCapability('v_max');
if($voltage >= $min && $voltage <= $max) {
$this->debug("invalid voltage for channel: $channel, $voltage");
return true;
}
*/
$this->err("Voltage requested is invalid: $voltage >= $min (min), <= $max (max)");
return false;
}
public function lock() {
$ret = false;
$this->request("IFLOCK");
$r = $this->reply();
$this->debug("[lock] " . $r);
if (!empty($r)) {
(int)$r;
if ($r == 1) {
$ret = true;
$this->setInfo("lock", PsuCpx400LockStatus::Locked);
}
}
return $ret;
}
public function unlock() {
$ret = false;
$this->request("IFUNLOCK");
$r = $this->reply();
$this->debug("[unlock] " . $r);
if (!empty($r)) {
(int)$r;
if ($r == 0) {
$ret = true;
$this->setInfo("lock", PsuCpx400LockStatus::Unlocked);
}
}
return $ret;
}
public function isLocked() {
$this->requestLockStatus();
$lock = $this->getInfo("lock");
if ($lock == PsuCpx400LockStatus::Unlocked)
return false;
return true;
}
public function local() {
$this->request("LOCAL");
return true;
}
/* @return true when OK, false otherwise */
public function setVoltage($channel, $value, $retries = 5, $timeout_ms = 100) {
$channel = (int)$channel;
$value = (float)$value;
if (!($this->isValidVoltage($channel, $value)))
return false;
$v = 0.00;
$this->request("V".$channel." $value");
usleep($this->__requestDelayUs);
for ($i = 0; $i < $retries; $i++) {
$v = $this->getVoltage($channel);
if ($v == $value) {
$this->debug("[setVoltage] Requested voltage correctly set: \"$v\"");
return true;
}
$this->debug("[setVoltage] Verify try $i, volt: \"$v\"");
usleep(1000 * $timeout_ms);
}
$this->fail("[setVoltage] Requested voltage not correctly set to \"$value\": \"$v\"");
return false;
}
/* Set current for all outputs */
public function setVoltageAll($value) {
for ($i = 1; $i < 3; $i++) {
$this->setVoltage($i, $value);
}
}
public function getVoltage($channel) {
(int)$channel = $channel;
// TODO check channel
$this->request("V$channel?");
$v = $this->reply();
if (!empty($v)) {
$v = explode(" ", $v);
$v = (float)$v[1];
$this->debug("[getVoltage] (channel: " . $channel . "): " . $v);
$this->setChannelInfo($channel, "v", $v);
return $v;
}
$this->fail("[getVoltage] Unexpected reply \"$v\"");
return 0;
}
public function incVoltage($channel, $verify = false) {
$channel = (int)$channel;
if (!($this->isValidChannel($channel)))
return;
// TODO check PSU voltage after increment...
if (!$verify)
$this->request("INCV".$channel);
else
$this->request("INCV".$channel."V");
usleep($this->__requestDelayUs);
$this->getVoltage($channel);
}
public function getIncVoltage($channel) {
(int)$channel = $channel;
// TODO check channel
$this->request("DELTAV$channel?");
$v = $this->reply();
if (!empty($v)) {
$v = explode(" ", $v);
$v = (float)$v[1];
$this->debug("[getIncVoltage] (channel: " . $channel . "):" . $v);
$this->setChannelInfo($channel, "v_inc", $v);
return $v;
}
$this->fail("[getIncVoltage] Unexpected reply \"$v\"");
return 0;
}
public function setIncVoltage($channel, $step) {
$channel = (int)$channel;
$step = (float)$step;
if ($step == 0.00) {
$this->warn("[setIncVoltage] Step of 0.00V is invalid, setting to minimal 0.01V");
$step = 0.01;
}
$this->request("DELTAV".$channel." $step");
$this->getIncVoltage($channel);
}
public function setMinVoltage($channel, $value) {
$this->setChannelInfo($channel, "v_umin", $value);
}
public function setMaxVoltage($channel, $value) {
$this->setChannelInfo($channel, "v_umax", $value);
}
public function getMinVoltage($channel) {
return $this->getChannelInfo($channel, "v_umin");
}
public function getMaxVoltage($channel) {
return $this->getChannelInfo($channel, "v_umax");
}
public function setCurrent($channel, $value) {
$channel = (int)$channel;
$value = (float)$value;
$this->request("I$channel $value");
$this->getCurrent($channel);
return true;
}
/* Set current for all outputs */
public function setCurrentAll($value) {
for ($i = 1; $i < 3; $i++) {
$this->setCurrent($i, $value);
}
}
public function getCurrent($channel) {
(int)$channel = $channel;
$this->request("I$channel?");
$c = $this->reply();
$this->debug("[getCurrent] reply: " . $c);
if (!empty($c)) {
$c = explode(" ", $c);
$c = (float)$c[1];
$this->debug("[getCurrent] (channel: " . $channel . "):" . $c);
$this->setChannelInfo($channel, "i", $c);
return $c;
}
return 0;
}
public function incCurrent($channel) {
$channel = (int)$channel;
$this->request("INCI".$channel);
$this->getCurrent($channel);
}
public function getIncCurrent($channel) {
(int)$channel = $channel;
$this->request("DELTAI$channel?");
$v = $this->reply();
if (!empty($v)) {
$v = explode(" ", $v);
$v = (float)$v[1];
$this->debug("[getIncCurrent] (channel: " . $channel . "):" . $v);
$this->setChannelInfo($channel, "i_inc", $v);
return $v;
}
return 0;
}
public function setIncCurrent($channel, $step) {
$channel = (int)$channel;
$step = (float)$step;
if ($step == 0.00) {
$this->warn("[setIncCurrent] Step of 0.00A is invalid, setting to minimal value of 0.01A");
$step = 0.01;
}
$this->request("DELTAI".$channel." $step");
$this->getIncCurrent($channel);
}
public function setMinCurrent($channel, $value) {
$this->setChannelInfo($channel, "i_umin", $value);
}
public function setMaxCurrent($channel, $value) {
$this->setChannelInfo($channel, "i_umax", $value);
}
public function getMinCurrent($channel) {
return $this->getChannelInfo($channel, "i_umin");
}
public function getMaxCurrent($channel) {
return $this->getChannelInfo($channel, "i_umax");
}
public function outputOn($channel) {
$channel = (int)$channel;
$this->request("OP$channel 1");
}
public function outputOff($channel) {
$channel = (int)$channel;
// TODO check channel id
$this->request("OP$channel 0");
}
/* Enable all outputs */
public function outputsOn() {
$this->request("OPALL 1");
}
/* Disable all outputs */
public function outputsOff() {
$this->request("OPALL 0");
}
/** Disable all outputs, set all voltage and current to zero */
public function reset() {
$this->outputsOff();
$this->resetLimits();
for ($i = 1; $i < 3; $i++) {
$this->setVoltage($i, 0.00);
$this->setCurrent($i, 0.01);
$this->setIncVoltage($i, 0.01);
$this->setIncCurrent($i, 0.01);
}
}
public function resetLimits() {
for ($i = 1; $i < 3; $i++) {
$this->setMinVoltage($i, $this->getCapability("v_min"));
$this->setMaxVoltage($i, $this->getCapability("v_max"));
$this->setMinCurrent($i, $this->getCapability("i_min"));
$this->setMaxCurrent($i, $this->getCapability("i_max"));
$this->setIncVoltage($i, 0.01);
$this->setIncCurrent($i, 0.01);
}
}
public function info() {
$info = sprintf(
"===
PSU CPX400 Status
> Host: tcp://%s:%d
> Serial: %s Version: %s
> Lock: %s
> Channel 1: [%s] %.02f V %.02f I (%0.2f Vstep, %0.2f IStep)
> Channel 2: [%s] %.02f V %.02f I (%0.2f Vstep, %0.2f IStep)
===\n",
$this->getInfo("host"), $this->getInfo("port"),
$this->getInfo("serial"), $this->getInfo("version"),
PsuCpx400LockStatus::str($this->getInfo("lock")),
$this->getChannelInfo(1, "enabled"),
$this->getChannelInfo(1, "v"), $this->getChannelInfo(1, "i"),
$this->getChannelInfo(1, "v_inc"), $this->getChannelInfo(1, "i_inc"),
$this->getChannelInfo(2, "enabled"),
$this->getChannelInfo(2, "v"), $this->getChannelInfo(2, "i"),
$this->getChannelInfo(2, "v_inc"), $this->getChannelInfo(2, "i_inc")
);
return $info;
}
}