using System;
using ltrModulesNet;


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


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


        static int Main(string[] args)
        {          
            /* LTR11_Init() вызывается уже в конструкторе */
            ltr12api hltr12 = new ltr12api();
            /* отрываем модуль. Используем упрощенный вариант функции с указанием только слота.
             * (есть вариант как с только со слотом, так и с серийным крейта и слотом 
             *  + полный) */
            _LTRNative.LTRERROR err = hltr12.Open(SLOT);
            if (err != _LTRNative.LTRERROR.OK)
            {
                Console.WriteLine("Не удалось открыть модуль. Ошибка {0}: {1}",
                    err, ltr12api.GetErrorString(err));
            }
            else
            {
               
                /* выводим информацию из hltr12.ModuleInfo */
                Console.WriteLine("Информация о модуле: ");
                Console.WriteLine("  Название модуля: {0}", hltr12.ModuleInfo.Name);
                Console.WriteLine("  Серийный номер : {0}", hltr12.ModuleInfo.Serial);
                Console.WriteLine("  Версия прошивки: {0}", hltr12.ModuleInfo.FirmwareVersionStr);

                /* --------------- задание параметров работы модуля ------------ */

                /* для заполнения полей конфируации используется отдельная структура.
                 * сначала получаем копию текущих настроек из поля Cfg описателя, 
                 * изменяем нужные поле, после чего записываем измененую конфигруацию
                 * обратно в поле Cfg описатиля и передаем настройки в модуль с помощью SetADC */
                ltr12api.CONFIG Cfg = hltr12.Cfg;
                /* режим старта сбора данных - внутренний */
                Cfg.AcqStartSrc = ltr12api.AcqStartSources.INT;
                /* режим синхронизации АПЦ - внутренний */
                Cfg.ConvStartSrc = ltr12api.ConvStartSources.INT;
                /* Дополнительный такт для измерения смещения нуля во время сбора (если не требуется - 0)*/
                Cfg.BgLChCnt = 1; 
                /* количество опрашиваемых  каналов*/
                Cfg.LChCnt = 3;
                /* таблица управления логическими каналами. Для упрощения сделан
                 * метод установки лог. канала,  который принимает номер логического канала и его параметры 
                 * (номер физического опрашиваемого канала и режим измерения) */
                for (byte i = 0; i < Cfg.LChCnt; ++i)
                {
                    Cfg.SetLChannel(i, i, ltr12api.ChModes.COMM);
                }
                
                /* частота дискретизации - 400 кГц. Данный метод сам устанавливает поля
                 * делителей в конфигурации */
                Cfg.AdcFreq = 400000;

                hltr12.Cfg = Cfg;
                /* передача установленных настроек в модуль */
                err = hltr12.SetADC();
                if (err != _LTRNative.LTRERROR.OK)
                {
                    Console.WriteLine("Не удалось установить настройки модуля. Ошибка {0}: {1}",
                         err, ltr12api.GetErrorString(err));
                }
                else
                {
                    /* после SetADC() обновляется поле AdcFreq и EnabledChCnt. Становится равной действительной
                     * установленной частоте */
                    Console.WriteLine("Модуль настроен успешно. Установленная частота АЦП {0}, частот на канал {1}",
                            hltr12.State.AdcFreq.ToString("F7"), hltr12.State.FrameFreq.ToString("F7"));
                }
            }

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

            if (err == _LTRNative.LTRERROR.OK)
            {           
                /* для вычисления размера принимаемого массива используем полученное после 
                 * настройки значение количества слов на кадр (чтобы учесть каналы фонового измерения
                 * нуля, если используются). */
                int recv_data_cnt = RECV_BLOCK_CH_SIZE * (int)hltr12.State.FrameWordsCount;
                uint[] rbuf = new uint[recv_data_cnt];
                double[] data = new double[recv_data_cnt];

                /* запуск сбора данных */
                err = hltr12.Start();
                if (err != _LTRNative.LTRERROR.OK)
                {
                    Console.WriteLine("Не удалось запустить сбор данных. Ошибка {0}: {1}",
                         err, ltr12api.GetErrorString(err));
                }
                else
                {
                    _LTRNative.LTRERROR stop_err;
                    for (int i = 0; (i < RECV_BLOCK_CNT) && 
                            (err == _LTRNative.LTRERROR.OK); i++)
                    {
                        int rcv_cnt;
                        /* в таймауте учитываем время выполнения самого преобразования*/
                        uint tout = RECV_TOUT + (uint)(RECV_BLOCK_CH_SIZE * hltr12.Cfg.LChCnt / hltr12.State.AdcFreq + 1);
                        /* прием необработанных слов. есть варинант с tmark и без него для удобства */
                        rcv_cnt = hltr12.Recv(rbuf, (uint)rbuf.Length, tout);

                        /* значение меньше 0 => код ошибки */
                        if (rcv_cnt < 0)
                        {
                            err = (_LTRNative.LTRERROR)rcv_cnt;
                            Console.WriteLine("Ошибка приема данных. Ошибка {0}: {1}",
                                              err, ltr12api.GetErrorString(err));
                        }
                        else if (rcv_cnt != rbuf.Length)
                        {
                            err = _LTRNative.LTRERROR.ERROR_RECV_INSUFFICIENT_DATA;
                            Console.WriteLine("Приняли недостаточно данных: запрашивали {0}, приняли {1}",
                                              rbuf.Length, rcv_cnt);
                        }
                        else
                        {
                            err = hltr12.ProcessData(rbuf, data, ref rcv_cnt, 
                                ltr12api.ProcFlags.CALIBR
                                | ltr12api.ProcFlags.CONV_UNIT
                                | ltr12api.ProcFlags.ZERO_OFFS_COR
                                | ltr12api.ProcFlags.ZERO_OFFS_AUTORECALC);
                            if (err != _LTRNative.LTRERROR.OK)
                            {
                                Console.WriteLine("Ошибка обработки данных. Ошибка {0}: {1}",
                                                   err, ltr12api.GetErrorString(err));
                            }
                            else
                            {
                                /* при успешной обработке для примера выводим по одному значению
                                 * для каждого канала */
                                Console.Write("Блок {0}.", i+1);
                                for (int ch=0; ch < hltr12.Cfg.LChCnt; ch++)
                                {                    
                                    /* если все ок - выводим значение (для примера только первое) */
                                    Console.Write(" {1}", ch + 1, data[ch].ToString("F7"));
                                    if (ch==(hltr12.Cfg.LChCnt-1))
                                        Console.WriteLine("");
                                    else
                                        Console.Write(", ");
                                }
                            }
                        }
                    }

                    /* останавливаем сбор данных */
                    stop_err = hltr12.Stop();
                    if (stop_err != _LTRNative.LTRERROR.OK)
                    {
                        Console.WriteLine("Не удалось остановить сбор данных. Ошибка {0}: {1}",
                             stop_err, ltr12api.GetErrorString(stop_err));
                        if (err == _LTRNative.LTRERROR.OK)
                            err = stop_err;
                    }                        
                }
            }
            

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

            return (int)err;
        }
    }
}
