//          задача опpоса UMCM по MODBUS-протоколу

#include  "complex.h"
#include  "screen.h"

typedef struct {   // структура данных для опроса контроллера UMCM
   word_s   kzreg;            // kz опроса регуляторов
   word_s   kzai;             // kz опроса аналоговых входов
   word_s   kzdi;             // kz опроса дискретных входов
   word_s   kzdo;             // kz опроса дискретных выходов
   word_s   kzvar;            // kz опроса переменных
   word_s   kolreg;           // количество регуляторов в контроллере
   word_s   yesai;            // признак наличия аналоговых входов
   word_s   yesdi;            // признак наличия дискретных входов
   word_s   yesdo;            // признак наличия дискретных выходов
   word_s   yesvar;           // признак наличия переменных
   byte  baskreg[140];     // буфер запроса регуляторов  (137 max для 12 рег)
   byte  bansreg[260];     // буфер ответа регуляторов (255 max для 12 рег)
   byte  baskai[8];        // буфер запроса аналоговых входов
   byte  bansai[102];      // буфер ответа аналоговых входов
   byte  baskdi[8];        // буфер запроса дискретных входов
   byte  bansdi[40];       // буфер ответа дискретных входов
   byte  baskdo[8];        // буфер запроса дискретных выходов
   byte  bansdo[40];       // буфер ответа дискретных выходов
   byte  baskvar[20];      // буфер запроса переменных
   byte  bansvar[260];     // буфер ответа переменных (255 max для 60 var)
} UMC_MOD;

typedef struct
  {
              byte   nam[5];
              byte   str;
              byte   col;
              float  min;
              float  max;
              byte   frmt[6];
  } rec_koeffUMCM;

rec_koeffUMCM st_kfUMCM[5] = {
                        { "Кп =",  6, 43,  0.1, 1000.0,"%7.2f" },
                        { "Тд =",  7, 43,  0.0,   10.0,"%7.2f" },
                        { "Ти =",  8, 43,  0.0,   50.0,"%7.2f" },
                        { "Ввг=",  9, 43, -5.0,  105.0,"%7.2f" },
                        { "Внг=", 10, 43, -5.0,  105.0,"%7.2f" }
                      };

word_s scanUMCM(controller *ptr_c,byte *mask,word_s lask,byte *mans,word_s lans);
word_s mode_UMCM(controller *p_c, analog *p_a, word_s mode);
word_s so_UMCM(controller *p_c, analog *p_a, word_s cur_so);
word_s switch_UMCM(controller *p_c,digit *p_d,word_s nom_do,byte val_do);
word form_ks_UMCM(unsigned char *st,word_s len);
extern float float_intel(byte *bufr);

extern word_s setting(analog *a_ptr,float work_f);
extern void koeff_sc(analog *a_ptr);
extern word_s cur_kf[],pos_kf[],x_kf[],y_kf[], numrec, lenrec, fh, N_MAN;
extern char t_sc[], *recfil;


extern void v24_sendask(sioptr port,byte *masask,word_s lask);
extern word_s setting(analog *pt, float vf);

float kfsUMCM[5];

char no_mem_taskUMCM[] = "TASKUMCM.C - Мало памяти";

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

