//---------------------------------------------------------------------------


#pragma hdrstop

#include "LTR25_ProcessThread.h"

// Время, за которое будет отображаться вычисленное значение (в мс)
#define RECV_BLOCK_TIME          1000
// Дополнительный  постоянный таймаут на прием данных (в мс)
#define RECV_TOUT                4000


//---------------------------------------------------------------------------

#pragma package(smart_init)

 __fastcall TLTR25_ProcessThread::TLTR25_ProcessThread(bool CreateSuspended)
    : TThread(CreateSuspended), stop(false), err (LTR_OK) {

}

/* обновление индикаторов формы результатами последнего измерения.
   Метод должен выполняться только через Syncronize, который нужен
   для доступа к элементам VCL не из основного потока */
void __fastcall TLTR25_ProcessThread::updateData() {
    for (int ch=0; ch < LTR25_CHANNEL_CNT; ch++) {
        if (ChValidData[ch]) {
            if (ChStatus[ch] == LTR25_CH_STATUS_OK) {
                edtChVal[ch]->Text = FloatToStrF(ChPP[ch], ffFixed, 8, 6);
            } else if (ChStatus[ch] == LTR25_CH_STATUS_SHORT) {
                edtChVal[ch]->Text = "КЗ";
            } else if (ChStatus[ch] == LTR25_CH_STATUS_OPEN) {
                edtChVal[ch]->Text = "Обрыв";
            }
        } else {
            edtChVal[ch]->Text = "";
        }
    }
}


void __fastcall TLTR25_ProcessThread::Execute() {
    DWORD *rcv_buf=0;
    double *data=0;
    INT err = LTR_OK;
    // номера разрешенных каналов
    BYTE ch_nums[LTR25_CHANNEL_CNT];
    INT ch_cnt=0;  //количество разрешенных каналов
    INT recv_wrd_cnt;  //количество принимаемых сырых слов за раз
    INT recv_data_cnt; //количество обработанных слов, которые должны принять за раз

    //обнуляем переменные
    for (INT ch=0; ch < LTR25_CHANNEL_CNT; ch++)
        ChValidData[ch]=false;
    Synchronize(updateData);

    //Проверяем, сколько и какие каналы разрешены
    for (INT ch=0; ch < LTR25_CHANNEL_CNT; ch++) {
        if (phltr25->Cfg.Ch[ch].Enabled) {
            ch_nums[ch_cnt] = ch;
            ch_cnt++;
        }
    }

    /* Определяем, сколко преобразований будет выполненно за заданное время
      => будем принимать данные блоками такого размера */
    recv_data_cnt =  (INT)(phltr25->State.AdcFreq*RECV_BLOCK_TIME/1000) * ch_cnt;
    /* В 24-битном формате каждому отсчету соответствует два слова от модуля,
                   а в 20-битном - одно */
    recv_wrd_cnt = phltr25->Cfg.DataFmt == LTR25_FORMAT_32 ? 2*recv_data_cnt : recv_data_cnt;

    //выделяем массивы для приема данных
    rcv_buf = new DWORD[recv_wrd_cnt];
    data = new double[recv_data_cnt];

    err = LTR25_Start(phltr25);
    if (err==LTR_OK) {
        while (!stop && (err==LTR_OK)) {
            /* Принимаем данные */
            INT recv_size = LTR25_Recv(phltr25, rcv_buf, 0, recv_wrd_cnt, RECV_TOUT + RECV_BLOCK_TIME);
            //Значение меньше нуля соответствуют коду ошибки
            if (recv_size < 0) {
                err=recv_size;
            } else if (recv_size < recv_wrd_cnt) {
                err=LTR_ERROR_RECV_INSUFFICIENT_DATA;
            } else {
                double ch_max[LTR25_CHANNEL_CNT];
                double ch_min[LTR25_CHANNEL_CNT];
                DWORD  ch_cur_status[LTR25_CHANNEL_CNT];
                bool   ch_valid[LTR25_CHANNEL_CNT];

                err=LTR25_ProcessData(phltr25, rcv_buf, data, &recv_size,
										LTR25_PROC_FLAG_VOLT |
										LTR25_PROC_FLAG_PHASE_COR |
										LTR25_PROC_FLAG_SIGN_COR,
										ch_cur_status);
                if (err==LTR_OK) {
                    for (INT ch=0; ch < LTR25_CHANNEL_CNT; ch++) {
                        ch_valid[ch] = false;
                    }

                    for (INT ch=0; ch < ch_cnt; ch++) {
                        ChStatus[ch_nums[ch]] = ch_cur_status[ch];
                        ch_min[ch_nums[ch]]   = data[ch];
                        ch_max[ch_nums[ch]]   = data[ch];
                        ch_valid[ch_nums[ch]] = true;
                    }

                    // получаем кол-во отсчетов на канал
                    recv_size = (INT) (recv_size/ch_cnt);

                    // рассчет минимального и максимального значения для всех каналов,
                    // которые разрешены и для которых статус = OK
                    for (INT i=0; i < recv_size; i++) {
                        for (INT ch=0; ch < ch_cnt; ch++) {
                            if (ch_cur_status[ch] == LTR25_CH_STATUS_OK) {
                                if (ch_min[ch_nums[ch]] > data[ch_cnt*i + ch])
                                    ch_min[ch_nums[ch]] = data[ch_cnt*i + ch];
                                if (ch_max[ch_nums[ch]] < data[ch_cnt*i + ch])
                                    ch_max[ch_nums[ch]] = data[ch_cnt*i + ch];
                            }
                        }
                    }

                    // вычисляем пик-пик просто как разницу максимального и минимального
                    for (INT ch=0; ch < LTR25_CHANNEL_CNT; ch++) {
                        if (ch_valid[ch]) {
                            if (ChStatus[ch] == LTR25_CH_STATUS_OK)
                                ChPP[ch] = ch_max[ch] - ch_min[ch];
                        }
                        ChValidData[ch] = ch_valid[ch];
                    }
                    // обновляем значения элементов управления
                    Synchronize(updateData);
                }
            }
        } // while (!stop && (err==LTR_OK))

        /* По выходу из цикла отсанавливаем сбор данных.
            Чтобы не сбросить код ошибки (если вышли по ошибке)
            результат останова сохраняем в отдельную переменную */
        INT stoperr= LTR25_Stop(phltr25);
        if (err == LTR_OK)
            err= stoperr;
    }

    delete []rcv_buf;
    delete []data;
}
