#!/usr/bin/php
<?php
#
# A very limited script engine that sends and receives CAN messages.
#
# (C) 2009-2026, Kees Verruijt, Harlingen, The Netherlands.
#
# This file is part of CANboat.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

require_once('canboat-default.inc');

$command = getCanboatDefault('N2K_WRITE_COMMAND', null);

$n2k_write_format = getCanboatDefault('N2K_WRITE_FORMAT', 'CANBOAT');
if ($n2k_write_format == 'YDWG')
{
  $n2k_write_proto = gethostbyname(getCanboatDefault('N2K_WRITE_PROTO', 'udp'));
  $n2k_write_host  = gethostbyname(getCanboatDefault('N2K_WRITE_HOST', 'ydwg'));
  $n2k_write_port  = getCanboatDefault('N2K_WRITE_PORT', '1457');
  $send_product_info="18EAFF00 14 f0 01\r\n"; # ./send-message/format-message 255 request_pgn 126996
  $send_config_info="18EAFF00 16 f0 01\r\n";  # ./send-message/format-message 255 request_pgn 126998
  $n2k_host = $n2k_write_host;
  $n2k_port = $n2k_write_port;
}
elseif ($n2k_write_format == "CANBOAT")
{
  $n2k_write_proto = gethostbyname(getCanboatDefault('N2K_WRITE_PROTO', 'tcp'));
  $n2k_write_host  = gethostbyname(getCanboatDefault('N2K_WRITE_HOST', 'localhost'));
  $n2k_write_port  = getCanboatDefault('N2K_WRITE_PORT', '2600');
  $send_product_info="2012-06-17-15:02:11.000,6,59904,0,255,3,14,f0,01\n"; # ./send-message/format-message 255 request_pgn 126996
  $send_config_info="2012-06-17-15:02:11.000,6,59904,0,255,3,16,f0,01\n";  # ./send-message/format-message 255 request_pgn 126998
  $n2k_host = $n2k_write_host;
  $n2k_port = $n2k_write_port - 3;
}
else
{
  die("Unknown N2K_WRITE_FORMAT='$format' in '/etc/default/canboat'\n");
}


print "n2k_write_host = $n2k_write_host\n";

$n2k_write_socket = null;

function openN2kd()
{
  global $n2k_write_format, $n2k_write_socket, $n2k_write_host, $n2k_write_port, $n2k_write_proto;

  if ($n2k_write_socket === null)
  {
    if ($n2k_write_proto == 'udp')
    {
      $n2k_write_socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
    }
    else
    {
      $errno = 0;
      $errstr = '';
      $n2k_write_socket = @fsockopen($n2k_write_host, $n2k_write_port, $errno, $errstr, 15);
      if (!$n2k_write_socket || !is_resource($n2k_write_socket))
      {
        fwrite(STDERR, "Cannot connect to N2KD: $errstr\n");
        return false;
      }
    }
    $n2k_open_timestamp = microtime(true);
  }
  return true;
}

function sendToN2K($pgn)
{
  global $n2k_write_socket, $n2k_write_proto, $n2k_write_host, $n2k_write_port;

  if (!openN2kd())
  {
    return;
  }

  if ($n2k_write_proto == 'udp')
  {
    socket_sendto($n2k_write_socket, $pgn, strlen($pgn), 0, $n2k_write_host, $n2k_write_port);
  }
  else if (openN2kd() && !@fwrite($n2k_write_socket, $pgn))
  {
    $n2k_write_socket = null;
    if (openN2kd())
    {
      fwrite($n2k_write_socket, $pgn);
    }
    else
    {
      $n2k_write_socket = null;
    }
  }
}

function getN2KData($query, $ais = false)
{
  global $n2k_host, $n2k_port;
  global $src, $debug;
  global $n2kdatafile;

  $port = $n2k_port;
  if ($ais)
  {
    $port += 4;
  }


  $errno = 0;
  $errstr = '';
  $s = '';

  if ($n2kdatafile)
  {
    if ($debug) echo "Querying n2kdatafile $n2kdatafile";

    $fd = fopen($n2kdatafile, 'r');

    while (!feof($fd))
    {
      $s .= fgets($fd, 32768);
    }
    fclose($fd);
  }
  else
  {
    if ($debug) echo "Querying N2K server $n2k_host:$port query '$query'\n";

    $fd = socket_create(AF_INET, SOCK_STREAM, getprotobyname('tcp'));
    if (!socket_connect($fd, $n2k_host, $port) || !$fd || !is_resource($fd))
    {
      if ($debug) { echo "N2K request failed\n"; }
      return null;
    }
    if ($query)
    {
      socket_write($fd, $query);
    }
    // socket_shutdown($fd, 1); // No more writes

    while (($block = @socket_read($fd, 32768, PHP_BINARY_READ)) !== false && strlen($block) > 0)
    {
      $s .= $block;
    }
    socket_close($fd);
  }

  $s .= "\n";
  $data = json_decode($s, true);

  if ($debug)
  {
    echo "RAW DATA LEN: " . strlen($s) . "\n";
    $fd = fopen("raw.json", "w");
    fwrite($fd, $s);
    fclose($fd);
    if ($data)
    {
      echo "JSON ARRAY LEN: " . count($data) . "\n";
    }
    else
    {
      echo "JSON ERROR: " . json_last_error() . "\n";
    }
  }
  return $data;
}

function value($arr, $key, $default = null)
{
  if (array_key_exists($key, $arr))
  {
    return $arr[$key];
  }
  return $default;
}

sendToN2K($send_product_info);
sendToN2K($send_config_info);

$data = getN2KData('');
if (!is_array($data) || !is_array($data[126996]))
{
  echo "No product information received.\n";
  if ($debug)
  {
    print_r($data);
  }
  exit(1);
}

$devices = $data[126996];

print "Device information:\n";
$x = str_repeat('-', 32);
printf("%3.3s | %-32.32s | %-20.20s | %-20.20s | %-11.11s | %-6.6s\n", "Src", "Name", "Version", "Model", "N2K Version", "Load");
printf("%3.3s | %-32.32s | %-20.20s | %-20.20s | %-11.11s | %-6.6s\n", $x, $x, $x, $x, $x, $x);

foreach ($devices as $src => $device)
{
  if (!is_array($device))
  {
    continue;
  }
  $id      = $device['fields']['Model ID'];
  $version = $device['fields']['Software Version Code'];
  $model   = value($device['fields'], 'Model Version', '?');
  $n2kver  = value($device['fields'], 'NMEA 2000 Version', '?');
  $load    = value($device['fields'], 'Load Equivalency', '1') * 50;

  if (preg_match('/(\d{1,3})_\d+/', $src, $matches))
  {
    $src = $matches[1];
  }

  printf("%3d | %-32.32s | %-20.20s | %-20.20s | %-11.11s | %-4.4dmA\n", $src, $id, $version, $model, $n2kver, $load);
}

$config = $data[126998];
print_r($config);
if (is_array($config))
{
  print "Config information:\n";
  foreach ($config as $src => $conf)
  {
    if (!is_array($conf))
    {
      continue;
    }
    $manu    = value($conf['fields'], 'Manufacturer Information', null);

    if ($manu)
    {
      if (preg_match('/(\d{1,3})_\d+/', $src, $matches))
      {
        $src = $matches[1];
      }

      printf("%3d | %s\n", $src, $manu);
    }
  }
}

?>
