using System;
using ltrModulesNet;


/* Данный пример демонстрирует работу с модулем LTR27 из программы на языке C#.
 * Пример представляет собой консольную программу, которая устанавливает связь с модулем,
 * выводит информацию о модуле, устанавливает настройки и собирает заданное кол-во 
 * блоков заданного размера, выводя на экран только по первому значению для каждого канала.
 * 
 * Необходимо установить номер слота, в котором вставлен модуль (константа SLOT).
 * Настройки сбора задаются в коде при конфигурации модуля.
 */


namespace ltr27_console
{
    class ltr27_console
    {
         /* Номер слота в крейте, где вставлен модуль */
        const int SLOT = 6;
        /* Количество отсчетов на канал, принмаемых за раз */
        const int RECV_BLOCK_CH_SIZE = 10;
        /* Количество блоков, которые нужно принять и выйти */
        const int RECV_BLOCK_CNT = 50;
        /* Таймаут на ожидание данных при приеме (без учета времени преобразования) */
        const int RECV_TOUT = 4000;

        static int Main(string[] args)
        {          
            double adcFreq = 10; /* частота сбора в Гц */

            /* LTR27_Init() вызывается уже в конструкторе */
            ltr27api hltr27 = new ltr27api();
            /* отрываем модуль. Используем упрощенный вариант функции с указанием только слота.
             * (есть вариант как с только со слотом, так и с серийным крейта и слотом 
             *  + полный) */
            _LTRNative.LTRERROR err = hltr27.Open(SLOT);
            if (err != _LTRNative.LTRERROR.OK)
            {
                Console.WriteLine("Не удалось открыть модуль. Ошибка {0}: {1}",
                    err, ltr27api.GetErrorString(err));
            }
            else
            {
                /* Считываем информацию о конфигурации модуля и о мезанинах */
                err = hltr27.GetConfig();
                if (err != _LTRNative.LTRERROR.OK)
                {
                    Console.WriteLine("Не удалось прочитать конфигурацию модуля. Ошибка {0}: {1}",
                            err, ltr27api.GetErrorString(err));
                }
                else
                {
                    err = hltr27.GetDescription(ltr27api.Descriptions.MODULE);


                    for (int i = 0; (i < ltr27api.LTR27_MEZZANINE_NUMBER) &&
                        (err == _LTRNative.LTRERROR.OK); i++)
                    {
                        if (hltr27.Mezzanine[i].Name != "EMPTY")
                        {
                            err = hltr27.GetDescription((ushort)((ushort)ltr27api.Descriptions.MEZZANINE1 << i));
                        }
                    }

                    if (err != _LTRNative.LTRERROR.OK)
                    {
                        Console.WriteLine("Не удалось прочитать описание модуля или мезонинов. Ошибка {0}: {1}",
                                          err, ltr27api.GetErrorString(err));
                    }
                }                        
            }

            /* выводим информацию о модуле */
            if (err == _LTRNative.LTRERROR.OK)
            {
                Console.WriteLine("  Информация о модуле :");
                Console.WriteLine("      Название        : {0}", hltr27.ModuleInfo.Module.DeviceName);
                Console.WriteLine("      Серийный номер  : {0}", hltr27.ModuleInfo.Module.SerialNumber);

                if (hltr27.ModuleInfo.Cpu.Active)
                {
                    Console.WriteLine("  Информация о процессоре :");
                    Console.WriteLine("     Название        : {0}", hltr27.ModuleInfo.Cpu.Name);
                    Console.WriteLine("     Частота клока   : {0} Hz", hltr27.ModuleInfo.Cpu.ClockRate);
                    Console.WriteLine("     Версия прошивки : {0}.{1}.{2}.{3}",
                        (hltr27.ModuleInfo.Cpu.FirmwareVersion >> 24) & 0xFF,
                        (hltr27.ModuleInfo.Cpu.FirmwareVersion >> 16) & 0xFF,
                        (hltr27.ModuleInfo.Cpu.FirmwareVersion >> 8) & 0xFF,
                        hltr27.ModuleInfo.Cpu.FirmwareVersion & 0xFF);
                    Console.WriteLine("     Комментарий     : {0}", hltr27.ModuleInfo.Cpu.Comment);
                }
                else
                {
                    Console.WriteLine("  Не найдено действительное описание процессора!!!");
                }

                for (int i = 0; (i < ltr27api.LTR27_MEZZANINE_NUMBER); i++)
                {
                    if (hltr27.ModuleInfo.Mezzanine[i].Active)
                    {
                        Console.WriteLine("    Информация о мезонине в слоте {0} :", i + 1);
                        Console.WriteLine("      Название        : {0}", hltr27.ModuleInfo.Mezzanine[i].Name);
                        Console.WriteLine("      Серийный номер  : {0}", hltr27.ModuleInfo.Mezzanine[i].SerialNumber);
                        Console.WriteLine("      Ревизия         : {0}", hltr27.ModuleInfo.Mezzanine[i].Revision);
                        for (int j = 0; (j < 4); j++)
                        {
                            Console.WriteLine("      Калибр. коэф. {0} : {1}", j,
                                              hltr27.ModuleInfo.Mezzanine[i].Calibration[j].ToString("F5"));
                        }
                    }
                }
            }

            if (err == _LTRNative.LTRERROR.OK) {
                /* установка частоты сбора АЦП - 10 Гц. Метод сам заполняет поле делителя */
                hltr27.FillAdcFreqParams(adcFreq, out adcFreq);

                err = hltr27.SetConfig();
                if (err != _LTRNative.LTRERROR.OK)
                {
                    Console.WriteLine("Не удалось записать настройки модуля. Ошибка {0}: {1}",
                        err, ltr27api.GetErrorString(err));
                }
            }

            /* Запуск сбора данных (если не был запущен) */
            if (err == _LTRNative.LTRERROR.OK) 
            {
                err = hltr27.ADCStart();
                if (err != _LTRNative.LTRERROR.OK)
                {
                    Console.WriteLine("Не удалось запустить сбор данных. Ошибка {0}: {1}",
                        err, ltr27api.GetErrorString(err));
                }
            }


            if (err == _LTRNative.LTRERROR.OK)
            {
                int recv_data_cnt =  RECV_BLOCK_CH_SIZE*ltr27api.LTR27_CHANNELS_CNT;
                uint[] rbuf = new uint[recv_data_cnt];
                double[] data = new double[recv_data_cnt];               

                Console.WriteLine("Сбор данных запущен успешно");
                /* запуск сбора данных */
                err = hltr27.ADCStart();
                if (err != _LTRNative.LTRERROR.OK)
                {
                    Console.WriteLine("Не удалось запустить сбор данных. Ошибка {0}: {1}",
                         err, ltr27api.GetErrorString(err));
                }
                else
                {   
                    for (int b = 0; (b < RECV_BLOCK_CNT) && 
                            (err == _LTRNative.LTRERROR.OK); b++)
                    {
                        int rcv_cnt;
                        /* в таймауте учитываем время выполнения самого преобразования*/
                        uint tout = RECV_TOUT + (uint)(1000 * RECV_BLOCK_CH_SIZE / adcFreq + 1);
                        /* прием необработанных слов. есть варинант с tmark и без него для удобства */
                        rcv_cnt = hltr27.Recv(rbuf, (uint)rbuf.Length, tout);

                        /* значение меньше 0 => код ошибки */
                        if (rcv_cnt < 0)
                        {
                            err = (_LTRNative.LTRERROR)rcv_cnt;
                            Console.WriteLine("Ошибка приема данных. Ошибка {0}: {1}",
                                              err, ltr27api.GetErrorString(err));
                        }
                        else if (rcv_cnt != rbuf.Length)
                        {
                            err = _LTRNative.LTRERROR.ERROR_RECV_INSUFFICIENT_DATA;
                            Console.WriteLine("Приняли недостаточно данных: запрашивали {0}, приняли {1}",
                                              rbuf.Length, rcv_cnt);
                        }
                        else
                        {
                            uint proc_cnt = (uint)rcv_cnt;
                            err = hltr27.ProcessData(rbuf, data, ref proc_cnt, true, true);
                            if (err == _LTRNative.LTRERROR.OK)
                            {
                                /* при успешной обработке для примера выводим по одному значению
                                     * для каждого канала */
                                Console.Write("Блок {0}.", b + 1);           
                                for (int ch = 0; ch < ltr27api.LTR27_CHANNELS_CNT; ch++)
                                {
                                    int mezzanine_idx = ch / ltr27api.LTR27_MAZZANINE_CHANNELS_CNT;
                                    if (hltr27.Mezzanine[mezzanine_idx].Name != "EMPTY")
                                    {
                                        Console.Write(" {0} {1}", data[ch].ToString("F4"), hltr27.Mezzanine[mezzanine_idx].Unit);
                                    }
                                }
                                Console.Write("\n");                                
                            }
                            else
                            {
                                Console.WriteLine("Ошибка обработки данных! Ошибка {0}: {1}",
                                                 err, ltr27api.GetErrorString(err));
                            }
                        }
                    }

                     /* останов сбора данных */
                    _LTRNative.LTRERROR  stoperr = hltr27.ADCStop();
                    if (stoperr != _LTRNative.LTRERROR.OK)
                    {
                        Console.WriteLine("Не удалось остановить сбор данных. Ошибка {0}: {1}",
                            stoperr, ltr27api.GetErrorString(stoperr));
                        if (err == _LTRNative.LTRERROR.OK)
                            err = stoperr;
                    }
                    else
                    {
                        Console.WriteLine("Сбор данных остановлен успешно");
                    }
                }
            }

            /* закрываем соединение */
            if (hltr27.IsOpened() == _LTRNative.LTRERROR.OK)
                hltr27.Close();

            return (int)err;
        }
    }
}
