Accessing the P2 wifi repeater and camera

The cable feeds data into the camera unit. The camera unit contains the camera and the wifi. The video and telemetry data are sent by the wifi. You can modify the android app to separate the telemetry data to a file, it's not overlaid on the video feed. Replacing the camera would be tricky though, as you'd need to find the data path for the video feed into the wifi -- which is internal to the camera module. Probably analysing the data over the board - to - board connectors in the FC200 would give the answer....
 
kwatts,

Excuse my dumbness, how did you get into Linux System #2. I had no problem getting into system #1. I'm having telemetry problems. I'm not getting any telemetry data sent to the App. See this post: viewtopic.php?f=7&t=17803
I thought maybe I could look around in system 2.

Thanks for your help!
 
MonsieurAnon said:
Hrmm.

I found someone who lost their OSD after a crash, where they had to replace their Vision cable. The stock DJI mini-osd operates by taking video in and outputting overlayed footage onboard your drone. Are you suggesting that the P2V would broadcast OSD information without the camera? If so, then what someone said earlier about simply replacing the camera with say, a goPro would be a great solution for a lot of mods that people want ... as they could still use the repeater and app.

Also, I found various people talking about the dB hack that has been discussed in this thread. A number of them pointed out that by changing the country code to BO the dB setting sticks ... and does indeed give better range.

My experience is with the P2V+, so it may be different on other models.

With the P2V+, the only overlay on the FPV is that of the record time for when a video is being recorded. All other metrics are generated in the UI based on data from various ser2net streams (or some other feed type, but I believe ser2net is used for all of it). The camera itself may provide feedback via a method other than ser2net for photo taking / video taking state (so the UI can update the simulated shutter and/or the record/photo button availability).

LK
 
I wonder if you can use the ser2net connections and something like com0com to talk to windows and the ground station software. Therefore bypassing the DJI datalink. The app seems to be the hold up not the Flight controller. Anyone want to give it a try on the ground and see if it works?
 
Reading this very interesting thread i wonder if anyone could advise me on a small project I've been thinking about for a while now.

I'd like to provide an internet link for the phantom network for use in areas of poor or no ground coverage on 2g / 3g mobile networks.

I had an idea about binding a raspberry pi fitted with both WiFi and mobile broadband dongles direct to the cameras hidden SSID hotspot to act as a gateway to the internet for the ground based phone which would be connected to the repeaters hotspot.

If I've picked up the details from the various threads on the forum correctly it sounds like the whole DJI 2.4 setup effectively gives a flat network layer so in theory all connected devices should be able to communicate and allow me to setup the raspberry pi to provide the internet gateway.

Having strapped a phone to the landing gear of the quad running a signal strength logging app I know I can get sufficient phone reception at a height of around 500 feet in the area I wish to use it. Unfortunately the phones hotspot doesn't have the range to connect direct which is why I wondered about piggybacking on the phantoms link to give greater range.

Without going into huge detail from what you have found out about the DJI setup so far does this sound like a feasible plan?
 
kwatts said:
When I did have the P2 Vision (crash and burn, faulty battery, which, DJI seemed to ignore - support is really taking a dive there) I spent a few hrs and was able to fully get the telemetry data and control. It was using the native libs, but, there is a way to connect and for those of you at there that are good at network protocols may be able to figure out the communication protocol being used.

In any case (and apologies if this has been posted/found already):
- To connect to the repeater, you can ssh [email protected] or go to http://192.168.1.1:80/openwrt and for both the admin password is "19881209".
- You can just connect
directly to the wifi from your laptop... seems a bit flakey but
generally works
- The (android) app has a native lib you can use to communicate through as well.

It´s a very interesting mod, despite of I´m not an expert about communication I´m going to check it out and see what happen. nice contribution.
Best regards
 
verygreen said:
Linux system #1 - the wifi manager, gives out dhcp leases and such. Lives at ip address 192.168.1.2, based on openwrt. Root password is 19881209
- Nothing really interesting there.

Linux system #2 - general purpose system. Lives at 192.168.1.1 This one provides file access to pictures and videos when accessed from your phone app for example, also provides telemetry.
- Telemetry is provided on port 2001 (obtained from serial port 0 on the SoC at 115200 bps)
- web server on port 80 that does not seem to serve any useful purpose, there's half removed lua stuff from openwrt that does not really work.
- another web server on port 1026 - This one you use to access pictures from phone app.
* When you go to "Album" apge in the app, it sends a control signal to the camera and camera enters "usb storage" mode, becoming visible as a usb flashdrive to this ystem that is then mounted to /mnt/sda1

