Packet Data Transmission over DMR

Things about DMR
Post Reply
kc9uhi
Site Admin
Posts: 107
Joined: Mon Dec 02, 2013 10:46 pm

Packet Data Transmission over DMR

Post by kc9uhi » Mon Jan 16, 2017 4:08 pm

Goal: upload data from a mobile unit (pi data logger in vehicle) to a fixed station/database
Method: udp packets via DMR (MotoTRBO)

First test is a success. I can send text from one point to another over a DMR simplex link.

Setup: two raspberry pis with trbo radios attached via USB. Just connecting the cable will create a usb0 network interface on the pi. Add a route table entry so the pi knows to send info destined for 12.0.0.0/8 over the usb0 interface. I used socat to receive/send data over udp. Whatever went in on the sending side came out on the receiving side. The example small-txt-file below is just that - a small text file with a couple lines of generic sample text.

Receiving radio needs to have "Forward to PC" set to "via USB", on the Network tab in CPS.

Receiving side:

Code: Select all

# route add -net 12.0.0.0/7 gw 192.168.10.1
# socat -u udp-recv:4041 stdout 
Sending side:

Code: Select all

# route add -net 12.0.0.0/7 gw 192.168.10.1
# cat small-txt-file | socat -u stdin udp-sendto:REMOTE_IP:4041
The REMOTE_IP above gets filled in with the IP addr of the receiving radio.
How to determine this (assuming default CAI network of 12):
First Octet: 13
Second Octet: ($id >> 16) & 0xff
Third Octet: ($id >> 8) & 0xff
Fourth Octet: $id & 0xff
Example: using $id of 3155055, resulting ip is 12.48.36.111
Illustration: 3155055 in binary is 00110000 00100100 01101111. Split the address into three bytes, convert to decimal -> 00110000=48 00100100=36 01101111=111

update: 25Jan2017
Using the default CAI network of 12, the attached pc operates on the 13.0.0.0/8 network. Thus, sending packets to the 13.* address goes directly to attached pc without needing "Forward to PC" set in the codeplug. This allows text-messaging on the radio to work in conjunction with data over dmr.

User avatar
kb9mwr
Posts: 128
Joined: Tue Dec 03, 2013 10:59 am

Re: Packet Data Transmission over DMR

Post by kb9mwr » Fri Jan 20, 2017 3:39 pm

So even with nothing connected by the radio USB cable, is it possible to ping a radio to determine if it is on? I tend to think so, just looking for clarification.

kc9uhi
Site Admin
Posts: 107
Joined: Mon Dec 02, 2013 10:46 pm

Re: Packet Data Transmission over DMR

Post by kc9uhi » Fri Jan 20, 2017 6:40 pm

If the radio is on the same frequency/timeslot as the requesting device, I would think that the ARS 'ping' command would generate a 'pong' response from the radio.

Edit: 25Jan2017
Tested-- requires the selected channel to have ARS enabled in the codeplug

kc9uhi
Site Admin
Posts: 107
Joined: Mon Dec 02, 2013 10:46 pm

Re: Packet Data Transmission over DMR

Post by kc9uhi » Thu Jan 26, 2017 6:04 pm

Code below to send/receive files over TRBO. Server script runs on base unit, waits for connection from client. Spawns child process to receive and verify data. Received files are placed in the 'infile' folder, located in same directory as scripts. Handles multiple clients at the same time.

disclaimer:
Of course, it's in php. There might be errors. Seems to send text files alright. Might send binary too. Both sides spew some random debugging info to stdout.


server: $ php file-server.php
client: $ php file-send.php <filename> <server_radio_id>


Server scripts:
file-server.php

Code: Select all

<?php
  set_time_limit(0);
  $sock = stream_socket_server('udp://0.0.0.0:4041', $errno, $errstr, STREAM_SERVER_BIND);
  if (!$sock) {
    die("$errstr ($errno)");
  }

  $PIDS = array();

  do {
    $pkt = stream_socket_recvfrom($sock, 1000, 0, $peer);

    $pid = pcntl_fork();
    if ($pid == -1) {
      die ('could not fork');
    } elseif ($pid) {
      // parent
      $PIDS[] = $pid;
    } else {
      // child
      include "file-xfer.inc.php";
      exit;
    }
    /** cleanup dead children **/
    foreach ($PIDS as $pid) pcntl_waitpid($pid,$status,WNOHANG);
  } while ($pkt !== false);

  /** cleanup dead parents **/
  foreach ($PIDS as $pid) {
    $returnPid = pcntl_waitpid($pid,$status);
    unset($PIDS[$pid]);
  }
  fclose($sock);
