//---------------------------------------------------------------------------
#include <vcl\vcl.h>
#include <stdio.h>
#pragma hdrstop

#include "Serial.h"
//---------------------------------------------------------------------------
__fastcall TSerial::TSerial(int Number)
{
  FNumber=Number;
  char FileName[5];
  sprintf(FileName,"COM%i",FNumber);
  ConfigPanel=NULL;

  FHandle=CreateFile(FileName,GENERIC_READ|GENERIC_WRITE,
    0,NULL,OPEN_EXISTING,0,NULL);
  if(FHandle==INVALID_HANDLE_VALUE)
    throw Exception(
      AnsiString("Sériový port ")+FileName+" nelze otevřít");
  GetDCB();
  SetDCB();
}
//---------------------------------------------------------------------------
__fastcall TSerial::TSerial()
{
  char FileName[5];
  ConfigPanel=NULL;

  for(int i=1;i<=4;i++){
    FNumber=Number;
    sprintf(FileName,"COM%i",FNumber);
    FHandle=CreateFile(FileName,GENERIC_READ|GENERIC_WRITE,
    0,NULL,OPEN_EXISTING,0,NULL);
    if(FHandle!=INVALID_HANDLE_VALUE) break;
  }
  if(FHandle==INVALID_HANDLE_VALUE)
    throw Exception("Žádný sériový port nelze otevřít");
  GetDCB();
  SetDCB();
}
//---------------------------------------------------------------------------
__fastcall TSerial::~TSerial()
{
  CloseHandle(FHandle);
}
//---------------------------------------------------------------------------
void __fastcall TSerial::SetupComm(DWORD InQueue,DWORD OutQueue)
{
  ::SetupComm(FHandle,InQueue,OutQueue);
}
//---------------------------------------------------------------------------
DWORD __fastcall TSerial::GetInputQueue()
{
  DWORD d;COMSTAT cs;
  ClearCommError(FHandle,&d,&cs);
  return(cs.cbInQue);
}
//---------------------------------------------------------------------------
DWORD __fastcall TSerial::GetOutputQueue()
{
  DWORD d;COMSTAT cs;
  ClearCommError(FHandle,&d,&cs);
  return(cs.cbOutQue);
}
//---------------------------------------------------------------------------
DWORD __fastcall TSerial::GetRIT()
{
  GetCommTimeouts(FHandle,&to);
  return(to.ReadIntervalTimeout);
}
//---------------------------------------------------------------------------
DWORD __fastcall TSerial::GetRTTM()
{
  GetCommTimeouts(FHandle,&to);
  return(to.ReadTotalTimeoutMultiplier);
}
//---------------------------------------------------------------------------
DWORD __fastcall TSerial::GetRTTC()
{
  GetCommTimeouts(FHandle,&to);
  return(to.ReadTotalTimeoutConstant);
}
//---------------------------------------------------------------------------
DWORD __fastcall TSerial::GetWTTM()
{
  GetCommTimeouts(FHandle,&to);
  return(to.WriteTotalTimeoutMultiplier);
}
//---------------------------------------------------------------------------
DWORD __fastcall TSerial::GetWTTC()
{
  GetCommTimeouts(FHandle,&to);
  return(to.WriteTotalTimeoutConstant);
}
//---------------------------------------------------------------------------
void __fastcall TSerial::SetRIT(DWORD Timeout)
{
  GetCommTimeouts(FHandle,&to);
  to.ReadIntervalTimeout=Timeout;
  SetCommTimeouts(FHandle,&to);
}
//---------------------------------------------------------------------------
void __fastcall TSerial::SetRTTM(DWORD Timeout)
{
  GetCommTimeouts(FHandle,&to);
  to.ReadTotalTimeoutMultiplier=Timeout;
  SetCommTimeouts(FHandle,&to);
}
//---------------------------------------------------------------------------
void __fastcall TSerial::SetRTTC(DWORD Timeout)
{
  GetCommTimeouts(FHandle,&to);
  to.ReadTotalTimeoutConstant=Timeout;
  SetCommTimeouts(FHandle,&to);
}
//---------------------------------------------------------------------------
void __fastcall TSerial::SetWTTM(DWORD Timeout)
{
  GetCommTimeouts(FHandle,&to);
  to.WriteTotalTimeoutMultiplier=Timeout;
  SetCommTimeouts(FHandle,&to);
}
//---------------------------------------------------------------------------
void __fastcall TSerial::SetWTTC(DWORD Timeout)
{
  GetCommTimeouts(FHandle,&to);
  to.WriteTotalTimeoutConstant=Timeout;
  SetCommTimeouts(FHandle,&to);
}
//---------------------------------------------------------------------------
int __fastcall TSerial::WriteByte(Byte byte)
{
  DWORD w;
  WriteFile(FHandle,&byte,1,&w,NULL);
  return(w);
}
//---------------------------------------------------------------------------
int __fastcall TSerial::WriteChar(char Char)
{
  DWORD w;
  WriteFile(FHandle,&Char,1,&w,NULL);
  return(w);
}
//---------------------------------------------------------------------------
int __fastcall TSerial::WriteString(const AnsiString& String)
{
  DWORD w;
  WriteFile(FHandle,String.c_str(),String.Length(),&w,NULL);
  return(w);
}
//---------------------------------------------------------------------------
int __fastcall TSerial::ReadString(AnsiString& String,int Length)
{
  DWORD r;
  char *str=new char[Length+1];
  ReadFile(FHandle,str,Length,&r,NULL);
  str[r]='\0';
  String=str;
  delete[]str;
  return(r);
}
//---------------------------------------------------------------------------
int __fastcall TSerial::ReadByte(Byte* byte)
{
  DWORD r;
  ReadFile(FHandle,byte,1,&r,NULL);
  return(r);
}
//---------------------------------------------------------------------------
int __fastcall TSerial::ReadChar(char* Char)
{
  DWORD r;  
  ReadFile(FHandle,Char,1,&r,NULL);
  return(r);
}
//---------------------------------------------------------------------------
void __fastcall TSerial::PurgeInput()
{
  PurgeComm(FHandle,PURGE_RXCLEAR);
}
//---------------------------------------------------------------------------
void __fastcall TSerial::GetDCB()
{
  GetCommState(FHandle,&dcb);
}
//---------------------------------------------------------------------------
void __fastcall TSerial::SetDCB()
{
  dcb.fAbortOnError=FALSE;   //sssssssssssssssss
  SetCommState(FHandle,&dcb);
  if(ConfigPanel)
    ConfigPanel->Update();
}
//---------------------------------------------------------------------------
TBaudRate __fastcall TSerial::GetBaudRate()
{
  GetDCB();
  return((TBaudRate)dcb.BaudRate);
}
//---------------------------------------------------------------------------
void __fastcall TSerial::SetBaudRate(TBaudRate ABaudRate)
{
  GetDCB();
  dcb.BaudRate=ABaudRate;
  SetDCB();
}
//---------------------------------------------------------------------------
TParity __fastcall TSerial::GetParity()
{
  GetDCB();
  return((TParity)dcb.Parity);
}
//---------------------------------------------------------------------------
void __fastcall TSerial::SetParity(TParity AParity)
{
  GetDCB();
  dcb.Parity=AParity;
  SetDCB();
}
//---------------------------------------------------------------------------
TStopBits __fastcall TSerial::GetStopBits()
{
  GetCommState(FHandle,&dcb);
  return((TStopBits)dcb.StopBits);
}
//---------------------------------------------------------------------------
void __fastcall TSerial::SetStopBits(TStopBits AStopBits)
{
  GetDCB();
  dcb.StopBits=AStopBits;
  SetDCB();
}
//---------------------------------------------------------------------------
TByteSize __fastcall TSerial::GetByteSize()
{
  GetDCB();
  return((TByteSize)dcb.ByteSize);
}
//---------------------------------------------------------------------------
void __fastcall TSerial::SetByteSize(TByteSize AByteSize)
{
  GetDCB();
  dcb.ByteSize=AByteSize;
  SetDCB();
}
//---------------------------------------------------------------------------
DWORD __fastcall TSerial::gms()
{
  DWORD d;
  GetCommModemStatus(FHandle,&d);
  return(d);
}
//---------------------------------------------------------------------------
bool __fastcall TSerial::GetCTS()
{
  return(gms()&MS_CTS_ON);
}
//---------------------------------------------------------------------------
bool __fastcall TSerial::GetDSR()
{
  return(gms()&MS_DSR_ON);
}
//---------------------------------------------------------------------------
bool __fastcall TSerial::GetRING()
{
  return(gms()&MS_RING_ON);
}
//---------------------------------------------------------------------------
bool __fastcall TSerial::GetRLSD()
{
  return(gms()&MS_RLSD_ON);
}
//---------------------------------------------------------------------------
void __fastcall TSerial::SetDTR(bool Status)
{
  EscapeCommFunction(FHandle,
    Status?SETDTR:CLRDTR);
}
//---------------------------------------------------------------------------
void __fastcall TSerial::SetRTS(bool Status)
{
  EscapeCommFunction(FHandle,
    Status?SETRTS:CLRRTS);
}
//---------------------------------------------------------------------------
void __fastcall TSerial::SetTxD(bool Status)
{
  EscapeCommFunction(FHandle,
    Status?SETBREAK:CLRBREAK);
}
//---------------------------------------------------------------------------
__fastcall TConfigPanel::TConfigPanel(
  TWinControl* Owner,int X, int Y,TSerial *Serial)
{
  this->Serial=Serial;
  FAutoSet=true;

  lBaudRate=new TLabel((TControl*)Owner);
  lBaudRate->Parent=Owner;
  lBaudRate->Left=X+20;
  lBaudRate->Top=Y+20;
  lBaudRate->Caption="Bitů za sekundu:";
  cbBaudRate=new TComboBox((TControl*)Owner);
  cbBaudRate->Parent=Owner;
  cbBaudRate->Left=X+120;
  cbBaudRate->Top=lBaudRate->Top-2;
  cbBaudRate->Style=csDropDownList;
  cbBaudRate->Items->Add(br9600);
  cbBaudRate->Items->Add(br19200);
  cbBaudRate->Items->Add(br38400);
  cbBaudRate->Items->Add(br57600);
  cbBaudRate->Items->Add(br115200);

  lByteSize=new TLabel((TControl*)Owner);
  lByteSize->Parent=Owner;
  lByteSize->Left=X+20;
  lByteSize->Top=lBaudRate->Top+40;
  lByteSize->Caption="Datových bitů:";
  cbByteSize=new TComboBox((TControl*)Owner);
  cbByteSize->Parent=Owner;
  cbByteSize->Left=X+120;
  cbByteSize->Top=lByteSize->Top-2;
  cbByteSize->Style=csDropDownList;
//  cbByteSize->Items->Add(bs4);
//  cbByteSize->Items->Add(bs5);
//  cbByteSize->Items->Add(bs6);
//  cbByteSize->Items->Add(bs7);
  cbByteSize->Items->Add(bs8);

  lParity=new TLabel((TControl*)Owner);
  lParity->Parent=Owner;
  lParity->Left=X+20;
  lParity->Top=lByteSize->Top+40;
  lParity->Caption="Parita:";
  cbParity=new TComboBox((TControl*)Owner);
  cbParity->Parent=Owner;
  cbParity->Left=X+120;
  cbParity->Top=lParity->Top-2;
  cbParity->Style=csDropDownList;
  cbParity->Items->AddObject("žádná",(TObject*)pNo);
  cbParity->Items->AddObject("lichá",(TObject*)pOdd);
  cbParity->Items->AddObject("sudá",(TObject*)pEven);

  lStopBits=new TLabel((TControl*)Owner);
  lStopBits->Parent=Owner;
  lStopBits->Left=X+20;
  lStopBits->Top=lParity->Top+40;
  lStopBits->Caption="Stop-bitů";
  cbStopBits=new TComboBox((TControl*)Owner);
  cbStopBits->Parent=Owner;
  cbStopBits->Left=X+120;
  cbStopBits->Top=lStopBits->Top-2;
  cbStopBits->Style=csDropDownList;
  cbStopBits->Items->AddObject("1",(TObject*)sb10);
  cbStopBits->Items->AddObject("2",(TObject*)sb20);

  Update();
  cbBaudRate->OnChange=Change;
  cbByteSize->OnChange=Change;
  cbParity->OnChange=Change;
  cbStopBits->OnChange=Change;
  Serial->ConfigPanel=this;
}
//---------------------------------------------------------------------------
void __fastcall TConfigPanel::Update()
{
  cbBaudRate->ItemIndex=
    cbBaudRate->Items->IndexOf(Serial->BaudRate);
  cbByteSize->ItemIndex=
    cbByteSize->Items->IndexOf(Serial->ByteSize);
  cbParity->ItemIndex=
    cbParity->Items->IndexOfObject(
      (TObject*)Serial->Parity);
  cbStopBits->ItemIndex=
    cbStopBits->Items->IndexOfObject(
      (TObject*)Serial->StopBits);
}
//---------------------------------------------------------------------------
void __fastcall TConfigPanel::SaveChanges(bool Save)
{
  if(Save){
    Serial->BaudRate=(TBaudRate)
      cbBaudRate->Items->Strings
        [cbBaudRate->ItemIndex].ToInt();
    Serial->ByteSize=(TByteSize)
      cbByteSize->Items->Strings
        [cbByteSize->ItemIndex].ToInt();
    Serial->Parity=(TParity)
      cbParity->Items->Objects
        [cbParity->ItemIndex];
    Serial->StopBits=(TStopBits)
      cbStopBits->Items->Objects
        [cbStopBits->ItemIndex];
  }
}
//---------------------------------------------------------------------------
void __fastcall TConfigPanel::Change(TObject *Sender)
{
  if(FAutoSet){
    Serial->ConfigPanel=NULL;
    SaveChanges(true);
    Update();
    Serial->ConfigPanel=this;
  }  
}
//---------------------------------------------------------------------------
__fastcall TConfigPanel::~TConfigPanel()
{
  Serial->ConfigPanel=NULL;

  delete(cbBaudRate);
  delete(cbByteSize);
  delete(cbParity);
  delete(cbStopBits);
  delete(lBaudRate);
  delete(lByteSize);
  delete(lParity);
  delete(lStopBits);
}
//---------------------------------------------------------------------------
