//---------------------------------------------------------------------------
// Функции для работы с чипами DS1991
//---------------------------------------------------------------------------
#pragma hdrstop
#include "DS1991.h"
#include "ProgressBar.h"        // для использования прогресс-бара
#include "MainProgram.h"        // для работы с формой
#include "ChipFunctions.h"      // переменные для работы с памятью чипа
#include "PortFunctions.h"      // для работы с портом
#include "CalcCRC.h"            // для расчёта CRC
#include "SendMsgFunctions.h"   // для отправки сообщений в лог
//---------------------------------------------------------------------------
#pragma package(smart_init)
//---------------------------------------------------------------------------
//--- ЗАПИСЬ В SCRATCHPAD (0x96) (только из области 4) ----------------------
//---------------------------------------------------------------------------
// output:      Success
DS1991_OUTPUT_DATA DS1991_WriteToScratchpad()
{ WRITE_BUFFER wr_buf;                  // буфер для отправки данных
  READ_BUFFER rd_buf;                   // буфер для приёма данных
  DS1991_OUTPUT_DATA OutputData;        // результат выполнения команды

  OutputData.Test=0;
  OutputData.Success=false;             // инициализируем результаты нулями

  // включаем прогресс-бар
  Application->CreateForm(__classid(TLBar),&LBar);      // создаём форму с прогресс-баром
  LBar->Show();                                         // показываем её в немодальном окне

  // посылаем Reset
  wr_buf.Size=1;
  wr_buf.Data[0]=0x60;
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(1);
  // посылаем Match ROM
  wr_buf.Size=2;
  wr_buf.Data[0]=0x61;                                  // SendByte_1W
  wr_buf.Data[1]=0x55;                                  // Match ROM
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(1);
  // посылаем 8 байт ROM-адреса
  for(unsigned int i=0; i<8; i++)                       // перебираем все слова
  { wr_buf.Size=2;
    wr_buf.Data[0]=0x61;                                // SendByte_1W
    wr_buf.Data[1]=SelectedChip.ROM[i];                 // ROM Bytes
    if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                           LBar->Free();          // уничтожаем форму с прогресс-баром
                           ClosePort();
                           return OutputData;
                         }
    Sleep(1);
  }
  // посылаем Write Scratchpad
  wr_buf.Size=2;
  wr_buf.Data[0]=0x61;                                  // SendByte_1W
  wr_buf.Data[1]=0x96;                                  // Write Scratchpad
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(10);
  // посылаем Address
  wr_buf.Size=2;
  wr_buf.Data[0]=0x61;                                  // SendByte_1W
  wr_buf.Data[1]=0xC0;                                  // стартовый адрес блокнота
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(1);
  //посылаем инверсный адрес (one's complement)
  wr_buf.Size=2;
  wr_buf.Data[0]=0x61;                                  // SendByte_1W
  wr_buf.Data[1]=0x3F;                                  // инверсный стартовый адрес блокнота
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(1);
  //*** отправляем содержимое блокнота ***
  for(unsigned int i=0; i<SelectedChip.Area4Size; i++)          // перебираем все слова, которые нужно отправить
  { wr_buf.Size=2;
    wr_buf.Data[0]=0x61;                                // SendByte_1W
    wr_buf.Data[1]=SelectedChip.Area4[i];               // байт из блокнота
    if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");        // ошибка загрузки пакета
                           LBar->Free();                // уничтожаем форму с прогресс-баром
                           ClosePort();
                           return OutputData;
                         }
    LBar->ProgressBar1->Position=100*(i+1)/SelectedChip.Area4Size;      // вычисляем новую позицию прогресс-бара
    Sleep(1);
  }
  // посылаем Reset когда всё записали
  wr_buf.Size=1;
  wr_buf.Data[0]=0x60;
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(1);
  LBar->Free();                                         // уничтожаем форму с прогресс-баром
  OutputData.Success=true;
  return OutputData;          // посылаем ответ
}
//---------------------------------------------------------------------------
//--- ЧТЕНИЕ ИЗ SCRATCHPAD (0x69) (только в Area4) --------------------------
//---------------------------------------------------------------------------
// output:      Success
DS1991_OUTPUT_DATA DS1991_ReadFromScratchpad()
{ WRITE_BUFFER wr_buf;                  // буфер для отправки данных
  READ_BUFFER rd_buf;                   // буфер для приёма данных
  DS1991_OUTPUT_DATA OutputData;        // здесь формируем ответ

  OutputData.Test=0;
  OutputData.Success=false;             // инициализируем ответ

  // включаем прогресс-бар
  Application->CreateForm(__classid(TLBar),&LBar);      // создаём форму с прогресс-баром
  LBar->Show();                                         // показываем её в немодальном окне

  // посылаем Reset
  wr_buf.Size=1;
  wr_buf.Data[0]=0x60;
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(1);
  // посылаем Match ROM
  wr_buf.Size=2;
  wr_buf.Data[0]=0x61;                                  // SendByte_1W
  wr_buf.Data[1]=0x55;                                  // Match ROM
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(1);
  // посылаем 8 байт ROM-адреса
  for(unsigned int i=0; i<8; i++)                       // перебираем все слова
  { wr_buf.Size=2;
    wr_buf.Data[0]=0x61;                                // SendByte_1W
    wr_buf.Data[1]=SelectedChip.ROM[i];                 // ROM Bytes
    if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                           LBar->Free();          // уничтожаем форму с прогресс-баром
                           ClosePort();
                           return OutputData;
                         }
    Sleep(1);
  }
  // команда чтения Scratchpad-а
  wr_buf.Size=2;
  wr_buf.Data[0]=0x61;                                  // SendByte_1W
  wr_buf.Data[1]=0x69;                                  // Read Scratchpad
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(10);
  // посылаем Address
  wr_buf.Size=2;
  wr_buf.Data[0]=0x61;                                  // SendByte_1W
  wr_buf.Data[1]=0xC0;                                  // стартовый адрес блокнота
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(1);
  //посылаем инверсный адрес (one's complement)
  wr_buf.Size=2;
  wr_buf.Data[0]=0x61;                                  // SendByte_1W
  wr_buf.Data[1]=0x3F;                                  // инверсный стартовый адрес блокнота
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(1);
  //*** читаем содержимое блокнота ***
  for(unsigned int i=0; i<SelectedChip.Area4Size; i++)  // перебираем все слова блокнота (Area4)
  { // посылаем команду чтения
    wr_buf.Size=1;
    wr_buf.Data[0]=0x62;                                // ReadByte_1W
    if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                           LBar->Free();          // уничтожаем форму с прогресс-баром
                           ClosePort();
                           return OutputData;
                         }
    Sleep(1);
    // читаем очередной байт
    rd_buf=ReadFrom();                              // читаем
    if(!rd_buf.Size) { SendMsgToLogForm(21,"");          // ошибка приёма пакета
                       LBar->Free();                    // уничтожаем форму с прогресс-баром
                       ClosePort();
                       return OutputData;
                     }
    SelectedChip.Area4[i]=rd_buf.Data[0];                               // сохраняем прочитанный байт в область блокнота
    LBar->ProgressBar1->Position=100*(i+1)/SelectedChip.Area4Size;      // вычисляем новую позицию прогресс-бара
    Sleep(1);
  }
  // посылаем команду чтения чтобы прочитать ещё один байт (Test)
  Sleep(1);
  wr_buf.Size=1;
  wr_buf.Data[0]=0x62;                                  // команда чтения байта
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(1);
  // принимаем ещё один байт (Test)
  rd_buf=ReadFrom();                                // читаем
  if(!rd_buf.Size) { SendMsgToLogForm(21,"");          // ошибка приёма пакета
                     LBar->Free();                  // уничтожаем форму с прогресс-баром
                     ClosePort();
                     return OutputData;
                   }
  OutputData.Test=rd_buf.Data[0];
  Sleep(1);
  // посылаем Reset когда всё прочитали
  wr_buf.Size=1;
  wr_buf.Data[0]=0x60;
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                         LBar->Free();                  // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(1);
  LBar->Free();                                         // уничтожаем форму с прогресс-баром
  OutputData.Success=true;
  return OutputData;
}
//---------------------------------------------------------------------------
//--- КОПИРОВАНИЕ ИЗ SCRATCHPAD В SUBKEY (0x3С) -----------------------------
//---------------------------------------------------------------------------
// input:       Input.AreaNumber - куда копируем блокнот (в область 1, 2 или 3)
// output:      Success
DS1991_OUTPUT_DATA DS1991_CopyScratchpadToMemory(DS1991_INPUT_DATA InputData)
{ WRITE_BUFFER wr_buf;                  // буфер для отправки данных
  READ_BUFFER rd_buf;                   // буфер для приёма данных
  DS1991_OUTPUT_DATA OutputData;        // здесь формируем ответ
  unsigned char SA;                     // subkey address
  unsigned char BS[8];                  // массив байт BlockSelector

  BS[0]=0x56;   BS[1]=0x56;     BS[2]=0x7F;     BS[3]=0x51;
  BS[4]=0x57;   BS[5]=0x5D;     BS[6]=0x5A;     BS[7]=0x7F;

  OutputData.Test=0;
  OutputData.Success=false;             // инициализируем ответ
  SA=(InputData.AreaNumber-1)<<6;       // вычисляем адрес области, в которую будем писать

  // включаем прогресс-бар
  Application->CreateForm(__classid(TLBar),&LBar);      // создаём форму с прогресс-баром
  LBar->Show();                                         // показываем её в немодальном окне

  // посылаем Reset
  wr_buf.Size=1;
  wr_buf.Data[0]=0x60;
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(1);
  // посылаем Match ROM
  wr_buf.Size=2;
  wr_buf.Data[0]=0x61;                                  // SendByte_1W
  wr_buf.Data[1]=0x55;                                  // Match ROM
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(1);
  // посылаем 8 байт ROM-адреса
  for(unsigned int i=0; i<8; i++)                       // перебираем все слова
  { wr_buf.Size=2;
    wr_buf.Data[0]=0x61;                                // SendByte_1W
    wr_buf.Data[1]=SelectedChip.ROM[i];                 // ROM Bytes
    if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                           LBar->Free();          // уничтожаем форму с прогресс-баром
                           ClosePort();
                           return OutputData;
                         }
    Sleep(1);
  }
  // посылаем Copy Scratchpad
  wr_buf.Size=2;
  wr_buf.Data[0]=0x61;                                  // SendByte_1W
  wr_buf.Data[1]=0x3C;                                  // Copy Scratchpad
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(1);
  // посылаем адрес области, куда нужно копировать (subkey address)
  wr_buf.Size=2;
  wr_buf.Data[0]=0x61;                                  // SendByte_1W
  wr_buf.Data[1]=SA;                                    // вычисленный ранее адрес области, куда копируем блокнот
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(1);
  // посылаем инверсный адрес области, куда копируем блокнот (one's complement)
  wr_buf.Size=2;
  wr_buf.Data[0]=0x61;                                  // SendByte_1W
  wr_buf.Data[1]=~SA;                                   // инверсный адрес области, куда копируем блокнот
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(1);
  // посылаем block selector code (8 bytes)
  for(unsigned int i=0; i<8; i++)
  { wr_buf.Size=2;
    wr_buf.Data[0]=0x61;                                  // SendByte_1W
    wr_buf.Data[1]=BS[i];
    if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                           LBar->Free();            // уничтожаем форму с прогресс-баром
                           ClosePort();
                           return OutputData;
                         }
    Sleep(1);
  }
  // передаём пароль от выбранной области (8 bytes)
  for(unsigned int i=0; i<8; i++)
  { wr_buf.Size=2;
    wr_buf.Data[0]=0x61;                                // SendByte_1W
    switch(InputData.AreaNumber)
    { case 1:  wr_buf.Data[1]=SelectedChip.Area1[i+8];  // Password Bytes
               break;
      case 2:  wr_buf.Data[1]=SelectedChip.Area2[i+8];  // Password Bytes
               break;
      case 3:  wr_buf.Data[1]=SelectedChip.Area3[i+8];  // Password Bytes
               break;
      default: wr_buf.Data[1]=0;
               break;
    }
    if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                           LBar->Free();          // уничтожаем форму с прогресс-баром
                           ClosePort();
                           return OutputData;
                         }
    LBar->ProgressBar1->Position=100*(i+1)/8;           // вычисляем новую позицию прогресс-бара
    Sleep(1);
  }
  Sleep(10);
  // посылаем Reset когда всё записали
  wr_buf.Size=1;
  wr_buf.Data[0]=0x60;
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  LBar->Free();                                         // уничтожаем форму с прогресс-баром
  OutputData.Success=true;
  return OutputData;            // посылаем ответ
}
//---------------------------------------------------------------------------
//--- ЧТЕНИЕ SUBKEY DATA ИЗ УКАЗАННОЙ ОБЛАСТИ (1, 2 или 3) (0x66) -----------
//---------------------------------------------------------------------------
// input:       Input.AreaNumber - какую область читаем (1, 2 или 3)
// output:      Success
DS1991_OUTPUT_DATA DS1991_ReadSubKey(DS1991_INPUT_DATA InputData)
{ WRITE_BUFFER wr_buf;                  // буфер для отправки данных
  READ_BUFFER rd_buf;                   // буфер для приёма данных
  DS1991_OUTPUT_DATA OutputData;        // здесь формируем ответ
  unsigned char SA;                     // subkey address
  unsigned char ID[8];                  // readed ID

  OutputData.Test=0;
  OutputData.Success=false;             // инициализируем ответ
  SA=(InputData.AreaNumber-1)<<6;       // вычисляем адрес области, из которой будем читать
  SA+=0x10;                             // данные начинаются с адреса 0x10

  // включаем прогресс-бар
  Application->CreateForm(__classid(TLBar),&LBar);      // создаём форму с прогресс-баром
  LBar->Show();                                         // показываем её в немодальном окне

  // посылаем Reset
  wr_buf.Size=1;
  wr_buf.Data[0]=0x60;
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(1);
  // посылаем Match ROM
  wr_buf.Size=2;
  wr_buf.Data[0]=0x61;                                  // SendByte_1W
  wr_buf.Data[1]=0x55;                                  // Match ROM
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(1);
  // посылаем 8 байт ROM-адреса
  for(unsigned int i=0; i<8; i++)                       // перебираем все слова
  { wr_buf.Size=2;
    wr_buf.Data[0]=0x61;                                // SendByte_1W
    wr_buf.Data[1]=SelectedChip.ROM[i];                 // ROM Bytes
    if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                           LBar->Free();          // уничтожаем форму с прогресс-баром
                           ClosePort();
                           return OutputData;
                         }
    Sleep(1);
  }
  // посылаем Read SubKey
  wr_buf.Size=2;
  wr_buf.Data[0]=0x61;                                  // SendByte_1W
  wr_buf.Data[1]=0x66;                                  // Read SubKey
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(1);
  // посылаем адрес области, из которой нужно читать данные (subkey address + data start)
  wr_buf.Size=2;
  wr_buf.Data[0]=0x61;                            // SendByte_1W
  wr_buf.Data[1]=SA;                              // вычисленный ранее адрес читаемой области
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");    // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(1);
  // посылаем инверсный адрес области, из которой нужно считать данные (one's complement)
  wr_buf.Size=2;
  wr_buf.Data[0]=0x61;                            // SendByte_1W
  wr_buf.Data[1]=~SA;                             // инверсный адрес читаемой области
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");    // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(1);
  // принимаем 8 байт идентификатора
  for(unsigned int i=0; i<8; i++)
  { // посылаем команду чтения
    wr_buf.Size=1;
    wr_buf.Data[0]=0x62;                                // ReadByte_1W
    if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                           LBar->Free();          // уничтожаем форму с прогресс-баром
                           ClosePort();
                           return OutputData;
                         }
    Sleep(1);
    // читаем очередной байт
    rd_buf=ReadFrom();                              // читаем
    if(!rd_buf.Size) { SendMsgToLogForm(21,"");          // ошибка приёма пакета
                       LBar->Free();                    // уничтожаем форму с прогресс-баром
                       ClosePort();
                       return OutputData;
                     }
    ID[i]=rd_buf.Data[0];                       // сохраняем прочитанный байт
    LBar->ProgressBar1->Position=100*(i+1)/8;           // вычисляем новую позицию прогресс-бара
    Sleep(1);
  }
  // передаём пароль от выбранной области
  for(unsigned int i=0; i<8; i++)
  { wr_buf.Size=2;
    wr_buf.Data[0]=0x61;                                // SendByte_1W
    switch(InputData.AreaNumber)
    { case 1:  wr_buf.Data[1]=SelectedChip.Area1[i+8];  // Password Bytes
               break;
      case 2:  wr_buf.Data[1]=SelectedChip.Area2[i+8];  // Password Bytes
               break;
      case 3:  wr_buf.Data[1]=SelectedChip.Area3[i+8];  // Password Bytes
               break;
      default: wr_buf.Data[1]=0;
               break;
    }
    if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                           LBar->Free();          // уничтожаем форму с прогресс-баром
                           ClosePort();
                           return OutputData;
                         }
    LBar->ProgressBar1->Position=100*(i+1)/8;           // вычисляем новую позицию прогресс-бара
    Sleep(1);
  }
  // принимаем байты данных из выбранной области (64-0x10)
  for(unsigned int i=0; i<SelectedChip.Area4Size-0x10; i++)
  { // посылаем команду чтения
    wr_buf.Size=1;
    wr_buf.Data[0]=0x62;                                // ReadByte_1W
    if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                           LBar->Free();          // уничтожаем форму с прогресс-баром
                           ClosePort();
                           return OutputData;
                         }
    Sleep(1);
    // читаем очередной байт
    rd_buf=ReadFrom();                              // читаем
    if(!rd_buf.Size) { SendMsgToLogForm(21,"");          // ошибка приёма пакета
                       LBar->Free();                    // уничтожаем форму с прогресс-баром
                       ClosePort();
                       return OutputData;
                     }
    switch(InputData.AreaNumber)
    { case 1:  SelectedChip.Area1[i+0x10]=rd_buf.Data[0];    // сохраняем прочитанный байт в область 1
               break;
      case 2:  SelectedChip.Area2[i+0x10]=rd_buf.Data[0];    // сохраняем прочитанный байт в область 2
               break;
      case 3:  SelectedChip.Area3[i+0x10]=rd_buf.Data[0];    // сохраняем прочитанный байт в область 3
               break;
      default: break;
    }
    LBar->ProgressBar1->Position=100*(i+1)/(SelectedChip.Area4Size-0x10);       // вычисляем новую позицию прогресс-бара
    Sleep(1);
  }
  // посылаем команду чтения чтобы прочитать ещё один байт (Test)
  wr_buf.Size=1;
  wr_buf.Data[0]=0x62;                                  // команда чтения байта
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(1);
  // принимаем ещё один байт (Test)
  rd_buf=ReadFrom();                                // читаем
  if(!rd_buf.Size) { SendMsgToLogForm(21,"");          // ошибка приёма пакета
                     LBar->Free();                  // уничтожаем форму с прогресс-баром
                     ClosePort();
                     return OutputData;
                   }
  OutputData.Test=rd_buf.Data[0];
  Sleep(1);
  // посылаем Reset когда всё записали
  wr_buf.Size=1;
  wr_buf.Data[0]=0x60;
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  LBar->Free();                                         // уничтожаем форму с прогресс-баром
  OutputData.Success=true;
  return OutputData;            // посылаем ответ
}
//---------------------------------------------------------------------------
//--- ЗАПИСЬ SUBKEY DATA В УКАЗАННУЮ ОБЛАСТЬ (1, 2 или 3) (0x99) ------------
//---------------------------------------------------------------------------
// input:       Input.AreaNumber - из какой области пишем (1, 2 или 3)
// output:      Success
DS1991_OUTPUT_DATA DS1991_WriteSubKey(DS1991_INPUT_DATA InputData)
{ WRITE_BUFFER wr_buf;                  // буфер для отправки данных
  READ_BUFFER rd_buf;                   // буфер для приёма данных
  DS1991_OUTPUT_DATA OutputData;        // здесь формируем ответ
  unsigned char SA;                     // subkey address
  unsigned char ID[8];                  // readed ID

  OutputData.Test=0;
  OutputData.Success=false;             // инициализируем ответ
  SA=(InputData.AreaNumber-1)<<6;       // вычисляем адрес области, в которую будем писать
  SA+=0x10;                             // данные начинаются с адреса 0x10

  // включаем прогресс-бар
  Application->CreateForm(__classid(TLBar),&LBar);      // создаём форму с прогресс-баром
  LBar->Show();                                         // показываем её в немодальном окне

  // посылаем Reset
  wr_buf.Size=1;
  wr_buf.Data[0]=0x60;
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(1);
  // посылаем Match ROM
  wr_buf.Size=2;
  wr_buf.Data[0]=0x61;                                  // SendByte_1W
  wr_buf.Data[1]=0x55;                                  // Match ROM
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(1);
  // посылаем 8 байт ROM-адреса
  for(unsigned int i=0; i<8; i++)                       // перебираем все слова
  { wr_buf.Size=2;
    wr_buf.Data[0]=0x61;                                // SendByte_1W
    wr_buf.Data[1]=SelectedChip.ROM[i];                 // ROM Bytes
    if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                           LBar->Free();          // уничтожаем форму с прогресс-баром
                           ClosePort();
                           return OutputData;
                         }
    Sleep(1);
  }
  // посылаем Write SubKey
  wr_buf.Size=2;
  wr_buf.Data[0]=0x61;                                  // SendByte_1W
  wr_buf.Data[1]=0x99;                                  // Write SubKey
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(1);
  // посылаем адрес области, в которую нужно писать данные (subkey address + data start)
  wr_buf.Size=2;
  wr_buf.Data[0]=0x61;                            // SendByte_1W
  wr_buf.Data[1]=SA;                              // вычисленный ранее адрес записываемой области
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");    // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(1);
  // посылаем инверсный адрес области, в которую нужно писать данные (one's complement)
  wr_buf.Size=2;
  wr_buf.Data[0]=0x61;                            // SendByte_1W
  wr_buf.Data[1]=~SA;                             // инверсный адрес записываемой области
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");    // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(1);
  // принимаем 8 байт идентификатора (потом можно проверить его на совпадение)
  for(unsigned int i=0; i<8; i++)
  { // посылаем команду чтения
    wr_buf.Size=1;
    wr_buf.Data[0]=0x62;                                // ReadByte_1W
    if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                           LBar->Free();          // уничтожаем форму с прогресс-баром
                           ClosePort();
                           return OutputData;
                         }
    Sleep(1);
    // читаем очередной байт
    rd_buf=ReadFrom();                              // читаем
    if(!rd_buf.Size) { SendMsgToLogForm(21,"");          // ошибка приёма пакета
                       LBar->Free();                    // уничтожаем форму с прогресс-баром
                       ClosePort();
                       return OutputData;
                     }
    ID[i]=rd_buf.Data[0];                       // сохраняем прочитанный байт
    LBar->ProgressBar1->Position=100*(i+1)/8;           // вычисляем новую позицию прогресс-бара
    Sleep(1);
  }
  // передаём пароль от выбранной области
  for(unsigned int i=0; i<8; i++)
  { wr_buf.Size=2;
    wr_buf.Data[0]=0x61;                                // SendByte_1W
    switch(InputData.AreaNumber)
    { case 1:  wr_buf.Data[1]=SelectedChip.Area1[i+8];  // Password Bytes
               break;
      case 2:  wr_buf.Data[1]=SelectedChip.Area2[i+8];  // Password Bytes
               break;
      case 3:  wr_buf.Data[1]=SelectedChip.Area3[i+8];  // Password Bytes
               break;
      default: wr_buf.Data[1]=0;
               break;
    }
    if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                           LBar->Free();          // уничтожаем форму с прогресс-баром
                           ClosePort();
                           return OutputData;
                         }
    LBar->ProgressBar1->Position=100*(i+1)/8;           // вычисляем новую позицию прогресс-бара
    Sleep(1);
  }
  // передаём байты данных из выбранной области (64-0x10)
  for(unsigned int i=0; i<SelectedChip.Area4Size-0x10; i++)
  { wr_buf.Size=2;
    wr_buf.Data[0]=0x61;                                // SendByte_1W
    switch(InputData.AreaNumber)
    { case 1:  wr_buf.Data[1]=SelectedChip.Area1[i+0x10];  // Password Bytes
               break;
      case 2:  wr_buf.Data[1]=SelectedChip.Area2[i+0x10];  // Password Bytes
               break;
      case 3:  wr_buf.Data[1]=SelectedChip.Area3[i+0x10];  // Password Bytes
               break;
      default: wr_buf.Data[1]=0;
               break;
    }
    if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                           LBar->Free();          // уничтожаем форму с прогресс-баром
                           ClosePort();
                           return OutputData;
                         }
    LBar->ProgressBar1->Position=100*(i+1)/(SelectedChip.Area4Size-0x10);       // вычисляем новую позицию прогресс-бара
    Sleep(1);
  }
  Sleep(10);
  // посылаем Reset когда всё записали
  wr_buf.Size=1;
  wr_buf.Data[0]=0x60;
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  LBar->Free();                                         // уничтожаем форму с прогресс-баром
  OutputData.Success=true;
  return OutputData;            // посылаем ответ
}
//---------------------------------------------------------------------------
//--- ЗАПИСЬ ID И PASSWORD В УКАЗАННУЮ ОБЛАСТЬ (1, 2 или 3) (0x5A) ----------
//---------------------------------------------------------------------------
// input:       Input.AreaNumber - из какой области пишем (1, 2 или 3)
// output:      Success
DS1991_OUTPUT_DATA DS1991_WritePassword(DS1991_INPUT_DATA InputData)
{ WRITE_BUFFER wr_buf;                  // буфер для отправки данных
  READ_BUFFER rd_buf;                   // буфер для приёма данных
  DS1991_OUTPUT_DATA OutputData;        // здесь формируем ответ
  unsigned char SA;                     // subkey address
  unsigned char ID[8];                  // readed ID

  OutputData.Test=0;
  OutputData.Success=false;             // инициализируем ответ
  SA=(InputData.AreaNumber-1)<<6;       // вычисляем адрес области, в которую будем писать

  // включаем прогресс-бар
  Application->CreateForm(__classid(TLBar),&LBar);      // создаём форму с прогресс-баром
  LBar->Show();                                         // показываем её в немодальном окне

  // посылаем Reset
  wr_buf.Size=1;
  wr_buf.Data[0]=0x60;
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(1);
  // посылаем Match ROM
  wr_buf.Size=2;
  wr_buf.Data[0]=0x61;                                  // SendByte_1W
  wr_buf.Data[1]=0x55;                                  // Match ROM
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(1);
  // посылаем 8 байт ROM-адреса
  for(unsigned int i=0; i<8; i++)                       // перебираем все слова
  { wr_buf.Size=2;
    wr_buf.Data[0]=0x61;                                // SendByte_1W
    wr_buf.Data[1]=SelectedChip.ROM[i];                 // ROM Bytes
    if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                           LBar->Free();          // уничтожаем форму с прогресс-баром
                           ClosePort();
                           return OutputData;
                         }
    Sleep(1);
  }
  // посылаем Write Password
  wr_buf.Size=2;
  wr_buf.Data[0]=0x61;                                  // SendByte_1W
  wr_buf.Data[1]=0x5A;                                  // Write Password
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(1);
  // посылаем адрес области, для которой нужно записать ID и Password (subkey address)
  wr_buf.Size=2;
  wr_buf.Data[0]=0x61;                            // SendByte_1W
  wr_buf.Data[1]=SA;                              // вычисленный ранее subkey адрес
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");    // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(1);
  // посылаем инверсный адрес области, для которой нужно записать ID и Password (one's complement)
  wr_buf.Size=2;
  wr_buf.Data[0]=0x61;                            // SendByte_1W
  wr_buf.Data[1]=~SA;                             // инверсный subkey адрес
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");    // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  Sleep(1);
  // принимаем 8 байт идентификатора
  for(unsigned int i=0; i<8; i++)
  { // посылаем команду чтения
    wr_buf.Size=1;
    wr_buf.Data[0]=0x62;                                // ReadByte_1W
    if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                           LBar->Free();          // уничтожаем форму с прогресс-баром
                           ClosePort();
                           return OutputData;
                         }
    Sleep(1);
    // читаем очередной байт
    rd_buf=ReadFrom();                              // читаем
    if(!rd_buf.Size) { SendMsgToLogForm(21,"");          // ошибка приёма пакета
                       LBar->Free();                    // уничтожаем форму с прогресс-баром
                       ClosePort();
                       return OutputData;
                     }
    ID[i]=rd_buf.Data[0];                       // сохраняем прочитанный байт
    LBar->ProgressBar1->Position=100*(i+1)/8;           // вычисляем новую позицию прогресс-бара
    Sleep(1);
  }
  // передаём принятый идентификатор обратно
  for(unsigned int i=0; i<8; i++)
  { wr_buf.Size=2;
    wr_buf.Data[0]=0x61;                                // SendByte_1W
    wr_buf.Data[1]=ID[i];                               // Password Bytes
    if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                           LBar->Free();          // уничтожаем форму с прогресс-баром
                           ClosePort();
                           return OutputData;
                         }
    LBar->ProgressBar1->Position=100*(i+1)/8;           // вычисляем новую позицию прогресс-бара
    Sleep(1);
  }
  Sleep(10);
  // передаём байты нового идентификатора
  for(unsigned int i=0; i<8; i++)
  { wr_buf.Size=2;
    wr_buf.Data[0]=0x61;                                // SendByte_1W
    switch(InputData.AreaNumber)
    { case 1:  wr_buf.Data[1]=SelectedChip.Area1[i];    // new ID Bytes
               break;
      case 2:  wr_buf.Data[1]=SelectedChip.Area2[i];    // new ID Bytes
               break;
      case 3:  wr_buf.Data[1]=SelectedChip.Area3[i];    // new ID Bytes
               break;
      default: wr_buf.Data[1]=0;
               break;
    }
    if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                           LBar->Free();          // уничтожаем форму с прогресс-баром
                           ClosePort();
                           return OutputData;
                         }
    LBar->ProgressBar1->Position=100*(i+1)/8;           // вычисляем новую позицию прогресс-бара
    Sleep(1);
  }
  // передаём байты нового пароля
  for(unsigned int i=0; i<8; i++)
  { wr_buf.Size=2;
    wr_buf.Data[0]=0x61;                                // SendByte_1W
    switch(InputData.AreaNumber)
    { case 1:  wr_buf.Data[1]=SelectedChip.Area1[i+8];  // new Password Bytes
               break;
      case 2:  wr_buf.Data[1]=SelectedChip.Area2[i+8];  // new Password Bytes
               break;
      case 3:  wr_buf.Data[1]=SelectedChip.Area3[i+8];  // new Password Bytes
               break;
      default: wr_buf.Data[1]=0;
               break;
    }
    if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                           LBar->Free();          // уничтожаем форму с прогресс-баром
                           ClosePort();
                           return OutputData;
                         }
    LBar->ProgressBar1->Position=100*(i+1)/8;           // вычисляем новую позицию прогресс-бара
    Sleep(1);
  }
  Sleep(10);
  // посылаем Reset когда всё записали
  wr_buf.Size=1;
  wr_buf.Data[0]=0x60;
  if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");          // ошибка загрузки пакета
                         LBar->Free();            // уничтожаем форму с прогресс-баром
                         ClosePort();
                         return OutputData;
                       }
  LBar->Free();                                         // уничтожаем форму с прогресс-баром
  OutputData.Success=true;
  return OutputData;            // посылаем ответ
}
//---------------------------------------------------------------------------
 