#-------------------------------------------------------------------------------
# Name:        ParserAlignedPacket
# Purpose:
#
# Author:      DCollins
#
# Created:     19/12/2013
#
# Copyright 2014 Diarmuid Collins
#
#    This program is free software; you can redistribute it and/or
#    modify it under the terms of the GNU General Public License
#    as published by the Free Software Foundation; either version 2
#    of the License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

import struct


class ParserAlignedPacket():
    """A class that handles parser aligned packets. Unpack a buffer to populate the field into a list of parserblocks"""
    def __init__(self):
        self.parserblocks = []
        self.numberofblocks =0


    def unpack(self,buf):
        """Pass a buffer containing all the Parser alignd payload and this method will
        unpack all the fields. Returns a list of parserblocks"""
        fullbufferlen = len(buf)
        bufferparsed = 0
        while bufferparsed < fullbufferlen:
            block = ParserAlignedBlock()
            # unpack and add the amount unpacked to the running total
            bufferparsed += block.unpack(buf[bufferparsed:])
            self.parserblocks.append(block)



class ParserAlignedBlock():
    """A class to handle a single Parser Block. Returns an object containing all the fields of a parser block"""
    def __init__(self):

        self.error = False
        self.errorcode = 0
        self.quadbytes = 1
        self.messagecount = 0
        self.busid = 1
        self.elapsedtime = 2
        self.payload = ""

        self.format = '>HBBL'
        self.headerlen = struct.calcsize(self.format)


    def unpack(self,buf):
        """Unpack a single parser block. Unsually called only from the iNetXParser unpack method. Returns the length of the
        parser block"""
        # Unpack the fields
        (error_and_quad,self.messagecount,self.busid,self.elapsedtime)=struct.unpack_from(self.format,buf)
        # MSB bit is the error flag
        if ((error_and_quad >> 15) == 1):
            self.error = True
        else:
            self.error = False

        # As error code and quad bytes are not byte aligned I have to do some shifting and masking
        self.errorcode = (error_and_quad >> 9) & 0x3f
        self.quadbytes = error_and_quad & 0x1ff
        payload_length_in_bytes = (self.quadbytes - 2)*4

        # Raise an exception if the payload is not as expected
        if len(buf) < self.headerlen+payload_length_in_bytes:
            raise ValueError
        self.payload = buf[self.headerlen:self.quadbytes*4]
        # Return the length of the block as a courtesy
        return self.quadbytes*4


class ARINC429():
    """This is not working yet. Don't use it"""
    MESSAGE_LEN = 4 # 4 bytes
    LABEL_REVERSE = [
        0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, #   0 -   8
        0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0, #   9 -  15
        0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8, #  16 -  23
        0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, #  24 -  31
        0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4, #  32 -  39
        0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4, #  40 -  47
        0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, #  48 -  55
        0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc, #  56 -  63
        0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2, #  64 -  71
        0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, #  72 -  79
        0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea, #  80 -  87
        0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa, #  88 -  95
        0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, #  96 - 103
        0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6, # 104 - 111
        0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee, # 112 - 119
        0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, # 120 - 127
        0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1, # 128 - 135
        0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1, # 136 - 143
        0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, # 144 - 151
        0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9, # 152 - 159
        0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5, # 160 - 167
        0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, # 168 - 175
        0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed, # 176 - 183
        0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd, # 184 - 191
        0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, # 192 - 199
        0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3, # 200 - 207
        0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb, # 208 - 215
        0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, # 216 - 223
        0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7, # 224 - 231
        0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7, # 232 - 239
        0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, # 240 - 247
        0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff, # 248 - 255
        0x00
    ]
    def __init__(self):
        self.parity = None
        self.ssm = None
        self.data = None
        self.sdi = None
        self.label = None

    def unpack(self,buf):
        if len(buf) != ARINC429.MESSAGE_LEN:
            raise ValueError
        (byte1,byte2,byte3,byte4) = struct.unpack('BBBB',buf)
        self.parity = byte1 / 128
        self.ssm = (byte1/32) % 4
        self.data = ((byte1 %32) * 256 + byte2 ) * 64 + (byte3 /4)
        self.sdi = byte3 % 4
        self.label = ARINC429.LABEL_REVERSE[byte4]



