import numpy as np
import struct
import os
import logging
from scipy.io import wavfile

# Logger configuration
logging.basicConfig(
    filename='debug.log',  # The file where the logs will be saved
    level=logging.INFO,    # logging.DEBUG - full debug; logging.INFO - partial debug
    format='%(message)s',  # Single line format
    filemode='w'           # The log file will be overwritten with each run of the program.
)

def LOG_DEBUG(message):
    if DEBUG:
        logging.debug(message)

def LOG_INFO(message):
    if DEBUG:
        logging.info(message)


# Function for calculating the moving average.
def moving_average(data, window_size):
    return np.convolve(data, np.ones(window_size)/window_size, mode='same')


def output_states_to_rs232(output_states, output_states_times):
   rs232_data = []

   LOG_DEBUG("")
   #LOG_DEBUG("OTPUT STATES:")
   #LOG_DEBUG(', '.join(str(x) for x in output_states))

   # Grouping bits into bytes.
   i = 0
   while 1:
        # displaying the counter every 10000
        #plik.write(str(i)+ ' ')

        # Waiting for the start bit
        if output_states[i] == 0:
           byte = output_states[i+1:i+9]  # Retrieve 8 bits
           byte_value = int(''.join(map(str, byte)), 2)
           LOG_INFO("")
           LOG_INFO(f"{output_states_times[i]:.6f}")
           LOG_INFO(f"byte: {byte}   {hex(byte_value)}")

           rs232_data.append(byte) # Add to the RS-232 list
           i=i+9     # skip the read byte + stop bit
           if output_states[i] != 1:     # checking the stop bit
              LOG_INFO(f"Stop bit error at position: {i}")

        if i < len(output_states) - 10:
            i = i + 1
        else:
           break

   return rs232_data

FSK_and_Header = [
    0x46,0x55,0x4a,0x49,0x00,0x00,0x00,0x00,0x62,0x61,0x75,0x64,0x00,0x00,0x58,0x02,
    0x64,0x61,0x74,0x61,0x84,0x00,0xc0,0x37,0x55,0x55,0xfa,0x00,0x01,0x6c,0x03,0xff,
    0x03,0x78,0xcb,0x9b,0xbd,0x81,0x03,0x38,0xeb,0x81,0x9d,0x81,0x03,0xca,0xd0,0xf4,
    0x8f,0x8f,0x55,0x4b,0x0d,0x82,0x54,0x21,0x41,0x0d,0x13,0x84,0x0d,0x19,0x84,0x2e,
    0x81,0x85,0x60,0x83,0x53,0x10,0x81,0x21,0x80,0x83,0x53,0x80,0x13,0x83,0x6f,0x18,
    0x84,0x51,0x6d,0x49,0x71,0x89,0x41,0x4e,0x51,0x60,0x21,0x61,0x51,0x5c,0x60,0x83,
    0x53,0x6c,0x2d,0x10,0x63,0x6c,0xcf,0x8f,0x55,0x0f,0xd3,0x7f,0x4c,0x71,0x3e,0x52,
    0x84,0x1e,0xbd,0x6e,0x4b,0x51,0x78,0x69,0x07,0x95,0x38,0x95,0x51,0x7d,0xa1,0x0e,
    0x7e,0x10,0x87,0x53,0x10,0xb2,0x81,0x10,0x90,0x53,0x99,0x6c,0xa8,0x2b,0x10,0x85,
    0x53,0x30,0xb3,0x83,0x10,0x90,0x53,0x99,0xe1,0x00,0x01
]

