using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.IO.Ports;


namespace UC864G_test_tool
{
    public partial class Form1 : Form
    {
        delegate void Set_btn_gpswprCallback(string text);
        delegate void DecodeInputCallback();
        delegate void ConsoleWriteCallback(Color color, string text);

        public struct gps_point
        {
            public string time;
            public string date;
            public string lat;
            public string lon;
            public string speed;
            public string alt;
        }

        string InputData = String.Empty;
        string InputBuff = String.Empty;
        string InputBuffDebug = String.Empty;
        string InputCommand = String.Empty;
        string PinNumber = String.Empty;
        
        char CR = (char)13;
        int DecodeLayer;
        const int get_param_N = 4;
        const int AtBuffSize = 20;
        string[] AtBuff = new string[AtBuffSize];
        const int AtMemorySize = 20;
        string[] AtMemory = new string[AtMemorySize];
        int AtBuffPntInd = 0;
        int AtBuffExInd = 0;
        int AcT = -1;
        int AtMemoryPntInd = 0;
        int AtMemoryPntSel = 0;
        int AtMemoryUsed = 0;
        int VoiceCallStat = 0;

        bool SendAtInProgress = false;
        bool GpsPwr = false;  
        bool GpxSaving = false;
        bool BuffFree = true;
        bool AtBuffFull = false;
        bool PinOk = false;
        bool PinRequested = false;
        int ProgSequence = 0;
        bool NetworkRegistered = false;
        bool GpsFirstSetup = true;
        bool CntrlDisabled = false;
        bool CntrlHardDisabled = false;
        bool ExpWord = false;
        bool DisableRsTx = false;

        gps_point GpsTmp;


        public Form1()
        {
            InitializeComponent();

            cmb_GpsPeriod.SelectedIndex = 2;    //5s perioda pro zaznam gps
            cmb_Fun.SelectedIndex = 0;    //plna funkcnost modulu
            tmr_GpsPeriod.Interval = Convert.ToInt32(cmb_GpsPeriod.SelectedItem.ToString()) * 1000;

            string[] ports = SerialPort.GetPortNames(); //najde seriove porty
            foreach (string port in ports)
            {
                cmbComSelect.Items.Add(port);
            }
        }
        


        private void btn_connect_Click(object sender, EventArgs e)
        {
            if (port.IsOpen) port.Close();
            port.PortName = cmbComSelect.SelectedItem.ToString();

            try
            {
                port.Open();
                tmr_Prim.Enabled = true;
                PinNumber = tb_Pin.Text;
            }
            catch
            {
                MessageBox.Show("Sériový port " + port.PortName + " nemohl být otevřen!", "UC864-G Test Tool", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                cmbComSelect.SelectedText = "";
            }  
        }

        private void cmbComSelect_SelectionChangeCommitted(object sender, EventArgs e)
        {
            btn_connect.Enabled = true;
        }

        //************************************************************************************************
        //************************************************************************************************
        //************************************************************************************************
        private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            InputData = port.ReadExisting();
            if (InputData != String.Empty)
            {
                ConsoleWrite(Color.Black, InputData);
                InputBuff += InputData;
                InputBuffDebug += InputData;
                if (InputBuffDebug.Length > 300) InputBuffDebug = InputBuffDebug.Substring(InputBuffDebug.Length - 200, 200); 
                tmr_DecodeError.Stop();
                DecodeInput();
            }
        }