void taskUMCM(controller *ptr_c)
{
  word_s i, k, nomv, val, begin, kz;
  word_s offr;
  float valf;
  analog *ptr_a;
  digit *ptr_d;
  UMC_MOD **pCN;

//  Определение опрашиваемых контроллеров и подготовка запросов

  pCN = (UMC_MOD **)calloc(32,4);   // массив указателей на UMC
  if(pCN==NULL) { eprintf(RED_,no_mem_taskUMCM); return; }
  for(i=0; i<32; i++) pCN[i]=NULL;

  for(i=0, ptr_a=ptr_c->a_ptr; i < ptr_c->num_ap; i++, ptr_a++) {
    if(ptr_a->mod_cod==M_INP || !ptr_a->param1) continue; // не задан контр.
    k=ptr_a->param1-1;
    if(pCN[k]==NULL) {
      pCN[k] = (UMC_MOD *)calloc(1,sizeof(UMC_MOD));
      if(pCN[k]==NULL) { eprintf(RED_,no_mem_taskUMCM); return; }
      pCN[k]->yesai=pCN[k]->yesdi=pCN[k]->yesdo=pCN[k]->yesvar=0;

      pCN[k]->kolreg=0;
      memset(pCN[k]->baskreg,0,sizeof(pCN[k]->baskreg));
      pCN[k]->baskreg[0]=k+1;    // номер контроллера
      pCN[k]->baskreg[1]=0x14;   // код функции - общее чтение данных
      pCN[k]->baskreg[2]=12;     // нач. колич. следующих байт в запр. до KS

      pCN[k]->baskreg[10]=0x00;  // header = 0 - чтение
      pCN[k]->baskreg[11]=0x03;  // 03 - выборочное чтение (не сплошное)
      pCN[k]->baskreg[12]=0x00;  // колич. запраш. values(будет формироваться)

      pCN[k]->baskreg[14]=0x02;  // таблица 2 - динамические параметры
    }
    if(ptr_a->nomin_var) {         // если задана переменная или регулятор
      if(ptr_a->type_mech) {       // если регулятор
       pCN[k]->baskreg[2] += 10;  // длина запр. увелич. на 10
       pCN[k]->baskreg[12] += 5;  // кол val+=5: PV,SP,OUT,REM_mod,MAN_mod
       pCN[k]->baskreg[15+pCN[k]->kolreg*10+0]=ptr_a->nomin_var; // ном алгоб
       pCN[k]->baskreg[15+pCN[k]->kolreg*10+1]=0x09;             // инд PV
       pCN[k]->baskreg[15+pCN[k]->kolreg*10+2]=ptr_a->nomin_var; // ном алгоб
       pCN[k]->baskreg[15+pCN[k]->kolreg*10+3]=0x0a;             // инд SP
       pCN[k]->baskreg[15+pCN[k]->kolreg*10+4]=ptr_a->nomin_var; // ном алгоб
       pCN[k]->baskreg[15+pCN[k]->kolreg*10+5]=0x0b;             // инд OUT
       pCN[k]->baskreg[15+pCN[k]->kolreg*10+6]=ptr_a->nomin_var; // ном алгоб
       pCN[k]->baskreg[15+pCN[k]->kolreg*10+7]=0x03;             // инд REM
       pCN[k]->baskreg[15+pCN[k]->kolreg*10+8]=ptr_a->nomin_var; // ном алгоб
       pCN[k]->baskreg[15+pCN[k]->kolreg*10+9]=0x04;             // инд MAN
       pCN[k]->kolreg++;
      }
      else pCN[k]->yesai=1;           // если нерегулируемая переменная
    }
  }

  for(i=0, ptr_d=ptr_c->d_ptr; i < ptr_c->num_dp; i++, ptr_d++) {
    if(!ptr_d->param1) continue; // не задан контр.
    k=ptr_d->param1-1;
    if(pCN[k]==NULL) {
      pCN[k] = (UMC_MOD *)calloc(1,sizeof(UMC_MOD));
      if(pCN[k]==NULL) { eprintf(RED_,no_mem_taskUMCM); return; }
      pCN[k]->kolreg=
      pCN[k]->yesai=
      pCN[k]->yesdi=
      pCN[k]->yesdo=
      pCN[k]->yesvar= 0;
    }

    if(ptr_d->nom_var !=-1 || ptr_d->nom_vr2 !=-1 ||
       ptr_d->nom_vr3 !=-1 || ptr_d->nom_vr4 !=-1)     pCN[k]->yesdi=1;

    if(ptr_d->nom_dout > 0 ||
       ptr_d->nom_dot2 > 0 || ptr_d->nom_dot3 > 0)  pCN[k]->yesdo=1;

    else if(ptr_d->nom_dout < -1 ||
           ptr_d->nom_dot2 < -1 || ptr_d->nom_dot3 < -1)  pCN[k]->yesvar=1;
  }

  for(i=0; i<32; i++) {
    if(pCN[i]==NULL) continue;

    pCN[i]->baskai[0]=i+1; pCN[i]->baskai[1]=4;
    pCN[i]->baskai[2]=0x18; pCN[i]->baskai[3]=0x00;
    pCN[i]->baskai[4]=0x00; pCN[i]->baskai[5]=48;

    pCN[i]->baskdi[0]=i+1; pCN[i]->baskdi[1]=2;
    pCN[i]->baskdi[2]=0; pCN[i]->baskdi[3]=0;
    pCN[i]->baskdi[4]=1; pCN[i]->baskdi[5]=0;

    pCN[i]->baskdo[0]=i+1; pCN[i]->baskdo[1]=1;
    pCN[i]->baskdo[2]=0; pCN[i]->baskdo[3]=0;
    pCN[i]->baskdo[4]=1; pCN[i]->baskdo[5]=0;

    memset(pCN[i]->baskvar,0,sizeof(pCN[i]->baskvar));
    pCN[i]->baskvar[0]=i+1; pCN[i]->baskvar[1]=0x14;
    pCN[i]->baskvar[2]=0x0e; pCN[i]->baskvar[11]=2;
    pCN[i]->baskvar[12]=0x3c; pCN[i]->baskvar[14]=2;
    pCN[i]->baskvar[15]=0xfb;
  }

  begin = 1;

  while(!endrun) {
// /******************************************
    wait_flag_set(ptr_c->flag, 0L);                   ///
    clear_flag(ptr_c->flag);
// *******************************************/

//    t_delay(ptr_c->period*18);

    kz=0;
    for(i=0; i<32; i++) {              // опрос контроллеров
      if(pCN[i]==NULL) continue;

      if(pCN[i]->kolreg) {
       pCN[i]->kzreg = scanUMCM(ptr_c,pCN[i]->baskreg,15+pCN[i]->kolreg*10+2,
                                      pCN[i]->bansreg,13+pCN[i]->kolreg*20+2);
       if(pCN[i]->kzreg) kz=1;
      }

      if(pCN[i]->yesai) {
       pCN[i]->kzai = scanUMCM(ptr_c,pCN[i]->baskai,8,pCN[i]->bansai,101);
       if(pCN[i]->kzai) kz=1;
      }

      if(pCN[i]->yesdi) {
       pCN[i]->kzdi = scanUMCM(ptr_c,pCN[i]->baskdi,8,pCN[i]->bansdi,37);
       if(pCN[i]->kzdi) kz=1;
      }

      if(pCN[i]->yesdo) {
       pCN[i]->kzdo = scanUMCM(ptr_c,pCN[i]->baskdo,8,pCN[i]->bansdo,37);
       if(pCN[i]->kzdo) kz=1;
      }

      if(pCN[i]->yesvar) {
       pCN[i]->kzvar = scanUMCM(ptr_c,pCN[i]->baskvar,19,pCN[i]->bansvar,255);
       if(pCN[i]->kzdo) kz=1;
      }
    }

//    Разборка ответов  и  ПЕРВИЧНАЯ  ОБРАБОТКА  ИНФОРМАЦИИ

    offr = 13-20;        // смещение данных регуляторов в ответе

    for(i=0, ptr_a=ptr_c->a_ptr; i < ptr_c->num_ap; i++, ptr_a++) {
      if(ptr_a->mod_cod==M_INP ||
        !ptr_a->param1 || !ptr_a->nomin_var) continue; // не задан вход,рег

      k=ptr_a->param1-1;

      if(ptr_a->type_mech) {                      // если регулятор (PV)
       offr += 20;
       if(pCN[k]->kzreg) { ptr_a->novalid=1;  continue; }
       ptr_a->novalid=0;
       if(ptr_a->nolog)  continue;            // если логич. запpет обpаб.
       valf=float_intel(pCN[k]->bansreg+offr);
      }

      else {                                      // если нерегулир. перем.
       if(pCN[k]->kzai) { ptr_a->novalid=1;  continue; }
       ptr_a->novalid=0;
       if(ptr_a->nolog)  continue;            // если логич. запpет обpаб.
       valf=float_intel(pCN[k]->bansai+3+(ptr_a->nomin_var-1)*4);
      }

      if(valf > ptr_a->max_sc) { valf=ptr_a->max_sc; ptr_a->novalid=1; }
      else if(valf < ptr_a->min_sc) { valf=ptr_a->min_sc; ptr_a->novalid=1; }
      ///val=(float)ADC_SC*(valf-ptr_a->min_sc)/(ptr_a->max_sc-ptr_a->min_sc);
      val=setting(ptr_a,valf);

      if(ptr_a->var_cod == val && !begin) ptr_a->dif_var = 0;
      else {
       ptr_a->dif_var = 1;
       ptr_a->var_cod = val;
       ptr_a->var_tech = valf;        /// valtec(ptr_a,ptr_a->var_cod);
       if(ptr_a->min_reg && val < ptr_a->min_reg) ptr_a->bound_reg = 1;
       else if(ptr_a->max_reg && val > ptr_a->max_reg) ptr_a->bound_reg = 2;
       else ptr_a->bound_reg = 0;
       if(ptr_a->min_al && val < ptr_a->min_al) ptr_a->bound_al = 1;
       else if(ptr_a->max_al && val > ptr_a->max_al) ptr_a->bound_al = 2;
       else ptr_a->bound_al = 0;
      }

      if(ptr_a->type_mech) {                         // SP, OUT, REM, MAN

       if(ptr_a->set_din) ptr_a->set_din = 0;
       else {
         valf=float_intel(pCN[k]->bansreg+offr+4);         // SP
         if(valf > ptr_a->max_sc)  valf=ptr_a->max_sc;
         else if(valf < ptr_a->min_sc)  valf=ptr_a->min_sc;
         ///val=(float)ADC_SC*(valf-ptr_a->min_sc)/(ptr_a->max_sc-ptr_a->min_sc);
         val=setting(ptr_a,valf);
         if(ptr_a->set_cod == val && !begin) ptr_a->dif_set = 0;
         else {
           ptr_a->dif_set = 1;
           ptr_a->set_cod = val;
         }
       }

       if(ptr_a->out_din) ptr_a->out_din = 0;
       else {
         valf=float_intel(pCN[k]->bansreg+offr+8);         // OUT
         if(valf > 100.0)  valf=100.0;
         else if(valf < 0.0)  valf=0.0;
         val=valf*ADC_SC/100.0;
         if(ptr_a->out_cod == val && !begin) ptr_a->dif_out = 0;
         else {
           ptr_a->dif_out = 1;
           ptr_a->out_cod = val;
         }
       }

       if(ptr_a->mod_din) ptr_a->mod_din = 0;
       else {
         valf=float_intel(pCN[k]->bansreg+offr+16);                   // MAN
         if(valf==1.0) val=MAN;
         else if(float_intel(pCN[k]->bansreg+offr+12)==1.0) val=CAS;  // REM
         else val=AUTO;
         if(ptr_a->mod_cod == val && !begin) ptr_a->dif_mod = 0;
         else { ptr_a->dif_mod = 1;  ptr_a->mod_cod = val; }
       }
      }
    }

    for(i=0, ptr_d=ptr_c->d_ptr; i < ptr_c->num_dp; i++, ptr_d++) {
      if(ptr_d->nolog) continue;          // если логич. запpет обpаб.
      if(!ptr_d->param1) continue;             // не задан контроллер

      k=ptr_d->param1-1;

      if(ptr_d->nom_var !=-1) {
       if(pCN[k]->kzdi) { ptr_d->novalid=1;  continue; }
       nomv=ptr_d->nom_var-1;
       val = pCN[k]->bansdi[3+nomv/8] & (1 << (nomv%8));
       if(val) val=1;
       if(ptr_d->val_par == val) ptr_d->dif_par = 0;
       else { ptr_d->dif_par = 1;  ptr_d->val_par = val; }
#if (COUNT)
       if(ptr_d->reg_tim) {
         if(ptr_d->val_par) ptr_d->count_tim+=ptr_c->period;
         else               ptr_d->count_stop+=ptr_c->period;
       }
#endif
      }

      if(ptr_d->nom_vr2 !=-1) {
       if(pCN[k]->kzdi) { ptr_d->novalid=1;  continue; }
       nomv=ptr_d->nom_vr2-1;
       val = pCN[k]->bansdi[3+nomv/8] & (1 << (nomv%8));
       if(val) val=1;
       if(ptr_d->val_pr2 == val) ptr_d->dif_par = 0;
       else { ptr_d->dif_par = 1;  ptr_d->val_pr2 = val; }
      }

      if(ptr_d->nom_vr3 !=-1) {
       if(pCN[k]->kzdi) { ptr_d->novalid=1;  continue; }
       nomv=ptr_d->nom_vr3-1;
       val = pCN[k]->bansdi[3+nomv/8] & (1 << (nomv%8));
       if(val) val=1;
       if(ptr_d->val_pr3 == val) ptr_d->dif_par = 0;
       else { ptr_d->dif_par = 1;  ptr_d->val_pr3 = val; }
      }

      if(ptr_d->nom_vr4 !=-1) {
       if(pCN[k]->kzdi) { ptr_d->novalid=1;  continue; }
       nomv=ptr_d->nom_vr4-1;
       val = pCN[k]->bansdi[3+nomv/8] & (1 << (nomv%8));
       if(val) val=1;
       if(ptr_d->val_pr4 == val) ptr_d->dif_par = 0;
       else { ptr_d->dif_par = 1;  ptr_d->val_pr4 = val; }
      }

#if (PROTOC)
      if(ptr_d->archive) {
       if(ptr_d->dif_par) {
         val=ptr_d->val_par;
         val<<=6; val |=ptr_c->nom_ord; val<<=9; val |=i; val |=0x1000;
         c_write_wpipe(event_chn, val);
       }
       if(ptr_d->dif_pr2) {
         val=ptr_d->val_pr2;
         val<<=6; val |=ptr_c->nom_ord; val<<=9; val |=i; val |=0x2000;
         c_write_wpipe(event_chn, val);
       }
       if(ptr_d->dif_pr3) {
         val=ptr_d->val_pr3;
         val<<=6; val |=ptr_c->nom_ord; val<<=9; val |=i; val |=0x3000;
         c_write_wpipe(event_chn, val);
       }
       if(ptr_d->dif_pr4) {
         val=ptr_d->val_pr4;
         val<<=6; val |=ptr_c->nom_ord; val<<=9; val |=i; val |=0x4000;
         c_write_wpipe(event_chn, val);
       }
      }
#endif

      if(ptr_d->nom_dout !=-1) {
       if(ptr_d->nom_dout > 0) {                           // если модуль DO
         if(pCN[k]->kzdo) { ptr_d->novalid=1;  continue; }
         nomv=ptr_d->nom_dout-1;
         val = pCN[k]->bansdo[3+nomv/8] & (1 << (nomv%8));
         if(val) val=1;
       }
       else {                                              // если var
         if(pCN[k]->kzvar) { ptr_d->novalid=1;  continue; }
         nomv=-ptr_d->nom_dout-1;
         val=(word_s)float_intel(pCN[k]->bansvar+13+(nomv-1)*4);
       }
       if(ptr_d->val_out == val) ptr_d->dif_out = 0;
       else  { ptr_d->dif_out = 1;  ptr_d->val_out = val; }
      }

      if(ptr_d->nom_dot2 !=-1) {
       if(ptr_d->nom_dot2 > 0) {                           // если модуль DO
         if(pCN[k]->kzdo) { ptr_d->novalid=1;  continue; }
         nomv=ptr_d->nom_dot2-1;
         val = pCN[k]->bansdo[3+nomv/8] & (1 << (nomv%8));
         if(val) val=1;
       }
       else {                                              // если var
         if(pCN[k]->kzvar) { ptr_d->novalid=1;  continue; }
         nomv=-ptr_d->nom_dot2-1;
         val=(word_s)float_intel(pCN[k]->bansvar+13+(nomv-1)*4);
       }
       if(ptr_d->val_ot2 == val) ptr_d->dif_ot2 = 0;
       else  { ptr_d->dif_ot2 = 1;  ptr_d->val_ot2 = val; }
      }

      if(ptr_d->nom_dot3 !=-1) {
       if(ptr_d->nom_dot3 > 0) {                           // если модуль DO
         if(pCN[k]->kzdo) { ptr_d->novalid=1;  continue; }
         nomv=ptr_d->nom_dot3-1;
         val = pCN[k]->bansdo[3+nomv/8] & (1 << (nomv%8));
         if(val) val=1;
       }
       else {                                              // если var
         if(pCN[k]->kzvar) { ptr_d->novalid=1;  continue; }
         nomv=-ptr_d->nom_dot3-1;
         val=(word_s)float_intel(pCN[k]->bansvar+13+(nomv-1)*4);
       }
       if(ptr_d->val_ot3 == val) ptr_d->dif_ot3 = 0;
       else  { ptr_d->dif_ot3 = 1;  ptr_d->val_ot3 = val; }
      }

      ptr_d->novalid=0;
    }

    if(!kz) begin = 0;
  }
}
//-----------------------------------------------------------------

