using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Linq;
using System.Text;
using System.IO.Ports;
using System.Threading;
using System.Timers;


namespace ConsoleApplication1
{
    class XBee_Library
    {
        Byte[] recieveData = new Byte[1024];
        int recieveDataCounter = 0;  //udava cislo volneho pole v poli recieveData
        int recieveDataMemory = 0;  //udava promennou pro vyhodnoceni stavu stavoveho automatu
        int OKRecieved = 0;  //0 - nic neprijato, 1 - prijato "O", 2 - prijato "0K"
        Boolean ATMode = false;  //urcuje zda-li jsme v command modu, TRUE - jsme v command modu, FALSE - jsme v normalnim rezimu
        Boolean confirmMode = false;  //urcuje ze cekame na odpoved OK
        Boolean ATGoOn = false;  //nastavi se do TRUE pokud prijmeme "OK\r" v command modu


        Byte[] recieveSystemData = new Byte[64];
        int recieveSystemDataCounter = 0;  //udava cislo volneho pole v poli recieveSystemData
        int recieveSystemDataMemory = 0;  //udava promennou pro vyhodnoceni stavu stavoveho automatu

        Byte[] SPISensorSetup = new Byte[5];  //pole ukladajici nastaveni SPI rozhrani v mikrokontroleru

        SerialPort serialPortXBee = new SerialPort();  //vytvoreni instance serioveho portu
        private static System.Timers.Timer timerXBee;  //vytvoreni instance timeru

        //PC: INICIALIZACE FUNKCI V KNIHOVNE "XBee_Library"
        public void initialization()  //OK
        {
            SPISensorSetup[0] = Convert.ToByte(0x06);  //prvni byte urcuje pristup k SPI nastaveni
            timerXBee = new System.Timers.Timer(10);
            timerXBee.Elapsed += new ElapsedEventHandler(OnTimedEvent);
            timerXBee.Start();
        }

        //PC: PRIVATNI METODA PRO CTENI PRIJATYCH DAT A JEJICH UKLADANI DO PRISLUSNYCH POLI
        private void OnTimedEvent(object source, ElapsedEventArgs e)  //OK
        {
            if (serialPortXBee.IsOpen)
            {
                while (serialPortXBee.BytesToRead > 0)  //nacteme prijata data do stringu
                {
                    int memory = serialPortXBee.ReadByte();  //precti jeden Byte

                    if ((ATMode == true) || (confirmMode == true))
                    {
                        //test na prichozi OK
                        if (memory == 0x4F)  //znak O v ASCII
                        {
                            OKRecieved = 1;
                        }
                        else if (memory == 0x4B)
                        {
                            OKRecieved = 0;
                            ATGoOn = true;
                        }
                        else
                        {
                        }
                    }

                    if ((ATMode == false) && (confirmMode == false))
                    {
                        if (recieveSystemDataMemory > 0)  //nacitej data do slozky systemovych dat
                        {
                            recieveSystemData[recieveSystemDataCounter] = Convert.ToByte(memory);
                            recieveSystemDataCounter++;
                            recieveSystemDataMemory--;
                        }
                        else if (recieveDataMemory == 1)  //byla prijata hlavicka, zpracovavame data
                        {
                            recieveSystemDataMemory = memory;  //udava delku systemove zpravy v Bytech
                        }
                        else if (recieveDataMemory == 2)  //prijali jsme bud nahradu hlavicky nebo data
                        {
                            if (memory == 0x55)  //jde o nahradu za znaky nahrazujici hlavicky
                            {
                                recieveData[recieveDataCounter] = 0xBB;
                                recieveDataCounter++;
                            }
                            else  //slo o nahradu hlavicky
                            {
                                recieveData[recieveDataCounter] = 0xAA;
                                recieveDataCounter++;
                            }
                        }
                        else if (memory == 0xAA)  //obsahuji-li prijata data znak 0xAA, jde o hlavicku
                        {
                            recieveDataMemory = 1;
                        }
                        else if (memory == 0xBB)  //obsahuji-li data tento znak, jde o nahradu hlavicky ci o data
                        {
                            recieveDataMemory = 2;
                        }
                        else  //jde o obycejna data
                        {
                            recieveData[recieveDataCounter] = Convert.ToByte(memory);
                            recieveDataCounter++;
                        }

                        if (recieveDataCounter > 1023)
                        {
                            recieveDataCounter = 1023;
                        }
                        if (recieveSystemDataCounter > 63)
                        {
                            recieveSystemDataCounter = 63;
                        }
                    }
                }
            }
        }