System #3 - This is the actual camera. Lives at 192.168.1.10 It runs something very similar to what GoPro systems run (Ambarella)
- udp port 9000 is the video stream port. Possiblty it also has some camera control.
- tcp port 22 - This one is a mystery. It answers with "SSH-2.0-OpenSSH_6.2", but I checked RAM dumps and such and I do not see it having openssh inside, so I am not really sure where does this come from. Some sort of additional embedded node? root password unknown.
- This system mounts the sdcard most of the time to write stuff there and such.
- This system is mildly scriptable in the same way as GoPro cameras, so at least some of their scripts would work here as well, though some more investigations are needed (see e.g. this resource for a big compilation of recipes: https://github.com/KonradIT/autoexechack )

The root password for system #3, the "DJI-Pro" camera at 192.168.1.10, is: 123456

Code:
root@Dji-Pro:~# uname -a
Linux Dji-Pro 2.6.32.17-davinci1 #6 PREEMPT Wed Apr 9 05:21:55 PDT 2014 armv5tejl GNU/Linux
root@Dji-Pro:~# cat /proc/cpuinfo 
Processor       : ARM926EJ-S rev 5 (v5l)
BogoMIPS        : 215.44
Features        : swp half thumb fastmult edsp java 
CPU implementer : 0x41
CPU architecture: 5TEJ
CPU variant     : 0x0
CPU part        : 0x926
CPU revision    : 5

Hardware        : DaVinci DM36x EVM
Revision        : 0000
Serial          : 0000000000000000

It runs the following userland processes.
Code:
root@Dji-Pro:~# ps | tail
  406 root       0:00 /usr/local/sbin/sshd
  410 root       0:20 ./read_proc
  412 root       0:00 {autologin} /bin/sh /sbin/autologin
  413 root       0:00 -sh
  445 root       0:00 [flush-ubifs_0_0]
  446 root       0:01 sshd: root@pts/0
  450 root       0:00 -sh
  499 root       0:27 encode -v hehe.264 -y 1 -r 320x240
  500 root       3:27 server
  549 root       0:00 ps

root@Dji-Pro:~# ls -al /proc/500/fd
total 0
dr-x------    2 root     0                0 Jan  1 00:08 .
dr-xr-xr-x    6 root     0                0 Jan  1 00:02 ..
lr-x------    1 root     0               64 Jan  1 00:08 0 -> /dev/null
lrwx------    1 root     0               64 Jan  1 00:08 1 -> /dev/console
lrwx------    1 root     0               64 Jan  1 00:08 2 -> /dev/console
l-wx------    1 root     0               64 Jan  1 00:08 3 -> /mq_encoder
lr-x------    1 root     0               64 Jan  1 00:08 4 -> /mq_server
lrwx------    1 root     0               64 Jan  1 00:08 5 -> socket:[19642]


root@Dji-Pro:~# ls -al /proc/499/fd
total 0
dr-x------    2 root     0                0 Jan  1 00:08 .
dr-xr-xr-x    6 root     0                0 Jan  1 00:02 ..
lr-x------    1 root     0               64 Jan  1 00:08 0 -> /dev/null
lrwx------    1 root     0               64 Jan  1 00:08 1 -> /dev/console
l-wx------    1 root     0               64 Jan  1 00:08 10 -> pipe:[16024]
lrwx------    1 root     0               64 Jan  1 00:08 11 -> /dev/davinci_resizer
lrwx------    1 root     0               64 Jan  1 00:08 12 -> /dev/davinci_previewer
lrwx------    1 root     0               64 Jan  1 00:08 13 -> /dev/video0
lr-x------    1 root     0               64 Jan  1 00:08 14 -> /dev/edma
lrwx------    1 root     0               64 Jan  1 00:08 15 -> /dev/mem
lrwx------    1 root     0               64 Jan  1 00:08 16 -> /dev/mem
lrwx------    1 root     0               64 Jan  1 00:08 17 -> /dev/mem
lrwx------    1 root     0               64 Jan  1 00:08 18 -> /dev/mem
lrwx------    1 root     0               64 Jan  1 00:08 2 -> /dev/console
lr-x------    1 root     0               64 Jan  1 00:08 3 -> /mq_encoder
l-wx------    1 root     0               64 Jan  1 00:08 4 -> /mq_server
lrwx------    1 root     0               64 Jan  1 00:08 5 -> /dev/cmem
lr-x------    1 root     0               64 Jan  1 00:08 6 -> /dev/irqk
lr-x------    1 root     0               64 Jan  1 00:08 7 -> pipe:[16023]
l-wx------    1 root     0               64 Jan  1 00:08 8 -> pipe:[16023]
lr-x------    1 root     0               64 Jan  1 00:08 9 -> pipe:[16024]

Oh, and after stumbling on GitHub user @cr3ative's gist Drift HD Ghost - Technical Notes and Root, I also had some success in using @evilwombat's gopro-fw-tools to extract a bunch of camera-related sections from the firmware_plus.bin file for the P2V+.

Regarding the WiFi Range Extender (aswell as the general purpose system at 192.168.1.1), you can download and install a lot of pre-built OpenWRT packages from http://downloads.openwrt.org/snapshots/trunk/ar71xx/packages/.

Since I was interested in the communication between the DJI Vision App and the camera, I installed tcpdump (with its libpcap dependency) to the WiFi-bridge like this:

Copy the packages from your Linux/Mac to the Wi-Fi range extender at 192.168.1.2.
Code:
$ scp tcpdump-mini_4.5.1-4_ar71xx.ipk libpcap_1.5.3-1_ar71xx.ipk [email protected]:/tmp
[email protected]'s password: 
tcpdump-mini_4.5.1-4_ar71xx.i 100%  137KB 137.3KB/s   00:00    
libpcap_1.5.3-1_ar71xx.ipk    100%   81KB  80.9KB/s   00:00

Then login to it and issue 'opkg install' to install the packages:
Code:
$ ssh [email protected]
[email protected]'s password: 19881209


BusyBox v1.19.4 (2013-04-22 22:41:57 CST) built-in shell (ash)
Enter 'help' for a list of built-in commands.

 -----------------------------------------------------
 DJI-INNOVATIONS
 -----------------------------------------------------
  * FC200-Vision+ RE   
  * [email protected]
  * 02/21/2014
  * Version 1.01
  * ART / DHCP down / ping
 -----------------------------------------------------
root@Phantom:~# cd /tmp
root@Phantom:/tmp# opkg install libpcap_1.5.3-1_ar71xx.ipk tcpdump-mini_4.5.1-4_ar71xx.ipk 
Installing libpcap (1.5.3-1) to root...
Installing tcpdump-mini (4.5.1-4) to root...
Configuring libpcap.
Configuring tcpdump-mini.
root@Phantom:/tmp# rm *.ipk
root@Phantom:/tmp#

To dump traffic to a local file named "dji-wifi-traffic.pcap" (hit Ctrl-C to abort):
Code:
$ ssh [email protected] tcpdump -i br-lan -s0 -w - port not 22 > dji-wifi-traffic.pcap
[email protected]'s password: 
tcpdump: listening on br-lan, link-type EN10MB (Ethernet), capture size 65535 bytes

A bit off-topic, but if anyone else is interested in how the communication between the remote and the Phantom works, checkout Hacking the Phantom - by Team Reaper (Jacob, Kyle and Scott).

Btw, did anyone succeed in decoding the video data that's sent over UDP from 192.168.1.10:9000?
Also, has anybody attempted to decode the communication that happens over the ser2net service, i.e, the telemetry?
 
OK, so I've spent a few hours sniffing the ser2net communication on port 2001 between the DJI Vision app (iOS for me) and the camera instance at 192.168.1.1.

It looks like it is a request - response protocol, with the client making the requests. Each packet consists of a header, some data and a XOR-based checksum. The header is made up of a two byte magic number that always starts the header, a total packet length, an unknown (status?) byte, a packet sequence number (starting from 0), data (with the starting byte, or bytes, specifying the command) and a checksum byte.

In C that would look something like this:
Code:
/**
 * Byte 00 .. 01 : Magic <0x55, 0xbb>
 * Byte 02 .. 02 : Total packet length, including magic and cksum 
 * Byte 03 .. 03 : Unknown, flag byte? Parts of it seems stable.
 * Byte 04 .. 05 : Packet sequence number
 * Byte 06 .. N-1: Command byte(s) and data (unknown)
 * Byte  N .. N  : Checksum (XOR over previous bytes)
 */
struct pkt {
    uint16_t magic;    /* Magic: 0x55, 0xbb */
    uint8_t len;    /* Packet length (including: magic, this byte, data, chksum byte) */
    uint8_t flags; /* App->Phantom: usually 0x08 or 0x0a.. flags? */
    uint16_t seq;    /* Packet counter, network byte order: 0..N */
    uint8_t data[255 - 6];
    uint8_t cksum;    /* for(i = cksum = 0; i < len - 1; i++) cksum ^= data[i]; */
};

/* .. .. .. */

static int readpacket(int fd) {
    struct pkt _pkt, *pkt = &_pkt;
    uint8_t cksum = 0, *p = (uint8_t *)&_pkt;
    uint8_t datalen, i;
    ssize_t n;

    if((n = read(fd, pkt, 6)) != 6) return -1;
    for(i = 0; i < 6; i++) cksum ^= *p++;

    if(pkt->magic != 0xbb55) {
        fprintf(stderr, "Invalid magic 0x%04x (expected 0xbb, 0x55)\n", pkt->magic);
        return -1;
    }
    else if(pkt->len < 9) {
        fprintf(stderr, "Invalid length %d (expected >= 9)\n", pkt->len);
        return -1;
    }

    datalen = pkt->len - 6 /* magic, len, flags, seq */ - 1 /* cksum */;
    if((n = read(fd, pkt->data, datalen)) != datalen) return -1;
    for(i = 0, p = pkt->data; i < datalen; i++) cksum ^= *p++;

    if((n = read(fd, &pkt->cksum, 1)) != 1) return -1;
    if(cksum != pkt->cksum) {
        fprintf(stderr, "Invalid checksum 0x%02x (expected 0x%02x)\n", pkt->cksum, cksum);
        return -1;
    }

    return parsepacket(pkt);
}


I'm curious what the data payload consists of but I've not quite figured it out yet. From experience with other protocols, it usually involves "command bytes" that identify a subroutine or task ("ping" so server can "pong", or "get battery level" so server can return data about battery level).

In some protocols, a single packet may contain multiple "entries" or structured data, such as TLVs (type, length, values). Initially I thought perhaps the Phantom used something like this, but so far I haven't managed to identify any such boundaries in the packet payloads.

Now I'm leaning towards the possibility that it's just a single "command byte" (perhaps byte 6, counting from zero) with a fixed length (for the command byte in question) data dump following it.

I made a PHP script to look at some statistics in data gathered from a sniffed session with the DJI Phantom idle. I've guessed that byte 6 is the command byte and the next byte, or bytes (up to three in my test script), may be some kind of sub-command. From those assumptions I generated a tree that listed what command bytes had what "subkey" (sub-command) bytes immediately following it.

Here's the output:
Code:
**********************************************
***** Using one byte of data as subkey *******

command byte 04 (byte0):
  subkey 01 (data1..N): seen 1 times with packet lengths: [9]
command byte 20 (byte0):
  subkey 14 (data1..N): seen 2 times with packet lengths: [15]
command byte 2d (byte0):
  subkey 00 (data1..N): seen 1 times with packet lengths: [9]
command byte 40 (byte0):
  subkey 00 (data1..N): seen 169 times with packet lengths: [9]
command byte 44 (byte0):
  subkey 00 (data1..N): seen 164 times with packet lengths: [9]
command byte 49 (byte0):
  subkey 00 (data1..N): seen 165 times with packet lengths: [9]
command byte 03 (byte0):
  subkey 00 (data1..N): seen 1 times with packet lengths: [9]
command byte 41 (byte0):
  subkey 00 (data1..N): seen 3 times with packet lengths: [9]
command byte 52 (byte0):
  subkey 00 (data1..N): seen 164 times with packet lengths: [9]
command byte 61 (byte0):
  subkey 00 (data1..N): seen 1 times with packet lengths: [9]
command byte 53 (byte0):
  subkey 00 (data1..N): seen 82 times with packet lengths: [9]
command byte 25 (byte0):
  subkey 00 (data1..N): seen 28 times with packet lengths: [9]
command byte 65 (byte0):
  subkey 00 (data1..N): seen 16 times with packet lengths: [9]
command byte 24 (byte0):
  subkey 96 (data1..N): seen 239 times with packet lengths: [14]
  subkey 00 (data1..N): seen 12 times with packet lengths: [14]


**********************************************
***** Using two bytes of data as subkey ******

command byte 04 (byte0):
  subkey 01__ (data1..N): seen 1 times with packet lengths: [9]
command byte 20 (byte0):
  subkey 1420 (data1..N): seen 2 times with packet lengths: [15]
command byte 2d (byte0):
  subkey 00__ (data1..N): seen 1 times with packet lengths: [9]
command byte 40 (byte0):
  subkey 00__ (data1..N): seen 169 times with packet lengths: [9]
command byte 44 (byte0):
  subkey 00__ (data1..N): seen 164 times with packet lengths: [9]
command byte 49 (byte0):
  subkey 00__ (data1..N): seen 165 times with packet lengths: [9]
command byte 03 (byte0):
  subkey 00__ (data1..N): seen 1 times with packet lengths: [9]
command byte 41 (byte0):
  subkey 00__ (data1..N): seen 3 times with packet lengths: [9]
command byte 52 (byte0):
  subkey 00__ (data1..N): seen 164 times with packet lengths: [9]
command byte 61 (byte0):
  subkey 00__ (data1..N): seen 1 times with packet lengths: [9]
command byte 53 (byte0):
  subkey 00__ (data1..N): seen 82 times with packet lengths: [9]
command byte 25 (byte0):
  subkey 00__ (data1..N): seen 28 times with packet lengths: [9]
command byte 65 (byte0):
  subkey 00__ (data1..N): seen 16 times with packet lengths: [9]
command byte 24 (byte0):
  subkey 9690 (data1..N): seen 132 times with packet lengths: [14]
  subkey 9680 (data1..N): seen 107 times with packet lengths: [14]
  subkey 0080 (data1..N): seen 11 times with packet lengths: [14]
  subkey 0090 (data1..N): seen 1 times with packet lengths: [14]


**********************************************
***** Using three bytes of data as subkey ****


command byte 04 (byte0):
  subkey 01____ (data1..N): seen 1 times with packet lengths: [9]
command byte 20 (byte0):
  subkey 142007 (data1..N): seen 2 times with packet lengths: [15]
command byte 2d (byte0):
  subkey 00____ (data1..N): seen 1 times with packet lengths: [9]
command byte 40 (byte0):
  subkey 00____ (data1..N): seen 169 times with packet lengths: [9]
command byte 44 (byte0):
  subkey 00____ (data1..N): seen 164 times with packet lengths: [9]
command byte 49 (byte0):
  subkey 00____ (data1..N): seen 165 times with packet lengths: [9]
command byte 03 (byte0):
  subkey 00____ (data1..N): seen 1 times with packet lengths: [9]
command byte 41 (byte0):
  subkey 00____ (data1..N): seen 3 times with packet lengths: [9]
command byte 52 (byte0):
  subkey 00____ (data1..N): seen 164 times with packet lengths: [9]
command byte 61 (byte0):
  subkey 00____ (data1..N): seen 1 times with packet lengths: [9]
command byte 53 (byte0):
  subkey 00____ (data1..N): seen 82 times with packet lengths: [9]
command byte 25 (byte0):
  subkey 00____ (data1..N): seen 28 times with packet lengths: [9]
command byte 65 (byte0):
  subkey 00____ (data1..N): seen 16 times with packet lengths: [9]
command byte 24 (byte0):
  subkey 969000 (data1..N): seen 132 times with packet lengths: [14]
  subkey 968000 (data1..N): seen 107 times with packet lengths: [14]
  subkey 008000 (data1..N): seen 11 times with packet lengths: [14]
  subkey 009000 (data1..N): seen 1 times with packet lengths: [14]

FWIW, here's the script I used to generate it:
Code:
#!/usr/bin/env php
<?php
/**
 * Parse Wireshark's Analyze/Follow TCP Stream/Hexdump save file
 * Attempt to identify where command byte boundaries are in order
 * to understand the protocol run over ser2net better
 *
 * Gather a dump of the ser2net traffic using:
 * $ ssh [email protected] tcpdump -n -i br-lan -s0 - port 2001 > dji.pcap
 * (assuming you've installed tcpdump from OpenWRT previously)
 *
 * - Open the pcap file with Wireshark
 * - Select menu Analyze, Follow TCP stream, choose hexdump output, save to file
 * 
 * Run this script on the output file:
 * $ php dji-parse-wireshark-hexdump.php dji-pcap-hexdump.txt
 *
 * To ignore debug data and only retrieve graph, redirect stderr to /dev/null:
 * $ php dji-parse-wireshark-hexdump.php dji-pcap-hexdump.txt 2>/dev/null
 *
 *
 * To experiment more with this, change $cmdbyte and $subkey in parse_packet()
 *
 */

$filename = 'php://stdin';
if($argc > 1) $filename = $argv[1];
$data = file_get_contents($filename);

$graph = array();
$graph_length = array();

function parse_packet($packet, $source) {
    global $graph, $graph_length;

    /* Two bytes magic (0x55, 0xbb) */
    $magic = base_convert(substr($packet, 0, 4), 16, 10);
    $magic = ($magic >> 8) | (($magic & 0xff) << 8);
    /* One byte total packet length, including magic, len and cksum */
    $len = base_convert(substr($packet, 4, 2), 16, 10);
    /* Status flag..? */
    $flags = base_convert(substr($packet, 6, 2), 16, 10);
    /* Packet sequence number */
    $seq = base_convert(substr($packet, 8, 4), 16, 10);
    $seq = ($seq >> 8) | (($seq & 0xff) << 8);
    /* Data bytes */
    $data = substr($packet, 12, -2);
    /* Checksum should be XOR over previous packet bytes */
    $cksum = base_convert(substr($packet, -2), 16, 10);


    /* Build tree over seen command bytes and potential subkeys */
    if($source === 'client') {
        $data0 = substr($data, 0, 2);
        $data1 = substr($data, 2, 2);
        $data2 = '__';
        $data3 = '__';
        if(strlen($data) > 4) $data2 = substr($data, 4, 2);
        if(strlen($data) > 6) $data3 = substr($data, 6, 2);

        /** XXX:
         * Try different variants here:
         * - is command byte the status byte?
         * - is subkey only the second data byte?
         * ....
         */
        $cmdbyte = $data0;
        $subkey = $data1 . $data2;
        $subkey = $data1;
        $subkey = $data1 . $data2 . $data3;

        if(!isset($graph[$cmdbyte]))
            $graph[$cmdbyte] = array();
        if(!isset($graph[$cmdbyte][$subkey]))
            $graph[$cmdbyte][$subkey] = 0;
        $graph[$cmdbyte][$subkey]++;

        $len_key = $cmdbyte . $subkey;
        if(!isset($graph_length[$len_key]))
            $graph_length[$len_key] = array();
        $graph_length[$len_key][] = $len;
    }

    $debug = sprintf("%s seq:% 06d, len % 3d, flag 0x%02x, data: '%s'\n",
        strtoupper($source), $seq, $len, $flags, $data);
    file_put_contents('php://stderr', $debug);
}

$packet = array('client' => '', 'server' => '');
foreach(explode("\n", $data) as $line) {
    if(preg_match('@^(    [0-9A-F]+  )@', $line, $m)) $source = 'server';
    else if(preg_match('@^([0-9A-F]+  )@', $line, $m)) $source = 'client';
    else continue;
    
    $remain = substr($line, strlen($m[1]));
    if(!preg_match_all('@([0-9a-f]{2} +)@', $remain, $m))
        die("ERR: Failed to match hex dump in line '$line'\n");

    $hexdump = preg_replace('@ @', '', implode('', $m[0]));
    if(substr($hexdump, 0, 4) === '55bb' && strlen($packet[$source])) {
        parse_packet($packet[$source], $source);
        $packet[$source] = '';
    }

    /* Append data to packet string */
    $packet[$source] .= (string)$hexdump;
}

/* Take care of the last packets */
foreach($packet as $source => $data)
    if(strlen($data))
        parse_packet($data, $source);

/* Dump out tree of possible command bytes and subkeys */
foreach($graph as $cmdbyte => $subkey_counts) {
    arsort($subkey_counts);
    echo "command byte $cmdbyte (byte0):\n";
    foreach($subkey_counts as $subkey => $cnt) {
        $len_key = $cmdbyte . $subkey;
        $lengths_seen = implode(', ', array_unique($graph_length[$len_key]));
        echo "  subkey $subkey (data1..N): seen $cnt times"
		." with packet lengths: [". $lengths_seen ."]\n";
    }
}
 
From a few of sample sessions, I've grouped the ser2net packets on what I believe is the command byte at offset 6 (byte #7) and then noted changed nibbles with a dot.

Each packets begins with a header (two bytes magic [0x55, 0xbb], length, unknown, two bytes sequence number, command byte). What follows is data and a final checksum byte.

Data the client sent, two separate sessions:
Code:
Packets grouped on: byte:0x04_at_offset_0x06
    55 bb 09 08 00 00 04 01 ea
Packets grouped on: byte:0x20_at_offset_0x06
    55 bb 0f 08 .. 00 20 14 20 07 14 04 43 2. ..
Packets grouped on: byte:0x2d_at_offset_0x06
    55 bb 09 08 02 00 2d 00 c0
Packets grouped on: byte:0x40_at_offset_0x06
    55 bb 09 08 .. 0. 40 00 ..
Packets grouped on: byte:0x44_at_offset_0x06
    55 bb 09 08 .. 0. 44 00 ..
Packets grouped on: byte:0x49_at_offset_0x06
    55 bb 09 0a .. 0. 49 00 ..
Packets grouped on: byte:0x03_at_offset_0x06
    55 bb 09 08 07 00 03 00 eb
Packets grouped on: byte:0x41_at_offset_0x06
    55 bb 09 08 .. 00 41 00 ..
Packets grouped on: byte:0x52_at_offset_0x06
    55 bb 09 0a .. 0. 52 00 ..
Packets grouped on: byte:0x61_at_offset_0x06
    55 bb 09 0a 0a 00 61 00 86
Packets grouped on: byte:0x53_at_offset_0x06
    55 bb 09 0a .. 0. 53 00 ..
Packets grouped on: byte:0x25_at_offset_0x06
    55 bb 09 0b .. 0. 25 00 ..
Packets grouped on: byte:0x65_at_offset_0x06
    55 bb 09 0a .. 0. 65 00 ..

Code:
Packets grouped on: byte:0x04_at_offset_0x06
    55 bb 09 08 00 00 04 01 ea
Packets grouped on: byte:0x20_at_offset_0x06
    55 bb 0f 08 .. 00 20 14 20 07 14 05 29 .. ..
Packets grouped on: byte:0x2d_at_offset_0x06
    55 bb 09 08 02 00 2d 00 c0
Packets grouped on: byte:0x40_at_offset_0x06
    55 bb 09 08 .. 0. 40 00 ..
Packets grouped on: byte:0x44_at_offset_0x06
    55 bb 09 08 .. 0. 44 00 ..
Packets grouped on: byte:0x49_at_offset_0x06
    55 bb 09 0a .. 0. 49 00 ..
Packets grouped on: byte:0x03_at_offset_0x06
    55 bb 09 08 07 00 03 00 eb
Packets grouped on: byte:0x41_at_offset_0x06
    55 bb 09 08 .. 00 41 00 ..
Packets grouped on: byte:0x52_at_offset_0x06
    55 bb 09 0a .. 0. 52 00 ..
Packets grouped on: byte:0x61_at_offset_0x06
    55 bb 09 0a 0a 00 61 00 86
Packets grouped on: byte:0x53_at_offset_0x06
    55 bb 09 0a .. 0. 53 00 ..
Packets grouped on: byte:0x25_at_offset_0x06
    55 bb 09 0b .. 0. 25 00 ..
Packets grouped on: byte:0x65_at_offset_0x06
    55 bb 09 0a .. 0. 65 00 ..
Packets grouped on: byte:0x24_at_offset_0x06
    55 bb 0e 0b .. 0. 24 .. .0 00 00 00 80 ..

Data the server sent, two separate sessions:
Code:
Packets grouped on: byte:0x04_at_offset_0x06
    55 bb 09 48 00 00 04 00 ab
Packets grouped on: byte:0x20_at_offset_0x06
    55 bb 09 48 .. 00 20 00 ..
Packets grouped on: byte:0x2d_at_offset_0x06
    55 bb 0a 48 02 00 2d 00 03 80
Packets grouped on: byte:0x40_at_offset_0x06
    55 bb 0d 48 .. 0. 40 00 0. 08 00 00 .. .. .. ..
    .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..
    .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..
    .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..
    .. .. .. .. .. .. .. .. .. ..
Packets grouped on: byte:0x44_at_offset_0x06
    55 bb 16 48 .. 0. 44 00 00 9c 1d 00 00 4e 19 00
    00 bc 0a 00 00 ..
Packets grouped on: byte:0x49_at_offset_0x06
    55 bb 3d 4a .. 0. 49 00 00 00 00 00 00 00 00 00
    00 00 00 00 00 00 00 00 00 6e 00 c8 c8 76 0a f3
    3f dc 13 16 f7 96 13 d0 3f 00 00 00 00 00 00 .0
    .. .. 40 b4 00 b4 00 5. 01 .. 2d .4 .. .. .. ..
    .. .. .. .. .. .. .. .. .. .. .. ..
Packets grouped on: byte:0x03_at_offset_0x06
    55 bb 09 48 07 00 03 00 ab
Packets grouped on: byte:0x41_at_offset_0x06
    55 bb 19 48 .. 00 41 00 31 2e 32 2e 35 67 00 00
    00 00 00 00 00 00 00 00 ..
Packets grouped on: byte:0x52_at_offset_0x06
    55 bb 0e 4a .. 0. 52 00 0. 00 00 00 00 ..
Packets grouped on: byte:0x61_at_offset_0x06
    55 bb 1e 4a 0a 00 61 00 ff 0a 3e fe 00 00 e8 03
    18 fc 00 00 e8 03 14 00 14 00 c8 00 00 c8
Packets grouped on: byte:0x53_at_offset_0x06
    55 bb 18 4a .. 0. 53 00 50 14 50 14 .. 0b .. 2d
    .. fc 63 37 28 03 00 ..
Packets grouped on: byte:0x25_at_offset_0x06
    55 bb 0f 4b .. 0. 25 00 31 00 00 00 .. 0d .. ..
    .. .. .. .. .. .. .. .. .. .. .. .. ..
Packets grouped on: byte:0x65_at_offset_0x06
    55 bb 1c 4a .. 0. 65 00 00 00 00 00 00 00 00 00
    00 00 00 00 00 00 00 00 00 00 00 ..

Code:
Packets grouped on: byte:0x04_at_offset_0x06
    55 bb 09 48 00 00 04 00 ab
Packets grouped on: byte:0x20_at_offset_0x06
    55 bb 09 48 .. 00 20 00 ..
Packets grouped on: byte:0x2d_at_offset_0x06
    55 bb 0a 48 02 00 2d 00 03 80
Packets grouped on: byte:0x40_at_offset_0x06
    55 bb 0d 48 .. 0. 40 00 0. 08 00 00 .. .. .. ..
    .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..
    .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..
    .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..
    .. .. .. .. .. .. .. .. .. ..
Packets grouped on: byte:0x44_at_offset_0x06
    55 bb 16 48 .. 0. 44 00 00 9c 1d 00 00 4e 19 00
    00 bc 0a 00 00 ..
Packets grouped on: byte:0x49_at_offset_0x06
    55 bb 3d 4a .. 0. 49 00 00 00 00 00 00 00 00 00
    00 00 00 00 00 00 00 00 00 6e 00 c8 c8 76 0a f3
    3f dc 13 16 f7 96 13 d0 3f 00 00 00 00 00 00 00
    .. .. .. b4 00 b4 00 5. 01 .. 2c .. .. .. .. ..
    .. .. .. .. .. .. .. .. .. .. .. ..
Packets grouped on: byte:0x03_at_offset_0x06
    55 bb 09 48 07 00 03 00 ab
Packets grouped on: byte:0x41_at_offset_0x06
    55 bb 19 48 .. 00 41 00 31 2e 32 2e 35 67 00 00
    00 00 00 00 00 00 00 00 ..
Packets grouped on: byte:0x52_at_offset_0x06
    55 bb 0e 4a .. 0. 52 00 0. .0 .. .. .. .. .. ..
    .. .. .. .. .. .. .. .. .. .. .. .. ..
Packets grouped on: byte:0x61_at_offset_0x06
    55 bb 1e 4a 0a 00 61 00 ff 0a 3e fe 00 00 e8 03
    18 fc 00 00 e8 03 14 00 14 00 c8 00 00 c8
Packets grouped on: byte:0x53_at_offset_0x06
    55 bb 18 4a .. 0. 53 00 50 14 50 14 .. 08 .. 2c
    .. f. 63 2. 27 03 00 .. .. .. .. .. .. .. .. ..
    .. .. .. .. .. .. ..
Packets grouped on: byte:0x25_at_offset_0x06
    55 bb 0f 4b .. 0. 25 00 .. 00 00 00 .. 0d ..
Packets grouped on: byte:0x65_at_offset_0x06
    55 bb 1c 4a .. 0. 65 00 00 00 00 00 00 00 00 00
    00 00 00 00 00 00 00 00 00 00 00 .. .. .. .. ..
    .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..
    .. ..
Packets grouped on: byte:0x24_at_offset_0x06
    55 bb 0. 4. .. 0. 24 .. .. .. .. .. .. .. .. ..
    .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..
    .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..
    .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..
    .. .. .. .. .. .. .. .. .. .. .. .. .. .. .. ..
    .. .. .. .. .. .. ..
 
Are you on a Vision+? I ask because you said the password was 123456. My P2V Camera password is 123.

It looks like they are using the vpfe driver. Not familiar with it. The executables are in /opt/ti. When I am connected to the camera via ssh, the terminal is spammed with messages when connecting the app to the camera. It first appears to killall server and killall encode. Both of which are in the /opt/ti directory. Rebooting the camera and not connecting the app, I did the same manually from the CLI.

Code:
killall server
killall encode

After that, it looks like "server" relaunched on it's own. Something must be watching for it. But then running ./encode from within the /opt/ti directory gives you the parameters it accepts.

I have to put it down for now. May take another look this weekend.
 
onesNzeros said:
Are you on a Vision+? I ask because you said the password was 123456. My P2V Camera password is 123.

Yeah, I'm on a P2V+ with the latest firmware made available as of July, 2014. Interesting to see that there's different password on the P2V.

onesNzeros said:
It looks like they are using the vpfe driver. Not familiar with it. The executables are in /opt/ti. When I am connected to the camera via ssh, the terminal is spammed with messages when connecting the app to the camera. It first appears to killall server and killall encode. Both of which are in the /opt/ti directory. Rebooting the camera and not connecting the app, I did the same manually from the CLI.

After that, it looks like "server" relaunched on it's own. Something must be watching for it. But then running ./encode from within the /opt/ti directory gives you the parameters it accepts.

Yeah, the killall stuff comes from the read_proc process.
Code:
root@Dji-Pro:/opt/ti# ps |grep read_proc
  408 root       0:17 ./read_proc
  505 root       0:00 grep read_proc
root@Dji-Pro:/opt/ti# ls -al /proc/408/exe 
lrwxrwxrwx    1 root     0                0 Jan  1 00:04 /proc/408/exe -> /opt/ti/read_proc

Here are a few strings from it:
Code:
root@Dji-Pro:/opt/ti# strings read_proc 
...
killall -9 %s
server
encode
Cannot open /proc
/proc/%s/status
read status fail
%*s %s
err no err
/opt/ti/loadmodule-rc stop
/opt/ti/loadmodule-rc restart
proc error
hehe.264
320x240
running err
 pid of Xorg :%d ==%d
...
 
brizey said:
think it may be udt over udp

Yeah, the video data is definitely encapsulated in http://udt.sourceforge.net/udt4/ (UDT - UDP-based Data Transfer). I had a look at the process "server" running on the camera at 192.168.1.10 and it has mapped a library called "/usr/lib/libudt.so" according to /proc/<pid>/maps. There are also symbol references in the program to UDT-related methods:

Code:
# objdump -T server |grep UDT
00008dd0      DF *UND*	00000000              _ZN4CUDT4recvEPcS0_
00008e18      DF *UND*	00000000              _ZN4CUDT6setOptE6UDTOptPKvRKi
000121f0 g    DO .bss	00000018              _ZTV13CUDTException
00008e3c      DF *UND*	00000000              _ZN4CUDT16getCurrSndBlkNumEv
00008e6c      DF *UND*	00000000              _ZN4CUDT5traceERKiPKc
00008eb4      DF *UND*	00000000              _ZN4CUDT5resetEv
00008ec0      DF *UND*	00000000              _ZN4CUDT5pauseEv
00008ef0      DF *UND*	00000000              _ZN4CUDT4sendEPcRKiRKc
00008efc      DF *UND*	00000000              _ZN4CUDT4openEv
00008f38      DF *UND*	00000000              _ZN4CUDTC1Ev
00008f44      DF *UND*	00000000              _ZN13CUDTExceptionD1Ev
00008f74      DF *UND*	00000000              _ZN4CUDT6listenEv
00000000      DO *UND*	00000000              _ZTI13CUDTException
00008f8c      DF *UND*	00000000              _ZN13CUDTException15getErrorMessageEv

I attempted to use the example code provided at http://udt.sourceforge.net/udt4/doc/t-hello.htm to connect to the camera and can also confirm that the initial packet the sample code sends during UDT::connect() matches up with what the DJI Vision app send - and looks similar to what the camera ("server") sends back in response to the initial packet.

Unfortunately the sample code I used throws an uncatchable exception during UDT::connect() and so far I'm unable to understand why it fails. It would be helpful if the exception was catchable so that I could get a sensible error message out of the UDT library.
 
After some tinkering during this rainy, no-fly day, and of course with the fantastic guidance others have provided (hacksweden, where are you?), I may have something to offer as far as live telemetry data.. but I'm not entirely sure yet.

If you notice the ser2net configs, the main 2001 port is the raw data port to /dev/ttyS0. In the ser2net documentation, I read that you're able to have two connections per tty: a raw, and a telnet. In other words, even when using the Phantom app (which uses raw), you should be able to access this telnet port at the same time.

Note in ser2net.conf, we have the following:
Code:
3011:telnet:3:/dev/ttyS0:19200 banner2

And indeed when I telnet to the repeater on port 3011, I get the following:
Code:
λ telnet 192.168.1.2 3011
Trying 192.168.1.2...
Connected to 192.168.1.2.
Escape character is '^]'.
this is ser2net TCP port 3011 device /dev/ttyS0
second line third line
55BB07043897FF 
55BB07043883FF 
55BB07043887FF 
55BB07043897FF 
?
 B?NBBB?NB?
           B?NB?HB?B?NBB?NB?JB?B?JBB?NB?NB?B?JB?

55BB matches the magic that hacksweden encountered (although it's odd it's in plaintext and not bytes..? I'm missing something fundamental here). The 'nonsense' seemed to change as I moved the Phantom to different heights (as I don't get GPS indoors, but barometrics do), and stayed 'stable' when the Phantom was resting and the values weren't changing much. I can at least theorize that this may be NAZA readings, but was unprepared to test it using NAZADecoder (which expects 55AA,though), as I was connected to the repeater and not my normal WiFi.

Might play around with some PHP later just to see if I can get anything useful from it.
 
Code:
### encode -v hehe.264 -y 1 -r 320x240
### strings /opt/ti/encode | less

Usage: encode [options]
Options:
-s | --speechfile       Speech file to record to
-a | --audiofile        Audio file to play
-v | --videofile        Video file to record to
-y | --display_standard Video standard to use for display (see below).
                        Same video standard is used at input.
-r | --resolution       Video resolution ('width'x'height')
                        [video standard default]
-b | --videobitrate     Bit rate to encode video at [variable]
-p | --soundbitrate     Bit rate to encode audio at [96000]
-u | --samplerate       Sample rate to encode audio at [16000]
-w | --preview_disable  Disable preview [preview enabled]
-f | --write_disable    Disable recording of encoded file [enabled]
-I | --video_input      Video input source [video standard default]
-l | --linein           Use linein as sound input instead of mic
                        [off]
-k | --keyboard         Enable keyboard interface [off]
-t | --time             Number of seconds to run the demo [infinite]
-o | --osd              Show demo data on an OSD [off]
-h | --help             Print this message
Video standards available
        1       D1 @ 30 fps (NTSC)
        2       D1 @ 25 fps (PAL)
        3       720P @ 60 fps [Default]
        5       1080I @ 30 fps - for DM368
Video inputs available:
        1       Composite
        2       S-video
        3       Component
Video inputs available:
        1       Composite
        2       S-video
        3       Component
        4       Imager/Camera - for DM368
You must supply at least a video or a speech file or both
with appropriate extensions for the file formats.

Code:
root@Dji-Pro:/opt/ti# cat version
ENCODE VERSION   :E-V1.2
FaUDT VERSION   :U-V1.3

The "encode" binary is likely a modifyed "encode" demo application from Texas Instruments DaVinci DM36x SDK.

See also:
"encode" demo application home http://processors.wiki.ti.com/index.php ... pplication
"encode" command line options http://www.codeforge.com/read/42444/encode.txt__html
Texas Instruments DaVinci DM36x SDK http://www.ti.com/tool/linuxdvsdk-dm36x
 
Too lazy to sniff wifi with wireshark? :)
ssh to 192.168.1.1 and edit /etc/ser2net.conf. Add tr=tr1 tw=tw2to line starting with 2001
Code:
2001:raw:6:/dev/ttyS0:115200 tr=tr1 tw=tw1 NONE 1STOPBIT 8DATABITS -XONXOFF LOCAL -RTSCTS