#loader_block_2 = [0x20,0x10,0x04,0xA9,0xFF,0x8D,0x01,0xD3,0x4E,0x01,0xD3,0x4E,0x02,0xD3,0x4C,0x00,0x50,0xA2,0xFF,0x9A,0xA9,0x00,0x48,0x8F,0x04,0x03,0xA9,0xF8,0xAB,0xFF,0xA9,0xCC,0x48,0xA0,0x01,0x20,0x5C,0x04,0xA9,0x2C,0x8F,0x71,0x04,0xA9,0x81,0x8F,0x48,0xFE,0xA9,0x00,0x8F,0x04,0x03,0xA9,0xF3,0xAB,0xFF,0xA9,0xD8,0xA0,0x04,0x20,0x5C,0x04,0x68,0xAA,0x68,0x18,0xEB,0x00,0xA8,0x8A,0xEB,0x00,0x48,0x98,0x48,0xA0,0x02,0xA9,0x00,0x91,0x58,0x8F,0x41,0x00,0x8F,0x2F,0x02,0x8F,0x00,0xD4,0x60,0x48,0x8A,0xA2,0xFF,0x8F,0x08,0x03,0x68,0x8F,0x05,0x03,0x98,0x8F,0x09,0x03,0x8A,0x4B,0x40,0x8F,0x03,0x03,0x20,0x59,0xE4,0x10,0x04,0x68,0x68,0x68,0x68,0xAB,0x00,0xCA,0x60,0x80,0x80,0x85,0x80,0x5D]
#loader_block_3 = [0xA2,0x00,0x8A,0x9D,0x00,0xCE,0x9D,0x00,0xCF,0xCA,0xD0,0xF7,0xA2,0x18,0xA9,0xFF,0x9D,0x12,0xCE,0x9D,0xB2,0xCE,0x9D,0x52,0xCF,0x9D,0xB2,0xCF,0xCA,0x10,0xF1,0xA0,0x02,0xA9,0xEA,0x99,0x46,0xC1,0x99,0x78,0xC1,0x99,0x6F,0xC1,0x88,0x10,0xF4,0xA9,0xD0,0x8D,0x6F,0xEC,0x8D,0x97,0xEC,0xA9,0x03,0x8D,0x7E,0xEC,0xAD,0x0B,0xD4,0x30,0xFB,0x20,0x5C,0xCD,0x20,0x59,0xE4,0x6C,0x04,0x03,0xA9,0x00,0x85,0x4D,0x85,0x41,0x8D,0x18,0xD0,0x8D,0x1A,0xD0,0xAD,0xED,0xCD,0x8D,0x00,0xD4,0xA2,0x02,0x8E,0x1D,0xD0,0xCA,0x8E,0x1B,0xD0,0xA2,0x03,0xBD,0xE9,0xCD,0x9D,0x00,0xD0,0xBD,0xE5,0xCD,0x9D,0x12,0xD0,0xA9,0x03,0x9D,0x08,0xD0,0xCA,0x10,0xEC,0xA9,0xCC,0x8D,0x07,0xD4,0x4C,0x5F,0xE4,0xAD,0xF1,0xCD,0xD0,0x14,0xAD,0x10,0xD0,0xD0,0xBD,0xA2,0x00,0x8E,0xF2,0xCD,0x20,0x8C,0xCD,0xE8,0x8E,0xF1,0xCD,0x8E,0xF2,0xCD,0xA0,0x00,0x8C,0xF3,0xCD,0x20,0x98,0xCD,0xAD,0xEE,0xCD,0x20,0x67,0xCD,0xEE,0xF3,0xCD,0xAD,0xF3,0xCD,0xCD,0xF2,0xCD,0xD0,0xEC,0xA0,0x00,0x8C,0xF3,0xCD,0xAD,0x00,0xD3,0x29,0x0F,0xA0,0xFF,0xC9,0x0E,0xF0,0x19,0xC8,0xC9,0x07,0xF0,0x14,0xC8,0xC9,0x0D,0xF0,0x0F,0xC8,0xC9,0x0B,0xF0,0x0A,0xA2,0xBA,0xA9,0xCC,0x20,0x60,0xCD,0x4C,0x4A,0xCC,0x20,0x5C,0xCD,0xC8,0x98,0xAC,0xF3,0xCD,0xD9,0x4A,0xCB,0xF0,0x24,0xA9,0xC8,0x8D,0x00,0xD2,0xA9,0xAA,0x8D,0x01,0xD2,0xA9,0x40,0x20,0x67,0xCD,0xA9,0xA0,0x8D,0x01,0xD2,0xA9,0x0B,0x8D,0xEE,0xCD,0xA9,0x00,0x8D,0xEF,0xCD,0x8D,0xF1,0xCD,0x4C,0x4A,0xCC,0x20,0x98,0xCD,0xA2,0x19,0xA9,0xCD,0x20,0x60,0xCD,0xA9,0x0F,0x2D,0x00,0xD3,0x49,0x0F,0xD0,0xEA,0x20,0x5C,0xCD,0xEE,0xF3,0xCD,0xAD,0xF3,0xCD,0xCD,0xF2,0xCD,0xD0,0x8A,0x20,0x8C,0xCD,0xEE,0xF2,0xCD,0xAD,0xEE,0xCD,0x0A,0x20,0x67,0xCD,0xEE,0xEF,0xCD,0xAD,0xEF,0xCD,0xC9,0x0A,0xD0,0x12,0xAD,0xEE,0xCD,0xC9,0x01,0xF0,0x0B,0xCE,0xEE,0xCD,0xCE,0xEE,0xCD,0xA9,0x00,0x8D,0xEF,0xCD,0x4C,0x4A,0xCC,0xA2,0x83,0xA9,0xCC,0x8E,0x22,0x02,0x8D,0x23,0x02,0x60,0x8D,0xF0,0xCD,0x18,0x68,0x69,0x01,0x8D,0xF4,0xCD,0x68,0x69,0x00,0x8D,0xF5,0xCD,0xA2,0x81,0xA9,0xCD,0x20,0x60,0xCD,0x4C,0x4A,0xCC,0xCE,0xF0,0xCD,0xD0,0xF8,0x20,0x5C,0xCD,0x6C,0xF4,0xCD,0xAD,0x0A,0xD2,0x29,0x03,0xAE,0xF2,0xCD,0x9D,0x4A,0xCB,0x60,0x18,0x68,0x69,0x01,0x8D,0xF6,0xCD,0x68,0x69,0x00,0x8D,0xF7,0xCD,0xAE,0xF3,0xCD,0xBD,0x4A,0xCB,0xAA,0xBD,0xE5,0xCD,0x18,0x69,0x04,0x9D,0xE5,0xCD,0x8A,0x0A,0x0A,0x0A,0x0A,0x69,0x64,0x8D,0x00,0xD2,0xA9,0xAA,0x8D,0x01,0xD2,0xAD,0xEE,0xCD,0x20,0x67,0xCD,0xA9,0xA0,0x8D,0x01,0xD2,0xAE,0xF3,0xCD,0xBD,0x4A,0xCB,0xAA,0xBD,0xE5,0xCD,0x38,0xE9,0x04,0x9D,0xE5,0xCD,0x9D,0x12,0xD0,0x6C,0xF6,0xCD,0x42,0x82,0xB2,0xE2,0x6E,0x96,0x6E,0x46,0x08,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7D]
#loader_block_4 = [0xA2,0x80,0x86,0x3D,0x8E,0x8A,0x02,0x4C,0xD4,0xD8,0x85,0x02,0x84,0x03,0x60,0xA9,0x02,0xA0,0x00,0x20,0x0A,0xD8,0xA9,0xF3,0xA0,0xDC,0x85,0x04,0x84,0x05,0xA9,0x00,0x8F,0x00,0x00,0x8F,0x01,0x00,0x20,0x7A,0xFD,0x10,0x07,0xC0,0x88,0xD0,0x35,0x4C,0xBB,0xD9,0xA0,0x00,0x91,0x04,0xA6,0x3D,0x10,0x11,0xAC,0xFB,0xDA,0xD0,0x0C,0x8E,0xFB,0xDA,0xBD,0x00,0x04,0x9D,0xF5,0xDC,0xCA,0x10,0xF7,0xE6,0x04,0xD0,0x02,0xE6,0x05,0xE6,0x00,0xD0,0x02,0xE6,0x01,0xA5,0x00,0xC5,0x02,0xD0,0xC9,0xA5,0x01,0xC5,0x03,0xD0,0xC3,0x60,0xA9,0xFB,0x25,0x10,0x85,0x10,0x8D,0x0E,0xD2,0x20,0x8E,0xEF,0xA9,0x3C,0x8D,0x02,0xD3,0xA2,0x00,0x86,0x52,0xE8,0x8E,0xF0,0x02,0x8E,0x44,0x02,0xA9,0x2E,0x8D,0xED,0xCD,0xA9,0x63,0x85,0x00,0xA9,0xDB,0x85,0x01,0xA0,0x00,0xB1,0x00,0xC9,0x40,0xF0,0x0B,0x20,0xB0,0xF2,0xE6,0x00,0xD0,0xF1,0xE6,0x01,0xD0,0xED,0xA9,0xFF,0x8D,0xFC,0x02,0xAE,0xFC,0x02,0xE0,0x0C,0xD0,0xF9,0xBD,0xC7,0xD8,0x9D,0x00,0x20,0xCA,0x10,0xF7,0xA9,0x00,0x8D,0x44,0x02,0x85,0x02,0xA9,0x20,0x85,0x03,0xA9,0x02,0x85,0x09,0x6C,0xFC,0xFF,0xA9,0xFF,0x8D,0x01,0xD3,0xA9,0x0C,0x8D,0xFC,0x02,0x4C,0x80,0xC6,0xA2,0x04,0x86,0x01,0xA9,0x00,0x8F,0x09,0x00,0x8F,0x0A,0x00,0x8F,0x0B,0x00,0x8F,0x0C,0x00,0x8F,0x0D,0x00,0x8F,0x00,0x00,0xA8,0x91,0x00,0xC8,0xD0,0xFB,0xE8,0x86,0x01,0xE0,0xC0,0xD0,0xF4,0xA9,0xE9,0x8D,0x14,0x02,0xA9,0xDA,0x8D,0x15,0x02,0xA9,0x04,0x05,0x10,0x85,0x10,0x8D,0x0E,0xD2,0x20,0x0F,0xD8,0xAD,0xF3,0xDC,0x2D,0xF4,0xDC,0xC9,0xFF,0xD0,0x11,0xA9,0x74,0x8D,0xFC,0xDA,0xA9,0xE4,0x8D,0xFD,0xDA,0xA9,0x01,0x8D,0xFA,0xDA,0xD0,0xE2,0xAD,0xE0,0x02,0x0D,0xE1,0x02,0xD0,0x0C,0xAF,0xF3,0xDC,0x8F,0xE0,0x02,0xAF,0xF4,0xDC,0x8F,0xE1,0x02,0xAD,0xFA,0xDA,0xD0,0x03,0x4C,0x90,0xDA,0xAF,0xF3,0xDC,0x8F,0x40,0x02,0xAF,0xF4,0xDC,0x8F,0x41,0x02,0x20,0x0F,0xD8,0x38,0xAD,0xF3,0xDC,0xED,0x40,0x02,0x85,0x02,0xAD,0xF4,0xDC,0xED,0x41,0x02,0x85,0x03,0xE6,0x02,0xD0,0x02,0xE6,0x03,0xAD,0x40,0x02,0xAC,0x41,0x02,0x20,0x1A,0xD8,0xAD,0xE2,0x02,0x0D,0xE3,0x02,0xF0,0x2E,0xA9,0x60,0x8D,0x5C,0xE4,0x8D,0x53,0xE4,0x8D,0x77,0xE4,0x85,0x00,0xCE,0xF9,0xDA,0x20,0xAE,0xD9,0xEE,0xF9,0xDA,0xA9,0x4C,0x8D,0x5C,0xE4,0x8D,0x53,0xE4,0x8D,0x77,0xE4,0xA9,0x52,0x8D,0x02,0x03,0xA9,0x00,0x8F,0xE2,0x02,0x8F,0xE3,0x02,0x4C,0x0C,0xD9,0x6C,0xE2,0x02,0xA9,0xFF,0x8D,0x01,0xD3,0xA9,0x00,0x6C,0xE0,0x02,0xA5,0x10,0x29,0xFB,0x85,0x10,0x8D,0x0E,0xD2,0xA9,0x3C,0x8D,0x02,0xD3,0xA2,0x09,0xBD,0xB1,0xD9,0x9D,0x92,0x03,0xCA,0x10,0xF7,0xAD,0x30,0x02,0x48,0xAD,0x31,0x02,0x48,0xA9,0xFE,0x8D,0x30,0x02,0xA9,0xDA,0x8D,0x31,0x02,0xA9,0x2E,0x8D,0xED,0xCD,0xA9,0x01,0x8D,0xF8,0x03,0x8D,0xDC,0x02,0xA9,0xE0,0x8D,0x09,0xD4,0xA0,0x80,0xB9,0xF5,0xDC,0x99,0x00,0x04,0x88,0x10,0xF7,0xA9,0x11,0xA6,0x14,0x8E,0x17,0xD0,0xCD,0xDC,0x02,0xD0,0xF6,0xAD,0x0B,0xD4,0x30,0xFB,0x68,0x8D,0x31,0x02,0x68,0x8D,0x30,0x02,0xA9,0x5F,0x8D,0x22,0x02,0xA9,0xE4,0x8D,0x23,0x02,0xA2,0xFF,0x9A,0xA9,0x00,0x8F,0x6F,0x02,0x8F,0x07,0xD4,0xA2,0x1F,0x9D,0x00,0xD0,0xCA,0x10,0xFA,0xA9,0xA0,0x8F,0x01,0xD2,0xA9,0x22,0x8F,0x2F,0x02,0x8F,0x00,0xD4,0xA9,0x00,0x8F,0x44,0x02,0xA5,0x09,0xD0,0x04,0xA9,0x02,0x85,0x09,0xAE,0xE0,0x02,0x86,0x02,0xAC,0xE1,0x02,0x84,0x03,0xA5,0x0C,0x05,0x0D,0xD0,0x04,0x86,0x0C,0x84,0x0D,0xA5,0x0A,0x05,0x0B,0xD0,0x0A,0xAD,0xFC,0xDA,0x85,0x0A,0xAD,0xFD,0xDA,0x85,0x0B,0x38,0xA5,0x0A,0xE9,0x01,0xAA,0xA5,0x0B,0xE9,0x00,0x48,0x8A,0x48,0x18,0xA5,0x14,0x69,0x02,0xC5,0x14,0xD0,0xFC,0x4C,0x92,0x03,0xAF,0xF3,0xDC,0x8F,0x40,0x02,0xAF,0xF4,0xDC,0x8F,0x41,0x02,0x20,0x0F,0xD8,0x18,0xAD,0xF3,0xDC,0x69,0x06,0x85,0x0C,0xAD,0xF4,0xDC,0x69,0x00,0x85,0x0D,0x20,0x0F,0xD8,0xAF,0xF3,0xDC,0x8F,0x0A,0x00,0xAF,0xF4,0xDC,0x8F,0x0B,0x00,0xA0,0x06,0x0E,0x41,0x02,0x2E,0x40,0x02,0x88,0x10,0xF7,0xAC,0x40,0x02,0xAD,0x41,0x02,0x20,0x0A,0xD8,0xAF,0x0C,0x00,0x8F,0x04,0x00,0x8F,0xE0,0x02,0xAF,0x0D,0x00,0x8F,0x05,0x00,0x8F,0xE1,0x02,0x20,0x26,0xD8,0x4C,0xBB,0xD9,0xA9,0x34,0x8D,0x02,0xD3,0x2C,0xF9,0xDA,0x10,0x04,0xE6,0x14,0xE6,0x13,0x68,0x40,0x00,0x00,0x00,0x00,0x00,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x70,0x42,0x13,0xDB,0x02,0x41,0xFE,0xDA,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x70,0x72,0x65,0x73,0x69,0x6F,0x6E,0x65,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x28,0x25,0x2C,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7D,0xD3,0xC5,0xA0,0xC4,0xC5,0xD4,0xC5,0xC3,0xD4,0xCF,0xA0,0xD5,0xCE,0xC1,0xA0,0xC6,0xC1,0xCC,0xCC,0xC1,0xA0,0xC4,0xD5,0xD2,0xC1,0xCE,0xD4,0xC5,0xA0,0xCC,0xC1,0xA0,0xC3,0xC1,0xD2,0xC7,0xC1,0xA1,0x9B,0x1D,0x1D,0x1D,0x1D,0x1D,0x2D,0x20,0x52,0x65,0x62,0x6F,0x62,0x69,0x6E,0x65,0x20,0x6C,0x61,0x20,0x63,0x69,0x6E,0x74,0x61,0x20,0x68,0x61,0x73,0x74,0x61,0x20,0x65,0x6C,0x20,0x63,0x6F,0x6D,0x69,0x65,0x6E,0x7A,0x6F,0x7F,0x7F,0x20,0x20,0x64,0x65,0x20,0x6C,0x61,0x20,0x6D,0x69,0x73,0x6D,0x61,0x9B,0x2D,0x20,0x50,0x72,0x65,0x73,0x69,0x6F,0x6E,0x65,0x20,0x6C,0x61,0x73,0x20,0x74,0x65,0x63,0x6C,0x61,0x73,0x20,0x50,0x4C,0x41,0x59,0x20,0x79,0x20,0x52,0x45,0x54,0x55,0x52,0x4E,0x9B,0x9B,0x1D,0x2D,0x20,0x53,0x69,0x20,0x65,0x6C,0x20,0x65,0x72,0x72,0x6F,0x72,0x20,0x73,0x65,0x20,0x70,0x72,0x6F,0x64,0x75,0x63,0x65,0x20,0x65,0x6E,0x20,0x72,0x65,0x69,0x74,0x65,0x72,0x61,0x64,0x61,0x73,0x7F,0x7F,0x20,0x20,0x6F,0x63,0x61,0x73,0x69,0x6F,0x6E,0x65,0x73,0x3A,0x9B,0x9B,0x20,0x20,0x2D,0x43,0x6F,0x6D,0x70,0x72,0x75,0x65,0x62,0x65,0x20,0x6C,0x61,0x20,0x63,0x61,0x72,0x67,0x61,0x20,0x63,0x6F,0x6E,0x20,0x75,0x6E,0x20,0x63,0x61,0x73,0x73,0x65,0x74,0x74,0x65,0x9B,0x20,0x20,0x20,0x71,0x75,0x65,0x20,0x73,0x65,0x20,0x65,0x6E,0x63,0x75,0x65,0x6E,0x74,0x72,0x65,0x20,0x65,0x6E,0x20,0x62,0x75,0x65,0x6E,0x20,0x65,0x73,0x74,0x61,0x64,0x6F,0x9B,0x20,0x20,0x2D,0x48,0x75,0x6D,0x65,0x64,0x65,0x7A,0x63,0x61,0x20,0x75,0x6E,0x61,0x20,0x67,0x61,0x73,0x61,0x20,0x6C,0x69,0x6D,0x70,0x69,0x61,0x20,0x65,0x6E,0x20,0x61,0x6C,0x63,0x6F,0x68,0x6F,0x6C,0x9B,0x20,0x20,0x2D,0x4C,0x69,0x6D,0x70,0x69,0x65,0x20,0x63,0x75,0x69,0x64,0x61,0x64,0x6F,0x73,0x61,0x6D,0x65,0x6E,0x74,0x65,0x20,0x65,0x6C,0x20,0x63,0x61,0x62,0x65,0x7A,0x61,0x6C,0x20,0x79,0x7F,0x7F,0x20,0x20,0x20,0x65,0x6C,0x20,0x72,0x6F,0x64,0x69,0x6C,0x6C,0x6F,0x20,0x70,0x72,0x65,0x73,0x6F,0x72,0x9B,0x20,0x20,0x2D,0x43,0x6F,0x6E,0x74,0x72,0x6F,0x6C,0x65,0x20,0x65,0x6C,0x20,0x61,0x7A,0x69,0x6D,0x75,0x74,0x20,0x64,0x65,0x20,0x73,0x75,0x20,0x67,0x72,0x61,0x62,0x61,0x64,0x6F,0x72,0x40,0xFF]

