//---------------------------------------------------------------------------
#pragma hdrstop
#include "PortFunctions.h"      // переменные для функций работы с портом
#include "SendMsgFunctions.h"   // для отправки сообщений в лог
//---------------------------------------------------------------------------
#pragma package(smart_init)
//---------------------------------------------------------------------------
//--- ГЛОБАЛЬНЫЕ ПЕРЕМЕННЫЕ -------------------------------------------------
//---------------------------------------------------------------------------
HANDLE Port;                    // дескриптор порта
OVERLAPPED  ovr_wr, ovr_rd;     // результаты чтения/записи

int SelectedProgrammer;         // здесь будем хранить тип выбранного программатора
//---------------------------------------------------------------------------
//--- ОТПРАВКА ДАННЫХ ИЗ БУФЕРА В ПОРТ --------------------------------------
//---------------------------------------------------------------------------
bool WriteTo(WRITE_BUFFER wr_buf)
{ DWORD temp;

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

  Counter=0; rd_buf.Size=0;
  while(Counter<1000) // пытаемся читать 1000 раз
  { ClearCommError(Port,&temp,&port_status);    // заполняем структуру port_status
    rd_buf.Size=0;
    rd_buf.Size=port_status.cbInQue;            // кол-во принятых байт
    if(rd_buf.Size>0)                           // если есть что читать
    { ReadFile(Port,rd_buf.Data,rd_buf.Size,&temp,&ovr_rd);  //считать нужное кол-во байт
      return rd_buf;
    }
    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)
  { SendMsgToLogForm(2,"");    // Ошибка. COM-порт не доступен
    return;
  }
  else
  { if(GetCommState(Port,&dcb)==0)
    { SendMsgToLogForm(6,"");    // ошибка получения параметров COM-порта
      CloseHandle(Port);
      Port=INVALID_HANDLE_VALUE;
      return;
    }
    else
    { switch(SelectedProgrammer)
      { case 1:  dcb.BaudRate=115200;
                 break;
        case2:
        default:
                 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)
    { SendMsgToLogForm(7,"");    // ошибка установки параметров COM-порта
      CloseHandle(Port);
      Port=INVALID_HANDLE_VALUE;
      return;
    }

    SetupComm(Port,BUFSIZE+100,BUFSIZE+100);       //размеры очередей приёма и передачи
    PurgeComm(Port,PURGE_RXCLEAR|PURGE_TXCLEAR);   //очистить принимающий и передающий буферы порта

    // настраиваем шлюз
    wr_buf.Size=3;
    wr_buf.Data[0]=0x0A;     // disable autoload
    wr_buf.Data[1]=0x08;     // disable reports
    wr_buf.Data[2]=0x03;     // select 1W
    if(!WriteTo(wr_buf)) { SendMsgToLogForm(8,"");    // ошибка настройки шлюза
                           CloseHandle(Port);
                           Port=INVALID_HANDLE_VALUE;
                           return;
                         }
    if(SelectedProgrammer==2)
    {   //--- включаем питание на микруху и +12 Вольт ---
        // запрашиваем состояние PORTC (не PINC!)
        wr_buf.Size=1;
        wr_buf.Data[0]=0x12;                        // PORTCRead
        if(!WriteTo(wr_buf)) { SendMsgToLogForm(32," PORTCRead");    // ошибка отправки команды
                               CloseHandle(Port);
                               Port=INVALID_HANDLE_VALUE;
                               return;
                             }
        // принимаем байт, содержащий PORTC
        rd_buf=ReadFrom();                                          // читаем
        if(!rd_buf.Size) { SendMsgToLogForm(21," PORTC");           // ошибка приёма пакета
                           CloseHandle(Port);
                           Port=INVALID_HANDLE_VALUE;
                           return;
                         }
        wr_buf.Size=2;
        wr_buf.Data[0] = 0x11;                      // PORTCSetup
        wr_buf.Data[1] = rd_buf.Data[0] & 0xFB;     // сбрасываем бит 2 (включить +5 Вольт)
        wr_buf.Data[1] = rd_buf.Data[0] | 0x8;      // поднимаем бит 3 (включить +12 Вольт)
        if(!WriteTo(wr_buf)) { SendMsgToLogForm(32," PORTCSetup");  // ошибка отправки команды
                               CloseHandle(Port);
                               Port=INVALID_HANDLE_VALUE;
                               return;
                             }
        // запрашиваем состояние DDRC
        wr_buf.Size=1;
        wr_buf.Data[0]=0x10;                        // DDRCRead
        if(!WriteTo(wr_buf)) { SendMsgToLogForm(32," DDRCRead");    // ошибка отправки команды
                               CloseHandle(Port);
                               Port=INVALID_HANDLE_VALUE;
                               return;
                             }
        // принимаем байт, содержащий DDRC
        rd_buf=ReadFrom();                                          // читаем
        if(!rd_buf.Size) { SendMsgToLogForm(21," DDRC");            // ошибка приёма пакета
                           CloseHandle(Port);
                           Port=INVALID_HANDLE_VALUE;
                           return;
                         }
        wr_buf.Size=2;
        wr_buf.Data[0] = 0x0F;                      // DDRCSetup
        //wr_buf.Data[1] = rd_buf.Data[0] | 0x4;    // поднимаем бит 2 (линия управления +5В на выход)
        wr_buf.Data[1] = rd_buf.Data[0] | 0xC;      // поднимаем биты 2 и 3 (линии управления +5В и +12В на выход)
        if(!WriteTo(wr_buf)) { SendMsgToLogForm(32," DDRCSetup");   // ошибка отправки команды
                               CloseHandle(Port);
                               Port=INVALID_HANDLE_VALUE;
                               return;
                             }
    }
  }
}
//---------------------------------------------------------------------------