        //PC: PRIKAZ K OTEVRENI KOMUNIKACE SE SERIOVYM PORTEM
        public string openSerialPort(string portName, Int32 baudRate)  //OK
        {
            string answer = "";
            try
            {
                serialPortXBee.PortName = portName;
                serialPortXBee.BaudRate = baudRate;
                serialPortXBee.Handshake = Handshake.None;  //pevne dane modulem XBee 
                serialPortXBee.StopBits = StopBits.One;
                serialPortXBee.DataBits = 8;  //pevne dane modulem XBee
                serialPortXBee.Encoding = Encoding.ASCII;
                serialPortXBee.Parity = Parity.None;
                serialPortXBee.Open();
                if (serialPortXBee.IsOpen)
                {
                    answer = ("OK");
                }
                else
                {
                    answer = ("ERROR" + portName);
                }
            }
            catch
            {
                answer = ("ERROR" + portName);
            }
            return answer;
        }

        //PC: PRENASTAVENI KOMUNIKACNI RYCHLOSTI MODULU XBEE PRIPOJENEMU K XBEE
        public string PC_XBeeSetUp(Int32 baudRate)
        {
            string answer = "";
            string baudRateXBee = "";
            switch (baudRate)   //rozliseni pro baudrate v mikrokontroleru
            {
                case 4800: baudRateXBee = "2"; answer = "OK"; break;
                case 9600: baudRateXBee = "3"; answer = "OK"; break;
                case 19200: baudRateXBee = "4"; answer = "OK"; break;
                case 38400: baudRateXBee = "5"; answer = "OK"; break;
                case 57600: baudRateXBee = "6"; answer = "OK"; break;
                case 115200: baudRateXBee = "7"; answer = "OK"; break;
                default: answer = "ERROR"; break;
            }
            if (serialPortXBee.IsOpen)
            {
                try
                {
                    ATMode = true;

                    //vstup do AT modu
                    enterATCommandMode();  //vstup do Command modu
                    WaitForATGoOn();
                    

                    //nastaveni Baudrate
                    sendATCommand("ATBD " + baudRateXBee + "\r");
                    WaitForATGoOn();

                    //Aplikovani vsech nastavenych parametru
                    sendATCommand("ATAC \r");  //aplikuj nastavene parametry
                    WaitForATGoOn();

                    //prenastavi nastaveni portu
                    serialPortXBee.BaudRate = baudRate;

                    //ukonci AT mod
                    sendATCommand("ATCN \r");  //ukonci AT mod
                    WaitForATGoOn();

                    ATMode = false;
                    answer = "OK";
                }
                catch
                {
                    answer = "ERROR";
                }
            }
            else
            {
                answer = "ERROR";
            }
            return answer;
        }

        //PC: ODESLANI RETEZCE PRO VSTUP OD COMMAND MODU
        public void enterATCommandMode()
        {
            System.Threading.Thread.Sleep(1000);  //cekej sekundu
            serialPortXBee.Write("+++");  //odesli znaky +++
            System.Threading.Thread.Sleep(1000);  //cekej sukundu
        }

        //PC: ODESLANI RETEZCE SLOUZICIHO JAKO PRIKAZ V COMMAND MODU
        public void sendATCommand(string command)
        {
            serialPortXBee.Write(command);
        }

        //PC: PRIKAZ PRO CEKANI DOKUD NENI NASTAVENI BIT WaitForATGoOn
        private void WaitForATGoOn()
        {
            while (!ATGoOn)
            {
                Thread.Sleep(10);
            }
            ATGoOn = false;
        }


        //PC: PRENASTAVENI KOMUNIKACNI RYCHLOSTI SERIOVEHO PORTU
        public string setSerialPort(Int32 baudRate)  //OK
        {
            string answer = "";
            try
            {
                serialPortXBee.BaudRate = baudRate;
                answer = "OK";
            }
            catch
            {
                answer = "ERROR";
            }
            return answer;
        }

