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

#include <vcl.h>
#pragma hdrstop

#include "MainUnit.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TMainForm *MainForm;
//---------------------------------------------------------------------------
__fastcall TMainForm::TMainForm(TComponent* Owner)
    : TForm(Owner)
{
}
//---------------------------------------------------------------------------

void TMainForm::updateControls() {
    bool module_opened = (LTR25_IsOpened(&hltr25)==LTR_OK);
    bool devsel = (ltr25_list.Length > 0) && (cbbModulesList->ItemIndex >= 0);

    //обновление списка устройств и выбор можно делать только пока не открыто конкретное устройство
    btnRefreshDevList->Enabled = !module_opened;
    cbbModulesList->Enabled = !module_opened;

    //установить связь можно только если выбрано устройство
    btnOpen->Enabled = devsel;
    btnOpen->Caption =  module_opened ? "Закрыть соединение" : "Установить соединение";

    btnStart->Enabled = module_opened && !threadRunning;
    btnStop->Enabled = module_opened && threadRunning;

    //изменение настроек возможно только при открытом устройстве и не запущенном сборе
    bool cfg_en = module_opened && !threadRunning;

    cbbAdcFreq->Enabled = cfg_en;
    cbbDataFmt->Enabled = cfg_en;
    cbbISrcValue->Enabled = cfg_en;

    chkCh1En->Enabled = cfg_en;
    chkCh2En->Enabled = cfg_en;
    chkCh3En->Enabled = cfg_en;
    chkCh4En->Enabled = cfg_en;
    chkCh5En->Enabled = cfg_en;
    chkCh6En->Enabled = cfg_en;
    chkCh7En->Enabled = cfg_en;
    chkCh8En->Enabled = cfg_en;
}

void TMainForm::refreshDeviceList() {
    INT err = LTR_OK;
    int modules_cnt = 0;
    ltr25_list.Length = 0;
    cbbModulesList->Items->Clear();


    // устанавливаем связь с управляющим каналом сервера, чтобы получить список крейтов
    TLTR srv;
    LTR_Init(&srv);
    err=LTR_OpenSvcControl(&srv, LTRD_ADDR_DEFAULT, LTRD_PORT_DEFAULT);
    if (err!=LTR_OK) {
        MessageDlg("Не удалось установить связь с сервером: " + String(LTR_GetErrorString(err)),
                    mtError, TMsgDlgButtons() << mbOK,NULL);
    } else {
        char serial_list[LTR_CRATES_MAX][LTR_CRATE_SERIAL_SIZE];
        //получаем список серийных номеров всех подключенных крейтов
        err=LTR_GetCrates(&srv, &serial_list[0][0]);
        //серверное соединение больше не нужно - можно закрыть
        LTR_Close(&srv);
        if (err!=LTR_OK) {
             MessageDlg("Не удалось получить список крейтов: " + String(LTR_GetErrorString(err)),
                    mtError, TMsgDlgButtons() << mbOK,NULL);
        } else {
            for (int crate_ind=0 ; crate_ind < LTR_CRATES_MAX; crate_ind++) {
                //каждому крейту соответствует непустой серийный номер
                if (serial_list[crate_ind][0]!='\0') {
                    // Устанавливаем связь с каждым крейтом, чтобы получить список модулей
                    TLTR crate;
                    LTR_Init(&crate);
                    err =  LTR_OpenCrate(&crate, LTRD_ADDR_DEFAULT, LTRD_PORT_DEFAULT,
                                         LTR_CRATE_IFACE_UNKNOWN, serial_list[crate_ind]);
                    if (err==LTR_OK) {
                        WORD mids[LTR_MODULES_PER_CRATE_MAX];
                        err=LTR_GetCrateModules(&crate, mids);
                        if (err==LTR_OK) {
                            for (int module_ind=0; module_ind < LTR_MODULES_PER_CRATE_MAX; module_ind++) {
                                //ищем модули LTR25
                                if (mids[module_ind]==LTR_MID_LTR25) {
                                    // сохраняем информацию о найденном модуле, необходимую для
                                    // последующего установления соединения с ним, в список
                                    modules_cnt++;
                                    ltr25_list.Length=modules_cnt;
                                    ltr25_list[modules_cnt-1].csn = String(serial_list[crate_ind]);
                                    ltr25_list[modules_cnt-1].slot = module_ind+LTR_CC_CHNUM_MODULE1;
                                    // и добавляем в ComboBox для возможности выбора нужного
                                    cbbModulesList->AddItem("Крейт " + ltr25_list[modules_cnt-1].csn +
                                            ", Слот " + IntToStr(ltr25_list[modules_cnt-1].slot), NULL);
                                }
                            }
                        }        
                        //закрываем соединение с крейтом
                        LTR_Close(&crate);
                    }
                }
            }
        }
    }

    cbbModulesList->ItemIndex = 0;
    updateControls();
}

void TMainForm::closeDevice() {
    // остановка сбора и ожидание завершения потока
    if (threadRunning) {
        thread->stop=true;
        thread->WaitFor();
    }

    LTR25_Close(&hltr25);
}

