//---------------------------------------------------------------------------
#pragma hdrstop

#include "AT90S2333.h"          // переменные для работы с AT90S2333 / AT90S4433
#include "AVRFunctions.h"       // переменные для функций работы с чипами AVR
#include "PortFunctions.h"      // переменные для функций работы с портом
#include "LogFunctions.h"       // переменные для отправки сообщений в лог
#include "ChipFunctions.h"      // переменные для работы с чипом
#include "Main.h"               // переменные для работы с главной формой
//---------------------------------------------------------------------------
#pragma package(smart_init)
//---------------------------------------------------------------------------
//--- ПЕРЕВОД ЧИПА В РЕЖИМ ПРОГРАММИРОВАНИЯ КОМАНДОЙ PROGRAMMING ENABLE -----
//---------------------------------------------------------------------------
bool AT90S2333_ProgrammingEnable()
{ WRITE_BUFFER wr_buf;          // буфер для отправки данных
  READ_BUFFER rd_buf;           // буфер для приёма данных

  SendMsgToLog(18," enter Programming Mode");    // сообщаем о попытке перейти в режим параллельного программирования
  //--- устанавливаем направления работы линий и начальные уровни на них ---
  //--- линию RDY настраиваем на вход и отключаем подтягивающий резистор
  //--- линиии управления питанием пока тоже оставляем входами (их переключит команда, выполняющая алгоритм перехода)
  //--- все остальные линии настраиваем как выходы

  //--- настраиваем порт B
  wr_buf.Size=4;
  wr_buf.Data[0]=0x0B;                                    // DDRBSetup
  wr_buf.Data[1]=0x0;                                     // все линии на вход
  wr_buf.Data[2]=0x0D;                                    // PORTBSetup
  wr_buf.Data[3]=0x0;                                     // на всех линиях нули
  if(!WriteTo(wr_buf)) { SendMsgToLog(6," 0x0B 0x0 0x0D 0x0");        // ошибка отправки команды
                         CloseHandle(Port);
                         Port=INVALID_HANDLE_VALUE;
                         return false;
                       }
  //--- настраиваем порт C (Pagel (PC5) - не использутся, XA1(PC4) - не используется, BS1 (PC1) - используется в качестве BS)
  //--- неиспользуемые в данном чипе линии всё равно переключаем на выход (для универсальности)
  wr_buf.Size=4;
  wr_buf.Data[0]=0x0F;                                    // DDRCSetup
  wr_buf.Data[1]=0x32;  // 0011 0010                      // все используемые линии на выход, кроме RDY и управления питанием
  wr_buf.Data[2]=0x11;                                    // PORTCSetup
  wr_buf.Data[3]=0x0;                                     // на всех линиях нули (подтягивающие резисторы выключены)
  if(!WriteTo(wr_buf)) { SendMsgToLog(6," 0x0F 0x32 0x11 0x0");         // ошибка отправки команды
                         CloseHandle(Port);
                         Port=INVALID_HANDLE_VALUE;
                         return false;
                       }
  //--- настраиваем порт D (нули на всех линиях группы Prog_enable)
  //--- о сигнале PG можно не беспокоиться, он защищён маской и обычными командами не меняется
  wr_buf.Size=4;
  wr_buf.Data[0]=0x13;                                    // DDRDSetup
  wr_buf.Data[1]=0xFC;  // 1111 1100                      // все используемые линии на выход
  wr_buf.Data[2]=0x15;                                    // PORTDSetup
  wr_buf.Data[3]=0x0;                                     // на всех линиях нули (перед подачей питания нули нужны даже на WR, OE)
  if(!WriteTo(wr_buf)) { SendMsgToLog(6," 0x13 0xFC 0x15 0x0");         // ошибка отправки команды
                         CloseHandle(Port);
                         Port=INVALID_HANDLE_VALUE;
                         return false;
                       }
  Sleep(1);
  Sleep(Delays);//////////
  //--- выполняем алгоритм перехода в режим высоковольтного параллельного программирования для AVR ---
  wr_buf.Size=2;
  wr_buf.Data[0]=0x1D;                                    // выполнить расширенную команду
  wr_buf.Data[1]=0x0;                                     // команда Enter_HVP_ProgMode_AVR
  if(!WriteTo(wr_buf)) { SendMsgToLog(6," 0x1D 0x0");     // ошибка отправки команды
                         CloseHandle(Port);
                         Port=INVALID_HANDLE_VALUE;
                         return false;
                       }
  Sleep(1);
  Sleep(Delays);//////////
  //--- донастраиваем порт D - выставляем единицы на линиях WR, OE (выше мы уже настроили их на выход)
  wr_buf.Size=2;
  wr_buf.Data[0]=0x15;                                    // PORTDSetup
  wr_buf.Data[1]=PD_WORK;       // 0001 0100              // переключаем WR, OE в 1
  if(!WriteTo(wr_buf)) { SendMsgToLog(6," 0x15 0x14(PD_WORK)"); // ошибка отправки команды
                         CloseHandle(Port);
                         Port=INVALID_HANDLE_VALUE;
                         return false;
                       }
  SendMsgToLog(19," with success.");                    // сообщаем, что команда выполнена успешно
  return true;
}
//---------------------------------------------------------------------------
//--- СТИРАНИЕ ЧИПА КОМАНДОЙ CHIP ERASE -------------------------------------
//---------------------------------------------------------------------------
bool AT90S2333_ChipErase()
{ WRITE_BUFFER wr_buf;          // буфер для отправки данных
  READ_BUFFER rd_buf;           // буфер для приёма данных

  SendMsgToLog(18," erase the chip");    // сообщаем о попытке стереть чип
  if(!PhaseA(0x80))        return 0;                            // Load Command 0x80 - Chip Erase
  wr_buf.Size=2;
  wr_buf.Data[0]=0x1D;                                          // Do_Extended_Command
  wr_buf.Data[1]=0x08;                                          // GiveWR100NegPulse
  if(!WriteTo(wr_buf)) { SendMsgToLog(6," GiveWR100NegPulse");  // ошибка отправки команды
                         CloseHandle(Port);
                         Port=INVALID_HANDLE_VALUE;
                         return 0;
                       }
  Sleep(Delays);//////////
  // на линии RDY не генерируется какой-либо активности
  //--- сообщаем, что всё готово ---
  SendMsgToLog(19," with success.");            // чтение выполнено успешно
  return true;
}
//---------------------------------------------------------------------------
///////////////////////////////
// РАБОТА С ПАМЯТЬЮ ПРОГРАММ //
///////////////////////////////
//---------------------------------------------------------------------------
//--- ЧТЕНИЕ СЛОВА ПРОГРАММЫ ПО УКАЗАННОМУ АДРЕСУ ---------------------------
//---------------------------------------------------------------------------
bool AT90S2333_ReadProgramMemory(unsigned int Address, bool Action)
{ WRITE_BUFFER wr_buf;          // буфер для отправки данных
  READ_BUFFER rd_buf;           // буфер для приёма данных
  unsigned char a, b;    // младший и старший байты адреса слова

  // получаем адрес слова из адреса его младшего байта
  b = Address>>1;       // младший байт адреса слова
  a = Address>>9;       // старший байт адреса слова
  if(Address == 0)      // команда загружается один раз, в начале записи
  {     if(!PhaseA(0x02))       return 0;       // Load Command 0x02 - Read Flash
  }
  if(!PhaseC(a))        return 0;               // Load Address High Byte
  if(!PhaseB(b))        return 0;               // Load Address Low Byte

  //--- set DDRB to input and OE to 0 to read a flash word low byte (BS1 is already 0 after PhaseB)
  wr_buf.Size=5;
  wr_buf.Data[0]=0x0B;                                  // DDRBSetup
  wr_buf.Data[1]=0x0;                   // 0000 0000    // все линии на вход
  wr_buf.Data[2]=0x15;                                  // PORTDSetup
  wr_buf.Data[3]=PD_WORK & ~(1<<OE);    // 0001 0000    // сбрасываем OE
  wr_buf.Data[4]=0x17;                                  // PINBRead
  if(!WriteTo(wr_buf)) { SendMsgToLog(6," read flash word low byte");   // ошибка отправки команды
                         CloseHandle(Port);
                         Port=INVALID_HANDLE_VALUE;
                         return 0;
                       }
  //--- принимаем байт, содержащий PINB
  rd_buf=ReadFrom(1);                                   // читаем
  if(!rd_buf.Size) { SendMsgToLog(7," (PINB)");         // ошибка приёма пакета
                     CloseHandle(Port);
                     Port=INVALID_HANDLE_VALUE;
                     return 0;
                   }
  //--- сохраняем прочитанный байт в нужную область программы или сверяем с байтом в памяти ---
  if(!Action)   // если мы читаем байт
  {     SelectedChip.Area1[Address] = rd_buf.Data[0];
  }
  else          // если мы проверяем байт
  {     if(SelectedChip.Area1[Address] != rd_buf.Data[0])       // если байт не совпадает с тем, что в памяти
        {       return 0;               // запоминаем ошибку, если она произошла
        }
  }
  //--- set BS1 to 1 to read a flash word high byte, read byte, set OE
  wr_buf.Size=5;
  wr_buf.Data[0]=0x11;                                    // PORTCSetup
  wr_buf.Data[1]=PC_WORK | (1 << BS1);  // 0000 1010      // поднимаем BS1
  wr_buf.Data[2]=0x17;                                    // PINBRead
  wr_buf.Data[3]=0x15;                                    // PORTDSetup
  wr_buf.Data[4]=PD_WORK;               // 0001 0000      // поднимаем OE
  if(!WriteTo(wr_buf)) { SendMsgToLog(6," read flash word high byte");  // ошибка отправки команды
                         CloseHandle(Port);
                         Port=INVALID_HANDLE_VALUE;
                         return 0;
                       }
  //--- принимаем байт, содержащий PINB
  rd_buf=ReadFrom(1);                                   // читаем
  if(!rd_buf.Size) { SendMsgToLog(7," (PINB)");    // ошибка приёма пакета
                     CloseHandle(Port);
                     Port=INVALID_HANDLE_VALUE;
                     return 0;
                   }
  //--- сохраняем прочитанный байт в нужную область программы или сверяем с байтом в памяти ---
  if(!Action)   // если мы читаем байт
  {     SelectedChip.Area1[Address+1] = rd_buf.Data[0];
  }
  else          // если мы проверяем байт
  {     if(SelectedChip.Area1[Address+1] != rd_buf.Data[0])     // если байт не совпадает с тем, что в памяти
        {       return 0;       // запоминаем ошибку, если она произошла
        }
  }
  return true;
}
//---------------------------------------------------------------------------
//--- ЗАПИСЬ СЛОВА ПРОГРАММЫ ПО УКАЗАННОМУ АДРЕСУ ---------------------------
//---------------------------------------------------------------------------
bool AT90S2333_WriteProgramMemory(unsigned int Address)
{ WRITE_BUFFER wr_buf;          // буфер для отправки данных
  READ_BUFFER rd_buf;           // буфер для приёма данных
  unsigned char a, b;    // младший и старший байты адреса слова

  a = Address>>9; // старший байт адреса слова
  b = Address>>1; // младший байт адреса слова
  if(Address == 0)      // команда загружается один раз, в начале записи
  {     if(!PhaseA(0x10))       return 0;       // Load Command 0x10 - Write Flash
  }
  if(b==0)      // старший байт адреса загружается только при переходе на новую страницу
  {     if(!PhaseC(a))        return 0;         // Load Address High Byte
  }
  if(!PhaseB(b))                                return 0;       // Load Address Low Byte
  if(!PhaseD(SelectedChip.Area1[Address]))      return 0;       // Load Data Low Byte
  //--- PHASE X (Write Data Low Byte) START ---
  //--- set BS=0 (already done), Give WR a negative pulse ---
  wr_buf.Size=2;
  wr_buf.Data[0]=0x1D;                                  // Do_Extended_Command
  wr_buf.Data[1]=0x03;                                  // GiveWRNegPulse
  if(!WriteTo(wr_buf)) { SendMsgToLog(6," 0x1D 0x03");  // ошибка отправки команды
                         CloseHandle(Port);
                         Port=INVALID_HANDLE_VALUE;
                         return 0;
                       }
  Sleep(Delays);//////////
  // нужно дождаться RDY = high
  if(!WaitRDYHigh)      return 0;       // если не дождались - выходим с ошибкой
  //--- PHASE X (Write Data Low Byte) END ---

  if(!PhaseE(SelectedChip.Area1[Address+1]))    return 0;       // Load Data High Byte
  //--- PHASE X (Write Data High Byte) START ---
  //--- set BS=1 (already done), Give WR a negative pulse ---
  wr_buf.Size=2;
  wr_buf.Data[0]=0x1D;                                  // Do_Extended_Command
  wr_buf.Data[1]=0x03;                                  // GiveWRNegPulse
  if(!WriteTo(wr_buf)) { SendMsgToLog(6," GiveWRNegPulse");     // ошибка отправки команды
                         CloseHandle(Port);
                         Port=INVALID_HANDLE_VALUE;
                         return 0;
                       }
  Sleep(Delays);//////////
  // нужно дождаться RDY = high
  if(!WaitRDYHigh)      return 0;       // если не дождались - выходим с ошибкой
  //--- PHASE X (Write Data High Byte) END ---
  return true;
}
//---------------------------------------------------------------------------
/////////////////////////////
// РАБОТА С ПАМЯТЬЮ EEPROM //
/////////////////////////////
//---------------------------------------------------------------------------
//--- ЧТЕНИЕ БАЙТА ИЗ EEPROM ПО УКАЗАННОМУ АДРЕСУ ---------------------------
//---------------------------------------------------------------------------
bool AT90S2333_ReadEEPROMMemory(unsigned int Address, bool Action)
{ WRITE_BUFFER wr_buf;          // буфер для отправки данных
  READ_BUFFER rd_buf;           // буфер для приёма данных
  unsigned char b;      // байт адреса слова

  // получаем адрес слова из адреса его младшего байта
  b = Address;          // младший байт адреса байта
  if(Address == 0)
  {     if(!PhaseA(0x03))        return 0;       // Load Command 0x03 - Read EEPROM
  }
  if(!PhaseB(b))        return 0;       // Load Address Low Byte
  //--- set DDRB to input and OE to 0 to read a EEPROM byte (BS1 is already 0)
  wr_buf.Size=7;
  wr_buf.Data[0]=0x0B;                                  // DDRBSetup
  wr_buf.Data[1]=0x0;   // 0000 0000                    // все линии на вход
  wr_buf.Data[2]=0x15;                                    // PORTDSetup
  wr_buf.Data[3]=PD_WORK & ~(1<<OE);      // 0001 0000    // сбрасываем OE
  wr_buf.Data[4]=0x17;                                    // PINBRead
  wr_buf.Data[5]=0x15;                                    // PORTDSetup
  wr_buf.Data[6]=PD_WORK;               // 0001 0100      // поднимаем OE
  if(!WriteTo(wr_buf)) { SendMsgToLog(6," read EEPROM byte");       // ошибка отправки команды
                         CloseHandle(Port);
                         Port=INVALID_HANDLE_VALUE;
                         return 0;
                       }
  //--- принимаем байт, содержащий PINB
  rd_buf=ReadFrom(1);                                   // читаем
  if(!rd_buf.Size) { SendMsgToLog(7," (PINB)");    // ошибка приёма пакета
                     CloseHandle(Port);
                     Port=INVALID_HANDLE_VALUE;
                     return 0;
                   }
  //--- сохраняем прочитанный байт в нужную область данных  или сверяем с байтом в памяти ---
  if(!Action)   // если мы читаем байт
  {     SelectedChip.Area2[Address] = rd_buf.Data[0];
  }
  else          // если мы проверяем байт
  {     if(SelectedChip.Area2[Address] != rd_buf.Data[0])       // если байт не совпадает с тем, что в памяти
        {       return false;           // выходим с ошибкой
        }
  }
  return true;
}
//---------------------------------------------------------------------------
//--- ЗАПИСЬ БАЙТА В ПАМЯТЬ EEPROM ПО УКАЗАННОМУ АДРЕСУ ---------------------
//---------------------------------------------------------------------------
bool AT90S2333_WriteEEPROMMemory(unsigned int Address)
{ WRITE_BUFFER wr_buf;          // буфер для отправки данных
  READ_BUFFER rd_buf;           // буфер для приёма данных
  unsigned char b;      // байт адреса

  b = Address;          // младший байт адреса
  if(Address == 0)
  {     if(!PhaseA(0x11))                       return 0;       // Load Command 0x11 - Write EEPROM
  }
  if(!PhaseB(b))                                return 0;       // Load Address Low Byte
  if(!PhaseD(SelectedChip.Area2[Address]))      return 0;       // Load Data Low Byte
  //--- PHASE X (Write Data Low Byte) START ---
  //--- set BS=0 (already done), Give WR a negative pulse ---
  wr_buf.Size=2;
  wr_buf.Data[0]=0x1D;                                          // Do_Extended_Command
  wr_buf.Data[1]=0x03;                                          // GiveWRNegPulse
  if(!WriteTo(wr_buf)) { SendMsgToLog(6," GiveWRNegPulse");     // ошибка отправки команды
                         CloseHandle(Port);
                         Port=INVALID_HANDLE_VALUE;
                         return 0;
                       }
  Sleep(Delays);//////////
  // нужно дождаться RDY = high
  if(!WaitRDYHigh)        return 0;       // если не дождались - выходим с ошибкой
  //--- PHASE X (Write Data Low Byte) END ---
  return true;
}
//---------------------------------------------------------------------------
/////////////////////
// FUSES, LOCK ... //
/////////////////////
//---------------------------------------------------------------------------
//--- ЧТЕНИЕ FUSE- & LOCK-БИТОВ ---------------------------------------------
//---------------------------------------------------------------------------
bool AT90S2333_ReadFuseLockBits()
{ WRITE_BUFFER wr_buf;          // буфер для отправки данных
  READ_BUFFER rd_buf;           // буфер для приёма данных

  SendMsgToLog(18," read fuse- and lock-bits");    // сообщаем о попытке прочитать Lock-биты
  if(!PhaseA(0x04))                       return 0;     // Load Command 0x04 - Read Fuse & Lock
  //--- set DDRB to input and OE to 0 to read fuse byte (BS1 is already 0)
  wr_buf.Size=5;
  wr_buf.Data[0]=0x0B;                                    // DDRBSetup
  wr_buf.Data[1]=0x0;   // 0000 0000                      // все линии на вход
  wr_buf.Data[2]=0x15;                                    // PORTDSetup
  wr_buf.Data[3]=PD_WORK & ~(1<<OE);    // 0001 0000      // сбрасываем OE
  wr_buf.Data[4]=0x17;                                    // PINBRead
  if(!WriteTo(wr_buf)) { SendMsgToLog(6," read Fuse byte");     // ошибка отправки команды
                         CloseHandle(Port);
                         Port=INVALID_HANDLE_VALUE;
                         return 0;
                       }
  //--- принимаем байт, содержащий PINB
  rd_buf=ReadFrom(1);                                   // читаем
  if(!rd_buf.Size) { SendMsgToLog(7," (PINB)");    // ошибка приёма пакета
                     CloseHandle(Port);
                     Port=INVALID_HANDLE_VALUE;
                     return 0;
                   }
  //--- сохраняем прочитанный байт в нужную область фьюзов ---
  SelectedChip.Area3[0] = rd_buf.Data[0] | 0xC0;      // сохраняем фьюзы

  //--- set BS1=1 to read Lock byte, set OE to 1
  wr_buf.Size=5;
  wr_buf.Data[0]=0x11;                                          // PORTCSetup
  wr_buf.Data[1]=PC_WORK | (1 << BS1);  // 0000 1010            // сбрасываем XA1, поднимаем BS1
  wr_buf.Data[2]=0x17;                                          // PINBRead
  wr_buf.Data[3]=0x15;                                          // PORTDSetup
  wr_buf.Data[4]=PD_WORK;               // 0001 0100            // поднимаем OE
  if(!WriteTo(wr_buf)) { SendMsgToLog(6," read Lock byte");     // ошибка отправки команды
                         CloseHandle(Port);
                         Port=INVALID_HANDLE_VALUE;
                         return 0;
                       }
  //--- принимаем байт, содержащий PINB
  rd_buf=ReadFrom(1);                                   // читаем
  if(!rd_buf.Size) { SendMsgToLog(7," (PINB)");    // ошибка приёма пакета
                     CloseHandle(Port);
                     Port=INVALID_HANDLE_VALUE;
                     return 0;
                   }
  //--- сохраняем прочитанный байт в нужную область фьюзов ---
  SelectedChip.Area3[1] = rd_buf.Data[0] | 0xF9;      // сохраняем фьюзы

  SendMsgToLog(19," with success.");            // чтение выполнено успешно
  return true;
}
//---------------------------------------------------------------------------
//--- ЗАПИСЬ LOCK-БИТОВ -----------------------------------------------------
//---------------------------------------------------------------------------
bool AT90S2333_WriteLockBits()
{ WRITE_BUFFER wr_buf;          // буфер для отправки данных
  READ_BUFFER rd_buf;           // буфер для приёма данных

  SendMsgToLog(18," write lock-bits");    // сообщаем о попытке записать Lock-биты
  if(!PhaseA(0x20))                       return 0;     // Load Command 0x20 - Write Lock
  if(!PhaseD(SelectedChip.Area3[1]))      return 0;     // Load Data Low Byte = Lock Bits
  //--- выдаём импульс на линии WR ---
  wr_buf.Size=2;
  wr_buf.Data[0]=0x1D;                                          // Do_Extended_Command
  wr_buf.Data[1]=0x03;                                          // GiveWRNegPulse
  if(!WriteTo(wr_buf)) { SendMsgToLog(6," GiveWRNegPulse");     // ошибка отправки команды
                         CloseHandle(Port);
                         Port=INVALID_HANDLE_VALUE;
                         return 0;
                       }
  Sleep(Delays);//////////
  // нужно дождаться RDY = high
  if(!WaitRDYHigh)        return 0;             // если не дождались - выходим с ошибкой
  SendMsgToLog(19," with success.");            // запись выполнена успешно
  return true;
}
//---------------------------------------------------------------------------
//--- ЗАПИСЬ FUSE-БИТОВ (FUSE BYTE) -----------------------------------------
//---------------------------------------------------------------------------
bool AT90S2333_WriteFuseBits()
{ WRITE_BUFFER wr_buf;          // буфер для отправки данных
  READ_BUFFER rd_buf;           // буфер для приёма данных

  if(!PhaseA(0x40))                       return 0;     // Load Command 0x40 - Write Fuse
  if(!PhaseD(SelectedChip.Area3[0]))      return 0;     // Load Data Low Byte = Fuse Low
  //--- выдаём импульс 1,5 ms на линии WR ---
  wr_buf.Size=2;
  wr_buf.Data[0]=0x1D;                                          // Do_Extended_Command
  wr_buf.Data[1]=0x09;                                          // GiveWR15NegPulse
  if(!WriteTo(wr_buf)) { SendMsgToLog(6," GiveWR15NegPulse");   // ошибка отправки команды
                         CloseHandle(Port);
                         Port=INVALID_HANDLE_VALUE;
                         return 0;
                       }
  Sleep(Delays);//////////
  // не генерирует активности на RDY
  SendMsgToLog(19," with success.");            // запись выполнена успешно
  return true;
}
//---------------------------------------------------------------------------
//--- ЧТЕНИЕ БАЙТОВ СИГНАТУРЫ -----------------------------------------------
//---------------------------------------------------------------------------
unsigned int AT90S2333_ReadSignatureBytes()
{ WRITE_BUFFER wr_buf;          // буфер для отправки данных
  READ_BUFFER rd_buf;           // буфер для приёма данных
  unsigned int ChipID, Temp;    // ответ функции

  SendMsgToLog(18," read signature bytes");     // сообщаем о попытке прочитать байты сигнатуры
  ChipID = 0;                                   // обнуляем ответ
  //--- вычитываем последовательно 3 байта сигнатуры ---
  if(!PhaseA(0x08))                       return 0;     // Load Command 0x08 - Read Signature Bytes
  for(unsigned char i=0;i<3;i++)
  {     //--- команду повторять не обязательно, нужен только новый адрес
       if(!PhaseB(i))                    return 0;     // Load Address Low
        //--- READ DATA FROM THE CHIP ---
        //--- перенастраиваем линии порта B на вход, включаем OE, BS1=0, читаем состояние порта B, выключаем OE
        wr_buf.Size=7;
        wr_buf.Data[0]=0x0B;                                            // DDRBSetup
        wr_buf.Data[1]=0x0;                                             // все линии на вход
        wr_buf.Data[2]=0x15;                                            // PORTDSetup
        wr_buf.Data[3]=PD_WORK & ~(1<<OE);      // 0001 0000            // сбрасываем OE (BS1 is already 0 after PhaseB)
        wr_buf.Data[4]=0x17;                                            // PINBRead
        wr_buf.Data[5]=0x15;                                            // PORTDSetup
        wr_buf.Data[6]=PD_WORK;                 // 0001 0100            // поднимаем OE
        if(!WriteTo(wr_buf)) { SendMsgToLog(6," read Signature Byte");  // ошибка отправки команды
                               CloseHandle(Port);
                               Port=INVALID_HANDLE_VALUE;
                               return 0;
                             }
        // принимаем байт, содержащий PINB
        rd_buf=ReadFrom(1);                                   // читаем
        if(!rd_buf.Size) { SendMsgToLog(7," (PINB)");    // ошибка приёма пакета
                           CloseHandle(Port);
                           Port=INVALID_HANDLE_VALUE;
                           return 0;
                         }
        //--- вычисляем ID чипа
        Temp = rd_buf.Data[0];
        ChipID += (Temp << (8*i));
  }
  SendMsgToLog(19,"");            // чтение байтов сигнатуры завершено
  return ChipID;
}
//---------------------------------------------------------------------------