        //PC: UZAVRENI KOMUNIKACE SE SERIOVYM PORTEM
        public string closeSerialPort()  //OK
        {
            string answer = "";
            try
            {
                serialPortXBee.Close();
                answer = "OK";
            }
            catch
            {
                answer = "ERROR";
            }
            return answer;
        }

        //PC: PRIKAZ PRO ODESILANI DAT Z PC NA SENZOR
        public string sendData(string dataToSend)  //metoda posila znaky na seriovy port pocitace  //OK
        {                        //hlavicka je 0xAA, nahrada je 0xBB a nahrada 0xBB je 0xBB01
            string answer = "";
            try
            {
                string sendDataMemory = dataToSend;
                //hledame znaky 0xBB a nahrazujememe je znaky 0xBB55

                if (sendDataMemory.Contains("╗"))  //najde-li ASCII znak 0xBB
                {
                    sendDataMemory = sendDataMemory.Replace("╗", "╗7");  //nahradi ho znakem 0xBB55 
                }


                //hledame znaky 0xAA a nahrazujeme je znaky 0xBB
                if (sendDataMemory.Contains("¬"))  //najde-li ASCII znak 0xAA
                {
                    sendDataMemory = sendDataMemory.Replace("¬", "╗");  //nahradi ho znakem 0xBB
                }

                serialPortXBee.Write(sendDataMemory);
                answer = "OK";
            }
            catch
            {
                answer = "ERROR";
            }
            return answer;
        }

        //PC: FUNKCE PRO PRECTENI PRIJATYCH DAT Z MODULU XBEE
        public string recieveStoredData()  //OK
        {
            string message = Encoding.ASCII.GetString(recieveData, 0, recieveDataCounter);
            recieveDataCounter = 0;
            return message;
        }

        //PC: FUNKCE PRO PRECTENI SYSTEMOVYCH ZPRAV Z MODULU XBEE
        public string recieveStoredSystemData()  //OK
        {
            string message = Encoding.ASCII.GetString(recieveSystemData, 0, recieveSystemDataCounter);
            recieveSystemDataCounter = 0;
            return message;
        }

        //MIKROKONTROLER: PRIKAZ PRO POVOLENI PREPOSILANI DAT ZE SENZORU PRIPOJENEMU K ROZHRANI SPI DO PC
        //PRIKAZ NUTNO ODESLAT FUNKCI "loadSPISetupToMicrocontroler()"
        public string SPI_Data(string command)  //OK
        {
            string answer = "";
            if (command == "Start")
            {
                SPISensorSetup[1] = 0x00;  //Start sending data
                answer = "OK";
            }
            else if (command == "Stop")
            {
                SPISensorSetup[1] = 0x01;  //Stop sending data
                answer = "OK";
            }
            else
            {
                answer = "ERROR";
            }

            return answer;
        }

        //MIKROKONTROLER: PRIKAZ PRO NASTAVENI PORADI BITU DLE VYZNAMU (LSB, MSB) V ROZHRANI SPI
        //PRIKAZ NUTNO ODESLAT FUNKCI "loadSPISetupToMicrocontroler()"
        public string SPI_bitSequence(string bitSequence)  //OK
        {
            string answer = "";
            if (bitSequence == "LSB")
            {
                SPISensorSetup[2] = 0x00;  //LSB
                answer = "OK";
            }
            else if (bitSequence == "MSB")
            {
                SPISensorSetup[2] = 0x01;  //MSB
                answer = "OK";
            }
            else
            {
                answer = "ERROR";
            }
            return answer;
        }