def rs232_to_binary(rs232_data):

    binary_rs232 = []

    for byte in rs232_data:
        # Convert the list of bits to a byte
        byte.reverse()  # reversing the bits because the highest was at the end
        byte_value = int(''.join(map(str, byte)), 2)  # Conversion to an integer
        #print(byte_value)
        binary_rs232.append(byte_value.to_bytes(1, byteorder='big'))

    return binary_rs232


def Pulse_analize (filename):
    # Load WAV file.
    sample_rate, data = wavfile.read(os.path.join(working_directory, filename))
 
    # Check if the data is stereo
    if len(data.shape) == 2:
   
        # Take only one channel or the sum of the channels
        if left_or_right_channel == 1:
           data = data[:, 0]  # left
        elif left_or_right_channel == 2:
           data = data[:, 1]  # right
        else:
           data = data[:, 0] + data[:, 1]
       
        # Calculate the moving average
        moving_avg = moving_average(data, moving_average_window)
       
        # Subtract the moving average from the original data
        data = data - moving_avg
       
        # Sample times in the WAV file
        time = np.linspace(0, len(data) / sample_rate, num=len(data))
       
        # Find zero crossings
        zero_crossings = np.where(np.diff(np.sign(data)))[0]
       
        # Collecting zero crossing times
        zero_crossing_times = time[zero_crossings]
        LOG_DEBUG("zero_crossing_times: " + str(len(zero_crossings)) + " elements" )
       
        # Collecting the values of the digitization points preceding zero crossings
        preceding_values = data[zero_crossings-1]

        # List for storing the values of bits decoded by the Injektor
        output_states = []
        # List for storing the times of these bits
        output_states_times = []

        count_of_pilot_pulses = 0
        semi_bite = False
        ready_to_start_bit = False
        pilot = False
        started = False
        last_pulse_is_short = False
        output_states.append(1)
        output_states_times.append(0)
        last_state = 1

        # Impulse analysis
        for i in range(1, len(zero_crossing_times)):

          # Calculating the pulse length
          duration = zero_crossing_times[i] - zero_crossing_times[i-1]

          LOG_DEBUG("")
          LOG_DEBUG(f"time: {zero_crossing_times[i]:.6f}  duration: {duration:.6f}  preceding_value: {preceding_values[i]}")
          LOG_DEBUG(f"pilot: {pilot}   started: {started}")

          # Waiting for the pilot
          if not pilot:
            if (duration < pulse_width_treshold1) and (duration > 0.000050):  # short pulse
               LOG_DEBUG("short pulse - waiting for pilot")
               if last_pulse_is_short:
                  count_of_pilot_pulses = count_of_pilot_pulses + 1;
                  LOG_DEBUG(f"count_of_pilot_pulses: {count_of_pilot_pulses}")
                  output_states.append(1)
                  output_states_times.append(zero_crossing_times[i])
                  last_state = 1
                  LOG_DEBUG("I add the value 1")
                  LOG_DEBUG(f"count_of_pilot_pulses: {count_of_pilot_pulses}")
                  if count_of_pilot_pulses > 30:  # At least once every 30 pulses, a stop bit (high) must occur. If not, I consider the signal to be a pilot
                    LOG_DEBUG("I caught the pilot")
                    pilot = True
                    count_of_pilot_pulses = 0
                    ready_to_start_bit = True
               last_pulse_is_short = True
            else:
               LOG_DEBUG("other pulse - waiting for pilot")
               count_of_pilot_pulses = 0
               LOG_DEBUG("I reset the pilot flag")
               pilot = False
               last_pulse_is_short = False
      
          else:  # pilot==True
      
            if not started:
              # waiting for the start bit (long high pulse)
              LOG_DEBUG("Waiting for Start bit")
              if duration > pulse_width_treshold1:
                if preceding_values[i] >= 0:
                   LOG_DEBUG("long positive pulse (Start bit)")
                   output_states.append(0)  # Set LOW state
                   output_states_times.append(zero_crossing_times[i])
                   LOG_DEBUG("I add the value 0")
                   last_state = 0
                   started = True
                   semi_bite = False
                else:
                   LOG_DEBUG("long negative pulse")
                   #LOG_DEBUG(f"count_of_pilot_pulses: {count_of_pilot_pulses})
              #else:
               #LOG_DEBUG("short pulse")
               #LOG_DEBUG(f"count_of_pilot_pulses: {count_of_pilot_pulses}")

            else: # stared==True
              if (not semi_bite):
                 if duration > pulse_width_treshold2:
                     LOG_DEBUG("very long pulse")
                     output_states.append(1)
                     output_states_times.append(zero_crossing_times[i])
                     LOG_DEBUG("I add the value 1")
                     last_state = 1
                     pilot = False
                     started = False
      
                 else:
                   if duration > pulse_width_treshold1:
                       count_of_pilot_pulses = 0;
                       LOG_DEBUG(f"count_of_pilot_pulses: {count_of_pilot_pulses}")
                       # Checking if the pulse is positive
                       if preceding_values[i] >= 0:
                          LOG_DEBUG("long positeve pulse")
                          output_states.append(0)  # Set LOW state
                          output_states_times.append(zero_crossing_times[i])
                          LOG_DEBUG("I add the value 0")
                          last_state = 0
                       else:
                          LOG_DEBUG("long negatiwe pulse")
                          output_states.append(1)  # Set HIGH state
                          output_states_times.append(zero_crossing_times[i])
                          LOG_DEBUG("I add the value 1")
                          last_state = 1
      
                   else: # duration <= pulse_width_treshold1
                       LOG_DEBUG("short pulse")
                       semi_bite = True
                       count_of_pilot_pulses = count_of_pilot_pulses + 1
                       LOG_DEBUG(f"count_of_pilot_pulses: {count_of_pilot_pulses}")
                       if count_of_pilot_pulses > 30:  # At least once every 30 pulses, a stop bit (high) must occur. If not, I consider the signal to be a pilot
                           LOG_DEBUG("Pilot again - new block")
                           pilot = False
                           started = False
                           count_of_pilot_pulses = 0
                           LOG_DEBUG(f"count_of_pilot_pulses: {count_of_pilot_pulses}")
                           output_states.append(1)
                           output_states_times.append(zero_crossing_times[i])
                           last_state = 1
                           LOG_DEBUG("I add the value 1")
                           ready_to_start_bit = True
     
              else:  #semi_byte==True
                 LOG_DEBUG("second semi_byte")
                 output_states.append(last_state)
                 output_states_times.append(zero_crossing_times[i])
                 LOG_DEBUG(f"I add value last_state={last_state}")
                 started_byte = False
                 semi_bite = False
    else:
          print("The audio file is not stereo.")

    return output_states, output_states_times