word_s scanUMCM(controller *ptr_c,byte *mask,word_s lask,byte *mans,word_s lans)
{
  word_s i, kz, rept;

  while(request_resource(ptr_c->port_rsc,0L));     // захват поpта-pесурса
  tsk_outp(ptr_c->basaddr+7,3);                    // on this port
  while(1) {
    while((tsk_inp(ptr_c->basaddr+6) & 0x10)) {    // пока занята сеть (CTS==1)
      tsk_outp(ptr_c->basaddr+7,0);                   // off this port
      t_delay(1L);
      tsk_outp(ptr_c->basaddr+7,3);                   // on this port
    }
    tsk_outp(ptr_c->basaddr+4,0x02);               // занять сеть (RTS:=1)
    tsk_outp(ptr_c->basaddr+7,0);                  // off this port
    t_delay(1L);
    tsk_outp(ptr_c->basaddr+7,3);                  // on this port
    if(!(tsk_inp(ptr_c->basaddr+6) & 0x10)) break; // если сеть своб.(CTS==0)
    tsk_outp(ptr_c->basaddr+4,0x00);               // иначе освоб.сеть (RTS:=0)
  }

  *(word *)(mask+lask-2)=form_ks_UMCM(mask,lask-2);
/***
if(mask[1]==1 || mask[1]==2 || mask[1]==5) {
for(i=0; i<lask; i++) printf("%02X ",mask[i]); printf("\n\n");
}
***/
  rept=1;
  BEGN:
        rept--;
        if(rept < 0) goto END;
        for(i=0; i < lans; i++) mans[i]=0x00;
        while(v24_receive(ptr_c->port,2L) != -1);
        for(i=0; i<lask; i++) v24_send(ptr_c->port,mask[i],2L);
        i=0;
        kz=v24_receive(ptr_c->port,30L);
        if(kz==-1) goto BEGN;
        mans[i]=kz;

        for(i=1; i < lans; i++) {
          kz=v24_receive(ptr_c->port,2L);
          if(kz==-1) break;
          mans[i]=kz;
        }
        if(i==lans && mans[0]==mask[0] && mans[1]==mask[1] &&
           *(word *)(mans+lans-2) == form_ks_UMCM(mans,lans-2)) kz=0;
        else if(i==5 && mans[0]==mask[0] && mans[1]==(mask[1] | 0x80) &&
           *(word *)(mans+3) == form_ks_UMCM(mans,3)) kz=mans[2];
        else goto BEGN;

        if(kz==0 && (mask[1]==0x14 || mask[1]==0x04)) // если в ответе float
          for(i=0; i<lans-6; i++)                     // проверка 7F 80 00 01
            if(mans[i]==0x7f && mans[i+1]==0x80 &&
               mans[i+2]==0x00 && mans[i+3]==0x01)  { kz=10; break; }
  END:
/***
if(mask[1]==1 || mask[1]==2 || mask[1]==5) {
for(i=0; i<lans; i++) printf("%02X ",mans[i]); printf("\n\n");
}
***/
        tsk_outp(ptr_c->basaddr+4,0x00);         // освоб.сеть (RTS:=0)
        tsk_outp(ptr_c->basaddr+7,0);            // off this port
        release_resource(ptr_c->port_rsc);       // освоб.поpта-pесуpса

        if(kz) {
          i=mask[0]; i <<= 5; i |= mask[1]; i <<=5;
          kz=i+(kz&0x1f);                        // № котр, КОП, КОШ
///printf("kz=%04x\n",kz);
        }

        ptr_c->kz=kz;
        kz_com(kz,ptr_c);
        return kz;
}
//-------------------------------------------------------------------