        private void DecodeInput()
        {
            if (CntrlHardDisabled == true && VoiceCallStat < 2) return;  //rizeni je zcela zakazano
            if (this.InvokeRequired)
            {
                DecodeInputCallback d = new DecodeInputCallback(DecodeInput);
                this.Invoke(d);
            }
            else
            {
                if (InputBuff.Length < 5) return;
                int IndStart = 0;
                int IndEnd = 0;
                if (VoiceCallStat == 1)
                {
                    RemoveRedChars(); //odstrani zbytecne znaky
                    IndEnd = InputBuff.IndexOf('\r');
                    if (IndEnd == -1)
                    {
                        StartErrorTimer(3000);
                        return;
                    }
                    InputCommand = InputBuff.Substring(0, IndEnd);
                    if (InputCommand == "ATD" + tb_PhoneNumber.Text)
                    {
                        btn_Dial.Enabled = false;
                        VoiceCallStat = 2;
                        CntrlDis(true);
                        InputCommand = "VCDecode";
                        DecodeLayer = 1;
                        InputBuff = InputBuff.Substring(IndEnd, InputBuff.Length - IndEnd);
                    }
                }

                if (DecodeLayer == 0)  //===identifikace AT prikazu
                {
                    // hleda OK\r\n
                    while (InputBuff.ToString()[IndStart] != 'O' || InputBuff.ToString()[IndStart + 1] != 'K' || InputBuff.ToString()[IndStart + 2] != '\r' || InputBuff.ToString()[IndStart + 3] != '\n')
                    {
                        if (InputBuff.ToString()[IndStart] == 'E' && InputBuff.ToString()[IndStart + 1] == 'R' && InputBuff.ToString()[IndStart + 2] == 'R' && InputBuff.ToString()[IndStart + 3] == 'O')
                        {
                            InputBuff = InputBuff.Substring(IndStart + 4, InputBuff.Length - IndStart - 4); //odstrani cast stringu az po error
                            FinishDcd();
                            return;
                        }
                        IndStart++;
                        if (IndStart == InputBuff.Length - 3)
                        {
                            if (tmr_DecodeError.Enabled == false) StartErrorTimer(10000);  //supsti casovac kdyby nahodou neprisla zadna dalsi data
                            return; //nedorazil cely prikaz -> vyckej
                        } 
                    }
                    IndStart = 0;
                    while ((InputBuff.ToString()[IndStart] != 'A' || InputBuff.ToString()[IndStart + 1] != 'T') && IndStart < InputBuff.Length - 2)
                        IndStart++;
                    if (IndStart == InputBuff.Length - 2)
                    {
                        TerminateDcd(true);//nebyl nalezen zadny AT prikat -> spatna prichozy data -> zahod vse
                        FinishDcd();
                        return;
                    }
                    InputBuff = InputBuff.Substring(IndStart, InputBuff.Length - IndStart); //odstrani cast stringu az po "\r"

                    InputCommand = InputBuff.Remove(InputBuff.IndexOf('\r'));      //vyrizne prikaz
                    DecodeLayer = 1;
                }

                DisableRsTx = false;
                switch (InputCommand)
                {
                case "AT$GPSP?":
                    {
                        if (DecodeExpected("\r\r\n$GPSP: ") == false) break;   //prerusi pokud neni odpoved
                        ConsoleWrite(Color.Blue, "AT$GPSP? - identifikován úspěšně");
                        int GpsPwrState = DecodeInt(SeparateVal());
                        if (GpsFirstSetup == true)  //program zapnut poprve?
                        {
                            if (GpsPwrState == 1)
                            {
                                tmr_GpsPeriod.Start();
                                Set_btn_gpswpr("Vypnout");
                                GpsPwr = true;
                            }
                            else GpsPwr = false;
                            GpsFirstSetup = false;
                        }
                        else
                        {
                            if (GpsPwr == true)    //ma byt gps zapla?
                            {
                                if (GpsPwrState != 1)   // ano, je zapla?
                                {                     //gps je fyzicky vypla -> zapnout
                                    SendAt("AT$GPSP=1", true);
                                }
                            }
                            else
                            {
                                if (GpsPwrState == 1)   // ne, je vypla?
                                {                     //gps je fyzicky zapla -> vypnout
                                    SendAt("AT$GPSP=0", true);
                                }
                            }
                        }
                        DecodeWord();
                        FinishDcd();
                        break;
                    }

                case "AT$GPSP=1":
                    {
                        if (DecodeExpected("\r") == false) break;   //prerusi pokud neni odpoved
                        ConsoleWrite(Color.Blue, "AT$GPSP=1 - identifikován úspěšně");
                        if (String.Compare(DecodeWord(), "OK") == 0) Set_btn_gpswpr("Vypnout");    //gps uspesne zapnuta
                        if (this.InvokeRequired)
                        {
                            this.Invoke(new MethodInvoker(tmr_GpsPeriod.Start));
                        }
                        else
                        {
                            tmr_GpsPeriod.Start();
                        }
                        SendAt("AT$GPSACP" + CR, true);

                        //tmr_GpsPeriod.Enabled = true;
                        FinishDcd();
                        break;
                    }

                case "AT$GPSP=0":
                    {
                        if (DecodeExpected("\r") == false) break;   //prerusi pokud neni odpoved
                        ConsoleWrite(Color.Blue, "AT$GPSP=0 - identifikován úspěšně");
                        if (String.Compare(DecodeWord(), "OK") == 0) Set_btn_gpswpr("Zapnout");    //gps uspesne vypnuta
                        if (this.InvokeRequired)
                        {
                            this.Invoke(new MethodInvoker(tmr_GpsPeriod.Stop));
                        }
                        else
                        {
                            tmr_GpsPeriod.Stop();
                        }
                        //tmr_GpsPeriod.Enabled = false;
                        FinishDcd();
                        break;
                    }

                case "AT$GPSACP":
                    {
                        if (DecodeExpected("\r\r\n$GPSACP:") == false) break;   //prerusi pokud neni odpoved
                        ConsoleWrite(Color.Blue, "AT$GPSAC - identifikován úspěšně");
                        DecodeGps();
                        DecodeWord();
                        FinishDcd();
                        break;
                    }

                case "AT+CPIN?":
                    {
                        if (DecodeExpected("\r\r\n+CPIN: ") == false) break;   //prerusi pokud neni odpoved
                        ConsoleWrite(Color.Blue, "AT+CPIN? - identifikován úspěšně");
                        string ans = DecodeWord();
                        switch (ans)
                        {
                            case "READY":
                                {
                                    PinOk = true;
                                    lb_SimStat.Text = "Stav SIM: OK";
                                    PinRequested = false;
                                    break;
                                }
                            case "SIM PIN":
                                {
                                    ConsoleWrite(Color.Blue, "Je vyžadován kód PIN");
                                    if (tb_Pin.Text.Length == 4)
                                    {
                                        PinRequested = true;
                                        lb_SimStat.Text = "Stav SIM: Je vyžadován PIN";
                                        SendAt("AT#PCT", false);
                                    }
                                    else lb_PinEnter.Text = "<-- Zadejte číslo PIN a stiskněte Enter";
                                    break;
                                }
                            default:
                                {
                                    ConsoleWrite(Color.Violet, "Neznámý stav SIM.");
                                    lb_SimStat.Text = "Stav SIM: Chyba.";
                                    ProgSequence = -1;
                                    break;
                                }
                        }
                        DecodeWord();
                        FinishDcd();
                        break;
                    }

                case "AT#PCT":
                    {
                        if (DecodeExpected("\r\r\n#PCT:") == false) break;   //prerusi pokud neni odpoved
                        ConsoleWrite(Color.Blue, "AT#PCT - identifikován úspěšně");
                        int Pct = DecodeInt(SeparateVal());
                        if (Pct == 0)
                        {
                            MessageBox.Show("SIM karta je zablokovaná!", "UC864-G Test Tool", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                            ProgSequence = -1;  //prejde do error modu
                        }
                        else if (Pct < 3)
                        {
                            ConsoleWrite(Color.Violet, "SIM karta má pouze " + Pct.ToString() + " pokusy k odblokování. Z bezepčnostních důvodů zadejte PIN na jiném zařízení, poté se o to můžete pokusit zde.");
                            ProgSequence = -1;  //prejde do error modu
                        }
                        else if (PinRequested == true)
                        {
                            ConsoleWrite(Color.Blue, "Zadávám kód PIN");
                            SendAt("AT+CPIN=" + PinNumber.ToString(), false);
                        }
                        DecodeWord();
                        FinishDcd();
                        break;
                    }

                case "AT+CREG?":
                    {
                        if (DecodeExpected("\r\r\n+CREG:") == false) break;   //prerusi pokud neni odpoved
                        ConsoleWrite(Color.Blue, "AT+CREG - identifikován úspěšně");
                        SeparateVal();
                        int b = DecodeInt(SeparateVal());
                        switch (b)
                        {
                            case 0: NetworkRegistered = false; ProgSequence = 1; lb_RegStat.Text = "Stav modulu: Není registrován a nehledá operátora."; break;
                            case 1:
                                {
                                    NetworkRegistered = true;
                                    lb_RegStat.Text = "Stav modulu: Registrován u domovského operátora";
                                    if (ProgSequence != 2)
                                    {
                                        ProgSequence = 2;           //prejde do periodickeho kontrolovani site
                                        tmr_Prim.Interval = 250;
                                    }
                                    break;
                                }
                            case 2: NetworkRegistered = false; lb_RegStat.Text = "Stav modulu: Hledání operátora"; break;
                            case 3: NetworkRegistered = false; lb_RegStat.Text = "Stav modulu: Registrace byla odmítnuta"; break;
                            case 4: NetworkRegistered = false; lb_RegStat.Text = "Stav modulu: Neznámý"; break;
                            case 5: NetworkRegistered = true; lb_RegStat.Text = "Stav modulu: Zaregistrován (roaming)."; break;
                        }
                        SendAt("AT+COPS?", true);   //ziska data o operatorovi
                        DecodeWord();
                        FinishDcd();
                        break;
                    }

                case "AT+COPS?":
                    {
                        if (DecodeExpected("\r\r\n+COPS:") == false) break;   //prerusi pokud neni odpoved
                        ConsoleWrite(Color.Blue, "AT+COPS? - identifikován úspěšně");
                        SeparateVal();  //mode
                        SeparateVal();  //format
                        string OperName = DecodeString(SeparateVal());  //jmeno operatora
                        lb_Oper.Text = "Operátor: " + OperName;
                        AcT = DecodeInt(SeparateVal()); //pristupova technolgie
                        switch (AcT)
                        {
                            case 0: lb_AcT.Text = "Typ sítě: GSM"; rb_Gsm.Checked = true; break;
                            case 2: lb_AcT.Text = "Typ sítě: UMTS"; rb_Utran.Checked = true; break;
                        }
                        DecodeWord();
                        FinishDcd();
                        break;
                    }

                case "AT#MONI":
                    {
                        if (DecodeExpected("\r\r\n#MONI:") == false) break;   //prerusi pokud neni odpoved
                        ConsoleWrite(Color.Blue, "AT#MONI: - identifikován úspěšně");

                        tb_Report.Text = "";    //vymaze puvodni report

                        IndStart = InputBuff.IndexOf(':');  //najde prvni ":" a potom pred ni hleda posledni mezeru
                        while (InputBuff.ToString()[IndStart] != ' ' || IndStart == 0)
                        {
                            IndStart--;
                        }
                        if (IndStart != 0)
                        {
                            tb_Report.AppendText(InputBuff.Substring(1, IndStart - 1));
                        }

                        int IndR = InputBuff.IndexOf('\r'); //index konce zpravy
                        IndEnd = InputBuff.IndexOf(' ',IndStart + 1);
                        while (IndEnd < IndR && IndEnd != -1)
                        {
                            tb_Report.AppendText("\r\n" + InputBuff.Substring(IndStart +1, IndEnd - IndStart -1));
                            IndStart = IndEnd;
                            IndEnd = InputBuff.IndexOf(' ', IndStart + 1);
                        }
                        tb_Report.AppendText("\r\n" + InputBuff.Substring(IndStart + 1, IndR - IndStart - 1));

                        InputBuff = InputBuff.Substring(IndR, InputBuff.Length - IndR);
                        DecodeWord();
                        FinishDcd();
                        break;
                    }

                case "AT+CFUN?":
                    {
                        if (DecodeExpected("\r\r\n$GPSACP:") == false) break;   //prerusi pokud neni odpoved
                        ConsoleWrite(Color.Blue, "AT+CFUN? - identifikován úspěšně");
                        int Fun = DecodeInt(SeparateVal());
                        if (Fun > 2) cmb_Fun.SelectedIndex = Fun - 2;
                        else cmb_Fun.SelectedIndex = Fun - 1;
                        DecodeWord();
                        FinishDcd();
                        break;
                    }

                case "AT+CLVL?":
                    {
                        if (DecodeExpected("\r\r\n+CLVL:") == false) break;   //prerusi pokud neni odpoved
                        ConsoleWrite(Color.Blue, "AT+CLVL? - identifikován úspěšně");
                        int Clvl = DecodeInt(SeparateVal());
                        if (Clvl >=0 && Clvl <=10) tbar_Clvl.Value = Clvl;
                        DecodeWord();
                        FinishDcd();
                        break;
                    }

                case "AT#HFMICG?":
                    {
                        if (DecodeExpected("\r\r\n#HFMICG:") == false) break;   //prerusi pokud neni odpoved
                        ConsoleWrite(Color.Blue, "AT#HFMICG? - identifikován úspěšně");
                        int HfMicGain = DecodeInt(SeparateVal());
                        if (HfMicGain >= 0 && HfMicGain <= 7) tbar_MicGain.Value = HfMicGain;
                        DecodeWord();
                        FinishDcd();
                        break;
                    }

                case "VCDecode":
                    {
                        RemoveRedChars();
                        if (InputBuff.IndexOf('\r') == -1)
                        {
                            StartErrorTimer(10000);
                            return;
                        }  
                        string DialReport = DecodeWord();
                        switch (DialReport)
                        {
                            case "DIALING": ConsoleWrite(Color.Blue, "Vytáčení čísla."); break;
                            case "RINGING": ConsoleWrite(Color.Blue, "Cílová stanice zvoní."); break;
                            case "RELEASED": ConsoleWrite(Color.Blue, "Spojení ukončeno."); break;
                            case "CONNECTED":
                                {
                                    ConsoleWrite(Color.Blue, "Hovor byl přijat.");
                                    VoiceCallStat = 3;
                                    CntrlDis(false);
                                    FinishDcd();
                                    break;
                                }
                            default:
                                {
                                    ConsoleWrite(Color.Violet, "Chybné rozpoznání zpráv při hovoru");
                                    VoiceCallStat = 0;
                                    SendAt("AT+CHUP", false);
                                    FinishDcd();
                                    CntrlDis(false);
                                    break;
                                }
                        }
                        break;
                    }

                default:
                    {
                        TerminateDcd(false);    //odstrani necitelnou cast
                        FinishDcd();            //dekodovat zbytek bufferu
                        break;
                    }
                }
            }
        }

        private void StartErrorTimer(int delay)
        {
            tmr_DecodeError.Interval = delay;
            tmr_DecodeError.Start();
        }
                
        private void FinishDcd()
        {
            DecodeLayer = 0;
            if (InputBuff.Length < 5)   //je v buff dostatek dat?
            {
                BuffFree = true;    //neni
                if (SendAtInProgress == true) PortSend();   //posle dalsi prikaz je li to mozne
                return;
            }    
            int OkPos = 0;  //hleda dalsi OK tzn. zda buff obsahuje dalsi zpravy
            while (InputBuff.ToString()[OkPos] != 'O' || InputBuff.ToString()[OkPos + 1] != 'K' || InputBuff.ToString()[OkPos + 2] != '\r' || InputBuff.ToString()[OkPos + 3] != '\n')
            {
                OkPos++;
                if (OkPos == InputBuff.Length - 3)   //ok nenalezeno
                {
                    BuffFree = true;
                    if (SendAtInProgress == true) PortSend();   //posle dalsi prikaz je li to mozne
                    return;
                }
            }
            DecodeInput();  //OK nalezeno -> je co dekodovat
        }

        private void TerminateDcd(bool HardTerminate)   
        {
            if (HardTerminate == true)
            {
                InputBuff = "";     //smaze cely vstupni buffer natvrdo
                BuffFree = true;
            }
            else
            {
                int OkPos = 0;
                if (InputBuff.Length < 5)   //obsahuje buff dostatek dat?
                {
                    InputBuff = "";     //smaze cely vstupni buffer na tvrdo
                    BuffFree = true;
                }
                else
                {   //najde OK
                    while (InputBuff.ToString()[OkPos] != 'O' || InputBuff.ToString()[OkPos + 1] != 'K' || InputBuff.ToString()[OkPos + 2] != '\r' || InputBuff.ToString()[OkPos + 3] != '\n')
                    {
                        OkPos++;
                        if (OkPos == InputBuff.Length - 3)   //ok nenalezeno
                        {
                            InputBuff = "";     //smaze cely vstupni buffer na tvrdo
                            BuffFree = true;
                        }
                    }
                    InputBuff = InputBuff.Substring(OkPos + 4, InputBuff.Length - OkPos - 4);  //vymaze necitelna data bufferu az po OK
                }
            }
        }

        private bool DecodeExpected(string expected)
        {
            if (InputBuff.Length < InputCommand.Length + expected.Length || InputBuff.IndexOf('\r', InputCommand.Length + expected.Length) < InputCommand.Length + expected.Length) return false;    //obsahuje InputBuff dostatek dat?
            if (String.Compare(InputBuff, InputCommand.Length, expected, 0, expected.Length, true) == 0)    //ano, otestuj, zda odpovida
            {   //odpovida
                InputBuff = InputBuff.Substring(InputCommand.Length + expected.Length, InputBuff.Length - InputCommand.Length - expected.Length);
                return true;
            }
            else
            {   //nastala chyba
                TerminateDcd(false);
                FinishDcd();
                return false;
            }
        }

        private string SeparateVal()
        {
            if (InputBuff.ToString()[0] == ',')//kontroluje zda neni prvni znak carka -> neni neni hodnota
            {
                InputBuff = InputBuff.Substring(1, InputBuff.Length - 1);   //vyhodi carku
                return "null_value";
            } 
            int IndEnd = 0;
            while (InputBuff.ToString()[IndEnd] != ',' && InputBuff.ToString()[IndEnd] != '\r' && IndEnd < InputBuff.Length - 1)
                IndEnd++;      //najde prvni carku nebo konec vety
            if (IndEnd == 0) return " ";
            if (IndEnd == InputBuff.Length - 1 || InputBuff.ToString()[IndEnd - 1] == '\r')
                return " ";      //znak nebyl nalezen
            string str_ret = InputBuff.Substring(0, IndEnd);
            InputBuff = InputBuff.Substring(IndEnd+1, InputBuff.Length - IndEnd-1);
            return str_ret;
        }

        private void RemoveRedChars()
        {
            int IndStart = 0;
            while (InputBuff.ToCharArray()[IndStart] < 33)  //odstrani vsechny znaky \r \n
            {
                IndStart++;
                if (IndStart == InputBuff.Length) break;
            }
            InputBuff = InputBuff.Substring(IndStart, InputBuff.Length - IndStart); //orizne
        }
        

        private int DecodeInt(string value)
        {
            int IndStart = 0;
            while (value[IndStart] > 57 || value[IndStart] < 48)
            {
                IndStart++;
                if (IndStart == value.Length) return -321;  //žádné číslo nebylo nalezeno
            }
            int IndEnd = IndStart;
            while (value[IndEnd] <= 57 && value[IndEnd] >= 48)
            {
                IndEnd++;
                if (IndEnd == value.Length) break;
            }

            int int_ret = Convert.ToInt32(value.Substring(IndStart, IndEnd - IndStart));
            return int_ret;
        }

        private string DecodeString(string value)
        {
            int IndStart = 0;
            while (value[IndStart] != '\"')
            {
                IndStart++;
                if (IndStart == value.Length) return " ";      //znak nebyl nalezen
            }
            IndStart++;
            
            int IndEnd = IndStart;
            while (value[IndEnd] != '\"')
            {
                IndEnd++;
                if (IndEnd == value.Length) break;
            }
            string str_ret = value.Substring(IndStart, IndEnd - IndStart);
            return str_ret;
        }

        private string DecodeWord()
        {
            int IndStart = 0;
            while ((InputBuff.ToString()[IndStart] > 'z' || InputBuff.ToString()[IndStart] < 'A') && IndStart < InputBuff.Length - 1)
                IndStart++;
            if (IndStart == InputBuff.Length-1)
                return " ";      //znak nebyl nalezen
            int IndEnd = IndStart;
            while ((InputBuff.ToString()[IndEnd] <= 'z' && InputBuff.ToString()[IndEnd] >= 'A') || InputBuff.ToString()[IndEnd] == ' ')
            { 
                IndEnd++;
                if (IndEnd == InputBuff.Length - 1) break; // narazil na konec
            }
                
            string str_ret = InputBuff.Substring(IndStart, IndEnd - IndStart);
            InputBuff = InputBuff.Substring(IndEnd, InputBuff.Length - IndEnd);
            return str_ret;
        }

        private void DecodeGps()
        {
            System.Threading.Thread.CurrentThread.CurrentCulture = System.Globalization.CultureInfo.InvariantCulture;

            string tmpStr = SeparateVal();  //cas UTC
            if (tmpStr.Length != 11) return;
            lb_Time.Text = "Čas UTC:   " + tmpStr.Substring(1, 2) + ":" + tmpStr.Substring(3, 2) + ":" + tmpStr.Substring(5, 2);
            GpsTmp.time = lb_Time.Text.Substring(11,8);

            string lat = SeparateVal();  //latitude
            GpsTmp.lat = (Convert.ToInt32(lat.Substring(0, 2)) + (Convert.ToDouble(lat.Substring(2, 7))) / 60).ToString("0.000000000");
            lat = lat.Substring(0, 2) + "°" + lat.Substring(2, 8);

            string lon = SeparateVal();  //longitude
            GpsTmp.lon = (Convert.ToInt32(lon.Substring(0, 3)) + (Convert.ToDouble(lon.Substring(3, 7))) / 60).ToString("0.000000000");
            lon = Convert.ToInt32(lon.Substring(0, 3)).ToString() + "°" + lon.Substring(3, 8);  //longitude
            tb_GpsLoc.Text = lat + " " + lon;

            lb_GpsAcc.Text = "Přesnost:    " + SeparateVal() + "m";  //accuarcy

            tmpStr = SeparateVal();
            lb_GpsAlt.Text = "Nadmořská výška:    " + tmpStr + "m";  //altitude
            GpsTmp.alt = tmpStr;

            switch (DecodeInt(SeparateVal()))  //fix
            {
                case 0: lb_GpsFix.Text = "Fix: není"; break;
                case 2: lb_GpsFix.Text = "Fix: 2D"; break;
                case 3: lb_GpsFix.Text = "Fix: 3D"; break;
            }

            lb_GpsCrs.Text = "Azimut pohybu:    " + SeparateVal() + "°";  //course
            tmpStr = SeparateVal();
            lb_GpsSpd.Text = "Rychlost pohybu:    " + tmpStr + " km/h";  //speed km/h
            GpsTmp.speed = tmpStr;

            tmpStr = SeparateVal();  //speed knots
            tmpStr = SeparateVal();
            lb_Date.Text = "Datum UTC:    " + tmpStr.Substring(0, 2) + "." + tmpStr.Substring(2, 2) + "." + tmpStr.Substring(4, 2);  //date
            GpsTmp.date = tmpStr;
            lb_GpsSts.Text = "Počet satelitů:    " + Convert.ToInt32(SeparateVal()).ToString();  //satelites

            if (GpxSaving == true)
            {
                string WriteBuff = "<trkpt lat=\"" + GpsTmp.lat + "\" lon=\"" + GpsTmp.lon + "\"><ele>" + GpsTmp.alt + "</ele><time>20" + GpsTmp.date.Substring(4, 2) + "-" + GpsTmp.date.Substring(2, 2) + "-" + GpsTmp.date.Substring(0, 2) + "T" + GpsTmp.time + "Z</time>";
                WriteBuff += "<extensions><nmea:speed>" + GpsTmp.speed + "</nmea:speed></extensions></trkpt>";
                File.AppendAllText(tb_GpxPath.Text, WriteBuff);
            }
        }

        private void ConsoleWrite(Color color, string text)
        {
            if (this.InvokeRequired)
            {
                ConsoleWriteCallback d = new ConsoleWriteCallback(ConsoleWrite);
                this.Invoke(d, new object[] { color, text });
            }
            else
            {
                int start = rtb_console.TextLength;
                rtb_console.AppendText(text + "\n");
                int end = rtb_console.TextLength;
                rtb_console.Select(start, end - start);
                rtb_console.SelectionColor = color;
                rtb_console.Select(rtb_console.Text.Length, 0);
                rtb_console.ScrollToCaret();
                rtb_console.SelectionLength = 0;

                if (rtb_console.Text.Length > 30000)
                {
                    rtb_console.Select(0, 5000);
                    rtb_console.SelectedText = "\n";
                    rtb_console.Select(rtb_console.Text.Length, 0);
                    rtb_console.ScrollToCaret();
                    rtb_console.SelectionLength = 0;
                }
            }

        }

        void ConsoleLine()
        {
            ConsoleWrite(Color.Black, "———————————————————————————————————————————");
        }
        
        private void Set_btn_gpswpr(string text)
        {
            if (this.btn_gpspwr.InvokeRequired)
            {
                Set_btn_gpswprCallback d = new Set_btn_gpswprCallback(Set_btn_gpswpr);
                this.Invoke(d, new object[] { text });
            }
            else this.btn_gpspwr.Text = text;
        }


        private void btn_send_Click(object sender, EventArgs e)
        {
            SendAt(tb_send.Text, true);
        }

        private void tmr_Prim_Tick(object sender, EventArgs e)
        {
            if (CntrlDisabled != true) switch (ProgSequence)
            {
                case 0:     //startovaci sekvence programu
                {
                    SendAt("AT#GPIO=5,0,2", true);   //nastavi GPIO RfTxMon aktivni (cervena LED)
                    SendAt("AT#DIALMODE=2", true);  //rozsirene zpravy o stavu vytaceni
                    SendAt("AT+FCLASS=8", true);   //nastavi hlasovy mod
                    SendAt("AT+CMUT=0", true);      //povoli mikrofon
                    SendAt("AT#MONI=0", true);     //nastavi monitorovani serving cell
                    SendAt("AT+CLVL?", true);     //zjisti vystupni hlasitost"AT+CLVL="
                    SendAt("AT#HFMICG?", true);     //zjisti uroven zesileni mikrofonu HF
                    SendAt("AT$GPSP?", true);       //zjisti stav GPS
                    SendAt("AT+CPIN?", true);   //zkontroluje stav SIM
                    SendAt("AT+CREG?", true);   //zjisti zda je modul zaregistrovan do site
                    tmr_Prim.Interval = 10000;
                    ProgSequence = 1;
                    break;
                }
                case 1:     //ceka na pripojeni do site
                {
                    SendAt("AT+CPIN?", true);   //zkontroluje stav SIM
                    SendAt("AT+CREG?", true);   //zjisti zda je modul zaregistrovan do site
                    tmr_Prim.Interval = 10000;
                    break;
                }
                case 2: //periodicke ziskavani dat
                {
                    tmr_Prim.Interval = 6000;
                    SendAt("AT+CREG?", true);   //zjisti zda je modul zaregistrovan do site A NASLEDNE I INFO O OPERATOROVI
                    SendAt("AT#MONI", true);   //ziska vypis informaci o siti  
                    break;
                }
            }

        }

        private bool SendAt(string text, bool UseBuff)
        {
            if (UseBuff == true)    //ulozi AT prikaz do kruhoveho registru
            {
                if (AtBuffFull == true)
                    return false;   //buffer je plny
                AtBuff[AtBuffPntInd++] = text;
                if (AtBuffPntInd == AtBuffSize) AtBuffPntInd = 0;   //pokud je na konci bufferu -> zpet na zacatek
                if (AtBuffPntInd == AtBuffExInd) AtBuffFull = true; //bufer je plny -> zakaze zapis
                SendAtInProgress = true;   //v bufferu jsou data -> odesilej je
                if (BuffFree == true) PortSend(); //zahaji odesilani ihned
            }
            else
            {
                if (port.IsOpen)
                {
                    port.WriteLine(text + "\r");
                    ConsoleLine();
                    ConsoleWrite(Color.Red, text);
                }
                else return false;
            }
            return true;
        }

        private void PortSend()
        {
            if (CntrlDisabled == true || DisableRsTx == true) return;
            if (AtBuffPntInd != AtBuffExInd || (AtBuffPntInd == AtBuffExInd && AtBuffFull)) //ujisti se zda neni buff prazdny
            {
                if (port.IsOpen)
                {
                        port.WriteLine(AtBuff[AtBuffExInd++] + "\r");   //odesle data
                    BuffFree = false; //indikuje ze buff neni prazdny ptz se ocekavaji prichozi data
                    ConsoleLine();
                    ConsoleWrite(Color.Red, AtBuff[AtBuffExInd-1]); //-1 protoze se inkrementoval
                    if (AtBuffExInd == AtBuffSize) AtBuffExInd = 0;   //pokud je na konci bufferu -> zpet na zacatek
                    if (AtBuffFull == true) AtBuffFull = false; //byl buffer plny? uz neni -> povoli zapis
                    if (AtBuffExInd == AtBuffPntInd)    //je buffer prazdny?
                    {
                        SendAtInProgress = false;
                    }
                }
            }
        }

        private void CntrlDis(bool Disable)
        {
            if (Disable == true)
            {
                CntrlDisabled = true;
                CntrlHardDisabled = true;
            }
            else
            {
                CntrlDisabled = false;
                CntrlHardDisabled = false;
                if (SendAtInProgress == true) PortSend();   //posle dalsi prikaz je li to mozne
            }            
        }

        private void btn_gpspwr_Click(object sender, EventArgs e)
        {
            if (GpsPwr == false) GpsPwr = true;
            else GpsPwr = false;
            SendAt("AT$GPSP?", true);
        }


        private void tmr_GpsPeriod_Tick(object sender, EventArgs e)
        {
            if (CntrlDisabled != true) SendAt("AT$GPSACP" + CR, true);
        }

        private void cmb_GpsPeriod_SelectionChangeCommitted(object sender, EventArgs e)
        {
            tmr_GpsPeriod.Interval = Convert.ToInt32(cmb_GpsPeriod.SelectedItem.ToString()) * 1000;
        }

        private void btn_BrowseGpx_Click(object sender, EventArgs e)
        {
            SaveFileDialog dlg = new SaveFileDialog();
            dlg.AddExtension = true;
            dlg.DefaultExt = "gpx";
            dlg.DereferenceLinks = true;
            dlg.FileName = "Zaznam";
            dlg.Filter = "GPS Exchange Format|*.gpx";
            if (dlg.ShowDialog() == DialogResult.OK) tb_GpxPath.Text = dlg.FileName;
        }
        
        private void btn_GpsSave_Click(object sender, EventArgs e)
        {
            if (GpxSaving == false)
            {
                if (GpsPwr == false)
                {
                    MessageBox.Show("GPS Přijímač není zaplý.", "UC864-G Test Tool", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return;
                }
                
                if (File.Exists(tb_GpxPath.Text))
                {
                    MessageBox.Show("Soubor již existuje, vyberte jiný.", "RUC864-G Test Tool", MessageBoxButtons.OK, MessageBoxIcon.Warning);
                    return;
                }
                GpxSaving = true;
                tb_GpxPath.ReadOnly = true;
                File.AppendAllText(tb_GpxPath.Text, "<?xml version='1.0' encoding='ISO-8859-1' ?>\n<gpx version=\"1.1\" creator=\"UC864-G\" xmlns=\"http://www.topografix.com/GPX/1/1\"><trk><trkseg>");
                btn_GpsSave.Text = "Ukončit";
            }
            else
            {
                GpxSaving = false;
                tb_GpxPath.ReadOnly = false;
                File.AppendAllText(tb_GpxPath.Text, "</trkseg></trk></gpx>");
                btn_GpsSave.Text = "Zapnout";
            }
        }

        private void linkLabel1_Click(object sender, EventArgs e)
        {
            System.Diagnostics.Process.Start("http://maps.google.com/maps?q=" + GpsTmp.lat + "+" + GpsTmp.lon);
        }

        private void tb_send_KeyUp(object sender, KeyEventArgs e)
        {
            switch (e.KeyCode)
            {
                case Keys.Enter:
                    {
                        if (CntrlDisabled == true) SendAt(tb_send.Text, false);
                        else if (tb_send.Text != "") SendAt(tb_send.Text, true);

                        if (AtMemoryPntInd == AtMemorySize) AtMemoryPntInd = 0;   //pokud je na konci bufferu -> zpet na zacatek
                        AtMemory[AtMemoryPntInd++] = tb_send.Text;  //kruhova pamet odeslanych prikazu
                        if (AtMemoryUsed < AtMemorySize) AtMemoryUsed++;
                        AtMemoryPntSel = AtMemoryPntInd;
                        tb_send.Text = "";
                        break;
                    }
                case Keys.Up:
                    {
                        if (AtMemoryUsed > 0 && AtMemoryPntSel != AtMemoryPntInd - AtMemoryUsed) //ujisti se zda neni pamet prazdna nebo neni na jejim konci
                        {
                            if (--AtMemoryPntSel == -1) AtMemoryPntSel = AtMemorySize - 1;   //pokud podtece pamet prikazu -> jdi na konec
                            tb_send.Text = AtMemory[AtMemoryPntSel];   //nacte prikaz z pameti
                            tb_send.SelectionStart = 0;
                            tb_send.SelectionLength = tb_send.Text.Length;
                        }
                        break;
                    }
                case Keys.Down:
                    {
                        if (AtMemoryPntSel != AtMemoryPntInd -1)
                        {
                            if (++AtMemoryPntSel == AtMemorySize) AtMemoryPntSel = 0;   //pokud pretece pamet prikazu -> jdi na zacatek
                            tb_send.Text = AtMemory[AtMemoryPntSel];   //nacte prikaz z pameti
                            tb_send.SelectionStart = 0;
                            tb_send.SelectionLength = tb_send.Text.Length;
                        }
                        break;
                    } 
                default:
                    {
                        AtMemoryPntSel = AtMemoryPntInd;
                        break;
                    }
            }
        }

        private void tb_Pin_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Enter)
            {
                PinNumber = tb_Pin.Text;
                lb_PinEnter.Text = "";
            }
        }

