//Copyright+LGPL //----------------------------------------------------------------------------------------------------------------------------------------------- // Copyright 2000-2013 Makoto Mori, Nobuyuki Oba, Dave Bernstein //----------------------------------------------------------------------------------------------------------------------------------------------- // 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 // . //----------------------------------------------------------------------------------------------------------------------------------------------- //--------------------------------------------------------------------------- #include #pragma hdrstop #include "Cradio.h" #include "ComLib.h" #define WAITSTAT 0 CRADIOPARA RADIO; void InitRADIOPara(void) { RADIO.change = 1; strcpy(RADIO.StrPort, "NONE"); // ポートの名前 RADIO.BaudRate = 4800; // ボーレート RADIO.BitLen = 1; // 0-7Bit, 1-8Bit RADIO.Stop = 1; // 0-1Bit, 1-2Bit RADIO.Parity = 0; // 0-PN, 1-PE, 2-PO RADIO.flwXON = 0; // Xon/Xoff ON RADIO.flwCTS = 0; // CTS-RTS ON RADIO.usePTT = 0; RADIO.Cmdxx = 0; RADIO.CmdInit = ""; RADIO.CmdRx = "\\$000000000F"; RADIO.CmdTx = "\\$000000010F\\w10"; RADIO.ByteWait = 0; RADIO.cmdGNR = ""; RADIO.openGNR = 0; RADIO.PollType = 0; RADIO.PollInterval = 5; RADIO.PollOffset = 0; RADIO.PollScan = 0; } void LoadRADIOSetup(TMemIniFile *pIniFile) { AnsiString as = RADIO.StrPort; as = pIniFile->ReadString("RADIO", "PortName", as); StrCopy(RADIO.StrPort, as.c_str(), 31); RADIO.BaudRate = pIniFile->ReadInteger("RADIO", "BaudRate", RADIO.BaudRate); RADIO.BitLen = pIniFile->ReadInteger("RADIO", "BitLen", RADIO.BitLen); RADIO.Stop = pIniFile->ReadInteger("RADIO", "Stop", RADIO.Stop); RADIO.Parity = pIniFile->ReadInteger("RADIO", "Parity", RADIO.Parity); RADIO.flwXON = pIniFile->ReadInteger("RADIO", "flwXON", RADIO.flwXON); RADIO.flwCTS = pIniFile->ReadInteger("RADIO", "flwCTS", RADIO.flwCTS); RADIO.usePTT = pIniFile->ReadInteger("RADIO", "usePTT", RADIO.usePTT); RADIO.ByteWait = pIniFile->ReadInteger("RADIO", "ByteWait", RADIO.ByteWait); RADIO.Cmdxx = pIniFile->ReadInteger("RADIO", "Cmdxx", RADIO.Cmdxx); RADIO.CmdInit = pIniFile->ReadString("RADIO", "CmdInit", RADIO.CmdInit); RADIO.CmdRx = pIniFile->ReadString("RADIO", "CmdRx", RADIO.CmdRx); RADIO.CmdTx = pIniFile->ReadString("RADIO", "CmdTx", RADIO.CmdTx); RADIO.cmdGNR = pIniFile->ReadString("RADIO", "FileGNR", RADIO.cmdGNR); RADIO.openGNR = pIniFile->ReadInteger("RADIO", "OpenGNR", RADIO.openGNR); RADIO.PollType = pIniFile->ReadInteger("RADIO", "PollType", RADIO.PollType); RADIO.PollInterval = pIniFile->ReadInteger("RADIO", "PollInterval", RADIO.PollInterval); RADIO.PollOffset = pIniFile->ReadInteger("RADIO", "PollOffset", RADIO.PollOffset); } void SaveRADIOSetup(TMemIniFile *pIniFile) { pIniFile->WriteString("RADIO", "PortName", RADIO.StrPort); pIniFile->WriteInteger("RADIO", "BaudRate", RADIO.BaudRate); pIniFile->WriteInteger("RADIO", "BitLen", RADIO.BitLen); pIniFile->WriteInteger("RADIO", "Stop", RADIO.Stop); pIniFile->WriteInteger("RADIO", "Parity", RADIO.Parity); pIniFile->WriteInteger("RADIO", "flwXON", RADIO.flwXON); pIniFile->WriteInteger("RADIO", "flwCTS", RADIO.flwCTS); pIniFile->WriteInteger("RADIO", "usePTT", RADIO.usePTT); pIniFile->WriteInteger("RADIO", "ByteWait", RADIO.ByteWait); pIniFile->WriteInteger("RADIO", "Cmdxx", RADIO.Cmdxx); pIniFile->WriteString("RADIO", "CmdInit", RADIO.CmdInit); pIniFile->WriteString("RADIO", "CmdRx", RADIO.CmdRx); pIniFile->WriteString("RADIO", "CmdTx", RADIO.CmdTx); pIniFile->WriteString("RADIO", "FileGNR", RADIO.cmdGNR); pIniFile->WriteInteger("RADIO", "OpenGNR", RADIO.openGNR); pIniFile->WriteInteger("RADIO", "PollType", RADIO.PollType); pIniFile->WriteInteger("RADIO", "PollInterval", RADIO.PollInterval); pIniFile->WriteInteger("RADIO", "PollOffset", RADIO.PollOffset); } //--------------------------------------------------------------------------- // 注意: VCL オブジェクトのメソッドとプロパティを使用するには, Synchronize // を使ったメソッド呼び出しでなければなりません。次に例を示します。 // // Synchronize(UpdateCaption); // // ここで, UpdateCaption は次のように記述できます。 // // void __fastcall CCradio::UpdateCaption() // { // Form1->Caption = "スレッドから書き換えました"; // } //--------------------------------------------------------------------------- __fastcall CCradio::CCradio(bool CreateSuspended) : TThread(CreateSuspended) { m_CreateON = FALSE; // クリエイトフラグ m_fHnd = NULL; // ファイルハンドル m_wHnd = NULL; // 親のウインドウハンドル m_uMsg = WM_USER; m_ID = 0; // メッセージのID番号 m_Command = 0; // スレッドへのコマンド m_TxAbort = 0; // 送信中止フラグ m_txwp = m_txrp = m_txcnt = 0; m_PSKGNRId = 0; m_OpenGNR = 0; m_PollCnt = 0; m_rxcnt = 0; m_FreqEvent = 0; m_Freq[0] = 0; m_MarkFreq = 2125; m_ScanAddr = 0; m_pRadio = NULL; } //--------------------------------------------------------------------------- void __fastcall CCradio::Execute() { //---- スレッドのコードをここに記述 ---- // Priority = tpLower; while(1){ if( Terminated == TRUE ){ return; } if( m_Command == CRADIO_CLOSE ){ m_Command = 0; return; } if( m_CreateON == TRUE ){ if( m_txcnt ){ if( m_pRadio != NULL ){ if( !(m_pRadio->GetStatus() & mmrpstatusTXBUSY) ){ m_pRadio->PutChar(m_txbuf[m_txrp]); m_txrp++; if( m_txrp >= RADIO_TXBUFSIZE ){ m_txrp = 0; } m_txcnt--; } } else if( !TxBusy() ){ DWORD size=0; ::WriteFile( m_fHnd, &m_txbuf[m_txrp], 1, &size, NULL ); if( size ){ m_txrp++; if( m_txrp >= RADIO_TXBUFSIZE ){ m_txrp = 0; } m_txcnt--; } if( RADIO.ByteWait ) ::Sleep(RADIO.ByteWait); } ::Sleep(1); } else if( m_pRadio != NULL ){ if( m_pRadio->GetStatus() & mmrpstatusFREQ ){ long fq = m_pRadio->GetFreq(); if( fq ) UpdateFreq(double(fq)/1e4); } while(m_pRadio->GetStatus() & mmrpstatusRX){ CatchPoll(m_pRadio->GetChar()); } ::Sleep(10); } else { BYTE dmy[256]; while(1){ int len = RecvLen(); if( !len ) break; if( len >= sizeof(dmy) ) len = sizeof(dmy); Read(dmy, len); if( RADIO.PollType ){ BYTE *p = dmy; for( ; len; p++, len-- ){ CatchPoll(*p); } } } ::Sleep(10); } } else { ::Sleep(10); } } } //--------------------------------------------------------------------------- /*#$% ============================================================== 通信回線をオープンしスレッドをアクティブにする -------------------------------------------------------------- PortName : 回線の名前 pCP : COMMPARAのポインタ(ヌルの時はデフォルトで初期化) pWnd : メッセージ送信先のウインドウクラスのポインタ(ヌルの時はメインフレームウインドウ) nID : データ受信時のメッセージID RBufSize : 受信バッファのサイズ(default=2048) TBufSize : 送信バッファのサイズ(default=2048) -------------------------------------------------------------- TRUE/FALSE -------------------------------------------------------------- ============================================================== */ BOOL CCradio::Open(CRADIOPARA *cp, HWND hwnd, UINT uMsg, UINT nID) { if( m_CreateON == TRUE ) Close(); m_TxAbort = FALSE; m_PSKGNRId = 0; m_OpenGNR = 0; if( !strcmpi(cp->StrPort, "PSKGNR") || !strcmpi(cp->StrPort, "WD5GNR") || !strcmpi(cp->StrPort, "LOGGER")){ m_PSKGNRId = ::RegisterWindowMessage("PSKGNRFUNC"); m_CreateON = TRUE; if( RADIO.openGNR && (!RADIO.cmdGNR.IsEmpty()) && (strcmpi(cp->StrPort, "LOGGER")) ){ if( FindWindow("ThunderRT6Main", NULL) == NULL ){ ::WinExec(RADIO.cmdGNR.c_str(), SW_HIDE); m_OpenGNR = 1; } } return m_CreateON; } //AA6YQ 1.66 enable use of 2-digit com ports per http://support.microsoft.com/kb/115831/EN-US/ char *ComPort = new char[33]; StrCopy(ComPort,"\\\\.\\"); StrCat(ComPort,cp->StrPort); m_fHnd = ::CreateFile(ComPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); m_wHnd = hwnd; m_uMsg = uMsg; m_ID = nID; if( m_fHnd == INVALID_HANDLE_VALUE ) goto _mmr; // setup device buffers if( ::SetupComm( m_fHnd, DWORD(RADIO_COMBUFSIZE), DWORD(RADIO_COMBUFSIZE) ) == FALSE ){ ::CloseHandle(m_fHnd); _mmr:; m_pRadio = new CMMRadio(hwnd, uMsg); if( m_pRadio->Open(cp->StrPort) ){ m_CreateON = TRUE; Priority = tpLower; Resume(); // スレッドの実行 return TRUE; } else { delete m_pRadio; m_pRadio = 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.BaudRate = cp->BaudRate; m_dcb.fBinary = TRUE; m_dcb.ByteSize = USHORT(cp->BitLen ? 8 : 7); const UCHAR _tp[]={NOPARITY, EVENPARITY, ODDPARITY}; m_dcb.Parity = _tp[cp->Parity]; const UCHAR _ts[]={ONESTOPBIT,TWOSTOPBITS}; m_dcb.StopBits = _ts[cp->Stop]; if( cp->usePTT ){ m_dcb.fRtsControl = RTS_CONTROL_DISABLE; // 送信禁止 m_dcb.fDtrControl = DTR_CONTROL_DISABLE; // 送信禁止 } else { m_dcb.fRtsControl = RTS_CONTROL_ENABLE; } m_dcb.fOutxCtsFlow = (cp->flwCTS && !cp->usePTT) ? TRUE : FALSE; m_dcb.fInX = m_dcb.fOutX = cp->flwXON ? TRUE : FALSE; m_dcb.XonChar = 0x11; m_dcb.XoffChar = 0x13; m_dcb.fParity = FALSE; m_dcb.EvtChar = 0x0d; // dummy setting // m_dcb.fTXContinueOnXoff = TRUE; m_dcb.XonLim = USHORT(RADIO_COMBUFSIZE/4); // 1/4 of RBufSize m_dcb.XoffLim = USHORT(RADIO_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 CCradio::Close(void) { if( m_CreateON == TRUE ){ if( m_PSKGNRId ){ if( (m_OpenGNR || RADIO.change) && RADIO.openGNR ) ::SendMessage(HWND_BROADCAST, m_PSKGNRId, 1 , 0); m_PSKGNRId = 0; } else { if( m_ID ){ m_Command = CRADIO_CLOSE; // スレッド終了コマンド Priority = tpNormal; //スレッドは通常の優先度である WaitFor(); } if( m_pRadio != NULL ){ delete m_pRadio; m_pRadio = NULL; } else { ::CloseHandle(m_fHnd); } } } m_CreateON = FALSE; m_TxAbort = TRUE; } void CCradio::ReqClose(void) { if( m_CreateON == TRUE ){ if( m_PSKGNRId ){ return; } else { if( m_ID ){ m_Command = CRADIO_CLOSE; // スレッド終了コマンド Priority = tpNormal; //スレッドは通常の優先度である } } } } void CCradio::WaitClose(void) { if( m_CreateON == TRUE ){ if( m_PSKGNRId ){ if( (m_OpenGNR || RADIO.change) && RADIO.openGNR ) ::SendMessage(HWND_BROADCAST, m_PSKGNRId, 1 , 0); m_PSKGNRId = 0; } else { if( m_ID && m_Command ){ WaitFor(); } if( m_pRadio != NULL ){ delete m_pRadio; m_pRadio = NULL; } else { ::CloseHandle(m_fHnd); } } m_CreateON = FALSE; } m_TxAbort = TRUE; } /*#$% ============================================================== 受信バッファ内の格納データ長を得る -------------------------------------------------------------- -------------------------------------------------------------- データの長さ -------------------------------------------------------------- ============================================================== */ DWORD CCradio::RecvLen(void) { COMSTAT ComStat; DWORD dwErrorFlags; ::ClearCommError( m_fHnd, &dwErrorFlags, &ComStat ); return ComStat.cbInQue; } /*#$% ============================================================== 送信ビジーかどうか調べる -------------------------------------------------------------- -------------------------------------------------------------- : 送信ビジー状態 -------------------------------------------------------------- ============================================================== */ int CCradio::TxBusy(void) { #if 0 COMSTAT ComStat; DWORD dwErrorFlags; if( m_TxAbort ) return FALSE; ClearCommError( m_fHnd, &dwErrorFlags, &ComStat ); int f = ComStat.fRlsdHold; if( f ) return TRUE; if( m_dcb.fOutxCtsFlow ){ f |= ComStat.fCtsHold; } if( m_dcb.fOutX ){ f |= ComStat.fXoffHold; } return f ? TRUE : FALSE; #else COMSTAT ComStat; DWORD dwErrorFlags; ::ClearCommError( m_fHnd, &dwErrorFlags, &ComStat ); return ComStat.cbOutQue; #endif } /*#$% ============================================================== 通信回線からデータを取り出す -------------------------------------------------------------- p : バッファのポインタ len : バッファのサイズ -------------------------------------------------------------- 実際に受信したサイズ -------------------------------------------------------------- ============================================================== */ DWORD CCradio::Read(BYTE *p, DWORD len) { DWORD size=0; if( m_CreateON == TRUE ){ ::ReadFile( m_fHnd, p, len, &size, NULL ); } return size; } /*#$% ============================================================== 通信回線にデータを送信する -------------------------------------------------------------- -------------------------------------------------------------- -------------------------------------------------------------- ============================================================== */ void CCradio::PutChar(char c) { if( m_CreateON == TRUE ){ if( m_PSKGNRId ) return; if( m_txcnt < RADIO_TXBUFSIZE ){ m_txbuf[m_txwp] = c; m_txwp++; if( m_txwp >= RADIO_TXBUFSIZE ) m_txwp = 0; m_txcnt++; } } } /*#$% ============================================================== 通信回線にデータを送信する -------------------------------------------------------------- p : バッファのポインタ len : 送信するサイズ -------------------------------------------------------------- 実際に送信したサイズ -------------------------------------------------------------- ============================================================== */ void CCradio::Write(void *s, DWORD len) { if( m_CreateON == TRUE ){ if( m_PSKGNRId ) return; char *p; for( p = (char *)s; len; len--, p++ ){ PutChar(*p); } } } /*#$% ============================================================== 通信回線にデータを送信する -------------------------------------------------------------- p : バッファのポインタ len : 送信するサイズ -------------------------------------------------------------- 実際に送信したサイズ -------------------------------------------------------------- ============================================================== */ void CCradio::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 CCradio::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"; //JA7UDE 0428 Write(r, 1); } void CCradio::SendCommand(LPCSTR p) { int c; int f; for(f = 0; *p; p++){ if( *p == '\\' ){ f = 0; p++; switch(*p){ case '$': f = 1; continue; case 'x': case 'X': p++; if( *p == 'x' ){ c = RADIO.Cmdxx; } else { c = htoin(p, 2); } p++; break; case 'r': c = CR; break; case 'n': c = LF; break; case 'w': p++; c = atoin(p, 2); if( (c < 0) || (c >= 100) ) c = 100; if( c ) ::Sleep(c * 10); p++; continue; case '\\': c = '\\'; break; case 'c': // comment return; } } else if( f ){ p = SkipSpace(p); if( *p == 'x' ){ c = RADIO.Cmdxx; } else { c = htoin(p, 2); } p++; } else { c = *p; } PutChar(BYTE(c)); } } void CCradio::SetPTT(int sw) { if( m_PSKGNRId ){ ::SendMessage(HWND_BROADCAST, m_PSKGNRId, 0 , sw ? 1 : 0); if( sw ) ::Sleep(50); } else { if( sw ){ if( m_pRadio != NULL ){ m_pRadio->SetPTT(sw); } else if( RADIO.usePTT ){ ::EscapeCommFunction(m_fHnd, SETRTS); ::EscapeCommFunction(m_fHnd, SETDTR); } SendCommand(RADIO.CmdTx.c_str()); } else { if( m_pRadio != NULL ){ m_pRadio->SetPTT(sw); } else if( RADIO.usePTT ){ ::EscapeCommFunction(m_fHnd, CLRRTS); ::EscapeCommFunction(m_fHnd, CLRDTR); } SendCommand(RADIO.CmdRx.c_str()); } } } //-------------------------------------------------------- // 周波数が変化しているかどうか調べる int CCradio::IsFreqChange(LPCSTR pFreq) { if( RADIO.PollType ){ if( m_FreqEvent ) return 1; if( m_Freq[0] ){ if( strcmp(m_Freq, pFreq) ) return 1; } } return 0; } //-------------------------------------------------------- // タイマー処理 void CCradio::Timer(int tx, int interval) { if( m_CreateON == TRUE ){ if( m_PSKGNRId ) return; if( m_pRadio != NULL ){ if( m_pRadio->GetStatus() & mmrpstatusDEFCMD ){ LPCSTR p; switch(m_pRadio->GetDefCommand()){ case 1: p = RADIO.CmdTx.c_str(); break; case 2: p = RADIO.CmdRx.c_str(); break; default: p = RADIO.CmdInit.c_str(); break; } SendCommand(p); m_PollCnt = (5 + RADIO.PollInterval); } } if( (!tx) && RADIO.PollType ){ if( !m_PollCnt ){ if( m_pRadio != NULL ) m_pRadio->Polling(); if( m_ScanAddr ){ // アドレススキャン m_PollCnt = 4; if( m_ScanAddr <= 3 ){ m_ScanAddr++; } else { RADIO.Cmdxx++; if( RADIO.Cmdxx >= 0x80 ){ RADIO.Cmdxx = 0; } } } else { m_PollCnt = (5 + RADIO.PollInterval); } if( interval ){ m_PollCnt = m_PollCnt * 100 / interval; } switch(RADIO.PollType){ case RADIO_POLLYAESUHF: case RADIO_POLLFT1000D: case RADIO_POLLFT920: m_rxcnt = 0; SendCommand("\\$0000000210"); break; case RADIO_POLLYAESUVU: m_rxcnt = 0; SendCommand("\\$0000000003"); break; //1.66B. 1.70E AA6YQ case RADIO_POLLFT9000: case RADIO_POLLFT2000: case RADIO_POLLFT950: case RADIO_POLLFT450: case RADIO_POLLFT991: case RADIO_POLLFT891: m_rxcnt = 0; SendCommand("IF;"); break; case RADIO_POLLICOM: case RADIO_POLLOMNIVI: m_rxcnt = 0; SendCommand("\\$FEFExxE003FD"); break; case RADIO_POLLICOMN: case RADIO_POLLOMNIVIN: if( !m_Freq[0] || m_ScanAddr ){ m_rxcnt = 0; SendCommand("\\$FEFExxE003FD"); } break; case RADIO_POLLKENWOOD: m_rxcnt = 0; SendCommand("IF;"); break; case RADIO_POLLKENWOODN: if( !m_Freq[0] ){ m_rxcnt = 0; SendCommand("AI1;"); } break; case RADIO_POLLJST245: m_rxcnt = 0; SendCommand("I\r\n"); break; case RADIO_POLLJST245N: if( !m_Freq[0] ){ m_rxcnt = 0; SendCommand("I1\r\nL\r\n"); } break; default: break; } } m_PollCnt--; } } } //-------------------------------------------------------- // 周波数ポーリングデータの受信 void CCradio::CatchPoll(BYTE c) { switch(RADIO.PollType){ case RADIO_POLLYAESUHF: case RADIO_POLLFT1000D: case RADIO_POLLFT920: if( m_rxcnt < 5 ){ m_rxbuf[m_rxcnt] = c; m_rxcnt++; if( m_rxcnt == 5 ){ FreqYaesuHF(); } } break; //1.66B AA6YQ case RADIO_POLLFT9000: case RADIO_POLLFT2000: case RADIO_POLLFT950: case RADIO_POLLFT450: case RADIO_POLLFT891: //1.70H case RADIO_POLLFT991: //1.70H if( m_rxcnt < sizeof(m_rxbuf) ){ if( (c != 0x0d) && (c != 0x0f) ){ if( (c != ' ') || m_rxcnt ){ m_rxbuf[m_rxcnt] = c; // Data m_rxcnt++; if( c == ';' ){ if( (m_rxbuf[0] == 'I') && (m_rxbuf[1]=='F') ){ if( m_rxcnt >= 13 ) FreqYaesu9K2K(); } m_rxcnt = 0; } } } } else { m_rxcnt = 0; } break; case RADIO_POLLYAESUVU: if( m_rxcnt < 5 ){ m_rxbuf[m_rxcnt] = c; m_rxcnt++; if( m_rxcnt == 5 ){ FreqYaesuVU(); } } break; case RADIO_POLLICOM: case RADIO_POLLICOMN: case RADIO_POLLOMNIVI: case RADIO_POLLOMNIVIN: switch(m_rxcnt){ case 0: if( c == 0xfe ){ m_rxbuf[m_rxcnt] = c; // プリアンブル m_rxcnt++; } break; case 1: if( c != 0xfe ){ m_rxbuf[m_rxcnt] = c; // PC-Addr m_rxcnt++; } break; case 2: if( (c == RADIO.Cmdxx) || (m_ScanAddr && c) ){ m_rxbuf[m_rxcnt] = c; // Radio-Addr m_rxcnt++; } else { m_rxcnt = 0; } break; case 3: if( (c == 0x03) || ((c == 0x00)&&((RADIO.PollType == RADIO_POLLICOMN)||(RADIO.PollType == RADIO_POLLOMNIVIN))) ){ m_rxbuf[m_rxcnt] = c; // Respons-command m_rxcnt++; } else { m_rxcnt = 0; } break; default: if( m_rxcnt < sizeof(m_rxbuf) ){ m_rxbuf[m_rxcnt] = c; // Data m_rxcnt++; if( c == 0xfd ){ if( m_rxcnt >= 9 ){ FreqICOM(); if( m_ScanAddr && m_rxbuf[2] ){ RADIO.Cmdxx = m_rxbuf[2]; RADIO.PollScan = 0; m_ScanAddr = 0; } } m_rxcnt = 0; } } else { m_rxcnt = 0; } break; } break; case RADIO_POLLKENWOOD: case RADIO_POLLKENWOODN: if( m_rxcnt < sizeof(m_rxbuf) ){ if( (c != 0x0d) && (c != 0x0f) ){ if( (c != ' ') || m_rxcnt ){ m_rxbuf[m_rxcnt] = c; // Data m_rxcnt++; if( c == ';' ){ if( (m_rxbuf[0] == 'I') && (m_rxbuf[1]=='F') ){ if( m_rxcnt >= 13 ) FreqKenwood(); } m_rxcnt = 0; } } } } else { m_rxcnt = 0; } break; case RADIO_POLLJST245: case RADIO_POLLJST245N: if( m_rxcnt < sizeof(m_rxbuf) ){ if( (c == 'I') || m_rxcnt ){ m_rxbuf[m_rxcnt] = c; // Data m_rxcnt++; if( (c == 0x0d) || (c == 0x0f) ){ if( m_rxcnt >= 12 ) FreqJST245(); m_rxcnt = 0; } } } else { m_rxcnt = 0; } break; default: break; } } //---------------------------------------------------------- // 周波数の更新 (freq=MHz) // void CCradio::UpdateFreq(double freq) { if( freq < 0.001 ) return; switch(RADIO.PollOffset){ case 1: freq -= m_MarkFreq/1000000.0; break; case 2: freq += m_MarkFreq/1000000.0; break; default: break; } char bf[32]; sprintf(bf, "%.3lf", freq); if( strcmp(m_Freq, bf) ){ strcpy(m_Freq, bf); m_FreqEvent = 1; } } void CCradio::FreqYaesuHF(void) { ULONG fq; fq = m_rxbuf[1]; fq = fq << 8; fq |= m_rxbuf[2]; fq = fq << 8; fq |= m_rxbuf[3]; fq = fq << 8; fq |= m_rxbuf[4]; double f; switch(RADIO.PollType){ case RADIO_POLLFT1000D: // FT1000D f = 25600000.0; break; case RADIO_POLLFT920: // FT920 f = 1000000.0; break; default: // FT1000MP f = 1600000.0; break; } UpdateFreq(double(fq)/f); } void CCradio::FreqYaesuVU(void) { ULONG fq; fq = m_rxbuf[0] >> 4; fq *= 10; fq += m_rxbuf[0] & 0x0f; fq *= 10; fq += m_rxbuf[1] >> 4; fq *= 10; fq += m_rxbuf[1] & 0x0f; fq *= 10; fq += m_rxbuf[2] >> 4; fq *= 10; fq += m_rxbuf[2] & 0x0f; UpdateFreq( double(fq) / 1000.0 ); } void CCradio::FreqICOM(void) { // 0 1 2 3 4 5 6 7 8 9 // fe e0 40 03 90 09 02 07 00 fd // fe e0 40 03 90 09 02 07 fd ULONG fq = 0; if( m_rxbuf[8] != 0xfd ){ fq = (m_rxbuf[8] >> 4); fq *= 10; fq += (m_rxbuf[8] & 0x0f); } fq *= 10; fq += m_rxbuf[7] >> 4; fq *= 10; fq += m_rxbuf[7] & 0x0f; fq *= 10; fq += m_rxbuf[6] >> 4; fq *= 10; fq += m_rxbuf[6] & 0x0f; fq *= 10; fq += m_rxbuf[5] >> 4; fq *= 10; fq += m_rxbuf[5] & 0x0f; fq *= 10; fq += m_rxbuf[4] >> 4; fq *= 10; fq += m_rxbuf[4] & 0x0f; UpdateFreq(double(fq)/1e6); } void CCradio::FreqKenwood(void) { //0123456789012 //IF00021155000 +001000 0002000008 ; //abcdefghijklmnopqrstuvwxyz1234567890 <---- 桁位置 //c - m 周波数 21.155MHz ULONG fq = 0; m_rxbuf[13] = 0; if( sscanf((LPCSTR)&m_rxbuf[2], "%lu", &fq) == 1 ){ if( fq ) UpdateFreq(double(fq)/1e6); } } //AA6YQ 1.66B //G3WYW Fix for FT-991 1.70B void CCradio::FreqYaesu9K2K(void) { //000000000011111111112222222222 //012345678901234567890123456789 //IF000021155000+0000RTMVCTTS; <= FT991 //IF00021155000+0000RTMVCTTS; <= FT9K2K //abcdefghijklmnopqrstuvwxyz1234567890 <---- Digit position //f - m 周波数 freq 21.155MHz ULONG fq = 0; //G3WYW Feb 2016 am I a FT-991 or FT9K2K? if (m_rxbuf[26] == ';') { //FT9K2K m_rxbuf[13] = 0; if( sscanf((LPCSTR)&m_rxbuf[5], "%lu", &fq) == 1 ){ if( fq ) UpdateFreq(double(fq)/1e6); } } else //FT991 { m_rxbuf[14] = 0; if( sscanf((LPCSTR)&m_rxbuf[5], "%lu", &fq) == 1 ){ if( fq ) UpdateFreq(double(fq)/1e6); } } } void CCradio::FreqJST245(void) { // 0 1 2 3 4 5 6 7 8 9 10 11 12 // ”Iabdffffffffg” //  I:ヘッダー記号 //  a:使用アンテナ1桁(1〜3) //  b:バンド幅1桁(0〜2) //  d:モード1桁(0〜5) //  f:送受信周波数8桁(00100000〜53999998) //  g:AGC1桁(0〜2) ULONG fq = 0; m_rxbuf[12] = 0; LPCSTR p = (LPCSTR)&m_rxbuf[4]; for( ; *p; p++ ) if( !isdigit(*p) ) return; if( sscanf((LPCSTR)&m_rxbuf[4], "%lu", &fq) == 1 ){ if( fq ) UpdateFreq(double(fq)/1e6); } }