?>
file-xfer.php

Code: Select all

<?php
  $stime = time();
  print "  start: $stime\n";

  $xsock = stream_socket_server('udp://0.0.0.0:0', $xerrno, $xerrstr, STREAM_SERVER_BIND);
  if (!$xsock) {
   die("$xerrstr ($xerrno)");
  }

  list($xhost, $xport) = explode(":", stream_socket_get_name($xsock, FALSE));
  list($fname, $fsize, $fhash) = explode("/////", trim($pkt));

  stream_socket_sendto($sock, "$xport\n", 0, $peer);

  print "xfer: $xport; fname: $fname; fsize: $fsize;\n";

  $ftmp = "";

  stream_set_timeout($xsock, 120);
  while (strlen($ftmp) < $fsize) {
    $pkt = stream_socket_recvfrom($xsock, 900, 0, $peer);
    $ftmp .= $pkt;
    print "  size: " . strlen($ftmp) . "\n";
    stream_socket_sendto($xsock, "K", 0, $peer);
  }

  if (strlen($ftmp) == $fsize) {
    $hash = hash('md5', $ftmp);
    if ($hash == $fhash) {
      $fh = fopen("infile/$fname", 'w');
      fputs($fh, $ftmp);
      fclose($fh);
      // success-xfer
      $result = 0;
    } else {
      // bad hash
      $result = 2;
    }
  } else {
    // fail-xfer
    $result = 1;
  }


  stream_socket_sendto($xsock, "$result", 0, $peer);
  fclose($xsock);

  $etime = time();
  $dur = $etime - $stime;
  $abps = $fsize / $dur;
  print "  end: $etime\n  duration: $dur\n  abps: $abps\n\n";
  exit;
?>

Client script:
file-send.php

Code: Select all

<?php
  set_time_limit(0);

  $port_init = "4041";
  if ($argc !== 3) { die ("usage: file-send.php <filename> <target_id>\n"); }
  $file = $argv[1];
  $id = $argv[2];

  if (!is_numeric($id)) {
    die("id not numeric\n");
  }
  if (($id < 1) | ($id > 16776415)) {
    die("id out of range -- 1-16776415\n");
  }
  if (!is_file($file)) {
    die("file not valid\n");
  }

  $host = '13.' . (($id >> 16) & 0xFF) . '.' . (($id >> 8) & 0xFF) . '.' . ($id & 0xFF);

  $handle = fopen($file, "rb");
  $fname = basename($file);
  $fsize = filesize($file);
  $fhash = hash_file('md5', $file);
  if ($handle) {
    /* ititiate connection */
    $sock = stream_socket_client("udp://{$host}:{$port_init}", $errno, $errstr);
    if (!$sock) {
      die ("error: $errno - $errstr\n");
    }
    fwrite($sock, "$fname/////$fsize/////$fhash\n");
    $xport = trim(stream_socket_recvfrom($sock, 6));
    fclose($sock);

    $xsock = stream_socket_client("udp://{$host}:{$xport}", $errno, $errstr);
    if (!$xsock) {
      die ("x error: $errno = $errstr\n");
    }

    /* send file */
    $j = 1;
    stream_set_timeout($xsock, 90);
    while (!feof($handle)) {
      $buf = fread($handle, 900);

      #send buffer
      fwrite($xsock, $buf);
      print "sent: $j\n";
      $j++;
      $ret = stream_socket_recvfrom($xsock, 1);
      if ($ret !== "K") { die("error sending"); }
      sleep(1);
    }
    print "done sending\n";
    $ret = stream_socket_recvfrom($xsock, 1);
    if ($ret == "0") {
      echo "success!\n";
    } else {
      echo "fail -- $ret\n";
    }
    fclose($xsock);
    fclose($handle);
  }
?>

Post Reply

Who is online

Users browsing this forum: No registered users and 0 guests