word_s mode_UMCM(controller *p_c, analog *p_a, word_s mode)
{
  word_s kz;
  byte bask[30];
  byte bans[16];

  memset(bask,0,sizeof(bask));
  bask[0]=p_a->param1;      // номер контроллера
  bask[1]=0x15;              // код функции - общая запись данных
  bask[2]=24;                // колич. байт в команде до KS
  bask[10]=0x80;             // header = 80 - запись
  bask[11]=0x03;             // 03 - выборочная запись (не сплошная)
  bask[12]=0x02;             // колич. записываемых values - флаги REM, MAN
  bask[14]=0x02;             // таблица 2 - динамические параметры
  bask[15]=p_a->nomin_var;   // номер алгоблока регулятора
  bask[16]=0x03;             // индекс REM
  bask[21]=p_a->nomin_var;   // номер алгоблока регулятора
  bask[22]=0x04;             // индекс MAN

  if(mode==MAN) {bask[23]=0x3f; bask[24]=0x80;}      // REM==0.0, MAN:=1.0
  if(mode==CAS) {bask[17]=0x3f; bask[18]=0x80;}      // REM:=1.0, MAN==0.0
                                                     // REM==0.0, MAN==0.0
  kz = scanUMCM(p_c,bask,29,bans,14);
  p_a->mod_din = 1;
  return kz;
}
//-------------------------------------------------------------------

