mmtty/ctnc.cpp
2013-07-05 15:00:12 -05:00

703 lines
20 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//Copyright+LGPL
//-----------------------------------------------------------------------------------------------------------------------------------------------
// Copyright 2000-2013 Makoto Mori, Nobuyuki Oba
//-----------------------------------------------------------------------------------------------------------------------------------------------
// This file is part of MMTTY.
// MMTTY is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License
// as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
// MMTTY is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
// You should have received a copy of the GNU Lesser General Public License along with MMTTY. If not, see
// <http://www.gnu.org/licenses/>.
//-----------------------------------------------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------
#include <vcl.h>
#pragma hdrstop
#include "Ctnc.h"
#include "ComLib.h"
#define WAITSTAT 0
CTNCPARA TNC;
void InitTNCPara(void)
{
strcpy(TNC.StrPort, "NONE"); // ポートの名前
TNC.BaudRate = 1200; // ボーレート
TNC.BitLen = 1; // 0-7Bit, 1-8Bit
TNC.Stop = 0; // 0-1Bit, 1-2Bit
TNC.Parity = 0; // 0-PN, 1-PE, 2-PO
TNC.flwXON = 1; // Xon/Xoff ON
TNC.flwCTS = 0; // CTS-RTS ON
TNC.Echo = 2;
TNC.Type = (lcid != LANG_JAPANESE) ? 1 : 0; // 0-TNC241, 1-KAM
TNC.TncMode = 1; // Command mode
TNC.change = 1;
}
void LoadTNCSetup(TMemIniFile *pIniFile)
{
AnsiString as = TNC.StrPort;
as = pIniFile->ReadString("TNC", "PortName", as);
StrCopy(TNC.StrPort, as.c_str(), 31);
TNC.Type = pIniFile->ReadInteger("TNC", "Type", TNC.Type);
TNC.BaudRate = pIniFile->ReadInteger("TNC", "BaudRate", TNC.BaudRate);
TNC.BitLen = pIniFile->ReadInteger("TNC", "BitLen", TNC.BitLen);
TNC.Stop = pIniFile->ReadInteger("TNC", "Stop", TNC.Stop);
TNC.Parity = pIniFile->ReadInteger("TNC", "Parity", TNC.Parity);
TNC.flwXON = pIniFile->ReadInteger("TNC", "flwXON", TNC.flwXON);
TNC.flwCTS = pIniFile->ReadInteger("TNC", "flwCTS", TNC.flwCTS);
TNC.Echo = pIniFile->ReadInteger("TNC", "Echo", TNC.Echo);
}
void SaveTNCSetup(TMemIniFile *pIniFile)
{
pIniFile->WriteString("TNC", "PortName", TNC.StrPort);
pIniFile->WriteInteger("TNC", "Type", TNC.Type);
pIniFile->WriteInteger("TNC", "BaudRate", TNC.BaudRate);
pIniFile->WriteInteger("TNC", "BitLen", TNC.BitLen);
pIniFile->WriteInteger("TNC", "Stop", TNC.Stop);
pIniFile->WriteInteger("TNC", "Parity", TNC.Parity);
pIniFile->WriteInteger("TNC", "flwXON", TNC.flwXON);
pIniFile->WriteInteger("TNC", "flwCTS", TNC.flwCTS);
pIniFile->WriteInteger("TNC", "Echo", TNC.Echo);
}
//---------------------------------------------------------------------------
// 注意: VCL オブジェクトのメソッドとプロパティを使用するには, Synchronize
// を使ったメソッド呼び出しでなければなりません。次に例を示します。
//
// Synchronize(UpdateCaption);
//
// ここで, UpdateCaption は次のように記述できます。
//
// void __fastcall CCtnc::UpdateCaption()
// {
// Form1->Caption = "スレッドから書き換えました";
// }
//---------------------------------------------------------------------------
__fastcall CCtnc::CCtnc(bool CreateSuspended)
: TThread(CreateSuspended)
{
m_CreateON = FALSE; // クリエイトフラグ
m_fHnd = NULL; // ファイルハンドル
m_wHnd = NULL; // 親のウインドウハンドル
m_ID = 0; // メッセージのID番号
m_Command = 0; // スレッドへのコマンド
m_TxAbort = 0; // 送信中止フラグ
ClearTxFifo();
ClearRxFifo();
m_timeout = 200;
m_pMMT = NULL;
}
//---------------------------------------------------------------------------
void __fastcall CCtnc::ClearRxFifo(void)
{
m_rxwp = m_rxrp = m_rxcnt = 0;
}
//---------------------------------------------------------------------------
void __fastcall CCtnc::ClearTxFifo(void)
{
m_txwp = m_txrp = m_txcnt = 0;
}
//---------------------------------------------------------------------------
const BYTE tbl[]={
0x00, 0x10, 0x08, 0x18, // 00000 10000 01000 11000
0x04, 0x14, 0x0c, 0x1c, // 00100 10100 01100 11100
0x02, 0x12, 0x0a, 0x1a, // 00010 10010 01010 11010
0x06, 0x16, 0x0e, 0x1e, // 00110 10110 01110 11110
0x01, 0x11, 0x09, 0x19, // 00001 10001 01001 11001
0x05, 0x15, 0x0d, 0x1d, // 00101 10101 01101 11101
0x03, 0x13, 0x0b, 0x1b, // 00011 10011 01011 11011
0x07, 0x17, 0x0f, 0x1f, // 00111 10111 01111 11111
};
//---------------------------------------------------------------------------
BOOL __fastcall CCtnc::PutRxFifo(BYTE c)
{
if( m_rxcnt >= TNC_RXBUFSIZE ) return FALSE;
if( (TNC.Type == 2) && (cm.BitLen <= 6) ){
if( m_pMMT && (c >= 0x20) ){
m_rxbuf[m_rxwp] = c;
}
else {
m_rxbuf[m_rxwp] = tbl[c&0x1f];
}
}
else {
m_rxbuf[m_rxwp] = c;
}
m_rxwp++;
if( m_rxwp >= (int)sizeof(m_rxbuf) ) m_rxwp = 0; //JA7UDE 0428
m_rxcnt++;
return TRUE;
}
//---------------------------------------------------------------------------
void __fastcall CCtnc::Execute()
{
//---- スレッドのコードをここに記述 ----
// Priority = tpLower;
if( TNC.Type == 2 ){
m_PTT = GetPTT();
}
while(1){
if( Terminated == TRUE ){
return;
}
if( m_Command == CTNC_CLOSE ){
m_Command = 0;
return;
}
if( m_CreateON == TRUE ){
if( m_txcnt ){
if( !TxBusy() ){
BYTE d = m_txbuf[m_txrp];
if( TNC.Type == 2 && (cm.BitLen <= 6) ){
d = tbl[d & 0x1f];
}
if( IOPutChar(d) ){
m_txrp++;
if( m_txrp >= TNC_TXBUFSIZE ){
m_txrp = 0;
}
m_txcnt--;
}
}
::Sleep(1);
}
else if( m_rxcnt < (TNC_RXBUFSIZE/2) ){
int len = RecvLen();
if( len ){
BYTE bf[256];
if( len >= (int)sizeof(bf) ) len = sizeof(bf);
if( len && (m_rxcnt < int(sizeof(m_rxbuf) - len)) ){
int size = IORead(bf, len);
for( int i = 0; i < size; i++ ){
PutRxFifo(bf[i]);
}
if( m_wHnd != NULL ){
PostMessage( m_wHnd, m_ID, MMTMSG_NULL, 0);
}
}
}
::Sleep(((TNC.Type != 2) || m_pMMT) ? 10 : 1);
}
else {
::Sleep(10);
}
if( (TNC.Type == 2) && !m_pMMT ){
BOOL tx = GetPTT();
if( (tx != m_PTT) && (tx || !m_rxcnt) ){
m_PTT = tx;
PostMessage(m_wHnd, m_ID, MMTMSG_NULL, 0);
}
::Sleep(1);
}
}
else {
::Sleep(20);
}
}
}
//---------------------------------------------------------------------------
/*#$%
==============================================================
通信回線をオープンしスレッドをアクティブにする
--------------------------------------------------------------
PortName : 回線の名前
pCP : COMMPARAのポインタヌルの時はデフォルトで初期化
pWnd : メッセージ送信先のウインドウクラスのポインタ(ヌルの時はメインフレームウインドウ)
nID : データ受信時のメッセージID
RBufSize : 受信バッファのサイズ(default=2048)
TBufSize : 送信バッファのサイズ(default=2048)
--------------------------------------------------------------
TRUE/FALSE
--------------------------------------------------------------
==============================================================
*/
BOOL __fastcall CCtnc::Open(CTNCPARA *cp, HWND hwnd, UINT nID, COMMPARA *pp)
{
if( m_CreateON == TRUE ) Close();
m_TxAbort = FALSE;
m_wHnd = hwnd;
m_ID = nID;
m_fHnd = ::CreateFile(cp->StrPort, GENERIC_READ | GENERIC_WRITE,
0, NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if( m_fHnd == INVALID_HANDLE_VALUE ) goto _mmt;
// setup device buffers
if( ::SetupComm( m_fHnd, DWORD(TNC_COMBUFSIZE), DWORD(TNC_COMBUFSIZE) ) == FALSE ){
::CloseHandle(m_fHnd);
_mmt:;
m_pMMT = new CMMTnc;
if( m_pMMT->Open(cp->StrPort, m_wHnd, m_ID) ){
m_CreateON = TRUE;
Priority = tpLower;
Resume(); // スレッドの実行
return TRUE;
}
else {
delete m_pMMT;
m_pMMT = NULL;
return FALSE;
}
}
// purge any information in the buffer
::PurgeComm( m_fHnd, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR );
// set up for overlapped I/O
COMMTIMEOUTS TimeOut;
TimeOut.ReadIntervalTimeout = 0xffffffff;
TimeOut.ReadTotalTimeoutMultiplier = 0;
TimeOut.ReadTotalTimeoutConstant = 0;
TimeOut.WriteTotalTimeoutMultiplier = 0;
TimeOut.WriteTotalTimeoutConstant = 20000;
// TimeOut.WriteTotalTimeoutConstant = 1;
if( !::SetCommTimeouts( m_fHnd, &TimeOut ) ){
::CloseHandle( m_fHnd );
return FALSE;
}
::GetCommState( m_fHnd, &m_dcb );
m_dcb.fBinary = TRUE;
const UCHAR _tp[]={NOPARITY, EVENPARITY, ODDPARITY};
const UCHAR _ts[]={ONESTOPBIT,TWOSTOPBITS};
if( TNC.Type == 2 ){
memcpy(&cm, pp, sizeof(cm));
m_dcb.BaudRate = pp->Baud;
m_dcb.ByteSize = WORD(pp->BitLen);
m_dcb.Parity = WORD(pp->Parity);
m_dcb.StopBits = WORD(pp->Stop);
m_dcb.fOutxCtsFlow = FALSE;
m_dcb.fInX = m_dcb.fOutX = FALSE;
}
else {
m_dcb.BaudRate = cp->BaudRate;
m_dcb.ByteSize = USHORT(cp->BitLen ? 8 : 7);
m_dcb.Parity = _tp[cp->Parity];
m_dcb.StopBits = _ts[cp->Stop];
m_dcb.fOutxCtsFlow = cp->flwCTS ? TRUE : FALSE;
m_dcb.fInX = m_dcb.fOutX = cp->flwXON ? TRUE : FALSE;
}
m_dcb.fRtsControl = RTS_CONTROL_ENABLE;
m_dcb.XonChar = 0x11;
m_dcb.XoffChar = 0x13;
m_dcb.fParity = FALSE;
m_dcb.EvtChar = 0x00; // dummy setting
// m_dcb.fTXContinueOnXoff = TRUE;
m_dcb.XonLim = USHORT(TNC_COMBUFSIZE/4); // 1/4 of RBufSize
m_dcb.XoffLim = USHORT(TNC_COMBUFSIZE*3/4); // 3/4 of RBufSize
m_dcb.DCBlength = sizeof( DCB );
if( !::SetCommState( m_fHnd, &m_dcb ) ){
::CloseHandle( m_fHnd );
return FALSE;
}
// get any early notifications
if( !::SetCommMask( m_fHnd, EV_RXFLAG ) ){
::CloseHandle(m_fHnd);
return FALSE;
}
m_CreateON = TRUE;
Priority = tpLower;
Resume(); // スレッドの実行
return TRUE;
}
/*#$%
==============================================================
通信回線をクローズする
--------------------------------------------------------------
--------------------------------------------------------------
--------------------------------------------------------------
スレッドが終了するまで待つ
==============================================================
*/
void __fastcall CCtnc::Close(void)
{
if( m_CreateON == TRUE ){
if( m_ID ){
m_Command = CTNC_CLOSE; // スレッド終了コマンド
Priority = tpNormal; //スレッドは通常の優先度である
WaitFor();
}
if( m_pMMT ){
delete m_pMMT;
m_pMMT = NULL;
}
else {
::CloseHandle(m_fHnd);
}
m_CreateON = FALSE;
}
m_TxAbort = TRUE;
}
void __fastcall CCtnc::ReqClose(void)
{
if( m_CreateON == TRUE ){
if( m_ID ){
m_Command = CTNC_CLOSE; // スレッド終了コマンド
Priority = tpNormal; //スレッドは通常の優先度である
}
}
}
void __fastcall CCtnc::WaitClose(void)
{
if( m_CreateON == TRUE ){
if( m_ID && m_Command ){
WaitFor();
}
if( m_pMMT ){
delete m_pMMT;
m_pMMT = NULL;
}
else {
::CloseHandle(m_fHnd);
}
m_CreateON = FALSE;
}
m_TxAbort = TRUE;
}
//----------------------------------------------------------------------
BOOL __fastcall CCtnc::GetPTT(void)
{
DWORD d = 0;
BOOL tx = FALSE;
if( !m_pMMT ){
if( ::GetCommModemStatus(m_fHnd, &d) ){
tx = (d & MS_CTS_ON) != 0;
}
}
return tx;
}
/*#$%
==============================================================
受信バッファ内の格納データ長を得る
--------------------------------------------------------------
--------------------------------------------------------------
データの長さ
--------------------------------------------------------------
==============================================================
*/
DWORD __fastcall CCtnc::RecvLen(void)
{
if( m_pMMT ){
return m_pMMT->GetRxLen();
}
else {
COMSTAT ComStat;
DWORD dwErrorFlags;
::ClearCommError( m_fHnd, &dwErrorFlags, &ComStat );
return ComStat.cbInQue;
}
}
/*#$%
==============================================================
送信ビジーかどうか調べる
--------------------------------------------------------------
--------------------------------------------------------------
TRUE : 送信ビジー状態
--------------------------------------------------------------
==============================================================
*/
int __fastcall CCtnc::TxBusy(void)
{
if( m_pMMT ){
return m_pMMT->IsTxBusy();
}
else {
COMSTAT ComStat;
DWORD dwErrorFlags;
::ClearCommError( m_fHnd, &dwErrorFlags, &ComStat );
return ComStat.cbOutQue;
}
}
/*#$%
==============================================================
通信回線からデータを取り出す
--------------------------------------------------------------
p : バッファのポインタ
len : バッファのサイズ
--------------------------------------------------------------
実際に受信したサイズ
--------------------------------------------------------------
==============================================================
*/
int __fastcall CCtnc::IORead(BYTE *p, DWORD len)
{
DWORD size=0;
if( m_CreateON == TRUE ){
if( m_pMMT ){
for( ; len; len--, size++ ){
*p++ = m_pMMT->GetChar();
}
}
else {
::ReadFile( m_fHnd, p, len, &size, NULL );
}
}
return size;
}
int __fastcall CCtnc::IOPutChar(BYTE c)
{
DWORD size=0;
if( m_CreateON == TRUE ){
if( m_pMMT ){
m_pMMT->PutChar(c);
size = 1;
}
else {
::WriteFile( m_fHnd, &c, 1, &size, NULL );
}
}
return size;
}
/*#$%
==============================================================
通信回線にデータを送信する
--------------------------------------------------------------
--------------------------------------------------------------
--------------------------------------------------------------
==============================================================
*/
void __fastcall CCtnc::PutChar(char c)
{
if( m_CreateON == TRUE ){
if( m_txcnt < TNC_TXBUFSIZE ){
m_txbuf[m_txwp] = c;
m_txwp++;
if( m_txwp >= TNC_TXBUFSIZE ) m_txwp = 0;
m_txcnt++;
}
}
}
/*#$%
==============================================================
通信回線にデータを送信する
--------------------------------------------------------------
p : バッファのポインタ
len : 送信するサイズ
--------------------------------------------------------------
実際に送信したサイズ
--------------------------------------------------------------
==============================================================
*/
void __fastcall CCtnc::Write(void *s, DWORD len)
{
if( m_CreateON == TRUE ){
char *p;
for( p = (char *)s; len; len--, p++ ){
PutChar(*p);
}
}
}
/*#$%
==============================================================
通信回線にデータを送信する
--------------------------------------------------------------
p : バッファのポインタ
len : 送信するサイズ
--------------------------------------------------------------
実際に送信したサイズ
--------------------------------------------------------------
==============================================================
*/
void CCtnc::OutStr(LPCSTR fmt, ...)
{
va_list pp;
char bf[1024];
va_start(pp, fmt);
vsprintf( bf, fmt, pp );
va_end(pp);
Write(bf, strlen(bf));
}
void CCtnc::OutLine(LPCSTR fmt, ...)
{
va_list pp;
char bf[1024];
va_start(pp, fmt);
vsprintf( bf, fmt, pp );
va_end(pp);
Write(bf, strlen(bf));
char r[] = "\r";
Write( r, 1 );
//Write("\r", 1);
}
//---------------------------------------------------------------------------
void __fastcall CCtnc::SetPTT(int tx)
{
if( m_pMMT ) m_pMMT->SetPTT(tx);
}
//---------------------------------------------------------------------------
void __fastcall CCtnc::NotifyFreq(LONG mark, LONG space)
{
if( m_pMMT ){
m_pMMT->m_NMMT.m_markfreq = mark;
m_pMMT->m_NMMT.m_spacefreq = space;
}
}
//---------------------------------------------------------------------------
void __fastcall CCtnc::NotifyLevel(LONG sq, LONG lvl)
{
if( m_pMMT ){
m_pMMT->m_NMMT.m_sqlevel = sq;
m_pMMT->m_NMMT.m_siglevel = lvl;
}
}
//==============================================================================
// CMMTnc カスタムTNCエミュレーション
//==============================================================================
//---------------------------------------------------------------------------
__fastcall CMMTnc::CMMTnc(void)
{
m_hLib = NULL;
memset(&m_NMMT, 0, sizeof(m_NMMT));
m_NMMT.m_sampfreq = SampFreq;
m_NMMT.m_demfreq = DemSamp;
m_QueryResult = 0;
}
//---------------------------------------------------------------------------
__fastcall CMMTnc::~CMMTnc()
{
Close();
}
//---------------------------------------------------------------------------
void __fastcall CMMTnc::FreeLib(void)
{
if( m_hLib ){
FreeLibrary(m_hLib);
m_hLib = NULL;
}
}
//---------------------------------------------------------------------------
FARPROC __fastcall CMMTnc::GetProc(LPCSTR pName)
{
if( !m_hLib ) return NULL;
FARPROC fn = ::GetProcAddress(m_hLib, pName+1);
if( fn == NULL ){
fn = ::GetProcAddress(m_hLib, pName);
if( fn == NULL ) FreeLib();
}
return fn;
}
//---------------------------------------------------------------------------
void __fastcall CMMTnc::Close(void)
{
if( IsLib() ){
fmmtClose();
FreeLib();
}
}
//---------------------------------------------------------------------------
BOOL __fastcall CMMTnc::Open(LPCSTR pItemName, HWND hWnd, UINT uMsg)
{
Close();
m_ItemName = pItemName;
char LibName[MAX_PATH];
if( !*GetEXT(pItemName) ){
sprintf(LibName, "%s.mmt", pItemName);
pItemName = LibName;
}
m_hLib = ::LoadLibrary(pItemName);
if( m_hLib ){
fmmtQueryTnc = PROC(mmtQueryTnc);
fmmtOpen = PROC(mmtOpen);
fmmtClose = PROC(mmtClose);
fmmtSetPTT = PROC(mmtSetPTT);
fmmtPutChar = PROC(mmtPutChar);
fmmtGetChar = PROC(mmtGetChar);
fmmtIsTxBusy = PROC(mmtIsTxBusy);
fmmtGetRxLen = PROC(mmtGetRxLen);
fmmtNotify = PROC(mmtNotify);
fmmtNotifyFFT = PROC(mmtNotifyFFT);
fmmtNotifyXY = PROC(mmtNotifyXY);
if( m_hLib ){
m_QueryResult = fmmtQueryTnc((LPLONG)&TNC.Type, (LPLONG)&TNC.Echo);
if( !fmmtOpen(hWnd, uMsg, TNC.Type) ){
FreeLib();
}
}
}
return IsLib();
}
//---------------------------------------------------------------------------
void __fastcall CMMTnc::SetPTT(int ptt)
{
if( !IsLib() ) return;
fmmtSetPTT(ptt);
}
//---------------------------------------------------------------------------
void __fastcall CMMTnc::PutChar(BYTE c)
{
if( !IsLib() ) return;
fmmtPutChar(c);
}
//---------------------------------------------------------------------------
BYTE __fastcall CMMTnc::GetChar(void)
{
if( !IsLib() ) return 0;
return fmmtGetChar();
}
//---------------------------------------------------------------------------
BOOL __fastcall CMMTnc::IsTxBusy(void)
{
if( !IsLib() ) return FALSE;
return fmmtIsTxBusy();
}
//---------------------------------------------------------------------------
LONG __fastcall CMMTnc::GetRxLen(void)
{
if( !IsLib() ) return 0;
return fmmtGetRxLen();
}
//---------------------------------------------------------------------------
void __fastcall CMMTnc::Notify(void)
{
if( !IsLib() ) return;
if( m_QueryResult & ntNOTIFY ) fmmtNotify(&m_NMMT);
}
//---------------------------------------------------------------------------
void __fastcall CMMTnc::NotifyFFT(const int *pFFT)
{
if( !IsLib() ) return;
if( m_QueryResult & ntNOTIFYFFT ) fmmtNotifyFFT(pFFT, FFT_SIZE, SampFreq);
}
//---------------------------------------------------------------------------
void __fastcall CMMTnc::NotifyXY(const double *pX, const double *pY)
{
if( !IsLib() ) return;
if( !(m_QueryResult & ntNOTIFYXY) ) return;
LPLONG px = m_XY;
LPLONG py = &m_XY[XYCOLLECT];
for( int i = 0; i < XYCOLLECT; i++ ){
*px++ = LONG(*pX++);
*py++ = LONG(*pY++);
}
fmmtNotifyXY(m_XY);
}
//---------------------------------------------------------------------------