src.dualinventive.com/dinet/sec-multi-proxy/libdi/common/ditest-php/equipment/can.php

635 lines
16 KiB
PHP
Executable File

<?php
class CANMsgRegistry {
private $__Callbacks = array();
function register($callback, $ttype, $msgtype, $dtype) {
$cb = [ "callback" => $callback, "ttype" => $ttype, "msgtype" => $msgtype, "dtype" => $dtype];
$this->__Callbacks[] = $cb;
}
function execute($can, $msg, $context) {
$unhandled = true;
foreach ($this->__Callbacks as $cb) {
if ($msg['msgtype'] == $cb['msgtype'] &&
$msg['ttype'] == $cb['ttype'] &&
$msg['dtype'] == $cb['dtype']) {
call_user_func($cb['callback'], $can, $msg, $context);
$unhandled = false;
}
}
return $unhandled;
}
}
class CAN {
private $fd = null;
private $deviceUid = "";
private $msgRecvRegistry = null;
function __construct($iface = "can0", $deviceUid = "99123456789012345678901234567890") {
if ($iface == "")
return;
$this->deviceUid = $deviceUid;
$this->fd = di_can_open($iface);
di_can_set_nodeid($this->fd, $deviceUid);
$this->msgRecvRegistry = new CANMsgRegistry();
}
function __destruct() {
if ($this->fd != null) {
di_can_close($this->fd);
}
}
function isOpen() {
if ($this->fd) {
return true;
}
return false;
}
public function listInterfaces() {
if ($this->fd) {
return di_can_list($this->fd);
} else {
return array();
}
}
/* Get DiNet timestamp of Now */
public function timeNow() {
return intval(microtime(true) * 1000);
}
public function getDeviceUid() {
return $this->deviceUid;
}
public function registerMsgRecvCallback($callback, $ttype, $msgtype, $dtype) {
$this->msgRecvRegistry->register($callback, $ttype, $msgtype, $dtype);
}
public function recv($context = null) {
$msg = di_can_recv($this->fd);
if ($msg !== NULL) {
$this->msgRecvRegistry->execute($this, $msg, $context);
/* For RPC messages recode mpack to PHP */
if ($msg['msgtype'] == DI_CAN_MSGTYPE_RPC && $msg['ptype'] == DI_CAN_PTYPE_MSGPACK) {
$msg['result'] = msgpack_unpack($msg['msg']);
} else if ($msg['msgtype'] == DI_CAN_MSGTYPE_RAW) {
// NOTE(jjacobs): we dont convert at all ... for now
}
}
return $msg;
}
public function recvWait($action, $classMethod, $timeoutMs = -1) {
$start = microtime(true) * 1000;
while (true) {
if ((microtime(true) * 1000) > $start + $timeoutMs && $timeoutMs > 0) {
echo "Test failure timeout occurred";
return null;
}
$msg = $this->recv();
if (!$msg)
continue;
if ($msg['msgtype'] != DI_CAN_MSGTYPE_RPC)
continue;
$ttype = $this->convTtype($msg['ttype']);
$dtype = $this->convDtype($msg['dtype']);
if ($ttype == $action &&
$dtype == $classMethod)
return $msg;
}
}
/**
* Conversion functions for transfertype
* If dtype is a string e.g "req" -> DI_CAN_TRANSFERTYPE_REQUEST
* If dtype is a int e.g DI_CAN_TRANSFERTYPE_PUBLISH -> "pub"
*/
private function convTtype($ttype) {
$mapping = array (
"rep" => DI_CAN_TRANSFERTYPE_REPLY,
"req" => DI_CAN_TRANSFERTYPE_REQUEST,
"pub" => DI_CAN_TRANSFERTYPE_PUBLISH
);
if (is_string($ttype)) {
return $mapping[$ttype];
} else {
foreach($mapping as $k => $v) {
if ($v == $ttype)
return $k;
}
return "unknown";
}
}
/**
* Conversion functions for data type
* If dtype is a string e.g "device:ping" -> DI_RPC_TYPE_DEVICE_PING
* If dtype is a int e.g DI_RPC_TYPE_DEVICE_PING -> "device:ping"
*/
private function convDtype($dtype) {
$mapping = array (
"notify:info" => DI_RPC_TYPE_NOTIFY_INFO,
"notify:data" => DI_RPC_TYPE_NOTIFY_DATA,
"action:info" => DI_RPC_TYPE_ACTION_INFO,
"action:get" => DI_RPC_TYPE_ACTION_GET,
"action:set" => DI_RPC_TYPE_ACTION_SET,
"sensor:info" => DI_RPC_TYPE_SENSOR_INFO,
"sensor:data" => DI_RPC_TYPE_SENSOR_DATA,
"config:info" => DI_RPC_TYPE_CONFIG_INFO,
"config:get" => DI_RPC_TYPE_CONFIG_GET,
"config:set" => DI_RPC_TYPE_CONFIG_SET,
"config:reset" => DI_RPC_TYPE_CONFIG_RESET,
"device:ping" => DI_RPC_TYPE_DEVICE_PING,
"device:info" => DI_RPC_TYPE_DEVICE_INFO,
"device:data" => DI_RPC_TYPE_DEVICE_DATA,
"device:reset" => DI_RPC_TYPE_DEVICE_RESET,
"device:error" => DI_RPC_TYPE_DEVICE_ERROR
);
if (is_string($dtype)) {
return $mapping[$dtype];
} else {
foreach($mapping as $k => $v) {
if ($v == $dtype)
return $k;
}
return "unknown";
}
}
public function flush() {
while (true) {
$msg = $this->recv();
if ($msg == NULL)
break;
}
}
public function sendRaw($msg) {
$msg['msgtype'] = DI_CAN_MSGTYPE_RAW;
// TODO $msg['ptype'] = DI_CAN_PTYPE_???
$msg['ttype'] = $this->convTtype($msg['ttype']);
$msg['dtype'] = $this->convDtype($msg['datatype']);
di_can_send($this->fd, $msg);
}
public function sendRPC($msg) {
trigger_error('Deprecated: this function is deprecated -> use send()!', E_NOTICE);
$msg['msgtype'] = DI_CAN_MSGTYPE_RPC;
$msg['ptype'] = DI_CAN_PTYPE_MSGPACK;
$msg['ttype'] = $this->convTtype($msg['ttype']);
di_can_send($this->fd, $msg);
}
public function sendRawTime() {
$msg = [];
$msg['msgtype'] = DI_CAN_MSGTYPE_RAW;
$msg['ttype'] = DI_CAN_TRANSFERTYPE_PUBLISH;
$msg['ptype'] = DI_CAN_PTYPE_U64;
$msg['dtype'] = DI_CAN_RAW_DTYPE_DINET_TIME;
$msg['msg'] = intval(round(microtime(true) * 1000));
di_can_send($this->fd, $msg);
}
public function send($msg) {
di_can_send($this->fd, $msg);
}
public function msgQueue($msg, $interval_ms) {
return di_can_send_queue($this->fd, $msg, $interval_ms);
}
public function msgDequeue($token) {
di_can_send_dequeue($this->fd, $token);
}
/**
* Set device state (token, activation)
* state: "idle", "armed", "active"
* wait: for WUM tests, we need to wait in between IDLE->ARMED
* and ARMED- ->IDLE state changes for the single sound to
* finish. Default is '0' (don't wait) for DUU and DUM testing
*/
public function device_set_state(&$test, $state, $wait = 0) {
$s = $this->rpc_request_device_state();
if ($s == $state) {
$test->info("Device state already \"$state\", nothing to be done");
return;
}
$token = rand(1, 9999);
// Idle -> Active
if ($s == "idle" && $state == "active") {
$this->rpc_request_reply($test, 'config:set', ['uid' => DI_RPC_UID_CONFIG_DEVICE_TOKEN, "value" => $token]);
// for WUM we need to wait until the single sound has finished
if ($wait)
sleep(5);
$this->rpc_request_reply($test, 'config:set',['uid' => DI_RPC_UID_CONFIG_DEVICE_ACTIVATION, "value" => true] );
}
// Idle -> Armed
if ($s == "idle" && $state == "armed") {
$this->rpc_request_reply($test, 'config:set', ['uid' => DI_RPC_UID_CONFIG_DEVICE_TOKEN, "value" => $token]);
if ($wait)
sleep(5);
}
// Armed -> Idle
if ($s == "armed" && $state == "idle") {
$this->rpc_request_reply($test, 'config:reset', ['uid' => DI_RPC_UID_CONFIG_DEVICE_TOKEN]);
if ($wait)
sleep(5);
}
// Armed -> Active
if ($s == "armed" && $state == "active")
$this->rpc_request_reply($test, 'config:set', ['uid' => DI_RPC_UID_CONFIG_DEVICE_ACTIVATION, "value" => true]);
// Active -> Armed
if ($s == "active" && $state == "armed")
$this->rpc_request_reply($test, 'config:reset', ['uid' => DI_RPC_UID_CONFIG_DEVICE_ACTIVATION]);
// Active -> Idle
if ($s == "active" && $state == "idle") {
$this->rpc_request_reply($test, 'config:reset', ['uid' => DI_RPC_UID_CONFIG_DEVICE_ACTIVATION]);
$this->rpc_request_reply($test, 'config:reset', ['uid' => DI_RPC_UID_CONFIG_DEVICE_TOKEN]);
if ($wait)
sleep(5);
}
$msg = $this->rpc_request_reply($test, 'device:data');
if (!$msg) {
$test->failed("Expect device:data reply");
return;
}
$nstate = $msg['result'][0]['state']; // TODO(jjacobs): I'm not sure why result state is in an array
if ($nstate != $state)
$test->failed("Expected device state \"'$state'\", got \"'$nstate'\"");
$test->info("Old device state: $s");
$test->info("New device state: $nstate");
}
public function rpc_request_reply(&$test, $request, $params = null, $errorCode = null) {
$this->flush();
$dtype = $this->convDtype($request);
$msg = [
'msgtype' => DI_CAN_MSGTYPE_RPC,
'ttype' => DI_CAN_TRANSFERTYPE_REQUEST,
'dtype' => $dtype
];
if ($params !== null) {
$msg['ptype'] = DI_CAN_PTYPE_MSGPACK;
$msg['msg'] = msgpack_pack($params);
} else {
$msg['msg'] = null;
}
di_can_send($this->fd, $msg);
DiTestMsg::dbg("Waiting for reply: $request");
while(true) {
$msg = $this->recv();
if ($msg == NULL)
continue;
if ($msg['msgtype'] == DI_CAN_MSGTYPE_RPC &&
$msg['ttype'] == DI_CAN_TRANSFERTYPE_REPLY &&
$msg['dtype'] == $dtype) {
DiTestMsg::dbg("Got RPC reply: $request");
if ($msg['ptype'] == DI_CAN_PTYPE_MSGPACK)
$msg['result'] = msgpack_unpack($msg['msg']);
return $msg;
}
/** @TODO .... */
/*
if ($errorCode === null) {
if (check_rpc_no_error($test, $request, $msg)) {
break;
} else {
if (check_rpc_error($test, $request, $msg, $errorCode)) {
break;
}
}
}
*/
}
}
public function rpc_info_is_present(&$test, $result, $uid, $label, $type, $default = null) {
if (!is_array($result)) {
$test->failed("Result is not an array");
return;
}
$info = null;
foreach ($result as $x) {
if ($x['uid'] == $uid) {
$info = $x;
break;
}
}
if (!$info) {
$test->failed("Info not present in result (uid: $uid, label: $label, type: $type)");
return;
}
$test->equal($uid, $info['uid']);
$test->equal($label, $info['label']);
$test->equal($type, $info['type']);
$default_str = "";
if ($default) {
$test->equal($default, $info['default']);
$default_str = ", default: $default";
}
$test->info("Info result present: uid: $uid, label: $label, type: $type$default_str");
}
public function rpc_request_device_state() {
$this->flush();
$msg = [];
$msg['msgtype'] = DI_CAN_MSGTYPE_RPC;
$msg['ttype'] = DI_CAN_TRANSFERTYPE_REQUEST;
$msg['dtype'] = DI_RPC_TYPE_DEVICE_DATA;
di_can_send($this->fd, $msg);
while(true) {
$msg = $this->recv();
if ($msg === NULL)
continue;
if ($msg['msgtype'] == DI_CAN_MSGTYPE_RPC &&
$msg['ptype'] == DI_CAN_PTYPE_MSGPACK &&
$msg['dtype'] == DI_RPC_TYPE_DEVICE_DATA) {
$result = msgpack_unpack($msg['msg']);
DiTestMsg::dbg("Device state: '".$result[0]['state']."'");
return $result[0]['state'];
}
}
}
public function rpc_request_device_info() {
$this->flush();
$msg = [];
$msg['msgtype'] = DI_CAN_MSGTYPE_RPC;
$msg['ttype'] = DI_CAN_TRANSFERTYPE_REQUEST;
$msg['dtype'] = DI_RPC_TYPE_DEVICE_INFO;
$msg['dst_id'] = DI_CAN_NODEID_BROADCAST;
di_can_send($this->fd, $msg);
while(true) {
$msg = $this->recv();
if ($msg === NULL)
continue;
if ($msg['msgtype'] == DI_CAN_MSGTYPE_RPC &&
$msg['ttype'] = DI_CAN_TRANSFERTYPE_REPLY &&
$msg['ptype'] == DI_CAN_PTYPE_MSGPACK &&
$msg['dtype'] == DI_RPC_TYPE_DEVICE_INFO) {
$result = msgpack_unpack($msg['msg'])[0];
DiTestMsg::dbg("Type: '".$result['type']."'");
DiTestMsg::dbg("Revision: '".$result['revision']."'");
DiTestMsg::dbg("Version: '".$result['version']."'");
return $msg;
}
}
}
public function rpc_check_battery_voltage($test, $uid, $v_min, $v_max) {
while (true) {
$msg = $this->recv($this->fd);
if ($msg === NULL)
continue;
if ($msg['msgtype'] != DI_CAN_MSGTYPE_RPC)
continue;
if ($msg['ttype'] != DI_CAN_TRANSFERTYPE_PUBLISH)
continue;
if ($msg['dtype'] != DI_RPC_TYPE_SENSOR_DATA)
continue;
foreach ($msg['result'] as $v) {
if ($v['uid'] != $uid)
continue;
$bat_voltage = $v['value'];
if ($test->range($bat_voltage, $v_min, $v_max) == true) {
$test->passed("Battery voltage OK (uid: $uid) voltage ($bat_voltage)");
return true;
}
}
}
return false;
}
public function rpc_check_battery_state($test, $uid, $state) {
while (true) {
$msg = $this->recv($this->fd);
if ($msg === NULL)
continue;
if ($msg['msgtype'] != DI_CAN_MSGTYPE_RPC)
continue;
if ($msg['ttype'] != DI_CAN_TRANSFERTYPE_PUBLISH)
continue;
if ($msg['dtype'] != DI_RPC_TYPE_SENSOR_DATA)
continue;
foreach ($msg['result'] as $v) {
if ($v['uid'] != $uid)
continue;
$bat_state= $v['value'];
if ($test->equal($state, $bat_state) == true) {
$test->passed("Battery state OK (uid: $uid) state ($bat_state)");
return true;
} else {
break;
}
}
}
return false;
}
public function rpc_check_charger_state($test, $uid, $state) {
while (true) {
$msg = $this->recv($this->fd);
if ($msg === NULL)
continue;
if ($msg['msgtype'] != DI_CAN_MSGTYPE_RPC)
continue;
if ($msg['ttype'] != DI_CAN_TRANSFERTYPE_PUBLISH)
continue;
if ($msg['dtype'] != DI_RPC_TYPE_SENSOR_DATA)
continue;
foreach ($msg['result'] as $v) {
if ($v['uid'] != $uid)
continue;
$charger_state= $v['value'];
if ($state == $charger_state){
// if ($test->equal($state, $charger_state) == true) {
$test->passed("Charger state OK (uid: $uid) state ($charger_state)");
return true;
} else {
break;
}
}
}
return false;
}
public function rpc_check_alarm_notify($test, $alarm_system_expect, $alarm_button_expect) {
$system_alarm_handled = false;
$system_alarm_result = false;
$manual_alarm_handled = false;
$manual_alarm_result = false;
while (true) {
$msg = $this->recv($this->fd);
if ($msg === NULL){
continue;
}
if ($msg['msgtype'] != DI_CAN_MSGTYPE_RPC)
continue;
if ($msg['ttype'] != DI_CAN_TRANSFERTYPE_PUBLISH)
continue;
if ($msg['dtype'] != DI_RPC_TYPE_NOTIFY_DATA)
continue;
foreach ($msg['result'] as $v) {
$state = $v['value'];
if ($v['uid'] == DI_RPC_UID_WUM_ACTION_ALARM) {
if ($test->equal($alarm_system_expect, $state) == true) {
if ($state)
$test->passed("Got system alarm");
else
$test->passed("No system alarm");
$system_alarm_result = true;
} else {
$test->failed("failed on system alarm");
$system_alarm_result = false;
}
$system_alarm_handled = true;
break;
}
else if ($v['uid'] == DI_RPC_UID_WUM_NOTIFY_ALARM_MANUAL) {
if ($test->equal($alarm_button_expect, $state) == true) {
if ($state)
$test->passed("Got manual alarm");
else
$test->passed("No manual alarm");
$manual_alarm_result = true;
} else {
$test->failed("failed on manual alarm");
$manual_alarm_result = false;
}
$manual_alarm_handled = true;
break;
}
}
if ($system_alarm_handled && $manual_alarm_handled)
break;
}
return($system_alarm_result && $manual_alarm_result);
}
public function raw_request_device_uid() {
$this->flush();
$msg = [];
$msg['msgtype'] = DI_CAN_MSGTYPE_RAW;
$msg['ttype'] = DI_CAN_TRANSFERTYPE_REQUEST;
$msg['dtype'] = DI_CAN_RAW_DTYPE_DEVICE_UID;
di_can_send($this->fd, $msg);
while(true) {
$msg = $this->recv();
if ($msg === NULL)
continue;
if ($msg['msgtype'] == DI_CAN_MSGTYPE_RAW &&
$msg['ttype'] == DI_CAN_TRANSFERTYPE_REPLY &&
$msg['ptype'] == DI_CAN_PTYPE_STRING &&
$msg['dtype'] == DI_CAN_RAW_DTYPE_DEVICE_UID) {
DiTestMsg::info("Device uid: '".$msg['msg']."'");
return $msg['msg'];
}
}
}
public function raw_request_cloudlight_state() {
$this->flush();
$msg = [];
$msg['msgtype'] = DI_CAN_MSGTYPE_RAW;
$msg['ttype'] = DI_CAN_TRANSFERTYPE_REQUEST;
$msg['dtype'] = DI_CAN_RAW_DTYPE_CLOUDLIGHT_STATE;
di_can_send($this->fd, $msg);
while(true) {
$msg = $this->recv();
if (!$msg)
continue;
if ($msg['msgtype'] == DI_CAN_MSGTYPE_RAW &&
$msg['ttype'] == DI_CAN_TRANSFERTYPE_REPLY &&
$msg['ptype'] == DI_CAN_PTYPE_U8 &&
$msg['dtype'] == DI_CAN_RAW_DTYPE_CLOUDLIGHT_STATE) {
DiTestMsg::info("Cloudlight state: '". $msg['msg'] ."'");
return $msg['msg'];
}
}
}
public function check_rpc_no_error($test, $request, $msg) {
if (isset($msg) && $msg['ttype'] == DI_CAN_TRANSFERTYPE_REPLY && $msg['dtype'] == $this->convDtype($request)) {
if (!isset($msg['result']['code']))
$test->passed("Got reply without error for '$request'");
else
$test->failed("Got error on '$request', expected no error");
$test->isFalse(isset($msg['result']['code']));
return true;
}
return false;
}
}