word_s so_UMCM(controller *p_c, analog *p_a, word_s cur_so)
{
  word_s kz;
  byte bask[24];
  byte bans[16];

  memset(bask,0,sizeof(bask));
  bask[0]=p_a->param1;      // номер контроллера
  bask[1]=0x15;              // код функции - общая запись данных
  bask[2]=18;                // колич. байт в команде до KS
  bask[10]=0x80;             // header = 80 - запись
  bask[11]=0x03;             // 03 - выборочная запись (не сплошная)
  bask[12]=0x01;             // колич. записываемых values
  bask[14]=0x02;             // таблица 2 - динамические параметры
  bask[15]=p_a->nomin_var;   // номер алгоблока регулятора

  switch(cur_so) {
    case CUR_S : bask[16]=0x01;        // индекс LSP1
                *(float *)bans=valtec(p_a,p_a->set_cod);
                break;

    case CUR_O : bask[16]=0x05;        // индекс MAN_OUT
                *(float *)bans=100.0*p_a->out_cod/ADC_SC;
                break;
  }

  bask[17]=bans[3]; bask[18]=bans[2]; bask[19]=bans[1]; bask[20]=bans[0];

  kz = scanUMCM(p_c,bask,23,bans,14);
  return kz;
}
//-------------------------------------------------------------------

