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

#include "ATtiny2313.h"         // переменные для функций работы с чипами ATtiny2313
#include "AVRFunctions.h"       // переменные для функций работы с чипами AVR
#include "PortFunctions.h"      // переменные для функций работы с портом
#include "LogFunctions.h"       // переменные для отправки сообщений в лог
#include "ChipFunctions.h"      // переменные для работы с чипом
#include "Main.h"               // переменные для работы с главной формой
//---------------------------------------------------------------------------
#pragma package(smart_init)
//---------------------------------------------------------------------------
//--- ПЕРЕВОД ЧИПА В РЕЖИМ ПРОГРАММИРОВАНИЯ КОМАНДОЙ PROGRAMMING ENABLE -----
//---------------------------------------------------------------------------
bool ATtiny2313_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," set DDRB=0, PORTB=0");        // ошибка отправки команды
                         CloseHandle(Port);
                         Port=INVALID_HANDLE_VALUE;
                         return false;
                       }
  //--- настраиваем порт C
  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," set DDRC=0x32, PORTC=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," set DDRD=0xFC, PORTD=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," EnterHVPProgMode_AVR");       // ошибка отправки команды
                         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," set WR=1, OE=1");     // ошибка отправки команды
                         CloseHandle(Port);
                         Port=INVALID_HANDLE_VALUE;
                         return false;
                       }
  SendMsgToLog(19," with success.");                    // сообщаем, что команда выполнена успешно
  return true;
}
//---------------------------------------------------------------------------
//--- СТИРАНИЕ ЧИПА КОМАНДОЙ CHIP ERASE -------------------------------------
//---------------------------------------------------------------------------
bool ATtiny2313_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]=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;
}
//---------------------------------------------------------------------------
///////////////////////////////
// РАБОТА С ПАМЯТЬЮ ПРОГРАММ //
///////////////////////////////
//---------------------------------------------------------------------------
//--- ЧТЕНИЕ СЛОВА ПРОГРАММЫ ПО УКАЗАННОМУ АДРЕСУ ---------------------------
//--- на вход подаётся адрес младшего байта этого слова ---------------------
//---------------------------------------------------------------------------
bool ATtiny2313_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 Phase B)
  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 ATtiny2313_LoadProgramMemoryPage(unsigned int Address)
{ WRITE_BUFFER wr_buf;          // буфер для отправки данных
  READ_BUFFER rd_buf;           // буфер для приёма данных
  unsigned char b;      // байты адреса слова на странице

  //if( (SelectedChip.Area1[Address]==0xFF) && (SelectedChip.Area1[Address+1]==0xFF) )
  //{     return true;    // если оба байта 0xFF - скипаем (возможно тут нужно скипать только страницу целиком)
  //}

  b = Address>>1; // адрес слова на странице (старший полубайт указывает на часть адреса страницы, поскольку размер страницы 16 слов)
  if(Address == 0)
  {     if(!PhaseA(0x10))       return 0;       // Load Command 0x10 - Write Flash
  }
  if(!PhaseB(b))                                return 0;       // Load Address Low Byte
  if(!PhaseD(SelectedChip.Area1[Address]))      return 0;       // Load Data Low Byte
  if(!PhaseE(SelectedChip.Area1[Address+1]))    return 0;       // Load Data High Byte
  Sleep(Delays);//////////
  return true;
}
//---------------------------------------------------------------------------
//--- ЗАПИСЬ СТРАНИЦЫ БУФЕРА В ПАМЯТЬ ПРОГРАММЫ ПО УКАЗАННОМУ АДРЕСУ --------
//---------------------------------------------------------------------------
bool ATtiny2313_WriteProgramMemoryPage(unsigned int Address)
{ WRITE_BUFFER wr_buf;          // буфер для отправки данных
  READ_BUFFER rd_buf;           // буфер для приёма данных
  unsigned char a;              // старший байт адреса страницы

  a = Address>>9;                       // старший байт адреса страницы
  if(!PhaseC(a))        return 0;       // Load Address High Byte
  //--- PHASE G (Program Page) START ---
  //--- выдаём импульс на линии 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;       // если не дождались - выходим с ошибкой
  //--- PHASE G (Program Page) END ---
  //--- если передали все байты (залили последнюю страницу) - выходим из режима программирования
  if( (Address+2) == SelectedChip.Area1Size)
  {     //--- PHASE I (End Page Programming) ---
        if(!PhaseA(0x0))        return 0;       // Load Command 0x0 - No Operation
        //--- PHASE I (End Page Programming) END ---
  }
  return true;
}
//---------------------------------------------------------------------------
/////////////////////////////
// РАБОТА С ПАМЯТЬЮ EEPROM //
/////////////////////////////
//---------------------------------------------------------------------------
//--- ЧТЕНИЕ БАЙТА ИЗ EEPROM ПО УКАЗАННОМУ АДРЕСУ ---------------------------
//---------------------------------------------------------------------------
bool ATtiny2313_ReadEEPROMMemory(unsigned int Address, bool Action)
{ WRITE_BUFFER wr_buf;          // буфер для отправки данных
  READ_BUFFER rd_buf;           // буфер для приёма данных
  unsigned char a,b;            // байты адреса байта EEPROM

  // получаем адрес слова из адреса его младшего байта
  b = Address;          // младший байт адреса байта
  a = Address>>8;       // старший байт адреса байта (у нас всего 128 байт EEPROM, поэтому он всегда равен 0)
  if(Address==0)
  {    if(!PhaseA(0x03))        return 0;       // Load Command 0x03 - Read EEPROM
  }
  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 EEPROM byte (BS1 is already 0 after PhaseB)
  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 0;       // выходим с ошибкой
        }
  }
  return true;
}
//---------------------------------------------------------------------------
//--- ЗАГРУЗКА БАЙТА В СТРАНИЦУ БУФЕРА ПО УКАЗАННОМУ АДРЕСУ И ЗАПИСЬ СТРАНИЦЫ
//---------------------------------------------------------------------------
bool ATtiny2313_WriteEEPROMMemory(unsigned int Address)
{ WRITE_BUFFER wr_buf;          // буфер для отправки данных
  READ_BUFFER rd_buf;           // буфер для приёма данных
  unsigned char a,b;      // старший и младший байты адреса байта на странице

  b = Address;          // младший байт адреса (размер страницы 4 байта)
  a = Address>>8;       // старший байт адреса страницы
  if(Address == 0)
  {     if(!PhaseA(0x11))                       return 0;       // Load Command 0x11 - Write EEPROM
  }
  if(Address%4 == 0)                                            // страница EEPROM 4 байта, если мы в начале страницы
  {     if(!PhaseC(a))                          return 0;       // Load Address High Byte
  }
  if(!PhaseB(b))                                return 0;       // Load Address Low Byte
  if(!PhaseD(SelectedChip.Area2[Address]))      return 0;       // Load Data Low Byte
  if((Address+1)%4 == 0)            // страница EEPROM 4 байта, если мы в конце страницы
  {     //--- PHASE K (Program EEPROM Page) START ---
        //--- выдаём импульс на линии WR (BS already 0 after PhaseD) ---
        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 K (Program EEPROM Page) END ---
  }
  return true;
}
//---------------------------------------------------------------------------
/////////////////////
// FUSES, LOCK ... //
/////////////////////
//---------------------------------------------------------------------------
//--- ЧТЕНИЕ FUSE- & LOCK-БИТОВ ---------------------------------------------
//---------------------------------------------------------------------------
bool ATtiny2313_ReadFuseLockBits()
{ WRITE_BUFFER wr_buf;          // буфер для отправки данных
  READ_BUFFER rd_buf;           // буфер для приёма данных

  SendMsgToLog(18," read fuse- & lock-bits");           // сообщаем о попытке прочитать Fuse- & Lock-биты
  if(!PhaseA(0x04))                       return 0;     // Load Command 0x04 - Read Fuse & Lock
  //--- set DDRB to input, OE to 0, BS2(XA1)=0, BS1=0 to read fuse low byte
  wr_buf.Size=7;
  wr_buf.Data[0]=0x0B;                                  // DDRBSetup
  wr_buf.Data[1]=0x0;   // 0000 0000                    // все линии на вход
  wr_buf.Data[2]=0x11;                                  // PORTCSetup
  wr_buf.Data[3]=PC_WORK;               // 0000 1000    // сбрасываем XA1, сбрасываем BS1
  wr_buf.Data[4]=0x15;                                  // PORTDSetup
  wr_buf.Data[5]=PD_WORK & ~(1<<OE);    // 0001 0000    // сбрасываем OE
  wr_buf.Data[6]=0x17;                                  // PINBRead
  if(!WriteTo(wr_buf)) { SendMsgToLog(6," read Fuse Low bits"); // ошибка отправки команды
                         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];       // сохраняем прочитанный байт в Fuse Low
  //--- set BS2(XA1)=1, BS1=1 to read fuse high byte
  wr_buf.Size=3;
  wr_buf.Data[0]=0x11;                                                  // PORTCSetup
  wr_buf.Data[1]=PC_WORK | (1 << BS1) | (1<<XA1);       // 0001 1010    // поднимаем XA1, поднимаем BS1
  wr_buf.Data[2]=0x17;                                                  // PINBRead
  if(!WriteTo(wr_buf)) { SendMsgToLog(6," read Fuse High bits");        // ошибка отправки команды
                         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];       // сохраняем прочитанный байт в Fuse High
  //--- set BS2(XA1)=1, BS1=0 to read fuse extended byte
  wr_buf.Size=3;
  wr_buf.Data[0]=0x11;                                                  // PORTCSetup
  wr_buf.Data[1]=PC_WORK | (1<<XA1);       // 0001 1000                 // поднимаем XA1, сбрасываем BS1
  wr_buf.Data[2]=0x17;                                                  // PINBRead
  if(!WriteTo(wr_buf)) { SendMsgToLog(6," read Fuse Extended bits");    // ошибка отправки команды
                         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[2] = rd_buf.Data[0];       // сохраняем прочитанный байт в Fuse Extended
  //--- set BS2(XA1)=0, BS1=1 to read Lock byte
  wr_buf.Size=5;
  wr_buf.Data[0]=0x11;                                          // PORTCSetup
  wr_buf.Data[1]=PC_WORK | (1<<BS1);    // 0001 1000            // сбрасываем 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 bits");     // ошибка отправки команды
                         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[3] = rd_buf.Data[0];       // сохраняем прочитанный байт в Lock

  SendMsgToLog(19," with success.");            // чтение выполнено успешно
  return true;
}
//---------------------------------------------------------------------------
//--- ЗАПИСЬ LOCK-БИТОВ -----------------------------------------------------
//---------------------------------------------------------------------------
bool ATtiny2313_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[3]))      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;
}
//---------------------------------------------------------------------------
//--- ЧТЕНИЕ БАЙТОВ СИГНАТУРЫ -----------------------------------------------
//---------------------------------------------------------------------------
unsigned int ATtiny2313_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;
}
//---------------------------------------------------------------------------
//--- ЗАПИСЬ FUSE-БИТОВ (LOW FUSE BYTE) -------------------------------------
//---------------------------------------------------------------------------
bool ATtiny2313_WriteFuseBits()
{ WRITE_BUFFER wr_buf;          // буфер для отправки данных
  READ_BUFFER rd_buf;           // буфер для приёма данных

  SendMsgToLog(18," write fuse low byte");              // сообщаем о попытке записать старший байт фьюзов
  if(!PhaseA(0x40))                       return 0;     // Load Command 0x40 - Write Fuse
  if(!PhaseD(SelectedChip.Area3[0]))      return 0;     // Load Data Low Byte = Fuse Low
  // устанавливаем нужные уровни BS2(XA1) = 0, BS1 = 0
  // that's already done after PhaseD
  //--- выдаём импульс на линии 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-БИТОВ (HIGH FUSE BYTE) ------------------------------------
//---------------------------------------------------------------------------
bool ATtiny2313_WriteFuseHighBits()
{ WRITE_BUFFER wr_buf;          // буфер для отправки данных
  READ_BUFFER rd_buf;           // буфер для приёма данных

  SendMsgToLog(18," write fuse high byte");             // сообщаем о попытке записать старший байт фьюзов
  if(!PhaseA(0x40))                       return 0;     // Load Command 0x40 - Write Fuse
  if(!PhaseD(SelectedChip.Area3[1]))      return 0;     // Load Data Low Byte = Fuse High
  //--- устанавливаем нужные уровни на BS1=1, XA1(BS2)=0 ---
  wr_buf.Size=2;
  wr_buf.Data[0]=0x11;                                                  // PORTCSetup
  wr_buf.Data[1]=PC_WORK | (1<<BS1);    // 0000 1010                    // сбрасываем XA1(BS2), поднимаем BS1
  if(!WriteTo(wr_buf)) { SendMsgToLog(6," set BS1=1, BS2(XA1)=0");      // ошибка отправки команды
                         CloseHandle(Port);
                         Port=INVALID_HANDLE_VALUE;
                         return 0;
                       }
  //--- выдаём импульс на линии 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," 0x1D 0x03");  // ошибка отправки команды
                         CloseHandle(Port);
                         Port=INVALID_HANDLE_VALUE;
                         return 0;
                       }
  Sleep(Delays);//////////
  // нужно дождаться RDY = high
  if(!WaitRDYHigh)        return 0;     // если не дождались - выходим с ошибкой
  SendMsgToLog(19," with success.");    // запись выполнена успешно
  return true;
}
//---------------------------------------------------------------------------
//--- ЗАПИСЬ FUSE-БИТОВ (EXTENDED FUSE BYTE) --------------------------------
//---------------------------------------------------------------------------
bool ATtiny2313_WriteFuseExtendedBits()
{ WRITE_BUFFER wr_buf;          // буфер для отправки данных
  READ_BUFFER rd_buf;           // буфер для приёма данных

  SendMsgToLog(18," write fuse extended byte");         // сообщаем о попытке записать расширенный байт фьюзов
  if(!PhaseA(0x40))                       return 0;     // Load Command 0x40 - Write Fuse
  if(!PhaseD(SelectedChip.Area3[2]))      return 0;     // Load Data Low Byte = Fuse High
  //--- устанавливаем нужные уровни на BS1=0, XA1(BS2)=1 ---
  wr_buf.Size=2;
  wr_buf.Data[0]=0x11;                                                  // PORTCSetup
  wr_buf.Data[1]=PC_WORK | (1<<XA1);    // 0001 1000                    // поднимаем XA1(BS2), сбрасываем BS1
  if(!WriteTo(wr_buf)) { SendMsgToLog(6," set BS1=0, BS2(XA1)=1");      // ошибка отправки команды
                         CloseHandle(Port);
                         Port=INVALID_HANDLE_VALUE;
                         return 0;
                       }
  //--- выдаём импульс на линии 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;
}
//---------------------------------------------------------------------------
//--- ЧТЕНИЕ БАЙТОВ КАЛИБРОВКИ ----------------------------------------------
//---------------------------------------------------------------------------
bool ATtiny2313_ReadCalibrationBytes()
{ WRITE_BUFFER wr_buf;          // буфер для отправки данных
  READ_BUFFER rd_buf;           // буфер для приёма данных

  SendMsgToLog(18," read calibration bytes");   // сообщаем о попытке прочитать байты калибровки
  if(!PhaseA(0x40))                       return 0;     // Load Command 0x40 - Write Fuse
  for(unsigned char i=0;i<SelectedChip.Area4Size;i++)
  {     //--- команду повторять не обязательно, нужен только новый адрес
        if(!PhaseB(i))   return 0;      // Load Address Low Byte = i
        //--- устанавливаем нужные уровни на BS1=0, XA1(BS2)=1 ---
        wr_buf.Size=2;
        wr_buf.Data[0]=0x11;                                                  // PORTCSetup
        wr_buf.Data[1]=PC_WORK | (1<<BS1);    // 0000 1010                    // сбрасываем XA1(BS2), поднимаем BS1
        if(!WriteTo(wr_buf)) { SendMsgToLog(6," set BS1=1, BS2(XA1)=0");      // ошибка отправки команды
                               CloseHandle(Port);
                               Port=INVALID_HANDLE_VALUE;
                               return 0;
                             }
        //--- READ DATA FROM THE CHIP ---
        //--- перенастраиваем линии порта B на вход, включаем OE, читаем состояние порта 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
        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 Calibration Bytes");       // ошибка отправки команды
                               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.Area4[i] = rd_buf.Data[0];
  }
  SendMsgToLog(19,"");            // чтение байтов калибровки завершено
  return true;
}
//---------------------------------------------------------------------------

