Subversion Repositories Projects

Rev

Blame | Last modification | View Log | RSS feed

///============================================================================
/// This file is part of MIKROKOPTER SERIAL CONTROL TUTORIAL.
/// by JOHN C. MACDONALD at Ira A. Fulton College of Engineering and Technology
/// (http://hdl.lib.byu.edu/1877/2747)
/// (http://hdl.lib.byu.edu/1877/2748)
///============================================================================

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace MKLiveView
{
    static class FlightControllerMessage
    {
        public static byte[] CreateMessage(char commandId, byte address)
        {
            return CreateMessage(commandId, address, new byte[0]);
        }

        public static byte[] CreateMessage(char commandId, byte address, byte[] data)
        {
            List<byte> result = new List<byte>();
            //Encoding.ASCII.GetBytes(command);
           
            // add header
            result.Add(Convert.ToByte('#'));
            result.Add((byte)(Convert.ToByte('a') + address));
            result.Add(Convert.ToByte(commandId));

            // add data
            result.AddRange(Encode64(data));
           
            // add footer
            result.AddRange(getCRCBytes(result.ToArray()));
            result.Add(Convert.ToByte('\r'));

            return result.ToArray();
        }

        public static void ParseMessage(byte[] message, out char commandId, out byte address, out byte[] data)
        {
            // Debug.Assert(message.Length >= 6);
            if (message.Length >= 6)
            {
                // header
                // '#' == message[0]
                byte[] Data = new byte[message.Length - 3];
                Array.Copy(message, 0, Data, 0, message.Length - 3);
                byte[] crcData = getCRCBytes(Data);

                if (crcData.Length == 2 && crcData[0] == message[message.Length - 3] && crcData[1] == message[message.Length - 2])
                {

                    commandId = Convert.ToChar(message[2]);
                    address = (byte)(message[1] - Convert.ToByte('a'));

                    // data
                    data = Decode64(message, 3, message.Length - 6);
                }
                else
                {
                    commandId = '\0';
                    address = 255;
                    data = null;
                }
            }
            else
            {
                commandId = '\0';
                address = 0;
                data = null;
            }
            // footer
            // CRC1 == message[message.Length - 3]
            // CRC2 == message[message.Length - 2]
            // '\r' == message[message.Length - 1]
        }

        public static byte[] Encode64(byte[] data)
        {
            List<byte> encodedData = new List<byte>();

            byte a,b,c;
            int index = 0;
            byte k = Convert.ToByte('=');

            while (index < data.Length)
            {
                if (index < data.Length) a = data[index++]; else a = 0;
                if (index < data.Length) b = data[index++]; else b = 0;
                if (index < data.Length) c = data[index++]; else c = 0;

                encodedData.Add((byte)(k + (a >> 2)));
                encodedData.Add((byte)(k + (((a & 0x03) << 4) | ((b & 0xf0) >> 4))));
                encodedData.Add((byte)(k + (((b & 0x0f) << 2) | ((c & 0xc0) >> 6))));
                encodedData.Add((byte)(k + ( c & 0x3f)));
            }

            return encodedData.ToArray();
        }

       
        public static byte[] Decode64(byte[] data, int startIndex, int count)
        {
            // data should be in chunks of 4 right?
           // Debug.Assert(count % 4 == 0);

            List<byte> decodedData = new List<byte>();

            byte k = Convert.ToByte('=');
            byte a,b,c,d;
            byte x,y,z;
            int index = startIndex;

            while (index <= count + startIndex - 4)
            {
                a = (byte)(data[index++] - k);
                b = (byte)(data[index++] - k);
                c = (byte)(data[index++] - k);
                d = (byte)(data[index++] - k);

                x = (byte)((a << 2) | (b >> 4));
                y = (byte)(((b & 0x0f) << 4) | (c >> 2));
                z = (byte)(((c & 0x03) << 6) | d);

                decodedData.Add(x);
                decodedData.Add(y);
                decodedData.Add(z);
            }

            return decodedData.ToArray();
        }


        // cyclic redundancy check (CRC) or polynomial code checksum used to verify message
        // it is an insecure hash function designed to detect accidental changes to raw computer data (wikipedia)
        private static byte[] getCRCBytes(byte[] data)
        {
            byte[] crcBytes = new byte[2];

            uint tmpCRC = 0;
            for(int i = 0; i < data.Length ;i++)
            {
                tmpCRC += data[i];
            }
            tmpCRC %= 4096;
            crcBytes[0] = (byte)(Convert.ToByte('=') + tmpCRC / 64);
            crcBytes[1] = (byte)(Convert.ToByte('=') + tmpCRC % 64);

            return crcBytes;
        }
    }
}