word_s read_koeff_UMCM(controller *p_c, analog *p_a, float *koeffs)
{
  word_s kz, kp;
  byte bask[28];
  byte bans[36];

  for(kp=0; kp<5; kp++) koeffs[kp]=10010.0;

  memset(bask,0,sizeof(bask));
  bask[0]=p_a->param1;      // номер контроллера
  bask[1]=0x14;              // код функции - общее чтение данных
  bask[2]=22;                // колич. байт в запросе до KS
  bask[11]=0x03;             // 03 - выборочное чтение (не сплошное)
  bask[12]=0x05;             // колич. читаемых values
  bask[14]=0x01;             // таблица 1 - статические параметры
  bask[15]=p_a->nomin_var;   // номер алгоблока регулятора
  bask[16]=0x00;             // индекс Кп
  bask[17]=p_a->nomin_var;   // номер алгоблока регулятора
  bask[18]=0x01;             // индекс Тд
  bask[19]=p_a->nomin_var;   // номер алгоблока регулятора
  bask[20]=0x02;             // индекс Ти
  bask[21]=p_a->nomin_var;   // номер алгоблока регулятора
  bask[22]=14;               // индекс Ввг
  bask[23]=p_a->nomin_var;   // номер алгоблока регулятора
  bask[24]=15;               // индекс Внг

  kz = scanUMCM(p_c,bask,27,bans,35);
  if(!kz) for(kp=0; kp<5; kp++) koeffs[kp]=float_intel(bans+13+kp*4);
  return kz;
}
/*-------------------------------------------------------------------*/

