328 lines
8.1 KiB
PHP
Executable File
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);
|
|
}
|