//---------------------------------------------------------------------------
#pragma hdrstop
#include "PortFunctions.h"      // переменные для функций работы с портом
#include "LogFunctions.h"       // для отправки сообщений в лог
#include "Main.h"               // переменные для работы с главной формой
//---------------------------------------------------------------------------
#pragma package(smart_init)
//---------------------------------------------------------------------------
//--- ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ -------------------------------------------------
//---------------------------------------------------------------------------
HANDLE Port;                    // дескриптор порта
OVERLAPPED  ovr_wr, ovr_rd;     // результаты чтения/записи
//---------------------------------------------------------------------------
//--- ОТПРАВКА ДАННЫХ ИЗ БУФЕРА В ПОРТ --------------------------------------
//---------------------------------------------------------------------------
bool WriteTo(WRITE_BUFFER wr_buf)
{ DWORD temp;

  WriteFile(Port,wr_buf.Data,wr_buf.Size,&temp,&ovr_wr); // послать в порт данные
  WaitForSingleObject(ovr_wr.hEvent,20000);              // приостановить поток на 20 с или пока не завершится операция записи в порт
  if(GetOverlappedResult(Port,&ovr_wr,&temp,true)) return true;  // если операция завершилась успешно - вернуть истину
  else                                             return false; // если нет - ложь
}
//---------------------------------------------------------------------------
//--- ПРИЁМ ДАННЫХ ИЗ ПОРТА В БУФЕР -----------------------------------------
//---------------------------------------------------------------------------
READ_BUFFER ReadFrom(int Number)
{ READ_BUFFER rd_buf, temp_buf;
  COMSTAT     port_status;
  DWORD       temp, mask;
  int         Counter;

  Counter=0; rd_buf.Size=0; temp_buf.Size=0;
  while((Counter<1000) && (rd_buf.Size<Number)) // пытаемся читать 1000 раз или пока не прочитаем нужное количество байт
  { ClearCommError(Port,&temp,&port_status);    // заполняем структуру port_status
    temp_buf.Size=0;
    temp_buf.Size=port_status.cbInQue;          // кол-во принятых байт
    if(temp_buf.Size>0)                         // если есть что читать
    { ReadFile(Port,temp_buf.Data,temp_buf.Size,&temp,&ovr_rd);  //считать нужное кол-во байт во временный буфер
      for(int i=0; i<temp_buf.Size; i++)
      { rd_buf.Data[rd_buf.Size+i]=temp_buf.Data[i];    // копируем байты из временного буфера в выходной
      }
      rd_buf.Size += temp_buf.Size;             // увеличиваем количество байт в выходном буфере
    }
    Counter++;
    Sleep(1);
  }
  return rd_buf;
}
//---------------------------------------------------------------------------
//--- ОТКРЫТИЕ И НАСТРОЙКА COM-ПОРТА ----------------------------------------
//---------------------------------------------------------------------------
void OpenCom(char PortName[100])
{ DCB    dcb;           // структура DCB
  WRITE_BUFFER wr_buf;  // структура буфера для передачи описана в функциях порта
  READ_BUFFER rd_buf;   // буфер для приёма данных

  dcb.DCBlength=sizeof(DCB);
  // откроем выбранный порт. Чтобы открыть порт на nt-платформе надо указывать
  // "\\.\PortName", в СИ для печати символа \ надо его указывать 2 раза
  Port=CreateFile(PortName,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,NULL);
  if(Port==INVALID_HANDLE_VALUE)
  { SendMsgToLog(2,"");         // Ошибка. COM-порт не доступен
    return;
  }
  else
  { if(GetCommState(Port,&dcb)==0)
    { SendMsgToLog(4,"");       // ошибка получения параметров COM-порта
      CloseHandle(Port);
      Port=INVALID_HANDLE_VALUE;
      return;
    }
    else
    { dcb.BaudRate=250000;
      dcb.ByteSize=8;
      dcb.Parity=0;
      dcb.StopBits=2;
      dcb.fBinary=true;                         //двоичный режим обмена
      dcb.fOutxCtsFlow=false;                   //не отслеживать CTS
      dcb.fOutxDsrFlow=false;                   //не отслеживать DSR
      dcb.fDtrControl=DTR_CONTROL_DISABLE;      //отключить DTR
      dcb.fDsrSensitivity=false;                //забить на DSR
      dcb.fNull=false;                          //принимаем нулевые байты
      dcb.fRtsControl=RTS_CONTROL_DISABLE;      //отключить RTS
      dcb.fAbortOnError=false;                  //отключаем остановку чтения/записи при ошибке
    }
    if(SetCommState(Port,&dcb)==0)
    { SendMsgToLog(5,"");                       //ошибка установки параметров COM-порта
      CloseHandle(Port);
      Port=INVALID_HANDLE_VALUE;
      return;
    }

    SetupComm(Port,BUFSIZE+100,BUFSIZE+100);            //размеры очередей приёма и передачи
    PurgeComm(Port,PURGE_RXCLEAR|PURGE_TXCLEAR);        //очистить принимающий и передающий буферы порта
    //-----------------------------------------------------------------------------------------------
    //--- настраиваем шлюз (отменяем автозагрузку, отчёты и выбираем интерфейс SPI Mode 1, LSB-first)
    //-----------------------------------------------------------------------------------------------
    wr_buf.Size=3;
    wr_buf.Data[0]=0x0A;     // disable autoload
    wr_buf.Data[1]=0x08;     // disable reports
    wr_buf.Data[2]=0x02;     // select interface SPI
    if(!WriteTo(wr_buf)) { SendMsgToLog(6," 0x0A 0x08 0x02");    // ошибка настройки шлюза
                           CloseHandle(Port);
                           Port=INVALID_HANDLE_VALUE;
                           return;
                         }
    Sleep(1);
    Sleep(Delays);//////////
    //--- включаем сигнал PG ---
    wr_buf.Size=1;
    wr_buf.Data[0]=0x1E;        // Set Power Good to enable external DC/DC
    if(!WriteTo(wr_buf)) { SendMsgToLog(6," 0x1E");    // ошибка настройки шлюза
                           CloseHandle(Port);
                           Port=INVALID_HANDLE_VALUE;
                           return;
                         }
    Sleep(1);
    Sleep(Delays);//////////
    //--- читаем из шлюза последнюю ошибку ---
    //--- самый первый байт, прочитанный из шлюза после открытия порта, читается нулём и если сначала не прочитать ---
    //--- хотя бы 1 байт, то подключенный чип с первого раза не определяется, хер знает почему так ---
    wr_buf.Size=1;
    wr_buf.Data[0]=0x04;        // Read Error
    if(!WriteTo(wr_buf)) { SendMsgToLog(6," 0x1E");     // ошибка настройки шлюза
                           CloseHandle(Port);
                           Port=INVALID_HANDLE_VALUE;
                           return;
                         }
    rd_buf=ReadFrom(1);                                 // читаем
    if(!rd_buf.Size) { SendMsgToLog(7," (PINB)");    // ошибка приёма пакета
                           CloseHandle(Port);
                           Port=INVALID_HANDLE_VALUE;
                           return;
                         }
    //---------------------------------------------------------------
    //--- устанавливаем SPI Mode 1, передача младшим битом вперёд ---
    wr_buf.Size=2;
    wr_buf.Data[0]=0x40;     // LoadConfigSPI
    wr_buf.Data[1]=0x01;     // Low bit first, CPOL=0, CPHA=1
    if(!WriteTo(wr_buf)) { SendMsgToLog(6," 0x40 0x01");    // ошибка настройки шлюза
                           CloseHandle(Port);
                           Port=INVALID_HANDLE_VALUE;
                           return;
                         }
    Sleep(1);
    Sleep(Delays);//////////
    // питание у нас пока не подано, поскольку пины управления питанием настроены как входы
  }
}
//---------------------------------------------------------------------------