word_s set_kf_UMCM(controller *p_c, analog *p_a, word_s pos)
{
  word_s kz;
  byte bask[24];
  byte bans[16];

  memset(bask,0,sizeof(bask));
  bask[0]=p_a->param1;      // номер контроллера
  bask[1]=0x15;              // код функции - общая запись данных
  bask[2]=18;                // колич. байт в команде до KS
  bask[10]=0x80;             // header = 80 - запись
  bask[11]=0x03;             // 03 - выборочная запись (не сплошная)
  bask[12]=0x01;             // колич. записываемых values
  bask[14]=0x01;             // таблица 1 - статические параметры
  bask[15]=p_a->nomin_var;   // номер алгоблока регулятора

  switch(pos) {
    case 0:
    case 1:
    case 2: bask[16]=pos; break;
    case 3: bask[16]=14; break;
    case 4: bask[16]=15; break;
  }

  *(float *)bans=kfsUMCM[pos];
  bask[17]=bans[3]; bask[18]=bans[2]; bask[19]=bans[1]; bask[20]=bans[0];

  kz = scanUMCM(p_c,bask,23,bans,14);
  return kz;
}
/*-------------------------------------------------------------------*/

word_s switch_UMCM(controller *p_c,digit *p_d,word_s nom_do,byte val_do)
{
  word_s kz;
  byte ans[16];
  byte set[24];

  if(!p_d->param1 || !nom_do) return 0;
/*****
  if(nom_do==p_d->nom_dout && val_do==p_d->val_out ||
     nom_do==p_d->nom_dot2 && val_do==p_d->val_ot2 ||
     nom_do==p_d->nom_dot3 && val_do==p_d->val_ot3) return 0;
********/

  memset(set,0,sizeof(set));

  if(nom_do > 0) {                              // если модуль DO
    set[0]=p_d->param1;
    set[1]=5;
    set[3]=nom_do-1;
    if(val_do) set[4]=0xff;
    kz = scanUMCM(p_c,set,8,ans,8);
    if(kz) kz=scanUMCM(p_c,set,8,ans,8);

    if(!kz) if(val_do && (p_d->type_com==1 || nom_do==p_d->nom_dot3)) {
      t_delay(20L);
      set[4]=0;
      kz = scanUMCM(p_c,set,8,ans,8);
      if(kz) kz=scanUMCM(p_c,set,8,ans,8);
    }
  }

  else {                                           // если var
    set[0]=p_d->param1;      // номер контроллера
    set[1]=0x15;              // код функции - общая запись данных
    set[2]=18;                // колич. байт в команде до KS
    set[10]=0x80;             // header = 80 - запись
    set[11]=0x03;             // 03 - выборочная запись (не сплошная)
    set[12]=0x01;             // колич. записываемых values
    set[14]=0x02;             // таблица 2 - динамические параметры
    set[15]=0xfb;             // номер алгоблока регулятора
    set[16]=-nom_do-1-1;      // индекс var
    if(val_do) { set[17]=0x3f; set[18]=0x80; }    // :=1

    kz = scanUMCM(p_c,set,23,ans,14);
    if(kz) kz = scanUMCM(p_c,set,23,ans,14);

    if(!kz) if(val_do && (p_d->type_com==1 || nom_do==p_d->nom_dot3)) {
      t_delay(20L);
      set[17]=set[18]=0;

      kz = scanUMCM(p_c,set,23,ans,14);
      if(kz) kz = scanUMCM(p_c,set,23,ans,14);
    }
  }
  return kz;
}
//-------------------------------------------------------------------