        private void btn_Test_Click(object sender, EventArgs e)
        {
            
        }

        private void cmb_Fun_SelectionChangeCommitted(object sender, EventArgs e)
        {
            if (cmb_Fun.SelectedIndex > 1) SendAt("AT+CFUN=" + (cmb_Fun.SelectedIndex + 2).ToString(), true);
            else SendAt("AT+CFUN=" + (cmb_Fun.SelectedIndex + 1).ToString(), true);

            SendAt("AT+CFUN?", true);
        }

        private void rb_Utran_MouseClick(object sender, MouseEventArgs e)
        {
            SendAt("AT+COPS=0,0,\"xxx\",2", true);
            DisableRsTx = true;
            StartErrorTimer(15000);
        }

        private void rb_Gsm_MouseClick(object sender, MouseEventArgs e)
        {
            SendAt("AT+COPS=0,0,\"xxx\",0", true);
            DisableRsTx = true;
            StartErrorTimer(15000);
        }

        private void rb_LedOn_MouseClick(object sender, MouseEventArgs e)
        {
            SendAt("AT#GPIO=5,0,2", true);   //nastavi GPIO RfTxMon aktivni (cervena LED)
        }

        private void rb_LedOff_MouseClick(object sender, MouseEventArgs e)
        {
            SendAt("AT#GPIO=5,0,0", true);   //vypne GPIO RfTxMon (cervena LED)
        }