//функция, вызываемая по завершению потока сбора данных
//разрешает старт нового, устанавливает threadRunning
void __fastcall TMainForm::OnThreadTerminate(TObject *obj) {
    if (thread->err != LTR_OK) {
        MessageDlg("Сбор данных завершен с ошибкой: " + String(LTR25_GetErrorString(thread->err)),
                    mtError, TMsgDlgButtons() << mbOK,NULL);
    }

    threadRunning = false;
    updateControls();
}


void __fastcall TMainForm::btnRefreshDevListClick(TObject *Sender) {
    refreshDeviceList();
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::btnOpenClick(TObject *Sender) {
    // если соединение с модулем закрыто - то открываем новое
    if (LTR25_IsOpened(&hltr25)!=LTR_OK) {
        INT res = LTR_OK;
        // информацию о крейте и слоте берем из сохраненного списка по индексу
        // текущей выбранной записи
        TLTR_MODULE_LOCATION location = ltr25_list[ cbbModulesList->ItemIndex ];
        LTR25_Init(&hltr25);
        res=LTR25_Open(&hltr25, LTRD_ADDR_DEFAULT, LTRD_PORT_DEFAULT, location.csn.c_str(), location.slot);
        if (res!=LTR_OK) {
            MessageDlg("Не удалось установить связь с модулем: " +
                        String(LTR25_GetErrorString(res)), mtError, TMsgDlgButtons() << mbOK, 0);
        }

        if (res==LTR_OK) {
            edtDevSerial->Text = String(hltr25.ModuleInfo.Serial);
            edtVerPld->Text = IntToStr(hltr25.ModuleInfo.VerPLD);
            edtVerFPGA->Text = IntToStr(hltr25.ModuleInfo.VerFPGA);
        } else {
            LTR25_Close(&hltr25);
        }
    } else {
        closeDevice();
    }
    updateControls();
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::FormCreate(TObject *Sender) {
    thread = 0;
    LTR25_Init(&hltr25);

    refreshDeviceList();
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::FormClose(TObject *Sender, TCloseAction &Action) {
    closeDevice();
    delete thread;
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::btnStartClick(TObject *Sender) {
    /* Сохраняем значения из элементов управления в соответствующие
       поля описателя модуля. Для простоты здесь не делается доп. проверок, что
        введены верные значения... */
    hltr25.Cfg.FreqCode  = cbbAdcFreq->ItemIndex;
    hltr25.Cfg.DataFmt   = cbbDataFmt->ItemIndex;
    hltr25.Cfg.ISrcValue = cbbISrcValue->ItemIndex;

    hltr25.Cfg.Ch[0].Enabled   = chkCh1En->Checked;
    hltr25.Cfg.Ch[1].Enabled   = chkCh2En->Checked;
    hltr25.Cfg.Ch[2].Enabled   = chkCh3En->Checked;
    hltr25.Cfg.Ch[3].Enabled   = chkCh4En->Checked;
    hltr25.Cfg.Ch[4].Enabled   = chkCh5En->Checked;
    hltr25.Cfg.Ch[5].Enabled   = chkCh6En->Checked;
    hltr25.Cfg.Ch[6].Enabled   = chkCh7En->Checked;
    hltr25.Cfg.Ch[7].Enabled   = chkCh8En->Checked;

    INT res = LTR25_SetADC(&hltr25);
    if (res != LTR_OK) {
        MessageDlg("Не удалось установить настройки: " +
                   String(LTR25_GetErrorString(res)), mtError, TMsgDlgButtons() << mbOK, 0);
    }

    if (res == LTR_OK) {
        if (thread) {
            delete thread;
            thread = 0;
        }
        thread = new TLTR25_ProcessThread(true);
        /* Так как структура должна быть одна и та же, что используемая потоком,
            что в классе основного окна, то вынуждены передать ее как pointer */
        thread->phltr25 = &hltr25;
        /* Сохраняем элементы интерфейса, которые должны изменяться обрабатывающим
           потоком в класс потока */
        thread->edtChVal[0]=edtCh1Val;
        thread->edtChVal[1]=edtCh2Val;
        thread->edtChVal[2]=edtCh3Val;
        thread->edtChVal[3]=edtCh4Val;
        thread->edtChVal[4]=edtCh5Val;
        thread->edtChVal[5]=edtCh6Val;
        thread->edtChVal[6]=edtCh7Val;
        thread->edtChVal[7]=edtCh8Val;

        /*  устанавливаем функцию на событие завершения потока (в частности,
            чтобы отследить, если поток завершился сам из-за ошибки при сборе
            данных) */
        thread->OnTerminate = OnThreadTerminate;
        thread->Resume();

        threadRunning = true;
    }

    updateControls();
}
//---------------------------------------------------------------------------

void __fastcall TMainForm::btnStopClick(TObject *Sender) {
    // устанавливаем запрос на завершение потока
    if (threadRunning) {
        thread->stop=true;
    }
    btnStop->Enabled = false;
}
//---------------------------------------------------------------------------