def compute_checksum(chunk):
    checksum = 0
    for byte in chunk:
       checksum += int.from_bytes(bytes(byte), byteorder='big')
       if checksum > 255:
          checksum = (checksum & 0xFF) + 1  # Overflow

    return checksum

# Main function
def main():
  
    for filename in os.listdir(working_directory):
      if filename.endswith(single_file):
        filename_without_extension = os.path.splitext(filename)[0]
        print(os.path.join(working_directory, filename))
        LOG_DEBUG("File: " + os.path.join(working_directory, filename))
        output_states, output_states_times = Pulse_analize(filename)

        # Decoding SIO (RS-232)
        rs232_decoded = output_states_to_rs232(output_states, output_states_times)
        # Write to binary list
        binary_rs232 = rs232_to_binary(rs232_decoded)

        j=0
        with open(os.path.join(working_directory, filename_without_extension) + '_all_blocks.bin', 'wb') as output_file:
           for j in range(len(binary_rs232)):
              output_file.write(binary_rs232[j])
           current_position = j + 1

        startup_position = 0
        i = 0
        while True:
          if binary_rs232[i:i + len(Injector_block2_header)] == Injector_block2_header:
             print('Found')
             current_position = i
             startup_position = current_position
             with open(os.path.join(working_directory, filename_without_extension) + '_block2.bin', 'wb') as output_file:
               for j in range(i, i+Injector_block2_size):
                  output_file.write(binary_rs232[j])
               current_position = j + 1
             with open(os.path.join(working_directory, filename_without_extension) + '_block3.bin', 'wb') as output_file:
               for j in range(current_position, current_position+Injector_block3_size):
                  output_file.write(binary_rs232[j])
               current_position = j + 1
             with open(os.path.join(working_directory, filename_without_extension) + '_block4.bin', 'wb') as output_file:
               for j in range(current_position, current_position+Injector_block4_size):
                  output_file.write(binary_rs232[j])
               current_position = j + 1
             with open(os.path.join(working_directory, filename_without_extension) + '_reszta_blokow.bin', 'wb') as output_file:
               for j in range(current_position, len(binary_rs232) - 1):
                 output_file.write(binary_rs232[j])
             print("Data has been saved to binary files.")
             break

          if i < (len(binary_rs232) - len(Injector_block2_header) + 1):
             i = i + 1
          else:
             break

        bad_chekcsums = []
        current_position = startup_position
        with open(os.path.join(working_directory, filename_without_extension) + ".CAS", 'wb') as file:
             #file.write(struct.pack(f'{len(FSK_and_Header)}B', *FSK_and_Header))
             file.write(bytes(FSK_and_Header))

             # Writing the header of block 2 in CAS
             file.write(bytes(CAS_bolck2_header))
             # Writing the content of block 2 in CAS
             for j in range(current_position, current_position + Injector_block2_size):
               file.write(binary_rs232[j])
             current_position = j + 1
     
             # Writing the header of block 3 in CAS
             file.write(bytes(CAS_bolck3_header))
             # Writing the content of block 3 in CAS
             for j in range(current_position, current_position + Injector_block3_size):
               file.write(binary_rs232[j])
             current_position = j + 1
       
             # Writing the header of block 4 in CAS
             file.write(bytes(CAS_bolck4_header))
             # Writing the content of block 4 in CAS
             for j in range(current_position, current_position + Injector_block4_size):
               file.write(binary_rs232[j])
             current_position = j + 1
       
             # writing the remaining blocks of CAS (the actual program) along with the headers
             chunk_size = 130
             chunk_number = 1
             last_chunk = False
             while True:
               chunk = binary_rs232[current_position : current_position+chunk_size]
       
               # Compute the checksum
               checksum = compute_checksum(chunk[:-1])
       
               if checksum == int.from_bytes(chunk[-1]):
                   print('Block nr:', chunk_number, chunk[0],'  Checksum:', checksum, 'OK')
                   LOG_INFO(f"Block nr:{chunk_number}  {chunk[0]}  Checksum:{checksum}  OK")
               else:
                   print('Block nr:', chunk_number, chunk[0],'  Checksum:', checksum, 'BAD')
                   LOG_INFO(f"Block nr:{chunk_number}  {chunk[0]}  Checksum:{checksum}  BAD")
                   bad_chekcsums.append(chunk_number)
       
               # Writing the header of the block in CAS
               if chunk_number < 3:
                   new_data = b'\x64\x61\x74\x61\x82\x00' + IBG_first_two_ms.to_bytes(2, byteorder='little')
               else:
                   new_data = b'\x64\x61\x74\x61\x82\x00' + IBG_ms.to_bytes(2, byteorder='little')
               file.write(new_data)
       
               # Writing the content of the block in CAS
               for byte in chunk:
                  file.write(byte)
          
               if chunk[0] == b'\xfe':
                  last_chunk = True
       
               if current_position + chunk_size <= len(binary_rs232):
                   current_position = current_position + chunk_size
                   chunk_number = chunk_number + 1
                   if last_chunk:
                      break
               else:
                   break
                
        print("Bad chekcsums blocks:")
        print(bad_chekcsums)
        print("END")

 
