#******************************************************************************
#
#   hk310-reader.py
#
#   This utility reads the RS232 input to the NRF24LE1G chip in the 
#   HobbyKing HK310 transmitter.
#
#******************************************************************************
#
#   Author:         Werner Lane
#   E-mail:         laneboysrc@gmail.com
#
#******************************************************************************

import serial
import sys

STARTUP_MODE_NEUTRAL = 4

def stickCommand(data):
    h = data[4] & 0x0f
    l = data[6]
    st = (h << 8) + l
    
    h = (data[5] & 0xf0 ) >> 4
    l = data[7]
    th = (h << 8) + l
    
    h = data[5] & 0x0f
    l = data[8]
    ch3 = (h << 8) + l

    error = ""
    if crc16_ccitt(data[3:9]) != ((data[9] << 8) + data[10]):
        error = "ERROR: CRC16 does not match"
    
    #print "st=%04d th=%04d ch3=%04d  %s" % (st, th, ch3, error) 


def failsafeCommand(data):
    error = ""
    if crc16_ccitt(data[3:9]) != ((data[9] << 8) + data[10]):
        error = "ERROR: CRC16 does not match"
        
    st = data[6] - 120
    th = data[7] - 120
    mode = data[8]
    thEnabled = "off"
    if mode & 0x02: 
        thEnabled = "on "

    stEnabled = "off"
    if mode & 0x01: 
        stEnabled = "on "

    print "FAILSAFE: st=%4d%%, %s   th=%4d%%, %s  %s" % (st, stEnabled, th, thEnabled, error) 
                            
    #for i in (3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14):
    #    print "%02x " %  (data[i], ), 
    #print error


def preprocessor_reader(port):
    try:
        s = serial.Serial(port, 19200)
    except serial.SerialException, e:
        print("Unable to open port %s.\nError message: %s" % (port, e))
        sys.exit(0)

    data = []
    while True:
        data.append(ord(s.read(1)))
        if len(data) == 15:
            if data[0] != 0xff:
                data = data[1:]
            else:
                if data[1] == 0x55  and  data[2] == 0xaa:
                    checksum = 0;
                    for i in (3, 4, 5, 6, 7, 8, 9, 10):
                        checksum += data[i]

                    if checksum != ((data[13] << 8) + data[14]):
                        print "SERIAL CHECKSUM ERROR"                    

                    elif data[4] & 0xf0 == 0xa0:
                        stickCommand(data)
                    
                    elif data[4] & 0xf0 == 0xb0:
                        failsafeCommand(data)

                    else:
                        print "Unknown command 0x%1x" % data[4] >> 4

                elif data[1] == 0xaa  and  data[2] == 0x55:
                    print "STARTUP: ",
                    for i in (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14):
                        print "%02x " %  data[i], 
                    print
                else:
                    print "Unknown command header: ",
                    for i in (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14):
                        print "%02x " %  data[i], 
                    print

                data = []

def crc16_ccitt(data):
    crc = 0
    for i in data:
        b = i
        crc = crc ^ b << 8

        for _ in range(8):
            if crc & 0x8000:
                crc = crc << 1 ^ 0x1021
            else:
                crc = crc << 1

    return crc & 0xffff;


if __name__ == '__main__':
    try:
        port = sys.argv[1]
    except IndexError:
        port = '/dev/ttyUSB0'

    try:
        preprocessor_reader(port)
    except KeyboardInterrupt:
        print("")
        sys.exit(0)

@@ -469,33 +469,8 @@
 ys%0A%0A
-STARTUP_MODE_NEUTRAL = 4%0A
 %0Adef
@@ -568,25 +568,15 @@
 h = 
-(
 data%5B5%5D
- & 0xf0 )
  %3E%3E 
@@ -811,25 +811,24 @@
 h%22%0A    %0A    
-#
 print %22st=%250
@@ -834,16 +834,17 @@
 04d 
+ 
 th=%2504d 
 ch3=
@@ -839,16 +839,17 @@
 th=%2504d 
+ 
 ch3=%2504d
@@ -1279,17 +1279,16 @@
 %25%25, %25s  
- 
 th=%254d%25%25
@@ -1342,150 +1342,105 @@
 r) %0A
-                            %0A    #for i in (3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14):%0A    #    print 
+%0A%0Adef modelCode(data);%0A    print %22Model code: %22, ' '.join(%5B
 %22%2502x
- 
 %22 %25  
-(
 data%5Bi%5D
-, ), %0A    #print error
+ for i in range(15)%5D)
 %0A%0A%0Ad
@@ -2191,25 +2191,18 @@
 ata%5B
-4%5D & 0xf0
+3%5D
  == 0xa
-0
+a
 :%0A  
@@ -2297,25 +2297,18 @@
 ata%5B
-4%5D & 0xf0
+3%5D
  == 0xb
-0
+b
 :%0A  
@@ -2532,184 +2532,23 @@
     
-print %22STARTUP: %22,%0A                    for i in (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14):%0A                        print %22%2502x %22 %25  data%5Bi%5D, %0A                    print
+modelCode(data)
 %0A   
@@ -2644,105 +2644,29 @@
     
-for i in (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14):%0A                        print 
+print ' '.join(%5B
 %22%2502x
- 
 %22 %25 
@@ -2677,36 +2677,29 @@
 a%5Bi%5D
-, %0A                    print
+ for i in range(15)%5D)
 %0A%0A  
@@ -2723,16 +2723,17 @@
 a = %5B%5D%0A%0A
+%0A
 def crc1

Tweak the reader program