After this, copy of serial communiation on port tcp/2001 will come to /tmp/tr-blah-blah-blah and /tmp/tw-blah-blah-blah
 
"Check out the big brain on [seaowl]!"
Might have to check this out. Fantastic find. Guess I should have read the ser2net docs more.

And with that, note you can use 'tb' to write both to the same file for a complete tale of operation.
 
Well, reading this amazing story, I succesfully cloned the Phantom2 Vision+ Wi-Fi repeater. It is not a firmware clone, it is a functionality one.
Great thanks for all your posts, folks, it works!

I take a fresh OpenWRT binary distr, flashed it into Wi-Fi router, and configured it (the configuration is exactly the same, as one inside dji "extender").
If you dont like writing network configuration file from the scratch, you can copy /etc/config/wireless from your extender into your old good wifi router , and it works. I used a wifi router with a build-in directional antenna. The max quality video preview, and telemetry works great and reliable. Field testing show me >2km video link. But 5.8GHz r/c control sucks at this distances, and Phantom loses connection and does RTH dance!


Now I dig into topic of how Wi-Fi module does control of NAZA, and how to command NAZA from the Wi-Fi module and place waypoints.
Here is a chance to fly by Wifi-only, with no any 5.8GHz r/c transmitters.
 

Attachments

  • self-made-dji-phantom2-vision-extender-pic1.jpg
    self-made-dji-phantom2-vision-extender-pic1.jpg
    147.5 KB · Views: 2,067
Not a WiFi extender, but WiFi module inside phantom, play the main role of encoding and sending video to the ground. I think its possible, as just a 2 wires with digital signals connects the WiFi module to the gimbal. If we come to understanding how to use this signals in practice, - why not:)
 

Members online

No members online now.

Forum statistics

Threads
143,066
Messages
1,467,358
Members
104,935
Latest member
Pauos31