if __name__ == "__main__":
    Injector_block2_header = [ b'\x20', b'\x10', b'\x04', b'\xa9', b'\xff' ]
    Injector_block2_size = 132
    Injector_block3_size = 505
    Injector_block4_size = 1268

    CAS_bolck2_header = [ 0x7f, 0x62, 0x61, 0x75, 0x64, 0x00, 0x00, 0x9b,
                          0x0f, 0x64, 0x61, 0x74, 0x61, 0x84, 0x00, 0xa0,
                          0x13 ]

    CAS_bolck3_header = [ 0x64, 0x61, 0x74, 0x61, 0xf9, 0x01, 0x88, 0x01 ]

    CAS_bolck4_header = [ 0x64, 0x61, 0x74, 0x61, 0xf4, 0x04, 0x88, 0x01 ]


    # Settings
    left_or_right_channel = 2  #  1-left  2-right  3-both
    pulse_width_treshold1 = 0.000182  # 0.000190 - 0.000230
    pulse_width_treshold2 = 0.000400
    moving_average_window = 26        # 15 - 150
    DEBUG = False
    IBG_ms = 235  # Interblock Gaps length [ms] (0-65535) default 235
    IBG_first_two_ms = 400  # Interblock Gaps length for two first blocks
    working_directory = "/Injektor CD2 wavs/"
    single_file = "Keystone Kapers (Simon Injektor).wav"   # ".wav" -> all wav files in directory
    main()
