//---------------------------------------------------------------------------
#pragma hdrstop
#include "WireFunctions.h"      // переменные для функций 1-Wire
#include "PortFunctions.h"      // для работы с портом
#include "MainProgram.h"        // для работы с формой
#include "ProgressBar.h"        // для использования прогресс-бара
#include "CalcCRC.h"            // для расчёта CRC
#include "ChipFunctions.h"      // переменные для работы с памятью чипа
#include "FormFunctions.h"      // для работы с элементами формы чипа
#include "SendMsgFunctions.h"   // для отправки сообщений в лог
//---------------------------------------------------------------------------
#pragma package(smart_init)
//---------------------------------------------------------------------------
//--- ФУНКЦИЯ ВЫДАЧИ ОПИСАНИЯ УСТРОЙСТВА ПО КОДУ СЕМЕЙСТВА ------------------
//---------------------------------------------------------------------------
AnsiString GetDeviceDescription(unsigned char FamilyCode)
{ switch(FamilyCode)
  { case 0x1: return "DS2401/DS2411/DS1990A - Silicon Serial Number";				// сделано (нет команд, только ROM), реализована запись в RW1990
    case 0x2: return "DS1991 - 3x384-bits Secure NVRAM";							// сделано
    case 0x4: return "DS2404/DS1994 - Time Chip with 4096 NVRAM";					// сделано
    case 0x5: return "DS2405 - Addressable Switch";									// сделано
    case 0x6: return "DS1993 - 4096-bits of Nonvolatile Memory";					// сделано
    case 0x8: return "DS1992 - 1024-bits of Nonvolatile Memory";					// сделано
    case 0x9: return "DS2502/DS1982 - 1024-bits EPROM (add only)";					// сделано			// нужно напряжение программирования +12В
    case 0xA: return "DS1995 - 16384-bits of Nonvolatile Memory";					// сделано
    case 0xB: return "DS2505/DS1985 - 16384-bits EPROM (add only)";								// нужно напряжение программирования +12В
    case 0xC: return "DS1996 - 65536-bits of Nonvolatile Memory";					// сделано
	case 0xD: return "DS28E05 - 112 bytes EEPROM";									// сделано
    case 0xF: return "DS2506/DS1986 - 65536-bits EPROM (add only)";								// нужно напряжение программирования +12В
    case 0x10: return "DS18S20/DS1920 - Digital Thermometer";						// сделано
    case 0x12: return "DS2406/DS2407 - Dual Addr. Switch + 1Kb Memory";							// нужно напряжение программирования +12В
    case 0x14: return "DS2430A/DS1971 - 256-bits EEPROM + 64-bits OTP";         	// сделано
	case 0x18: return "DS1963S - 4096-bits Monetary Nonvolatile Memory with SHA-1";				// нестандартные тайминги (например, reset low минимум 540 мкс, у шлюза 500 мкс)
    case 0x1A: return "DS1963L - 4096-bits Monetary Nonvolatile Memory";			// сделано
    case 0x1B: return "DS2436 - Battery Id/Monitor Chip";								// дохера команд (позже сделаю)
    case 0x1C: return "DS28E04-100 - 4096-bits EEPROM with PIO";								// нестандартные тайминги (например, reset low минимум 504 мкс, максимум 640 мкс)
    case 0x1D: return "DS2423 - 4096-bits SRAM";									// сделано (like as DS1963L, except tamper-bytes)
    case 0x1F: return "DS2409 - MicroLAN Coupler";
    case 0x20: return "DS2450 - Quad A/D Converter";
    case 0x21: return "DS1921 - Thermochron";													// нестандартные тайминги (например, reset low минимум 540 мкс, максимум 640 мкс)
    case 0x22: return "DS1822 - Digital Thermometer";								// сделано (same as DS18B20)
    case 0x23: return "DS2433 - 4096-bits EEPROM";                              	// сделано
    case 0x24: return "DS2415 - Time Chip";											// сделано
    case 0x26: return "DS2438 - Smart Battery Monitor";
    case 0x27: return "DS2417 - Time Chip with Interrupt";							// сделано
    case 0x28: return "DS18B20 - Digital Thermometer";								// сделано
    case 0x29: return "DS2408 - 8-channel Addressable Switch";									// нестандартные тайминги (например, reset low минимум 660 мкс, максимум 720 мкс)
    case 0x2C: return "DS2890 - Digital Potentiometer";								// сделано
    case 0x2D: return "DS2431/DS28E07 - 1024-bits EEPROM";             	            // сделано
    case 0x2E: return "DS2770 - Battery Monitor & Charge Controller";
    case 0x30: return "DS2760/DS2761/DS2762 - Hi Prec. Li+ Battery Monitor";
    case 0x31: return "DS2720 - Addressable Single-Cell Lithium Protection IC";
    case 0x33: return "DS2432 / DS1961S - 1024-bits EEPROM with SHA1 Engine";		// сделано
    case 0x36: return "DS2740 - Hi-Precision Coulomb Counter";
    case 0x37: return "DS1977 - Password Protected 32KB EEPROM";								// нестандартные тайминги (здесь почти нормальные, можно попробовать)
    case 0x3A: return "DS2413 - 2-channel Addresasble Switch";									// нестандартные тайминги (например, reset low минимум 600 мкс, у шлюза 500 мкс)
    case 0x3B: return "MAX31826 - Digital Temperature Sensor";
    case 0x41: return "DS2422/DS1922L/DS1922T/DS1923 - 8KB Temp./Datalogger";					// нестандартные тайминги (например, reset low минимум 690 мкс, максимум 720 мкс)
    case 0x43: return "DS28EC20 - 20Kb EEPROM";													// нестандартные тайминги
    case 0x51: return "DS2751 - Multichemistry Battery Fuel Gauge";
    case 0x81: return "DS1420 - Serial ID Button";									// нет команд, только ROM
    case 0x82: return "DS1425 - 3x384-bit Secure NVRAM";							// сделано (same as DS1991)
    case 0x84: return "DS2404S/DS1427 - EconoRAM (4096-bits NVRAM) + Time Chip";	// сделано (same as DS1994)
    case 0x89: return "DS2502-E48/DS2502-UNW/DS1982U - 48-bit Node Address Chip";				// нужно напряжение программирования +12В
    case 0x8B: return "DS2505-UNW/DS1985U - 16Kb EPROM (add only) UniqueWare";					// нужно напряжение программирования +12В
    case 0x8F: return "DS2506-UNW/DS1986U - 64Kb EPROM (add only) UniqueWare";					// нужно напряжение программирования +12В
	case 0xE2: return "DS1964S - 512-bits Secure Authenticator with SHA-256";
    case 0xFF: return "LCD";
    default: return "Unknown Device";
  }
}
//---------------------------------------------------------------------------
//--- ПОИСК ВСЕХ УСТРОЙСТВ НА ШИНЕ 1-WIRE (0xF0) ----------------------------
//---------------------------------------------------------------------------
int SearchDevices()
{ //SEARCH DEVICES
  WRITE_BUFFER wr_buf;  // структура буфера для передачи описана в функциях порта
  READ_BUFFER rd_buf;   // структура буфера для чтения описана в функциях порта

  unsigned char CRC8, Temp, ROM[8];
  char buf[2], value[1], hexbuf[3];
  bool SlaveBit, ISlaveBit, LastDev;
  int Step, LastFork, ZeroFork, CurrentByte, CurrentBit;
  AnsiString TempStr;
  int  DevCounter;      // счётчик найденных устройств

  //инициализация
  DevCounter=0; CRC8=0;
  Form1->StringGrid1->RowCount=DevCounter+2; // задаём под них таблицу
  Form1->StringGrid1->Cells[0][1]="";
  Form1->StringGrid1->Cells[1][1]="";
  Form1->StringGrid1->Cells[2][1]="";
  // вывод собщения в лог
  SendMsgToLogForm(9,"");    // запускаем поиск устройств

  for(int i=0; i<8; i++)
  { ROM[i]=0; }  // сбрасываем ROM
  LastDev=false;
  LastFork=-1;
  //включаем прогресс-бар
  Application->CreateForm(__classid(TLBar),&LBar); // создаём форму с прогресс-баром
  LBar->Show();                   // показываем её в немодальном окне

  while(!LastDev) // пока не найдём последний девайс
  { CRC8=0; ZeroFork=-1; Step=0;
    //посылаем Reset
    wr_buf.Size=1;
    wr_buf.Data[0]=0x60;
    if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");// ошибка загрузки пакета
                           LBar->Free();        // уничтожаем форму с прогресс-баром
                           ClosePort();
                           return DevCounter;
                         }
    Sleep(1);
    //посылаем Search ROM
    wr_buf.Size=2;
    wr_buf.Data[0]=0x61;     //SendByte_1W
    wr_buf.Data[1]=0xF0;     //Search ROM
    if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");// ошибка загрузки пакета
                           LBar->Free();        // уничтожаем форму с прогресс-баром
                           ClosePort();
                           return DevCounter;
                         }
    Sleep(1);
    while(Step<64)      // пока не пройдём весь маршрут целиком (64 шага)
    { CurrentByte=Step/8; CurrentBit=Step-8*CurrentByte;
      //читаем с шины первый бит
      wr_buf.Size=1;
      wr_buf.Data[0]=0x64; // команда чтения бита
      if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");// ошибка загрузки пакета
                             LBar->Free();        // уничтожаем форму с прогресс-баром
                             ClosePort();
                             return DevCounter;
                           }
      Sleep(1);
      //принимаем пакет
      rd_buf=ReadFrom();
      if(!rd_buf.Size){ SendMsgToLogForm(11,"");// ошибка загрузки пакета
                        LBar->Free();        // уничтожаем форму с прогресс-баром
                        ClosePort();
                        return DevCounter;
                      }
      if(rd_buf.Data[0]==0x0F) SlaveBit=false;
      else                     SlaveBit=true;
      //читаем с шины второй бит
      wr_buf.Size=1;
      wr_buf.Data[0]=0x64; // команда чтения бита
      if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");// ошибка загрузки пакета
                             LBar->Free();        // уничтожаем форму с прогресс-баром
                             ClosePort();
                             return DevCounter;
                           }
      Sleep(1);
      //принимаем пакет
      rd_buf=ReadFrom();
      if(!rd_buf.Size){ SendMsgToLogForm(11,"");// ошибка загрузки пакета
                        LBar->Free();        // уничтожаем форму с прогресс-баром
                        ClosePort();
                        return DevCounter;
                      }
      if(rd_buf.Data[0]==0x0F) ISlaveBit=false;
      else                     ISlaveBit=true;
      //принятые биты равны или нет?
      if(SlaveBit==ISlaveBit)  // если равны - ошибка или узел
      { if (SlaveBit)          // если SlaveBit=1 (ошибка)
        { SendMsgToLogForm(12,"");// с шины считаны 2 единицы
          LBar->Free();        // уничтожаем форму с прогресс-баром
          ClosePort();
          return DevCounter;
        }
        else                   // если SlaveBit=0 (узел)
        { if(Step==LastFork)
          { wr_buf.Data[1]=1; }     // MasterBit=1
          else
          { if(Step>LastFork)
            { wr_buf.Data[1]=0; }
            else
            { wr_buf.Data[1]=ROM[CurrentByte]>>CurrentBit; }
            if((wr_buf.Data[1]&1)==0)    // если MasterBit=0
            { ZeroFork=Step; }
          }
        }
      }
      else // если не равны (точно не узел)
      { wr_buf.Data[1]=SlaveBit; }  // MasterBit=SlaveBit

      // сохраняем бит в ROM
      Temp=1<<CurrentBit;                     // нужный бит=1
      Temp=~Temp;                             // инвертируем (все биты = 1, кроме нужного)
      ROM[CurrentByte]=ROM[CurrentByte]&Temp; // обнуляем нужный бит в ROM
      Temp=(wr_buf.Data[1]&1)<<CurrentBit;    // нужный бит=MasterBit (сдвигаем младший бит в нужную позицию)
      ROM[CurrentByte]=ROM[CurrentByte]|Temp; // сохраняем MasterBit
      //вычисляем CRC8
      CRC8=CalcCRC8(CRC8, wr_buf.Data[1]);
      //отправляем бит в шину
      wr_buf.Size=2;
      wr_buf.Data[0]=0x63;
      if(!WriteTo(wr_buf)) { SendMsgToLogForm(11,"");// ошибка загрузки пакета
                             LBar->Free();        // уничтожаем форму с прогресс-баром
                             ClosePort();
                             return DevCounter;
                           }
      Sleep(1);
      Step=Step+1;
      // меняем позицию прогресс-бара
      LBar->ProgressBar1->Position=100*Step/64; // вычисляем новую позицию прогресс-бара
    }
    //готовимся искать следующий девайс
    LastFork=ZeroFork;
    if(LastFork<0)
     LastDev=true;
    if(CRC8==0)
    { DevCounter=DevCounter+1;                    // увеличиваем количество найденных девайсов
      Form1->StringGrid1->RowCount=DevCounter+1;  // задаём под них таблицу
      TempStr="";
      for(int i=0; i<8; i++)
      {  value[0]=ROM[i];
         BinToHex(value,hexbuf,1);       //преобразовать число в строку
         hexbuf[2]=0;                    //строка должна заканчиваться нулём
         TempStr=TempStr+hexbuf+" ";
      }
      Form1->StringGrid1->Cells[0][DevCounter]=IntToStr(DevCounter);
      Form1->StringGrid1->Cells[1][DevCounter]=TempStr;
      TempStr=GetDeviceDescription(ROM[0]);             // получаем описание из БД
      Form1->StringGrid1->Cells[2][DevCounter]=TempStr; // и вписываем его в третий столбец
      Form1->StringGrid1->ColWidths[2]=394;             // регулируем ширину третьего столбца
      SendMsgToLogForm(13,"");// CRC8 Ok
    }
    else
    { SendMsgToLogForm(14,"");// ошибка CRC8
      LBar->Free();      // уничтожаем форму с прогресс-баром
      ClosePort();
      return DevCounter;
    }
  }
  //*************************************************************************
  LBar->Free();         // уничтожаем форму с прогресс-баром
  SendMsgToLogForm(10,""); // поиск устройств успешно завершён
  return DevCounter;    // ответ - количество найденных девайсов
}
//---------------------------------------------------------------------------
