
import utilities as util

# compare sampled data with given threshold
def binarize_transmission( data, thd ):
    
    idle = True
    idle_thd = 2
    
#     for i in xrange(len(data)):
#          
#         if abs(data[i])<thd :
#             if idle:
#                 data[i] = 0
#             else:
#                 data[i] = data[i-1]
#             idle = True
#             
#         elif data[i] > thd:
#             data[i] = 1
#             idle = False
#         
#         else:
#             data[i] = -1
#             idle = False
    
    cnt = 0
    
    for i in xrange( len(data ) ):
        if abs(data[i])<thd :
            if idle:
                data[i] = 0
                cnt = 0
            else:
                if cnt > idle_thd :
                    idle = True
                    data[i] =  0
                else:    
                    cnt += 1
                    data[i] = data[i-1] if i > 0 else 0
        elif data[i] > thd:
            data[i] = 1
            cnt = 0
            idle = False
         
        else:
            data[i] = -1
            cnt = 0
            idle = False
            
    return data

# increase data pointer until first logic value is found
# preamble should start with high value 
def wait_preamble( data, ptr = 0 ):
       
    for ptr in xrange(ptr,len(data) ):
        if data[ptr] == 1:
            return ptr
        elif data[ptr] == -1:
            util.err_msg("Bus went low after idle")
            return -1
    
    return len(data)-1


# increase data pointer until first edge is found 
def wait_edge( data, ptr ):
    cnt = 1
    edges=[]
    
    for i in xrange( len(data) -1 ):
        if data[ptr] != data[ptr+1] :
            cnt += 1
            edges.append(i)
               
    return [edges, cnt ]

def get_logic( data ):

    # logic values are coded with edge
    # data is selected in such a way that edge should be in the middle
    # sample data before edge and after edge
    
    # logic symbol codes:
    # HH : V+ (special sign used in preamble/postamble)
    # HL : Logic 1
    # LH : Logic 0
    # LL : V- (special sign used in preamble/postamble)

    first_sample = 1*len(data)/4
    second_sample = 3*len(data)/4
    if data[first_sample] == 1:
        if data[second_sample] == 1 :
            # V+
            return 2
        elif data[second_sample] == -1:
            # L1
            return 1
        else:
            # last sign
            return 3
    elif data[first_sample] == -1:
        if data[second_sample] == -1:
            # V-
            return -2
        elif data[second_sample] == 1:
            # L0
            return -1
        else :
            # last sign
            return -3
    else:
        # idle
        return 0
        

# return samples containing one data bit
# actually simply returns given number of samples starting from given index
def get_byte( data, start, samples ):
    return [ data[ start : start+samples] , range(start, start+samples) ]


def list2words(msg_list):
    
    # frame len i bits!
    frame_bit_len = len(msg_list)
    
    # make sure that frame len is multiple of 8
    if (frame_bit_len%8) != 0:
        util.err_msg("Recorded transmission has %d bits. It should be multiple of 8." % len(msg_list))
        raise Exception("Recorded transmission has %d bits. It should be multiple of 8." % len(msg_list))
    
#     frame len in bytes
    frame_byte_len = frame_bit_len/8
    
    frame=[0]*frame_byte_len

    for i in xrange(frame_bit_len):
        bit = 1 if msg_list[i] > 0 else 0
        frame[i/8] += bit * (1<<(7-(i%8)))
        
    return frame

def verify_FSS(data):
    if data == [     1, -1,  1, -1,
                     1, -1,  1, -1,
                     1,  2, -2,  1,
                    -1, -2,  2, -1 ]:
        return True
    else :
        return False


def verify_FES(data):
    if data == [     1,  2, -2,  2,
                    -2,  1, -1, 1 ]:
        return True
    else :
        return False
    
def decode( data, thd = 10000, blen=20 ):
    
    data = binarize_transmission( data, thd )
    
    msg_list =[[]]
    msg_cnt = 0
    
    idle = True
    ptr = 0
    
    lastbyte = len(data)-1
    
    while(1):
        if idle:
            # make sure that bus is idle state
            if data[ptr] != 0:
                util.err_msg("Pointer does not point to inactive data")
                return -1
            
            # skip inactive bus state
            ptr = wait_preamble(data, ptr)
            
            # make sure that transmission started with high state
            if ptr == -1:
                return -1
            
            # it is not idle any more since previous function skipped it
            idle = False

        else:
            # get data set representing single sign
            # knowing sampling freq and bus freq blen may be derived
            [d, r] = get_byte(data, ptr, blen )
            
            # decode sign
            v = get_logic(d)
            
            # if bus is idle
            # save that state
            if v == 0:
                
                # record raw frame
                tmp = ""
                for i in xrange( len( msg_list[msg_cnt] ) ):
                    tmp += " "+str(msg_list[msg_cnt][i])
                    if (i%8)==7:
                        tmp += "\n"
                        
                tmp = tmp.replace("-2", "V-")
                tmp = tmp.replace("2", "V+")
                tmp = tmp.replace("-1", "0")
                tmp = tmp.replace("1", "1")
                util.info_msg("Recorded following signs: \n%s" % tmp)
                

                idle = True
                msg_cnt += 1
                msg_list.append([])
                
                
            # else append found byte to message
            else:
                if abs( v ) < 3 :
                    msg_list[msg_cnt].append(v)

            # go to next byte
            # new transmission will not start in such a short time
            ptr += blen
        
        # iterate as long as ptr exceed data length
        if ptr >= lastbyte:
            # cnt value is number of frames
            # 0 mean 0 frames!
            
            
            # on the other hand after finishing frame
            # list is allocated for following one
            # so list should have empty frame at the end
            if len( msg_list ) >= msg_cnt:
                msg_list.pop(msg_cnt)
            
            msg=[]
            for i in xrange(msg_cnt):
                if verify_FSS(msg_list[i][0:16]):
                    util.info_msg("Frame:%d Correct FSS detected. It will be deleted form returned frame"%i)
                    for k in xrange(16):
                        msg_list[i].pop(0)
                
                if verify_FES(msg_list[i][len(msg_list[i])-8:len(msg_list[i])]):
                    util.info_msg("Frame:%d Correct FES detected. It will be deleted form returned frame"%i)
                    for k in xrange(8):
                        msg_list[i].pop(len(msg_list[i])-1)
                
                
                msgbytes=list2words(msg_list[i])
                msg.append( msgbytes )
                
                # log data after FSS and FES removal
                tmp = ""
                for b in msgbytes :
                    tmp += " %x" % b
                util.info_msg("Recorded following frame (FSS and FES removed): %s" % tmp)
                util.info_msg("")
                 
            util.info_msg("Finished decoding transmission")
            util.info_msg("")
            return msg
    
    
        
    
    
    