        //MIKROKONTROLER: PRIKAZ PRO NASTAVENI FAZE HODIN A DAT ROZHRANI SPI
        //PRIKAZ NUTNO ODESLAT FUNKCI "loadSPISetupToMicrocontroler()"
        public string SPI_dataAndClock(string CPOL, string CPHA)  //OK
        {
            string answer = "";
            if (CPOL == "CPOL0" && CPHA == "CPHA0")
            {
                SPISensorSetup[3] = 0x00;  //CPOL = 0; CPHA = 0;
                answer = "OK";
            }
            else if (CPOL == "CPOL1" && CPHA == "CPHA0")
            {
                SPISensorSetup[3] = 0x01;  //CPOL = 1; CPHA = 0;
                answer = "OK";
            }
            else if (CPOL == "CPOL0" && CPHA == "CPHA1")
            {
                SPISensorSetup[3] = 0x02;  //CPOL = 0; CPHA = 1;
                answer = "OK";
            }
            else if (CPOL == "CPOL1" && CPHA == "CPHA1")
            {
                SPISensorSetup[3] = 0x03;  //CPOL = 1; CPHA = 1;
                answer = "OK";
            }
            else
            {
                answer = "ERROR";
            }
            return answer;
        }

        //MIKROKONTROLER: PRIKAZ PRO NASTAVENI FREKVENCE ROZHRANI SPI, PRIKAZ NUTNO ODESLAT FUNKCI "loadSPISetupToMicrocontroler()"
        public string SPI_frequency(string frequency)  //OK
        {
            string answer = "";
            if (frequency == "F0/4")
            {
                SPISensorSetup[4] = 0x00;  //crystal frequency / 4
                answer = "OK";
            }
            else if (frequency == "F0/16")
            {
                SPISensorSetup[4] = 0x01;  //crystal frequency / 16
                answer = "OK";
            }
            else if (frequency == "F0/64")
            {
                SPISensorSetup[4] = 0x02;  //crystal frequency / 64
                answer = "OK";
            }
            else if (frequency == "F0/128")
            {
                SPISensorSetup[4] = 0x03;  //crystal frequency / 128
                answer = "OK";
            }
            else
            {
                answer = "ERROR";
            }
            return answer;
        }

        //MIKROKONTROLER: PRIKAZ PRO NACTENI VSECH NASTAVENYCH VLASTNOSTI DO SPI KOMUNIKACNI JEDNOTKY
        public string loadSPISetupToMicrocontroler()  //OK
        {
            string answer = "";
            confirmMode = true;
            try
            {
                serialPortXBee.BaseStream.WriteByte(0xAA);  //hlavicka
                for (int count = 0; count < 5; count++)
                {
                    serialPortXBee.BaseStream.WriteByte(SPISensorSetup[count]);  //hlavicka 
                }
                WaitForATGoOn();  //cekame na OK, lze pouzit i mimo AT mod
                answer = "OK";
            }
            catch
            {
                answer = "ERROR";
                confirmMode = false;
            }
            confirmMode = false;
            return answer;
        }

        //MIKROKONTROLER: PRIKAZ PRO MIKROKONTROLER PRO ZMENU RYCHLOSTI KOMUNIKACE S MODULEM XBEE (USART)
        public string XBeeUSARTBaudrate(Int32 baudRate)
        {
            string answer = "";
            confirmMode = true;
            //prikaz XBee modulu na strane mikrokontroleru pro zmenu baudRate
            serialPortXBee.BaseStream.WriteByte(0xAA);  //hlavicka
            serialPortXBee.BaseStream.WriteByte(0x02);  //rozliseni pro program v mikrokontroleru

            switch (baudRate)   //rozliseni pro baudrate v mikrokontroleru
            {
                case 4800: serialPortXBee.BaseStream.WriteByte(0x02); answer = "OK"; break;
                case 9600: serialPortXBee.BaseStream.WriteByte(0x03); answer = "OK"; break;
                case 19200: serialPortXBee.BaseStream.WriteByte(0x04); answer = "OK"; break;
                case 38400: serialPortXBee.BaseStream.WriteByte(0x05); answer = "OK"; break;
                case 57600: serialPortXBee.BaseStream.WriteByte(0x06); answer = "OK"; break;
                case 115200: serialPortXBee.BaseStream.WriteByte(0x07); answer = "OK"; break;
                default: answer = "ERROR"; break;
            }
            serialPortXBee.BaseStream.WriteByte(0x00);  //nastaveni parity, v ATMEGA ale nefunguje
            WaitForATGoOn();
            confirmMode = false;

            return answer;
        }

