mirror of
https://github.com/n5ac/mmvari.git
synced 2025-12-06 04:12:03 +01:00
458 lines
12 KiB
C++
458 lines
12 KiB
C++
//---------------------------------------------------------------------------
|
||
#include <vcl.h>
|
||
#pragma hdrstop
|
||
|
||
#include "Main.h"
|
||
SYS sys;
|
||
//---------------------------------------------------------------------------
|
||
#pragma package(smart_init)
|
||
#pragma resource "*.dfm"
|
||
//---------------------------------------------------------------------------
|
||
void __fastcall SetDirName(LPSTR t, LPCSTR pName)
|
||
{
|
||
char drive[_MAX_DRIVE];
|
||
char dir[_MAX_DIR];
|
||
char name[_MAX_FNAME];
|
||
char ext[_MAX_EXT];
|
||
AnsiString Dir;
|
||
|
||
::_splitpath( pName, drive, dir, name, ext );
|
||
Dir = drive;
|
||
Dir += dir;
|
||
strncpy(t, Dir.c_str(), MAX_PATH-1);
|
||
}
|
||
//---------------------------------------------------------------------------
|
||
void __fastcall SetEXT(LPSTR t, LPCSTR pExt)
|
||
{
|
||
LPSTR p = LASTP(t);
|
||
for( ; p > t; p-- ){
|
||
if( *p == '.' ){
|
||
p++;
|
||
strcpy(p, pExt);
|
||
return;
|
||
}
|
||
}
|
||
}
|
||
//***************************************************************************
|
||
// TExtFSK (MainWindow) class
|
||
//---------------------------------------------------------------------------
|
||
__fastcall TComFSK::TComFSK(TComponent* Owner)
|
||
: TForm(Owner)
|
||
{
|
||
m_DisEvent = 1;
|
||
m_Left = 0;
|
||
m_Top = 0;
|
||
m_hPort = INVALID_HANDLE_VALUE;
|
||
m_X = 0;
|
||
m_Para = 45 << 16;
|
||
|
||
m_fMsg = TRUE;
|
||
m_fCheckError = FALSE;
|
||
m_fLimitSpeed = FALSE;
|
||
m_LimitMargin = 3;
|
||
|
||
m_strIniName = sys.m_ModuleName;
|
||
SetEXT(m_strIniName.c_str(), "ini");
|
||
PortName->ItemIndex = 0;
|
||
|
||
char drive[_MAX_DRIVE];
|
||
char dir[_MAX_DIR];
|
||
char name[_MAX_FNAME];
|
||
char ext[_MAX_EXT];
|
||
|
||
::_splitpath( sys.m_ModuleName, drive, dir, name, ext );
|
||
strupr(name);
|
||
AnsiString as = name;
|
||
as += " "VERNO;
|
||
Caption = as;
|
||
|
||
ReadIniFile();
|
||
|
||
CBERR->Checked = m_fCheckError;
|
||
CBLMT->Checked = m_fLimitSpeed;
|
||
|
||
Left = m_Left;
|
||
Top = m_Top;
|
||
WindowState = TWindowState(m_WindowState);
|
||
m_DisEvent = 0;
|
||
}
|
||
//---------------------------------------------------------------------------
|
||
// para: Upper16bits Speed(eg. 45)
|
||
// Lower16bits b1-b0 Stop (0-1, 1-1.5, 2-2)
|
||
// b5-b2 Length
|
||
void __fastcall TComFSK::SetPara(LONG para)
|
||
{
|
||
m_Para = para;
|
||
AnsiString as = int(para >> 16);
|
||
as += " baud";
|
||
LB->Caption = as;
|
||
OpenPort();
|
||
}
|
||
//---------------------------------------------------------------------------
|
||
void __fastcall TComFSK::FormClose(TObject *Sender, TCloseAction &Action)
|
||
{
|
||
m_WindowState = WindowState;
|
||
if( m_WindowState == wsNormal ){
|
||
m_Left = Left;
|
||
m_Top = Top;
|
||
}
|
||
|
||
if( IsOpen() && m_ptt ){
|
||
SetPTT(FALSE, FALSE);
|
||
}
|
||
|
||
ClosePort();
|
||
WriteIniFile();
|
||
}
|
||
//---------------------------------------------------------------------------
|
||
void __fastcall TComFSK::ReadIniFile(void)
|
||
{
|
||
TMemIniFile *pIniFile = new TMemIniFile(m_strIniName);
|
||
|
||
m_Top = pIniFile->ReadInteger("Window", "Top", m_Top);
|
||
m_Left = pIniFile->ReadInteger("Window", "Left", m_Left);
|
||
if( m_Top < 0 ) m_Top = 0;
|
||
if( m_Left < 0 ) m_Left = 0;
|
||
|
||
m_WindowState = (TWindowState)pIniFile->ReadInteger("Window", "State", WindowState);
|
||
|
||
AnsiString as = pIniFile->ReadString("Settings", "Port", "COM1");
|
||
int n = PortName->Items->IndexOf(as);
|
||
if( n < 0 ){
|
||
n = atoi(as.c_str());
|
||
if( n < 0 ) n = 0;
|
||
}
|
||
PortName->ItemIndex = n;
|
||
RGPTT->ItemIndex = pIniFile->ReadInteger("Settings", "PTT", RGPTT->ItemIndex);
|
||
RGSTOP->ItemIndex = pIniFile->ReadInteger("Settings", "STOP", RGSTOP->ItemIndex);
|
||
CBInvPTT->Checked = pIniFile->ReadInteger("Settings", "InvPTT", CBInvPTT->Checked);
|
||
m_fCheckError = pIniFile->ReadInteger("Settings", "CheckError", m_fCheckError);
|
||
m_fLimitSpeed = pIniFile->ReadInteger("Settings", "LimitSpeed", m_fLimitSpeed);
|
||
m_LimitMargin = pIniFile->ReadInteger("Settings", "LimitMargin", m_LimitMargin);
|
||
int ver = pIniFile->ReadInteger("Settings", "VER", 0);
|
||
if( ver < VERINI ) RGSTOP->ItemIndex = 1;
|
||
delete pIniFile;
|
||
}
|
||
//---------------------------------------------------------------------------
|
||
void __fastcall TComFSK::WriteIniFile(void)
|
||
{
|
||
TMemIniFile *pIniFile = new TMemIniFile(m_strIniName);
|
||
pIniFile->WriteInteger("Window", "Top", m_Top);
|
||
pIniFile->WriteInteger("Window", "Left", m_Left);
|
||
pIniFile->WriteInteger("Window", "State", WindowState);
|
||
pIniFile->WriteInteger("Settings", "VER", VERINI);
|
||
pIniFile->WriteString("Settings", "Port", PortName->Items->Strings[PortName->ItemIndex]);
|
||
pIniFile->WriteInteger("Settings", "PTT", RGPTT->ItemIndex);
|
||
pIniFile->WriteInteger("Settings", "InvPTT", CBInvPTT->Checked);
|
||
pIniFile->WriteInteger("Settings", "STOP", RGSTOP->ItemIndex);
|
||
pIniFile->WriteInteger("Settings", "CheckError", m_fCheckError);
|
||
pIniFile->WriteInteger("Settings", "LimitSpeed", m_fLimitSpeed);
|
||
pIniFile->WriteInteger("Settings", "LimitMargin", m_LimitMargin);
|
||
pIniFile->UpdateFile();
|
||
delete pIniFile;
|
||
}
|
||
//---------------------------------------------------------------------------
|
||
void __fastcall TComFSK::UpdateComStat(void)
|
||
{
|
||
char bf[128];
|
||
|
||
wsprintf(bf, "Status:%s", m_hPort != INVALID_HANDLE_VALUE ? "OK" : "NG");
|
||
LComStat->Color = m_hPort != INVALID_HANDLE_VALUE ? clBtnFace : clRed;
|
||
LComStat->Caption = bf;
|
||
}
|
||
//---------------------------------------------------------------------------
|
||
void __fastcall TComFSK::OpenPort(void)
|
||
{
|
||
ClosePort();
|
||
OpenPort_();
|
||
UpdateComStat();
|
||
SetPTT(FALSE, FALSE);
|
||
}
|
||
//---------------------------------------------------------------------------
|
||
BOOL __fastcall TComFSK::OpenPort_(void)
|
||
{
|
||
AnsiString pname = PortName->Items->Strings[PortName->ItemIndex];
|
||
|
||
m_hPort = ::CreateFile( pname.c_str(),
|
||
GENERIC_READ | GENERIC_WRITE,
|
||
0, NULL,
|
||
OPEN_EXISTING,
|
||
FILE_ATTRIBUTE_NORMAL,
|
||
NULL
|
||
);
|
||
if( m_hPort == INVALID_HANDLE_VALUE ){
|
||
AnsiString as = "\\\\.\\";
|
||
as += pname;
|
||
m_hPort = ::CreateFile( as.c_str(),
|
||
GENERIC_READ | GENERIC_WRITE,
|
||
0, NULL,
|
||
OPEN_EXISTING,
|
||
FILE_ATTRIBUTE_NORMAL,
|
||
NULL
|
||
);
|
||
}
|
||
if( m_hPort == INVALID_HANDLE_VALUE ) return FALSE;
|
||
|
||
if( ::SetupComm( m_hPort, DWORD(256), DWORD(2) ) == FALSE ){
|
||
::CloseHandle(m_hPort);
|
||
m_hPort = INVALID_HANDLE_VALUE;
|
||
return FALSE;
|
||
}
|
||
::PurgeComm( m_hPort, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR );
|
||
|
||
COMMTIMEOUTS TimeOut;
|
||
|
||
TimeOut.ReadIntervalTimeout = 0xffffffff;
|
||
TimeOut.ReadTotalTimeoutMultiplier = 0;
|
||
TimeOut.ReadTotalTimeoutConstant = 0;
|
||
TimeOut.WriteTotalTimeoutMultiplier = 0;
|
||
TimeOut.WriteTotalTimeoutConstant = 1000;
|
||
if( !::SetCommTimeouts( m_hPort, &TimeOut ) ){
|
||
::CloseHandle( m_hPort );
|
||
m_hPort = INVALID_HANDLE_VALUE;
|
||
return FALSE;
|
||
}
|
||
|
||
::GetCommState( m_hPort, &m_dcb );
|
||
m_dcb.fBinary = TRUE;
|
||
m_dcb.BaudRate = m_Para >> 16; // BAUD
|
||
m_dcb.ByteSize = 5; // 5 bits length
|
||
m_dcb.StopBits = BYTE(RGSTOP->ItemIndex);
|
||
m_dcb.Parity = NOPARITY;
|
||
m_dcb.XonChar = 0x11; // XON
|
||
m_dcb.XoffChar = 0x13; // XOFF
|
||
m_dcb.fParity = 0;
|
||
m_dcb.fOutxCtsFlow = FALSE;
|
||
m_dcb.fInX = m_dcb.fOutX = FALSE;
|
||
m_dcb.fOutxDsrFlow = FALSE;
|
||
m_dcb.EvtChar = 0x0d;
|
||
m_dcb.fRtsControl = RTS_CONTROL_DISABLE;
|
||
m_dcb.fDtrControl = DTR_CONTROL_DISABLE;
|
||
m_dcb.fTXContinueOnXoff = FALSE;
|
||
m_dcb.XonLim = USHORT(256/4);
|
||
m_dcb.XoffLim = USHORT(256*3/4);
|
||
m_dcb.DCBlength = sizeof( DCB );
|
||
|
||
if( !::SetCommState( m_hPort, &m_dcb ) ){
|
||
::CloseHandle( m_hPort );
|
||
m_hPort = INVALID_HANDLE_VALUE;
|
||
return FALSE;
|
||
}
|
||
|
||
if( !::SetCommMask( m_hPort, EV_RXFLAG ) ){
|
||
::CloseHandle(m_hPort);
|
||
m_hPort = INVALID_HANDLE_VALUE;
|
||
return FALSE;
|
||
}
|
||
return TRUE;
|
||
}
|
||
//---------------------------------------------------------------------------
|
||
void __fastcall TComFSK::ClosePort(void)
|
||
{
|
||
DeleteMMTimer();
|
||
if( IsOpen() ){
|
||
::CloseHandle(m_hPort);
|
||
m_hPort = INVALID_HANDLE_VALUE;
|
||
}
|
||
UpdateComStat();
|
||
}
|
||
//---------------------------------------------------------------------------
|
||
void __fastcall TComFSK::SetPort(int port, int sw)
|
||
{
|
||
switch(port){
|
||
case ptTXD:
|
||
::EscapeCommFunction(m_hPort, sw ? SETBREAK : CLRBREAK);
|
||
break;
|
||
case ptRTS:
|
||
::EscapeCommFunction(m_hPort, sw ? SETRTS : CLRRTS);
|
||
break;
|
||
case ptDTR:
|
||
::EscapeCommFunction(m_hPort, sw ? SETDTR : CLRDTR);
|
||
break;
|
||
}
|
||
}
|
||
//---------------------------------------------------------------------------
|
||
void __fastcall TComFSK::SetPTT(int sw, int msg)
|
||
{
|
||
m_ptt = sw;
|
||
if( CBInvPTT->Checked ){
|
||
sw = sw ? 0 : 1;
|
||
}
|
||
if( !m_ptt && m_ummTimerID ){
|
||
DeleteMMTimer();
|
||
}
|
||
SetPort(RGPTT->ItemIndex ? ptDTR : ptRTS, sw);
|
||
if( m_ptt ){
|
||
m_dwPending = 0;
|
||
}
|
||
|
||
m_X = 0;
|
||
if( msg ){
|
||
if( WindowState == wsMinimized) return;
|
||
Memo->Lines->Add(m_ptt ? "PTT ON" : "PTT OFF");
|
||
}
|
||
}
|
||
//---------------------------------------------------------------------------
|
||
void CALLBACK mmTimeProc(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
|
||
{
|
||
ASSERT(dwUser);
|
||
|
||
TComFSK *pComm = (TComFSK *)dwUser;
|
||
if( uID != pComm->m_ummTimerID ) return;
|
||
|
||
pComm->DoTimer();
|
||
}
|
||
//-----------------------------------------------------------------
|
||
void __fastcall TComFSK::DoTimer(void)
|
||
{
|
||
if( m_dwPending ){
|
||
if( m_hPort != INVALID_HANDLE_VALUE ){
|
||
::TransmitCommChar(m_hPort, BYTE(m_dwPending & 0x00ff));
|
||
}
|
||
m_dwPending = 0;
|
||
}
|
||
}
|
||
//-----------------------------------------------------------------
|
||
void __fastcall TComFSK::CreateMMTimer(void)
|
||
{
|
||
if( !m_fLimitSpeed ) return;
|
||
|
||
int baud = m_Para >> 16;
|
||
if( baud <= 0 ) return;
|
||
|
||
m_ummTimerID = 0;
|
||
if( ::timeGetDevCaps(&m_TimeCaps, sizeof(m_TimeCaps)) == TIMERR_NOERROR ){
|
||
::timeBeginPeriod(m_TimeCaps.wPeriodMin);
|
||
double dblSymTime = (14 + RGSTOP->ItemIndex) * 500.0 / double(baud);
|
||
double dblLmtTime = dblSymTime + m_LimitMargin;
|
||
int lmttime = int(dblLmtTime + 0.5);
|
||
if( m_fMsg && (WindowState == wsNormal) ){
|
||
char bf[64];
|
||
wsprintf(bf, "S=%d.%02dms, T=%ums", int(dblSymTime), int(dblSymTime * 100.0) % 100, lmttime);
|
||
Memo->Lines->Add(bf);
|
||
}
|
||
m_ummTimerID = ::timeSetEvent(lmttime, 0, mmTimeProc, DWORD(this), TIME_PERIODIC);
|
||
}
|
||
if( !m_ummTimerID ){
|
||
if( m_fMsg ){
|
||
Memo->Lines->Add("MM timer is not supported.");
|
||
}
|
||
}
|
||
m_fMsg = FALSE;
|
||
}
|
||
//-----------------------------------------------------------------
|
||
void __fastcall TComFSK::DeleteMMTimer(void)
|
||
{
|
||
if( m_ummTimerID ){
|
||
::timeKillEvent(m_ummTimerID);
|
||
m_ummTimerID = 0;
|
||
::timeEndPeriod(m_TimeCaps.wPeriodMin);
|
||
}
|
||
}
|
||
//-----------------------------------------------------------------
|
||
// <20><><EFBFBD>M<EFBFBD>r<EFBFBD>W<EFBFBD>[<5B><><EFBFBD>ǂ<EFBFBD><C782><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ׂ<EFBFBD>
|
||
int __fastcall TComFSK::IsBusy(void)
|
||
{
|
||
if( m_ummTimerID ){
|
||
return m_dwPending ? 1 : 0;
|
||
}
|
||
if( IsOpen() ){
|
||
if( m_dwPending ){
|
||
if( TransmitCommChar(m_hPort, BYTE(m_dwPending & 0x00ff)) ){
|
||
m_dwPending = 0;
|
||
}
|
||
return TRUE;
|
||
}
|
||
}
|
||
if( m_fCheckError || m_fLimitSpeed ) return FALSE;
|
||
if( !IsOpen() ) return FALSE;
|
||
|
||
COMSTAT ComStat;
|
||
DWORD dwErrorFlags;
|
||
|
||
ClearCommError(m_hPort, &dwErrorFlags, &ComStat);
|
||
return ComStat.fTxim;
|
||
}
|
||
//---------------------------------------------------------------------------
|
||
void __fastcall TComFSK::PutChar(BYTE c)
|
||
{
|
||
if( !m_ptt ) return;
|
||
|
||
if( m_fLimitSpeed && !m_ummTimerID ) CreateMMTimer();
|
||
|
||
if( m_ummTimerID ){
|
||
m_dwPending = c | 0x8000;
|
||
}
|
||
else if( IsOpen() ){
|
||
if( !TransmitCommChar(m_hPort, c) ){
|
||
if( m_fCheckError ){
|
||
m_dwPending = c | 0x8000;
|
||
}
|
||
}
|
||
}
|
||
if( WindowState == wsMinimized) return;
|
||
|
||
char bf[128];
|
||
if( m_X ){
|
||
int n = Memo->Lines->Count;
|
||
if( n ) n--;
|
||
strcpy(bf, AnsiString(Memo->Lines->Strings[n]).c_str());
|
||
wsprintf(&bf[strlen(bf)], " %02X", c);
|
||
if( !m_ptt ) return;
|
||
Memo->Lines->Strings[n] = bf;
|
||
}
|
||
else {
|
||
wsprintf(bf, "%02X", c);
|
||
Memo->Lines->Add(bf);
|
||
}
|
||
m_X++;
|
||
if( m_X >= 8 ) m_X = 0;
|
||
}
|
||
//---------------------------------------------------------------------------
|
||
void __fastcall TComFSK::PortNameChange(TObject *Sender)
|
||
{
|
||
if( m_DisEvent ) return;
|
||
|
||
OpenPort();
|
||
}
|
||
//---------------------------------------------------------------------------
|
||
void __fastcall TComFSK::SBMinClick(TObject *Sender)
|
||
{
|
||
if( m_DisEvent ) return;
|
||
|
||
if( WindowState == wsNormal ){
|
||
m_Left = Left;
|
||
m_Top = Top;
|
||
}
|
||
|
||
WindowState = wsMinimized;
|
||
m_WindowState = wsMinimized;
|
||
|
||
Memo->Lines->Clear();
|
||
m_X = 0;
|
||
}
|
||
//---------------------------------------------------------------------------
|
||
void __fastcall TComFSK::CBInvPTTClick(TObject *Sender)
|
||
{
|
||
if( m_DisEvent ) return;
|
||
SetPTT(m_ptt, FALSE);
|
||
}
|
||
//---------------------------------------------------------------------------
|
||
void __fastcall TComFSK::CBERRClick(TObject *Sender)
|
||
{
|
||
m_fCheckError = CBERR->Checked;
|
||
}
|
||
//---------------------------------------------------------------------------
|
||
void __fastcall TComFSK::CBLMTClick(TObject *Sender)
|
||
{
|
||
m_fLimitSpeed = CBLMT->Checked;
|
||
if( m_ptt && m_fLimitSpeed ){
|
||
CreateMMTimer();
|
||
}
|
||
else {
|
||
DeleteMMTimer();
|
||
}
|
||
}
|
||
//---------------------------------------------------------------------------
|
||
|