word form_ks_UMCM(unsigned char *st,word_s len)
{
  word i,j,ks;

  ks=0xffff;
  for(i=0; i<len; i++) {
    ks ^= st[i];
    for(j=0; j<8; j++) {
      if(ks&1) { ks >>= 1; ks ^= 0xA001; }
      else ks >>= 1;
    }
  }
  return ks;
}
/*-------------------------------------------------------------------*/
void stat_koefUMCM(word_s nscr)
{
 word_s i;


 request_resource(ekran,0L);

 _settextcolor(CYAN_);
 gprintf(4,34,"ПАРАМЕТРЫ  РЕГУЛЯТОРА");
 for(i=0; i < 5; i++) gprintf(st_kfUMCM[i].str,st_kfUMCM[i].col-4,st_kfUMCM[i].nam);
 cur_kf[nscr] = 0;
 pos_kf[nscr] = 0;
 if(p_a[nscr]->type_sc==SC_SQRT) t_sc[nscr]='К'; else t_sc[nscr]='Л';
 _settextcolor(WHITE_);
 gprintf(5,2,"Кольцо %d, порт %3X", p_c[nscr]->nomcontr,p_c[nscr]->basaddr);
 gprintf(6,2,"Контроллер %d, %s  Алгоблок %d", p_a[nscr]->param1,"PID",p_a[nscr]->nomin_var);
 gprintf(8,2,"Шкала   %c%8.1f %8.1f",t_sc[nscr],p_a[nscr]->min_sc,p_a[nscr]->max_sc);
 gprintf(9,2,"Гpаницы Р%8.1f %8.1f", valtec(p_a[nscr],p_a[nscr]->min_reg)+0.049,valtec(p_a[nscr],p_a[nscr]->max_reg)+0.049);
 gprintf(10,2,"Гpаницы А%8.1f %8.1f", valtec(p_a[nscr],p_a[nscr]->min_al)+0.049,valtec(p_a[nscr],p_a[nscr]->max_al)+0.049);
 _setcolor(WHITE_);
 line(0,Y0-LSC-12,565,Y0-LSC-12);
 release_resource(ekran);
}
//--------------- Инициаллиизация контроллера -----------------------
void enable_UMCM(void)
{
 word_s l_chan= 512,i;
 nearptr p_chan;
 controller * ptr_c;

 for(i = 0, ptr_c = c_ptr; i < c_num; i++, ptr_c++)
 {
  if(ptr_c->period==0 || ptr_c->typcontr!=UMCM ) continue;

  p_chan=calloc(1,l_chan);
  tsk_outp(ptr_c->basaddr+7,3);                // on port
  ptr_c->nomport=v24_define_port(ptr_c->basaddr,ptr_c->IRQ_line,ptr_c->vector);
  ptr_c->port=v24_install(ptr_c->nomport,0,p_chan,l_chan,NULL,256);
  if(!ptr_c->port){ ptr_c->period=0;ptr_c->kz=-1; eprintf(RED_,"Не могу инициализ. COM%d",ptr_c->nomport);continue;}
  v24_change_baud(ptr_c->port,(long)ptr_c->baud);
  v24_change_parity(ptr_c->port, PAR_NONE);
  v24_change_wordlength(ptr_c->port, 8);
  v24_change_stopbits(ptr_c->port, 1);
  v24_receive(ptr_c->port,2L);
 }
}
//--------------- Выключение контроллера -----------------------
void disable_UMCM(void)
{
 word_s i;
 controller *ptr_c;

 for(i = 0, ptr_c = c_ptr; i < c_num; i++, ptr_c++)
 {
  if(ptr_c->typcontr==UMCM && ptr_c->period) tsk_outp(ptr_c->basaddr+7,0);
 }
}
//-------------- Выдача сообщения об ошибке опроса -------------------------
word_s kz_mesage_UMCM(controller *pc,word_s kz,word_s chn,word_s kz_old)
{
 char *ps;

 if(pc->nom_ord!=chn || kz_old!= kz)
 {
  switch(kz&0x1f)
  {
   case 0x1f : ps="Нет связи   "; break;
   case    1 : ps="ОШ. функция "; break;
   case    2 : ps="ОШ. адрес   "; break;
   case    3 : ps="ОШ. значение"; break;
   case    4 : ps="ОШ. устр-ва "; break;
   case    6 : ps="Устр.занято "; break;
   case    7 : ps="Neg acknowl."; break;
   case    9 : ps="Переп. буфер"; break;
   case   10 : ps="ОШ.программы"; break;
   default   : ps="Ош. неопред.";
  }
  fgtext(RED_,280,337,"Кольцо %d UMC%2d КОП %2d: %s", pc->nomcontr,kz>>10,(kz>>5)&0x1f,ps);
 }
 return(pc->nom_ord);
}