src.dualinventive.com/dinet/libdi-php/bin/di-can-fakedevice

328 lines
8.1 KiB
PHP
Executable File

#!/usr/bin/php -q
<?php
$deviceUID = "99123456789012345678901234567800";
$projectID = 666;
/**
* di-can-fakedevice emulates a DI-Net CAN bus device node
*/
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) {
$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);
$unhandled = false;
}
}
if ($unhandled) {
echo "Unhandled msg" . PHP_EOL;
}
return $unhandled;
}
}
function raw_dinet_time($can, $msg) {
$time = $msg['msg'];
echo __FUNCTION__ . " (" . strval($time) .") ". date("M d Y H:i:s", $time / 1000) . PHP_EOL;
}
function raw_device_uid($can, $msg) {
global $deviceUID;
echo __FUNCTION__ . PHP_EOL;
$len = strlen($deviceUID);
echo "device:uid: $deviceUID (len: $len)" . PHP_EOL;
$rep = [
'dst_id' => $msg['src_id'],
'msgtype' => DI_CAN_MSGTYPE_RAW,
'ttype' => DI_CAN_TRANSFERTYPE_REPLY,
'dtype' => DI_CAN_RAW_DTYPE_DEVICE_UID,
'ptype' => DI_CAN_PTYPE_STRING,
'msg' => $deviceUID
];
di_can_send($can, $rep);
}
function raw_project_id($can, $msg) {
global $projectID;
echo __FUNCTION__ . PHP_EOL;
echo "project:id: $projectID" . PHP_EOL;
$rep = [
'dst_id' => $msg['src_id'],
'msgtype' => DI_CAN_MSGTYPE_RAW,
'ttype' => DI_CAN_TRANSFERTYPE_REPLY,
'dtype' => DI_CAN_RAW_DTYPE_PROJECT_ID,
'ptype' => DI_CAN_PTYPE_U32,
'msg' => intval($projectID)
];
di_can_send($can, $rep);
}
function raw_connection_state($can, $msg) {
echo __FUNCTION__ . " " . strval($msg['msg']). PHP_EOL;
}
function net_heartbeat($can, $msg) {
echo __FUNCTION__ . " " . bin2hex($msg['msg']) . PHP_EOL;
}
function net_node_uid($can, $msg) {
echo __FUNCTION__ . " " . $msg['msg'] . PHP_EOL;
}
function net_heartbeat_publish($can, $msg) {
$msg = [
'msgtype' => DI_CAN_MSGTYPE_NET,
'ttype' => DI_CAN_TRANSFERTYPE_PUBLISH,
'dst_id' => DI_CAN_NODEID_BROADCAST,
'dtype' => DI_CAN_NET_DTYPE_HEARTBEAT,
'ptype' => DI_CAN_PTYPE_STRUCT,
'msg' => hex3bin("0201") // DEVICE, PASSIVE
];
di_can_send($can, $msg);
}
function rpc_sensor_publish($can, $uid, $value) {
$msgpack = msgpack_pack([[
"uid" => $uid,
"value" => $value,
"time" => mstime()
]]);
$msg = [
'msgtype' => DI_CAN_MSGTYPE_RPC,
'ttype' => DI_CAN_TRANSFERTYPE_PUBLISH,
'dst_id' => DI_CAN_NODEID_BROADCAST,
'dtype' => DI_RPC_TYPE_SENSOR_DATA,
'ptype' => DI_CAN_PTYPE_MSGPACK,
'msg' => $msgpack
];
di_can_send($can, $msg);
}
function net_discover($can, $msg) {
echo __FUNCTION__ . " " . strval($msg['msg']). PHP_EOL;
$rep = [
'msgtype' => DI_CAN_MSGTYPE_NET,
'ttype' => DI_CAN_TRANSFERTYPE_REPLY,
'dst_id' => $msg['src_id'],
'dtype' => DI_CAN_NET_DTYPE_DISCOVER,
'ptype' => DI_CAN_PTYPE_STRUCT,
'msg' => hex2bin("0201") // DEVICE, PASSIVE
];
di_can_send($can, $rep);
}
function rpc_device_ping($can, $msg) {
echo __FUNCTION__ . PHP_EOL;
$rep = [
'dst_id' => $msg['src_id'],
'msgtype' => DI_CAN_MSGTYPE_RPC,
'ttype' => DI_CAN_TRANSFERTYPE_REPLY,
'dtype' => DI_RPC_TYPE_DEVICE_PING
];
di_can_send($can, $rep);
}
function rpc_device_info($can, $msg) {
echo __FUNCTION__ . PHP_EOL;
$rep = [
'dst_id' => $msg['src_id'],
'msgtype' => DI_CAN_MSGTYPE_RPC,
'ttype' => DI_CAN_TRANSFERTYPE_REPLY,
'dtype' => DI_RPC_TYPE_DEVICE_INFO,
'ptype' => DI_CAN_PTYPE_MSGPACK,
'msg' => msgpack_pack([[
"type" => "tws-3000-dum",
"version" => "0.1.2-fakedevice",
"revision" => 1337]]
)
];
di_can_send($can, $rep);
}
function rpc_config_info($can, $msg) {
echo __FUNCTION__ . PHP_EOL;
$rep = [
'dst_id' => $msg['src_id'],
'msgtype' => DI_CAN_MSGTYPE_RPC,
'ttype' => DI_CAN_TRANSFERTYPE_REPLY,
'dtype' => DI_RPC_TYPE_CONFIG_INFO,
'ptype' => DI_CAN_PTYPE_MSGPACK,
'msg' => msgpack_pack([])
];
di_can_send($can, $rep);
}
function rpc_sensor_info($can, $msg) {
echo __FUNCTION__ . PHP_EOL;
$rep = [
'dst_id' => $msg['src_id'],
'msgtype' => DI_CAN_MSGTYPE_RPC,
'ttype' => DI_CAN_TRANSFERTYPE_REPLY,
'dtype' => DI_RPC_TYPE_SENSOR_INFO,
'ptype' => DI_CAN_PTYPE_MSGPACK,
'msg' => msgpack_pack([])
];
di_can_send($can, $rep);
}
function rpc_notify_info($can, $msg) {
echo __FUNCTION__ . PHP_EOL;
$rep = [
'dst_id' => $msg['src_id'],
'msgtype' => DI_CAN_MSGTYPE_RPC,
'ttype' => DI_CAN_TRANSFERTYPE_REPLY,
'dtype' => DI_RPC_TYPE_NOTIFY_INFO,
'ptype' => DI_CAN_PTYPE_MSGPACK,
'msg' => msgpack_pack([])
];
di_can_send($can, $rep);
}
$registry = new CANMsgRegistry();
/** RAW */
$registry->register("raw_dinet_time", DI_CAN_TRANSFERTYPE_PUBLISH, DI_CAN_MSGTYPE_RAW, DI_CAN_RAW_DTYPE_DINET_TIME);
$registry->register("raw_device_uid", DI_CAN_TRANSFERTYPE_REQUEST, DI_CAN_MSGTYPE_RAW, DI_CAN_RAW_DTYPE_DEVICE_UID);
$registry->register("raw_project_id", DI_CAN_TRANSFERTYPE_REQUEST, DI_CAN_MSGTYPE_RAW, DI_CAN_RAW_DTYPE_PROJECT_ID);
$registry->register("raw_connection_state", DI_CAN_TRANSFERTYPE_PUBLISH, DI_CAN_MSGTYPE_RAW, DI_CAN_RAW_DTYPE_CONNECTION_STATE);
/** NET */
$registry->register("net_heartbeat", DI_CAN_TRANSFERTYPE_PUBLISH, DI_CAN_MSGTYPE_NET, DI_CAN_NET_DTYPE_HEARTBEAT);
$registry->register("net_discover", DI_CAN_TRANSFERTYPE_REQUEST, DI_CAN_MSGTYPE_NET, DI_CAN_NET_DTYPE_DISCOVER);
$registry->register("net_node_uid", DI_CAN_TRANSFERTYPE_REQUEST, DI_CAN_MSGTYPE_NET, DI_CAN_NET_DTYPE_NODE_UID);
$registry->register("net_node_uid", DI_CAN_TRANSFERTYPE_REPLY, DI_CAN_MSGTYPE_NET, DI_CAN_NET_DTYPE_NODE_UID);
/** RPC */
$registry->register("rpc_device_ping", DI_CAN_TRANSFERTYPE_REQUEST, DI_CAN_MSGTYPE_RPC, DI_RPC_TYPE_DEVICE_PING);
$registry->register("rpc_device_info", DI_CAN_TRANSFERTYPE_REQUEST, DI_CAN_MSGTYPE_RPC, DI_RPC_TYPE_DEVICE_INFO);
$registry->register("rpc_config_info", DI_CAN_TRANSFERTYPE_REQUEST, DI_CAN_MSGTYPE_RPC, DI_RPC_TYPE_CONFIG_INFO);
$registry->register("rpc_sensor_info", DI_CAN_TRANSFERTYPE_REQUEST, DI_CAN_MSGTYPE_RPC, DI_RPC_TYPE_SENSOR_INFO);
$registry->register("rpc_notify_info", DI_CAN_TRANSFERTYPE_REQUEST, DI_CAN_MSGTYPE_RPC, DI_RPC_TYPE_NOTIFY_INFO);
if (!isset($argv[1])) {
echo "argument expected" . PHP_EOL;
echo "usage: di-candump <iface, e.g \"can0\", \"vcan0\">" . PHP_EOL;
exit(1);
}
$fd = di_can_open($argv[1]);
if ($fd === null) {
echo "error opening: '".$argv[1]."'" . PHP_EOL;
echo "usage: di-can-fakedevice <iface, e.g \"can0\", \"vcan0\">" . PHP_EOL;
exit(1);
}
di_can_set_nodeid($fd, $deviceUID);
function mstime() {
return round(microtime(true) * 1000);
}
/**
* Sensor 666 triangle
*/
$next = 0;
$value = 0;
$up = true;
function publish_sensor_uid_666_triangle($fd) {
global $next;
global $value;
global $up;
if (mstime() >= $next) {
rpc_sensor_publish($fd, 666, $value);
$next = mstime() + 500;
if ($up)
$value += 1;
else
$value -= 1;
if ($value == 4)
$up = false;
else if ($value == -4)
$up = true;
}
}
declare(ticks=1); // php magic to make signal handler work...
function sig_handler($signo)
{
echo "Got signal $signo...\n";
di_can_close($GLOBALS['fd']);
unset($GLOBALS['fd']);
switch ($signo) {
case SIGINT:
exit;
break;
case SIGTERM:
exit;
break;
case SIGHUP:
break;
default:
}
}
pcntl_signal(SIGTERM, "sig_handler");
pcntl_signal(SIGHUP, "sig_handler");
pcntl_signal(SIGINT, "sig_handler");
while(true) {
$msg = di_can_recv($fd);
if ($msg === null)
continue;
$t = microtime(true);
$micro = sprintf("%06d",($t - floor($t)) * 1000000);
$d = new DateTime( date('Y-m-d H:i:s.'.$micro, $t) );
$timestr = $d->format("Y-m-d H:i:s.u");
// Convert src and dst node id to hex
$src_id = dechex($msg['src_id']);
$src_id = '0x' . str_pad($src_id, 8, "0", STR_PAD_LEFT);
$dst_id = dechex($msg['dst_id']);
$dst_id = '0x' . str_pad($dst_id, 8, "0", STR_PAD_LEFT);
echo "[" . $timestr . "] ($src_id -> $dst_id) ";
$registry->execute($fd, $msg);
}