        //MIKROKONTROLER: PRIKAZ PRO MIKROKONTROLER PRO ZMENU RYCHLOSTI KOMUNIKACE SE SENZOREM PO ROZHRANI USART
        public string SensorUSARTBaudrate(Int32 baudRate)
        {
            string answer = "";
            confirmMode = true;
            serialPortXBee.BaseStream.WriteByte(0xAA);  //hlavicka  
            serialPortXBee.BaseStream.WriteByte(0x01);  //rozliseni pro program v mikrokontroleru

            switch (baudRate)   //rozliseni pro baudrate v mikrokontroleru
            {
                case 4800: serialPortXBee.BaseStream.WriteByte(0x02); answer = "OK"; break;
                case 9600: serialPortXBee.BaseStream.WriteByte(0x03); answer = "OK"; break;
                case 19200: serialPortXBee.BaseStream.WriteByte(0x04); answer = "OK"; break;
                case 38400: serialPortXBee.BaseStream.WriteByte(0x05); answer = "OK"; break;
                case 57600: serialPortXBee.BaseStream.WriteByte(0x06); answer = "OK"; break;
                case 115200: serialPortXBee.BaseStream.WriteByte(0x07); answer = "OK"; break;
                default: answer = "ERROR"; break;
            }
            serialPortXBee.BaseStream.WriteByte(0x00);  //nastaveni parity, v ATMEGA ale nefunguje
            WaitForATGoOn();
            confirmMode = false;
            return answer;
        }

        //MIKROKONTROLER: PRIKAZ POVOLUJICI PREPOSILANI DAT ZE SENZORU PRIPOJENEMU K ROZHRANI USART DO PC
        public string SensorUSART_Data(string command)
        {
            string answer = "";
            confirmMode = true;
            serialPortXBee.BaseStream.WriteByte(0xAA);  //hlavicka   
            serialPortXBee.BaseStream.WriteByte(0x05);  //rozliseni pro program v mikrokontroleru
            switch (command)
            {
                //zacni preposilat data ze senzoru na modul XBee
                case "Start": serialPortXBee.BaseStream.WriteByte(0x00); answer = "OK"; break;
                //prestan preposilat data ze senzoru na modul XBee
                case "Stop": serialPortXBee.BaseStream.WriteByte(0x01); answer = "OK"; break;
                default: answer = "ERROR"; break;
            }
            WaitForATGoOn();
            confirmMode = false;
            return answer;

        }

        //MIKROKONTROLER: PRIKAZ PRO POSILANI TESTOVACICH DAT Z MIKROKONTROLERU DO PC PRO TESTOVANI KOMUNIKACE
        public string sendTestData(string command)
        {
            string answer = "";
            confirmMode = true;
            serialPortXBee.BaseStream.WriteByte(0xAA);  //hlavicka   
            serialPortXBee.BaseStream.WriteByte(0x04);  //rozliseni pro program v mikrokontroleru
            switch (command)
            {
                //zacni posilat testovaci data
                case "Start": serialPortXBee.BaseStream.WriteByte(0x00); answer = "OK"; break;
                //prestan posilat testovaci data
                case "Stop": serialPortXBee.BaseStream.WriteByte(0x01); answer = "OK"; break;
                default: answer = "ERROR"; break;
            }
            WaitForATGoOn();
            confirmMode = false;
            return answer;
        }

        //MIKROKONTROLER: OVLADANI LED DIOD
        public string LEDDiodesControl(string command)
        {
            string answer = "";
            confirmMode = true;
            serialPortXBee.BaseStream.WriteByte(0xAA);  //hlavicka   
            serialPortXBee.BaseStream.WriteByte(0x03);  //rozliseni pro program v mikrokontroleru
            switch (command)
            {
                //zapnuti LED diod
                case "TurnOn": serialPortXBee.BaseStream.WriteByte(0x00); answer = "OK"; break;
                case "TurnOff": serialPortXBee.BaseStream.WriteByte(0x01); answer = "OK"; break;
                default: answer = "ERROR"; break;
            }
            WaitForATGoOn();
            confirmMode = false;
            return answer;
        }

    }

}