        private void rb_AntAkt_CheckedChanged(object sender, EventArgs e)
        {
            SendAt("AT$GPSAT=1", true);
            
        }

        private void rb_AntPas_MouseClick(object sender, MouseEventArgs e)
        {
            SendAt("AT$GPSAT=1", true);
        }

        private void tbar_Clvl_ValueChanged(object sender, EventArgs e)
        {
            SendAt("AT+CLVL=" + tbar_Clvl.Value, true);
        }

        private void btn_CntrlDis_Click(object sender, EventArgs e)
        {
            if (CntrlDisabled == true)
            {
                CntrlDis(false);
                btn_CntrlDis.Text = "Vypnout řízení"; 
            }
            else
            {
                CntrlDis(true);
                btn_CntrlDis.Text = "Zapnout řízení";   
            }

        }

        private void tmr_DecodeError_Tick(object sender, EventArgs e)
        {
            tmr_DecodeError.Stop();
            TerminateDcd(true);
            CntrlDis(false);
            DisableRsTx = false;
            FinishDcd();
        }

        private void btn_Dial_Click(object sender, EventArgs e)
        {
            SendAt("ATD" + tb_PhoneNumber.Text.ToString(), true);
            VoiceCallStat = 1;
        }

        private void btn_Chup_Click(object sender, EventArgs e)
        {
            SendAt("AT+CHUP", false);
            btn_Dial.Enabled = true;
            CntrlDis(false);
            DecodeLayer = 0;
            VoiceCallStat = 0;
        }

        private void trackBar1_ValueChanged(object sender, EventArgs e)
        {
            SendAt("AT#HFMICG=" + tbar_MicGain.Value, true);
        }

        private void cmb_GpsPeriod_SelectedIndexChanged(object sender, EventArgs e)
        {

        }

    }
}