/* * th_send_eSMS.c - Uses Hayes modem as a text phone to send in eSMS string. * * Description: * Code to use a USB modem as a Text Phone. * * * It complies under Linux using GCC * It complies under Windows using Tiny C from Fabrice Bellard. * * http://bellard.org/tcc/ * https://en.wikipedia.org/wiki/Tiny_C_Compiler * https://www.cmrr.umn.edu/~strupp/serial.html#2_5_2 * *=8< do_eSMS.bat =============================================== * rem * rem do_eSMS.bat * rem * ..\tcc th_send_eSMS.c * th_send_eSMS * pause * exit *================================================================ * * on LINUX: * gcc -Wall -o "%e" "%f" * gcc th_send_eSMS.C -Wwrite-strings -pthread -o th_send_eSMS * on PC: tcc %f * * * based on code by James Henderson, 2012, * Modified Doug Rice 2014 * * Useful documentation:- * http://en.wikibooks.org/wiki/Serial_Programming/termios * * Useful documentation about the IIC and ultrasound modules. * http://www.robot-electronics.co.uk/htm/raspberry_pi_examples.htm * * ATI3 commands return CX93001-EIS_V0.2002-V92 * * details on USB modem used in lab. * https://en.wikipedia.org/wiki/Network_Caller_ID Use an Event driven approach. Periodically try and read characters, and append to RX buffer. Flush this buffer if wanted text is found, or not enough space for next read is available. This may be a problem in the future. Typically for a Device attempting to connect to a remote device, start a call and a protective timer. Upon significant events, adjust the duration for the protective timer during the call and use it's timeout to end the call. This script has a while loop that ticks every second, and a Holdoff variable, that is set to the required duration. Look for wantStr in received text from modem and work out how to adjust the Timeout. Line 315: char * modemRxStr( char * wantStr ); Poll the received text for the strings below: Line 638: if ( modemRxStr("NO DIALTONE") ){ - modem has not been plugged into Phone socket. if ( modemRxStr("BUSY") ){ - modem has rung a busy line. Line 647: if ( modemRxStr("CONNECT") ){ - remote modem detected, call at NGTS? Line 655: if ( modemRxStr("NO CARRIER")){ - Modem disconnected or hit a Voice line. Line 688: if ( modemRxStr("NGT ring ") ){ - NGTS platform ringing B-leg Line 695: if ( modemRxStr("NGT other person has hung-up") ){ - NGTS platform reports B-leg on hook Line 705: if ( modemRxStr("NGT Answered,") ){ - NGTS platform reports B-leg Answered Line 715: if ( modemRxStr("NGT waiting for free relay assistant")){ - NGTS platform reports connecting to Agent Line 725: if ( modemRxStr("Connected to Text Relay, pls wait...") ){ - NGTS platform reports at TRA Line 734: if ( modemRxStr("NGT helpdesk please type:") ){ - NGTS platform reports Helpdesk Line 1128: char * modemRxStr( char * wantStr ){ A thread is used to provide Keyboard events. These block the thread. The commands are under review. Q end the program. */ #ifdef comment Line 298: if ( key == 'e' ){ /* go to AT command mode */ Line 304: if ( key == 'c' ){ /* go to speech mode */ Line 308: if ( key == 'd' ){ /* dial eSMS number */ Line 313: if ( key == 'd' ){ /* dial eSMS number */ Line 316: if ( key == '0' ){ /* dial eSMS number 18000870 */ Line 319: if ( key == '1' ){ /* dial eSMS number 18000871*/ Line 322: if ( key == '2' ){ /* dial eSMS number 18000872*/ Line 325: if ( key == '3' ){ /* dial eSMS number 18000873*/ Line 328: if ( key == '4' ){ /* dial eSMS number 18000874*/ Line 331: if ( key == '5' ){ /* dial eSMS number 18000875*/ Line 334: if ( key == '6' ){ /* dial eSMS number 18000876*/ Line 337: if ( key == '7' ){ /* dial eSMS number 18000877*/ Line 348: if ( key == 'a' ){ /* Ambulance */ Line 352: if ( key == 'f' ){ /* fire */ Line 356: if ( key == 'p' ){ /* police */ Line 360: if ( key == 'g' ){ /* coastguard */ Line 393: if ( key == 's' ){ /* send the eSMS strings */ Line 412: if ( key == 'b' ){ /* answer */ Line 417: if ( key == 'h' ){ /* hang up */ Line 423: if ( key == 'q' ){ /* hang up */ Line 427: if ( key == 'Q' ){ /* hang up */ printf( "\n\rCommands:-\n\r" ); printf( "\n a-mulance, f-ire,p-olice,g-coastguard\n\r"); printf( "\n s-end eSMS messages,\n\r"); printf( "\n e-nd, d-ial eSMS, h-ang up, q-quit, Q-uit\n\r"); printf( " 0 to dial 18000870, \n\r"); printf( " 1 to dial 18000871, \n\r"); printf( " 2 to dial 18000872, \n\r"); printf( " 3 to dial 18000873, \n\r"); printf( " 4 to dial 18000874, \n\r"); printf( " 5 to dial 18000875, \n\r"); printf( " 6 to dial 18000876, \n\r"); printf( " 7 to dial 18000877, \n\r"); printf( " 8 to dial 180010800500888 - HelpDesk -text opt 1, \n\r"); printf( " 9 to type hello to Help Desk, \n\r"); #endif /* **************************************** Setting up a Hayes modem to be a text phone. **************************************** AT+MS? +MS: V92,1,300,48000,300,56000 OK AT+MS=v21 OK AT+MS? +MS: V21,0,300,300,300,300 OK atdt1800102920450004 CONNECT 9600 NGT ring ring NGT ring ring NGT Answered, please wait for connection NGT waiting for free relay assistant NGT waiting for free relay assistant NGT waiting for free relay assistant NGT waiting for free relay assistant NGT waiting for free relay assistant OK ath0 OK **************************************** To use the Hayes modem as a Text Phone: **************************************** AT+MS=V21 AT+MS? To check AT+MS=? Lists supported modes To answer incoming calls ATA To hang up:- ATH or ATH0 ATH1 - Go off hook ATD1800102920450002 - set up test call **************************************** To use the Hayes modem as a TAM **************************************** to go off hook and report DTMF **************************************** AT+FCLASS=8 AT+VLS=1 * */ /* * requirements:- * * connection to the modem. * to be able to send commands and buffer text from the modem. * On the buffered text I need to look for key strings and delete the start of the buffer. * Use a thread to block keyboard presses to enable debug and other commands. * * send example eSMS strings Micheal sent me. * * init(){ // set up Modem * while(1){ * // poll keyboard - map to events * //events:- * modem pots line events * * //commands:- * dial * send eSMS strings * } * */ /* Test Harness */ /******************************************** * Sec 1.0 Includes and #defines for TCC and or linux ********************************************/ #ifdef __TINYC__ #define tcc 1 #endif /* * * LINUX * */ #ifdef linux // gets rid of annoying "deprecated conversion from string constant blah blah" warning #pragma GCC diagnostic ignored "-Wwrite-strings" #pragma GCC diagnostic pop // gets rid of annoying "deprecated conversion from string constant blah blah" warning #pragma GCC diagnostic ignored "-Wwrite-strings" #include #include #include #include #include #include #include #include #include #include #include #include #include #define DELAY ; #define DELAYL usleep( 500000 ); #endif /* * * TCC * */ #ifdef tcc #include #include #include #include /* meh, Windows CE is special and can't handle URN path, just COM1: format snprintf(ret, RS232_STRLEN_DEVICE, "\\\\.\\COM%s", s); */ /* define to select config */ #define _MODEM_Prologe 1 #define MODEM_USB 1 #ifdef MODEM_Prologe #define COM_BAUD 9600 #define COM_PORT 12 // ////////// Modify as required. #endif #ifdef MODEM_USB #define COM_BAUD 19200 #define COM_PORT 4 // ////////// Modify as required. #endif #define RS232_STRLEN_DEVICE 11 #define DELAY ; #define DELAYM delay_ms( 1 ); #define DELAYL delay_ms( 100 ); #endif /******************************************** * Sec 2.0 defines ********************************************/ #define NDIGITS 16 #define MAX_BUFFER 512 /******************************************** * Sec 3.0 Protoypes ********************************************/ void writeBytes(int descriptor, int count); void readBytes(int descriptor, int count); void modemWriteBytes( char* modemCmdStr ); void modemReadBytes( int count ); void modemResetRxBuffer( void ); char * modemRxStr( char * wantStr ); /* look for wantStr in received text from modem */ void modemLogRxBuffer( int testNum ); void setStatus( int index ); /******************************************** * Sec 3.0 Protoypes - linux ********************************************/ #ifdef linux /* prototypes */ void initThread ( pthread_t threadP , void * message1 ); int initSerial ( int fd ); /* sleep() in tcc is in milliseconds, in linux sleep is seconds */ #define sleep dhr_sleep int dhr_sleep( int milliseconds ){ usleep( milliseconds*1000 ); } #endif /******************************************** * Sec 3.0 Protoypes - tcc ********************************************/ #ifdef tcc /* modified io_port was int */ HANDLE rs_initialise (int io_port, const long int BaudRate, const char parity, const char data); void rs_terminate(const int io_port); // delay_routines void delay_ms(clock_t millis); HANDLE hCom; //handle for serial port I/O void delay_ms(clock_t millis) { // This uses a lot of cpu time to run. find out hoe to use system timer. clock_t endtime; endtime = millis + clock(); while( endtime > clock() ) ; } #endif /******************************************** * Sec 4.0 Global Vars ********************************************/ int fd; // File descriptor of port we will talk to char serialBuffer[ MAX_BUFFER]; // Serial buffer sto store data for I/O char serialBufferTx[MAX_BUFFER]; // Serial buffer sto store data for I/O char serialBufferRx[MAX_BUFFER]; // Serial buffer sto store data for I/O char serialBufferStatus[MAX_BUFFER]; // Serial buffer sto store data for I/O char * serialBufferP ; /* used to append more text onto buffer */ char * statusStringP ; /* used to point to a status string */ int finished; //10:47 /******************************************** * Sec 4.0 Global Vars - STATUS Strings ********************************************/ /* these are displayed when things take a long time..*/ char * statusList[] ={ /*0*/ "", /*1*/ "Dialling...", /*2*/ "Connected...", /*3*/ "At NGTS node...", /*4*/ "At NGTS...", /*5*/ "At NGTS TRA...", /*6*/ "NGT text Number...", /*7*/ "NGT TRA typed GA:", /*8*/ "", /*9*/ "", /*10*/ "MODEM gone to Speech:", /*11*/ "MODEM ringing:", /*12*/ "MODEM answered call:", /*9*/ (char*)"last" }; /******************************************** * Sec 5.0 Threads - function ********************************************/ /* * getchar() blocks so put it in its own thread. * */ #ifdef __MSVCRT__ int thread2(){ int count; for( count = 0 ; count < 100 ; count++){ printf( "InThread.......................\n" ); sleep( 1000 ); } _endthreadex ( 100 ); } #endif int repeat; // CheckKey - Thread to wait for a keystroke. // #ifdef tcc void CheckKey( void * ignored ) #endif #ifdef linux void * CheckKey( void * ignored ) #endif { int fd; char key; while ( repeat < 1000 ){ repeat++; // _endthread implied /* block waiting for a key */ #ifdef tcc key = _getch(); #endif #ifdef linux key = getchar(); #endif //setStatus(0); /* key detected send some commands to the modem */ snprintf(serialBufferTx,99,"" ); if ( key == 'e' ){ /* go to AT command mode */ modemWriteBytes("+++" ); sleep(1000); modemWriteBytes("ATE0\r\n" ); setStatus(0); } if ( key == 'c' ){ /* go to speech mode */ modemWriteBytes("\n\rAT+FCLASS=8\n\rAT+VLS=1\n\r\n\rAT+FCLASS=8\n\rAT+VLS=1\n\r" ); setStatus(0); } if ( key == 'd' ){ /* dial eSMS number */ modemWriteBytes( "\n\rATDT18000870\n\r" ); setStatus(1); } if ( key == '0' ){ /* dial eSMS number 18000870 */ modemWriteBytes( "\n\rATDT18000870\n\r" ); setStatus(1); } if ( key == '1' ){ /* dial eSMS number 18000871*/ modemWriteBytes( "\n\rATDT18000871\n\r" ); setStatus(1); } if ( key == '2' ){ /* dial eSMS number 18000872*/ modemWriteBytes( "\n\rATDT18000872\n\r" ); setStatus(1); } if ( key == '3' ){ /* dial eSMS number 18000873*/ modemWriteBytes( "\n\rATDT18000873\n\r" ); setStatus(1); } if ( key == '4' ){ /* dial eSMS number 18000874*/ modemWriteBytes( "\n\rATDT18000874\n\r" ); setStatus(1); } if ( key == '5' ){ /* dial eSMS number 18000875*/ modemWriteBytes( "\n\rATDT18000875\n\r" ); setStatus(1); } if ( key == '6' ){ /* dial eSMS number 18000876*/ modemWriteBytes( "\n\rATDT18000876\n\r" ); setStatus(1); } if ( key == '7' ){ /* dial eSMS number 18000877*/ modemWriteBytes( "\n\rATDT18000877\n\r" ); setStatus(1); } if ( key == '8' ){ /* dial HelpDesk*/ modemWriteBytes( "\n\rATDT180010800500888\n\r" ); setStatus(1); } if ( key == '9' ){ /* Type something to TRA*/ modemWriteBytes( "Hello, Doug Here, I have a question" ); setStatus(0); } if ( key == 'P' ){ /* dial 02920450001*/ modemWriteBytes( "\n\rATDT02920450001\n\r" ); setStatus(1); } if ( key == 'S' ){ /* go to speech mode */ //snprintf(serialBufferTx,99,"\n\rAT+FCLASS=8\n\rAT+VLS=1\n\r\n\rAT+FCLASS=8\n\rAT+VLS=1\n\r", key ); modemWriteBytes( "\n\rAT+FCLASS=8\n\rAT+VLS=1\n\r\n\rAT+FCLASS=8\n\rAT+VLS=1\n\r" ); setStatus( 10 ); } if ( key == 'A' ){ /* answer */ //snprintf(serialBufferTx,99,"\n\rATH1\n\r", key ); modemWriteBytes( "\n\rATA\n\r" ); setStatus( 12 ); modemWriteBytes( "\n\rHello Doug Rice here...\n\r" ); } if ( key == 'z' ) { /* answer */ //snprintf(serialBufferTx,99,"\n\rATH1\n\r", key ); modemWriteBytes( "\n\rATA\n\r" ); setStatus( 12 ); modemWriteBytes( "\n\rHello Doug Rice here...\n\r" ); } if ( key == 'D' ){ /* answer */ //snprintf(serialBufferTx,99,"\n\rATH1\n\r", key ); modemWriteBytes( "Doug Here \n\r" ); setStatus( 12 ); } /* * press these keys to send these strings. * * */ if ( key == 'a' ){ /* Ambulance */ modemWriteBytes("\n\rAmbulance\n\r" ); setStatus(0); } if ( key == 'f' ){ /* fire */ modemWriteBytes( "\n\rfire\n\r" ); setStatus(0); } if ( key == 'p' ){ /* police */ modemWriteBytes( "\n\rpolice\n\r" ); setStatus(0); } if ( key == 'g' ){ /* coastguard */ modemWriteBytes( "\n\rcoastguard\n\r" ); setStatus(0); } /* userprefs.dat { "StoredPhrases":[ ["This is Text Relay, you have an emergencySMS message, the conversation has history and started at 12:01:28 Conversation ID: 9196 3606.\r","F2"], [" 12:01:30 << **999 Automated Reply** 999 received text but can't send help yet. ONLY REPLY IF YOU NEED HELP by texting the word Police, Fire, Ambulance or Coastguard to 999 GA\r","F3"], [" 12:13:22 >> Ok we will sort it GA\r","F4"], ["Conversation ID: 9196 3606 from 447917021579, \r","F5"]], "m_bFirstStartup":"false", "m_bCheckForUpdates":"true" } */ if ( key == 's' ){ /* send the eSMS strings */ setStatus(0); //modemWriteBytes("+++" ); sleep(100); // modemWriteBytes("ATH0\n\r" ); modemWriteBytes("This is Text Relay, you have an emergencySMS message, the conversation has history and started at 12:01:28 Conversation ID: 9196 3606.\r" ); sleep(2000); modemWriteBytes(" 12:01:30 << **999 Automated Reply** 999 received text but can't send help yet." ); sleep(2000); modemWriteBytes("ONLY REPLY IF YOU NEED HELP by texting the word Police, Fire, Ambulance or Coastguard to 999 GA\r" ); sleep(2000); modemWriteBytes(" 12:13:22 >> Ok we will sort it GA\r" ); sleep(2000); modemWriteBytes("Conversation ID: 9196 3606 from 447917021579, \r" ); setStatus(0); } /* * Press these keys to send these commands:- * * */ if ( key == 'b' ){ /* answer */ modemWriteBytes("\n\rATH1\n\r" ); setStatus(0); } if ( key == 'h' ){ /* hang up */ modemWriteBytes("+++" ); sleep(2000); // modemWriteBytes("ATH0\n\r" ); modemWriteBytes("ATH0\n\r" ); setStatus(0); } if ( key == 'q' ){ /* hang up */ modemWriteBytes("\r\n+++\r\n+++\r\nATH0\n\r" ); setStatus(0); } if ( key == 'Q' ){ /* hang up */ setStatus(0); finished = (1==1); } //printf( "\n\r==========InThread..repeat = %d :%s:......\n",repeat,serialBufferTx ); printf( "\n\rCommands:-\n\r" ); printf( "\n a-mulance, f-ire,p-olice,g-coastguard\n\r"); printf( "\n s-end eSMS messages,\n\r"); printf( "\n e-nd, d-ial eSMS, h-ang up, q-quit, Q-uit\n\r"); printf( " 0 to dial 18000870, \n\r"); printf( " 1 to dial 18000871, \n\r"); printf( " 2 to dial 18000872, \n\r"); printf( " 3 to dial 18000873, \n\r"); printf( " 4 to dial 18000874, \n\r"); printf( " 5 to dial 18000875, \n\r"); printf( " 6 to dial 18000876, \n\r"); printf( " 7 to dial 18000877, \n\r"); printf( " 8 to dial 180010800500888 - HelpDesk -text opt 1, \n\r"); printf( " 9 to type hello to Help Desk, \n\r"); printf( " S-peechmode, A-answer, D-oug, h-ang up, q-quit, Q-uit\n\r"); //printf( "\n\r\n\r" ); printf( "\n\rStatus: %s\n\r", statusStringP ); printf( "\n\rLast Modem: %s\n\r", serialBufferStatus ); } } /******************************************** * Sec 6.0 Main ********************************************/ int main(int argc, char **argv) { char modem_char; char * chrP; int holdOff; int tests_remaining; int testNum; char message1[10] ; holdOff = 0; tests_remaining = 0; testNum = 0; setStatus(0); /* serialBufferP = serialBuffer; serialBufferP[0] = '\0'; */ modemResetRxBuffer( ); printf( "th_send_eSMS.c - Uses Hayes modem as a text phone to send in eSMS strings."); #ifdef __MSVCRT__ //if windows start some threads. //https://msdn.microsoft.com/en-us/library/kdzttdcb.aspx /* unsigned long _beginthreadex (void *, unsigned, unsigned (__stdcall *) (void *), void*, unsigned, unsigned*); void _endthreadex (unsigned); */ printf(" __MSVCRT__"); // Launch CheckKey thread to check for keys _beginthread( CheckKey, 0, NULL ); #endif #ifdef linux pthread_t thread1; fd = initSerial ( fd ); initThread ( thread1, ( void *) NULL ); fd = initSerial ( fd ); #endif #ifdef tcc HANDLE hCom; OVERLAPPED o; BOOL fSuccess; DWORD dwEvtMask; /* char buff[100]; */ int io_port = COM_PORT; clock_t timeout; printf("\n++++++++\nThreads TCC version:- \n++++++++\n"); DELAYL DELAYL if(!rs_initialise( io_port , COM_BAUD , '8', 'N')) { printf("Opening Port Failed"); delay_ms(5000 ); exit(1); } rs_terminate(io_port); if(!rs_initialise( io_port , COM_BAUD , '8', 'N')) { printf("Opening Port Failed"); delay_ms(5000 ); exit(1); } #endif printf("\n ==================== \n"); printf(" Clearing call "); /* send commands to put modem in to Voice menu mode */ /* ATH1 OK ATh0 OK AT+MS=V21 OK AT+MS? +MS: V21,0,300,300,300,300 OK ATD1800102920450004 CONNECT 9600 NGT ring ring NGT ring ring NGT Answered, please wait for connection NGT waiting for free relay assistant Connected to Text Relay, pls wait... hello GA Your message has been left. Thank you for using Text Relay. SK Recorded Message Hello, you are through to Text Relay Assist service. Please type the name of the person you're calling GA Shall I say who is calling? GA Name or department to contact? GA OK ATh0 OK ATh0 OK */ /* send */ /* send commands to put modem in to Voice menu mode */ modemWriteBytes("=+++" ); modemReadBytes( 0 ); modemWriteBytes("=+++" ); modemReadBytes( 100 ); modemResetRxBuffer( ); modem_char == ' '; modemWriteBytes("-+++" ); modemWriteBytes( "ATZ\n\r" ); /*ATI3 Returns modem identity string */ sleep(500); modemWriteBytes( "ATI\n\r" ); /*ATI3 Returns modem identity string */ sleep(100); modemWriteBytes( "ATI1\n\r" ); /*ATI3 Returns modem identity string */ sleep(100); modemWriteBytes( "ATI2\n\r" ); /*ATI3 Returns modem identity string */ sleep(100); modemWriteBytes( "ATI3\n\r" ); /*ATI3 Returns modem identity string */ sleep(100); // modemWriteBytes( "+++" ); /*ATE0 Disables echo command.*/ // sleep(1000); modemWriteBytes( "ATE0\n\r" ); /*ATE0 Disables echo command.*/ modemWriteBytes( "ATH0\n\r" ); /*ATH0 H0 The modem goes on-hook (default).*/ modemWriteBytes( "ATI\n\r" ); /*ATI3 Returns modem identity string */ modemWriteBytes( "ATI1\n\r" ); /*ATI3 Returns modem identity string */ modemWriteBytes( "ATI2\n\r" ); /*ATI3 Returns modem identity string */ modemWriteBytes( "ATI3\n\r" ); /*ATI3 Returns modem identity string */ modemWriteBytes( "AT+MS=V21\n\r" ); /* set up V21 mode */ modemReadBytes( 100 ); modemResetRxBuffer( ); /* send call +++ ATH0 AT+MS=V21 ATDT1800102920450004 CONNECT 9600 +++ ATh0 ATH0 AT+MS=V21 ATDT1800102920450004 */ modemWriteBytes( "\n\rATI3\n\r" ); modemReadBytes( 50 ); sleep(250); modemWriteBytes( "\n\rAT+MS?\n\r" ); modemReadBytes( 50 ); sleep(250); /* zero the rx buffer as we are about to dial */ modemResetRxBuffer( ); printf("\n********************************\n"); //printf("Dialling...\n"); printf("press key for help ...\n"); /*Send to Test Number: 18000872 */ //modemWriteBytes( "\n\rATDT18000872\n\r" ); setStatus(0); printf( "\n------------------->\n:%s:\n", serialBufferTx ); printf("\n...waiting...\n"); /* we could get BUSY or NO CARRIER */ testNum = 0; tests_remaining = 100; testNum = 0; holdOff = 30; /* 20 second protective timer for first call */ modemReadBytes( 50 ); finished = (1==0); /* reset the buffer */ modemResetRxBuffer( ); /* ******************************************************************************* * * MAIN LOOP * ******************************************************************************* */ /* * Normally a circular buffer is used to buffer incoming text. * To avoid problems with the join use a linear buffer. * * This code has a linear buffer and each time around the loop try and get 50 characters. * Look in the linear buffer to see if any strings of interest are present. * * When an interesting string is found, as no previous strings of interest exist, reset the buffer. * Also run a command for the string of interest found. * * Possibly the string of interest is just the start of a command and you need to wait for more string * If the buffer is too big and no string of interest is present, chop off the front of the string. * * e.g. * I am looking for CONNECT,BUSY,NO CARRIER,NO DIALTONE, etc and NGT ring,NGT other person has hung-up, etc * * The buffer is: * CONNECT 9600 * NGT ring ring NGT ring ring NGT Answered, please wait for connection NGT waiting for free relay assistant NGT waiting for free relay assistant NGT waiting for free relay assistant NGT waiting for free relay assistant NGT waiting for free relay assistant * * Look for key words and reports * It takes a long time, to dial and get connected so you need a status */ while( ! finished ){ // printf( "\n\rStatus: %s\n\r", statusStringP ); /* Hold off for timer ticks, */ /* Is protective timer running, if it is holdoff will be > 0 */ if ( holdOff > 0 ){ holdOff--; //printf( "\n[holdoff:%2d ]\n", holdOff ); /* time to end the call, send +++ AT to break out of data mode. */ /* if ( holdOff == 1 ){ modemWriteBytes( "+++" ); sleep(1200); modemWriteBytes( "ATE1\n\rATH0\n\rATE0\n\r" ); } */ if ( holdOff == 0 ){ // finished = (1==1); } } /* end of if ( holdoff ) */ printf( "\n\r[%03d] Status: %s\n\r", holdOff, statusStringP ); /* * * ATD - Dial A Number * The ATD command dials the specified number. * In addition to numbers and dashes you can specify tone ("T") or pulse ("P") dialing, pause for one second (","), and wait for a dialtone ("W"): * ATDT 555-1212 * ATDT 18008008008W1234,1,1234 * ATD T555-1212WP1234 * The MODEM will reply with one of the following messages: NO DIALTONE BUSY NO CARRIER CONNECT CONNECT baud * * */ /* Try and read more bytes from the modem and append to RX buffer */ modemReadBytes( 50 ); if ( modemRxStr("NO DIALTONE") ){ printf( "NO DIALTONE - Is modem unplugged..."); sleep(5000); /* reset the buffer */ modemResetRxBuffer( ); finished = (1==1); } if ( modemRxStr("BUSY") ){ printf( "BUSY - Remote modem did not answer in time..."); sleep(5000); /* reset the buffer */ modemResetRxBuffer( ); finished = (1==1); } /* look for connect */ if ( modemRxStr("CONNECT") ){ printf( "connected to a modem..."); printf( "\ncmds:- a-ns, e-nd, c-onnect in speech, d-ial eSMS, h-ang up, s-end eSMS msg, q-quit, Q-uit\n"); holdOff = 0; /* 0 second protective timer for first call */ /* wait for the BAUD rate */ sleep(500); /* reset the buffer */ modemResetRxBuffer( ); /* At this point We are connected to a Modem */ setStatus(2); } /* look for MODEM not finding carrier because Backward release etc. */ if ( modemRxStr("NO CARRIER")){ printf( "not connected..."); modemLogRxBuffer( testNum ); sleep(1000); /* reset the buffer */ modemResetRxBuffer( ); setStatus(0); } /* look for MODEM not finding carrier because Backward release etc. */ /* RING ata CONNECT 9600 hello */ if ( modemRxStr("RING") ){ sleep(100); modemResetRxBuffer( ); printf( "doug Incoming call..."); modemResetRxBuffer( ); holdOff = 10 ; /* ATA\r\n remains in speech until another character is sent or timeout, ATA\r\n dropped */ modemWriteBytes( "ATA\r\n" ); /* listen for carrier, any character sent drops the line */ /* DO NOT send and char until CONNECT received, else the line is dropped */ /* S10 Delay between Loss of Carrier and Hang-Up 1–255 tenths of a second 14 (1.4 seconds) */ /* disable loss of carrier to hang up */ /* S38 Delay before Force Disconnect 0–255 seconds */ /* disable */ setStatus( 12 ); sleep(100); printf( "===Incoming call...."); holdOff = 4; } /******************************************** * * NGTS node sends status starting with NGT * ******************************************** /* I see dc1 characters 0x11 or code17 */ if ( modemRxStr("NGT") ){ // printf( "!!! @ NGT node: "); setStatus(3); } if ( modemRxStr("NGT ring ") ){ // printf( "!!! ngt ringing "); setStatus(4); } /*//NGT other person has hung-up*/ if ( modemRxStr("NGT other person has hung-up") ){ printf( " \n\n NGT other person has hung-up "); /* start a count down timer */ holdOff = 4; /* loop tick is 1 second */ /* reset the buffer */ modemResetRxBuffer( ); } if ( modemRxStr("NGT Answered,") ){ printf( " ngt Answered "); /* start a count down timer */ holdOff = 20; /* loop tick is 1 second */ /* hold off endingthe call for 20 seconds */ /* reset the buffer */ modemResetRxBuffer( ); } if ( modemRxStr("NGT waiting for free relay assistant")){ printf( " NGT waiting "); /* start a count down timer */ holdOff = 20; /* loop tick is 1 second */ /* hold off endingthe call for 20 seconds */ /* reset the buffer */ modemResetRxBuffer( ); //modemWriteBytes( "Hello, doug here, could i speak to Paul?\n\r" ); } if ( modemRxStr("Connected to Text Relay, pls wait...") ){ printf( " TRA on call "); /* start a count down timer */ holdOff = 20; /* loop tick is 1 second */ /* hold off endingthe call for 20 seconds */ /* reset the buffer */ modemResetRxBuffer( ); setStatus(2); } if ( modemRxStr("Connected text to text") ){ printf( " TRA on call "); /* start a count down timer */ holdOff = 20; /* loop tick is 1 second */ /* hold off endingthe call for 20 seconds */ /* reset the buffer */ modemResetRxBuffer( ); setStatus(0); } if ( modemRxStr("NGT helpdesk please type:") ){ printf( " Got to help desk"); /* start a count down timer */ holdOff = 4; /* loop tick is 1 second */ /* reset the buffer */ modemResetRxBuffer( ); // 1 // modemWriteBytes( "Hello, doug here, could i speak to Paul?\n\r" ); modemWriteBytes( "1" ); setStatus(5); } /************************************************ * * TRA sends GA to indicate caller has to talk * ************************************************/ if ( modemRxStr("GA") ){ printf( " TRA sent GA"); setStatus(7); /* start a count down timer */ holdOff = 0; /* loop tick is 1 second */ /* reset the buffer */ modemResetRxBuffer( ); } sleep(2000); } printf( " Ending program..."); modemWriteBytes("+++" ); sleep(2000); // modemWriteBytes("ATH0\n\r" ); modemWriteBytes("ATH0\n\r" ); setStatus(0); modemWriteBytes("+++" ); sleep(1000); modemWriteBytes("ATE0\r\n" ); exit(1); /* ******************************************************************** * * Incoming voice call and dtmf detector code * * Not reachable * * When configured in TAM mode the modem detect DTMF * ******************************************************************** * */ while(1){ serialBuffer[0] = 0x00; serialBuffer[1] = 0x00; // Mode we wish to set serialBuffer[2] = 0x00; // Mode we wish to set /* * * https://msdn.microsoft.com/en-us/library/windows/desktop/aa365683(v=vs.85).aspx * readBytes(fd, 2); // this block for ReadIntervalTimeout CommTimeouts.ReadIntervalTimeout = 5000 ; CommTimeouts.ReadTotalTimeoutConstant = 5000 ; * */ modemReadBytes( 50 ); if ( modemRxStr("TRA")){ modemResetRxBuffer( ); } if ( modemRxStr("GA")){ modemResetRxBuffer( ); } serialBuffer[0] = '\0'; readBytes(fd, 1); modem_char = serialBuffer[0]; serialBuffer[1] = 0x00; printf("%s",serialBuffer); if (modem_char == 'r' ) { printf(" ringing... press a"); } if (modem_char == 'd' ) { printf(" Call ended "); modemWriteBytes( "\n\rATH0\n\r" ); modem_char == ' '; }; if (modem_char == '1' ) { printf(" 1 pressed "); /* send a comment back */ modemWriteBytes( "\n\rHello to the help desk....\n\r" ); modem_char == ' '; } if (modem_char == '2' ) { printf(" 2 pressed "); } if (modem_char == '3' ) { printf(" 3 pressed "); } if (modem_char == '4' ) { printf(" 4 pressed "); } if (modem_char == '5' ) { printf(" 5 pressed "); } if (modem_char == '6' ) { printf(" 6 pressed "); } if (modem_char == '7' ) { printf(" 7 pressed "); } if (modem_char == '8' ) { printf(" 8 pressed "); } if (modem_char == '9' ) { printf(" 9 pressed "); } if (modem_char == '0' ) { printf(" 0 pressed "); } if (modem_char == '*' ) { printf(" * pressed "); } if (modem_char == '#' ) { printf(" # pressed "); printf(" Hanging up call "); /* send commands to put modem in to Voice menu mode */ modemWriteBytes( "\n\rATH0\n\r" ); printf( "\n:%s:\n", serialBufferTx ); writeBytes(fd, strlen( serialBufferTx ) ); modemWriteBytes( "" ); modem_char == ' '; } if (modem_char == 'R' ) { printf(" R - Ringing Detected "); modemWriteBytes( "" ); modem_char == ' '; sleep(100); /* send commands to put modem in to Voice menu mode */ modemWriteBytes( "\n\rATH1\n\r" ); printf( "\n:%s:\n", serialBufferTx ); writeBytes(fd, strlen( serialBufferTx ) ); sleep(250); modemWriteBytes( "\n\rAT+FCLASS=8\n\r" ); printf( "\n:%s:\n", serialBufferTx ); writeBytes(fd, strlen( serialBufferTx ) ); sleep(250); modemWriteBytes( "AT+VLS=1\n\r" ); printf( "\n:%s:\n", serialBufferTx ); writeBytes(fd, strlen( serialBufferTx ) ); modemWriteBytes( "" ); modem_char == ' '; } // Mode we wish to set sleep(20); } printf("\n ==================== \n"); close(fd); // Close port return 0; } /******************************************** * Sec 7.0 functions - inits ********************************************/ #ifdef linux void initThread ( pthread_t threadP , void * message1 ) { pthread_t thread1; int c; int iret1; static struct termios oldt, newt; /*tcgetattr gets the parameters of the current terminal STDIN_FILENO will tell tcgetattr that it should write the settings of stdin to oldt*/ tcgetattr( STDIN_FILENO, &oldt); /*now the settings will be copied*/ newt = oldt; /*ICANON normally takes care that one line at a time will be processed that means it will return if it sees a "\n" or an EOF or an EOL*/ //newt.c_lflag &= ~(ICANON); newt.c_lflag &= ~(ICANON | ECHO); /*Those new settings will be set to STDIN TCSANOW tells tcsetattr to change attributes immediately. */ tcsetattr( STDIN_FILENO, TCSANOW, &newt); /* Create independent threads each of which will execute function */ iret1 = pthread_create( &threadP, NULL, CheckKey, message1 ); /* Wait till threads are complete before main continues. Unless we */ /* wait we run the risk of executing an exit which will terminate */ /* the process and all threads before the threads have completed. */ // pthread_join( thread1, NULL); // pthread_join( thread2, NULL); } int initSerial ( int fd1 ) { int fd; //char *portName = "/dev/ttyAMA0"; // Name of the UART port on the Raspberry pi //char *portName = "/dev/ttyACM0"; // Name of the UART port on the Raspberry pi char * portName = "/dev/ttyUSB0"; // Name of the IIC module struct termios options; // Port options printf("\n=====================\nThreads Linux version:- \n=====================\n"); DELAYL DELAYL // O_RDWR | O_NOCTTY | O_NDELAY fd = open( portName, O_RDWR | O_NOCTTY ); // Open port for read and write not making it a controlling terminal if (fd == -1) { perror("openPort: Unable to open /dev/ttyUSB COM port "); // If open() returns an error exit(1); } else { printf("\n usb %s open \n",portName ); } // https://www.cmrr.umn.edu/~strupp/serial.html#2_5_2 //fcntl(fd, F_SETFL, 0); //fcntl(fd, F_SETFL, FNDELAY); tcgetattr(fd, &options); cfsetispeed(&options, B19200); // Set baud rate cfsetospeed(&options, B19200); cfmakeraw(&options); tcflush(fd, TCIFLUSH); // http://tldp.org/HOWTO/Serial-Programming-HOWTO/x115.html printf("c_cc[VMIN] %04X\n",options.c_cc[VMIN]); printf("c_cc[VTIME] %04X\n",options.c_cc[VTIME]); options.c_cc[VMIN] = 1; // wait for atleast these CHARs options.c_cc[VTIME] = 10; // wait deci seconds. printf("c_cflag %04X\n",options.c_cflag); printf("c_iflag %04X\n",options.c_iflag); printf("c_oflag %04X\n",options.c_oflag); printf("c_lflag %04X\n",options.c_lflag); options.c_cflag = B19200 | CRTSCTS | CS8 | CLOCAL | CREAD ; options.c_iflag = IGNPAR | ICRNL ; options.c_oflag = 0; options.c_lflag = 0; // ICANON; printf("c_cflag %04X\n",options.c_cflag); printf("c_iflag %04X\n",options.c_iflag); printf("c_oflag %04X\n",options.c_oflag); printf("c_lflag %04X\n",options.c_lflag); options.c_cc[VMIN] = 0; // wait for atleast these CHARs options.c_cc[VTIME] = 10; // wait deci seconds. tcsetattr(fd, TCSANOW, &options); //usleep(1000 ); // Sleep for UART to power up and set options DELAY tcflush(fd, TCIFLUSH); cfsetispeed(&options, B19200); // Set baud rate cfsetospeed(&options, B19200); cfmakeraw(&options); tcsetattr(fd, TCSAFLUSH, &options); tcflush(fd, TCIFLUSH); // http://tldp.org/HOWTO/Serial-Programming-HOWTO/x115.html //usleep(1000 divt); // Sleep for UART to power up and set options DELAY //int flags = fcntl(fd, F_GETFL, 0); //fcntl(fd, F_SETFL, flags | O_NONBLOCK); return fd; // https://www.cmrr.umn.edu/~strupp/serial.html /* WARNING:- I want get any available characters, but LINUX can block so get a char at a time. https://www.cmrr.umn.edu/~strupp/serial.html#2_5_2 Setting Software Flow Control Characters The VSTART and VSTOP elements of the c_cc array contain the characters used for software flow control. Normally they should be set to DC1 (021 octal) and DC3 (023 octal) which represent the ASCII standard XON and XOFF characters. Setting Read Timeouts UNIX serial interface drivers provide the ability to specify character and packet timeouts. Two elements of the c_cc array are used for timeouts: VMIN and VTIME. Timeouts are ignored in canonical input mode or when the NDELAY option is set on the file via open or fcntl. VMIN specifies the minimum number of characters to read. If it is set to 0, then the VTIME value specifies the time to wait for every character read. Note that this does not mean that a read call for N bytes will wait for N characters to come in. Rather, the timeout will apply to the first character and the read call will return the number of characters immediately available (up to the number you request). If VMIN is non-zero, VTIME specifies the time to wait for the first character read. If a character is read within the time given, any read will block (wait) until all VMIN characters are read. That is, once the first character is read, the serial interface driver expects to receive an entire packet of characters (VMIN bytes total). If no character is read within the time allowed, then the call to read returns 0. This method allows you to tell the serial driver you need exactly N bytes and any read call will return 0 or N bytes. However, the timeout only applies to the first character read, so if for some reason the driver misses one character inside the N byte packet then the read call could block forever waiting for additional input characters. VTIME specifies the amount of time to wait for incoming characters in tenths of seconds. If VTIME is set to 0 (the default), reads will block (wait) indefinitely unless the NDELAY option is set on the port with open or fcntl. */ } #endif #ifdef tcc HANDLE rs_initialise (int io_port, const long int BaudRate, const char parity, const char data) { // HANDLE hCom; OVERLAPPED o; BOOL fSuccess; DWORD dwEvtMask; BOOL bPortReady; DCB dcb; COMMTIMEOUTS CommTimeouts; /* meh, Windows CE is special and can't handle URN path, just COM1: format snprintf(ret, RS232_STRLEN_DEVICE, "\\\\.\\COM%d", io_port); */ char ComPortName[ RS232_STRLEN_DEVICE ]; /* URN support "\\.\COM255 */ snprintf(ComPortName, RS232_STRLEN_DEVICE , "\\\\.\\COM%d", io_port); // snprintf(ComPortName, RS232_STRLEN_DEVICE , "\\\\.\\COM12", io_port); printf( "Using com port:%s",ComPortName); sleep(1000); hCom = CreateFile(ComPortName, FILE_FLAG_OVERLAPPED | GENERIC_READ | GENERIC_WRITE, 3, // 0 - exclusive access NULL, // no security OPEN_EXISTING, 0, // no overlapped I/O NULL); // null template if ((int)hCom <= 0) { printf("serial port COM%d connect fail %s error %d\n\r", io_port, ComPortName, GetLastError()); return 0; } //else printf(" serial port COM%d connect OK \n\r", io_port); bPortReady = SetupComm(hCom, 128, 128); // set buffer sizes if (!bPortReady ) { printf("serial port COM%d SetupComm fail %d\n\r", io_port, GetLastError()); return 0; } //else printf(" serial port COM%d connect OK \n\r", io_port); // Set the event mask. fSuccess = SetCommMask(hCom, EV_CTS | EV_DSR); if (!fSuccess) { // Handle the error. printf("SetCommMask failed with error %d.\n", GetLastError()); return; } // Create an event object for use by WaitCommEvent. o.hEvent = CreateEvent( NULL, // default security attributes TRUE, // manual-reset event FALSE, // not signaled NULL // no name ); // Initialize the rest of the OVERLAPPED structure to zero. o.Internal = 0; o.InternalHigh = 0; o.Offset = 0; o.OffsetHigh = 0; // assert(o.hEvent); /* if (WaitCommEvent(hCom, &dwEvtMask, &o)) { if (dwEvtMask & EV_DSR) { // To do. } if (dwEvtMask & EV_CTS) { // To do. } } else { DWORD dwRet = GetLastError(); if( ERROR_IO_PENDING == dwRet) { printf("I/O is pending...\n"); // To do. } else printf("Wait failed with error %d.\n", GetLastError()); } */ bPortReady = GetCommState(hCom, &dcb); if (!bPortReady ) { printf("serial port COM%d GetCommState fail %d\n\r", io_port, GetLastError()); return 0; } // else printf(" serial port COM%d connect OK \n\r", io_port); dcb.BaudRate = BaudRate; if( data == '7') dcb.ByteSize = 7; else dcb.ByteSize = 8; if( parity == 'E') dcb.Parity = EVENPARITY; if( parity == 'O') dcb.Parity = ODDPARITY; else dcb.Parity = NOPARITY; dcb.StopBits = ONESTOPBIT; dcb.fAbortOnError = TRUE; // set XON/XOFF dcb.fOutX = FALSE; // XON/XOFF off for transmit dcb.fInX = FALSE; // XON/XOFF off for receive // set RTSCTS dcb.fOutxCtsFlow = FALSE; // turn off CTS flow control dcb.fRtsControl = FALSE; // RTS_CONTROL_HANDSHAKE; // // set DSRDTR dcb.fOutxDsrFlow = FALSE; // turn off DSR flow control //dcb.fDtrControl = DTR_CONTROL_ENABLE; // DTR handshake dcb.fDtrControl = DTR_CONTROL_DISABLE; // // dcb.fDtrControl = DTR_CONTROL_HANDSHAKE; // bPortReady = SetCommState(hCom, &dcb); if (!bPortReady ) { printf("serial port COM%d SetCommState fail %d\n\r", io_port, GetLastError()); return 0; } // Communication timeouts //COMMTIMEOUTS CommTimeouts; bPortReady = GetCommTimeouts (hCom, &CommTimeouts); CommTimeouts.ReadIntervalTimeout = 500 ; CommTimeouts.ReadTotalTimeoutConstant = 500 ; CommTimeouts.ReadTotalTimeoutMultiplier = 1 ; CommTimeouts.WriteTotalTimeoutConstant = 5 ; CommTimeouts.WriteTotalTimeoutMultiplier = 1 ; bPortReady = SetCommTimeouts (hCom, &CommTimeouts); if (!bPortReady ) { printf("serial port COM%d SetCommTimeouts fail %d\n\r", io_port, GetLastError()); return 0; } else { printf(" serial port COM%d connect OK \n\r", io_port); } return (hCom); } void rs_terminate(const int io_port) { CloseHandle(hCom); } #endif /******************************************** * Sec 7.0 functions - modem ********************************************/ void writeBytes(int descriptor, int count) { #ifdef linux int cnt; if (( cnt = write(descriptor, serialBufferTx, count)) == -1) { // Send data out perror("Error writing"); close(descriptor); // Close port if there is an error exit(1); } #endif #ifdef tcc BOOL bWriteRC; static DWORD iBytesWritten; bWriteRC = WriteFile(hCom, serialBufferTx, count, &iBytesWritten,NULL); return; #endif /* clear buffer after sending */ serialBufferTx[ 0 ] = '\0'; } void readBytes(int descriptor, int count) { /* for now reset is not enough space */ // printf( "\n readBuffer: %p %p \n%s\n%s\n", serialBuffer, serialBufferP, serialBuffer, serialBufferP ); /* for now reset is not enough space */ if ( ( serialBufferP + count ) > ( serialBuffer + MAX_BUFFER ) ){ serialBufferP = serialBuffer; printf("\nBuffer wrapped...\n"); } /* zero buffer */ serialBufferP[ 0 ] = '\0'; serialBufferP[ 1 ] = '_'; #ifdef linux int count_rd; int available ; available = count; /* we can read available char so only get what is available to prevent blocking */ //ioctl(int fd, int request, ...); ioctl(fd, FIONREAD, &available); /* if there are a lot of available characters only get up to count */ if ( available > count ) { available = count; } if ( ( count_rd = read(descriptor, serialBufferP, available ) ) == -1) { // Read back data into buf[] perror("Error reading "); close(descriptor); // Close port if there is an error exit(1); } // printf(" count: %d %d ", count_rd , count ); if ( count_rd > 0 ){ serialBufferP[ count_rd ] = '\0'; serialBufferP += count_rd; } #endif #ifdef tcc char rxchar; BOOL bReadRC; static DWORD iBytesRead; bReadRC = ReadFile(hCom, serialBufferP, count, &iBytesRead, NULL); if( iBytesRead >0 ){ serialBufferP[ iBytesRead ] = '\0'; serialBufferP[ iBytesRead+1 ] = '\0'; serialBufferP += iBytesRead; } #endif // printf( "\n readBuffer: %p %p \n:%s:\n:%s:\n", serialBuffer, serialBufferP, serialBuffer, serialBufferP ); /* printf( "\n\n%s\n",serialBuffer ); */ } void modemWriteBytes( char* modemCmdStr ){ snprintf(serialBufferTx,99, "%s",modemCmdStr ); snprintf(serialBufferStatus,99, "%s",modemCmdStr ); printf( "\n:%s:\n", serialBufferTx ); writeBytes(fd, strlen( serialBufferTx ) ); } void modemReadBytes( int count ){ readBytes(fd, count ); printf("\n:%s", serialBuffer ); } void modemResetRxBuffer( void ){ /* zero the rx buffer */ serialBufferP = serialBuffer; serialBufferP[0] = '\0'; } char * modemRxStr( char * wantStr ){ return strstr(serialBuffer, wantStr ); } /* include time_t t = time(NULL); struct tm tm = *localtime(&t); printf("now: %d-%d-%d %d:%d:%d\n", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec); */ void modemLogRxBuffer( int testNum ){ time_t now; FILE * opFile; /* Get the current time for the log */ time( &now ); opFile = fopen("th_log.js.txt","a+"); if( opFile ) { fprintf( opFile, "\n%s\ntestNum:,%d", ctime( &now ), testNum ); fprintf( opFile, "\n%s", serialBuffer ); // fprintf( opFile, "\n ftext( %d,\"%s\" );", testNum, serialBuffer ); fclose(opFile); opFile=0; } } /******************************************** * Sec 7.0 functions - status ********************************************/ void setStatus( int index ){ statusStringP = statusList[ index ]; } /******************************************** * Sec 8.0 Comments and captures from modem ********************************************/ /* Example of modem being used as a text phone. Textphone to voice phone – B- leg answers ATH1 OK ATh0 OK AT+MS=V21 OK AT+MS? +MS: V21,0,300,300,300,300 OK ATD1800102920450004 CONNECT 9600 NGT ring ring NGT ring ring NGT Answered, please wait for connection NGT waiting for free relay assistant Connected to Text Relay, pls wait... hello GA Your message has been left. Thank you for using Text Relay. SK Recorded Message Hello, you are through to Text Relay Assist service. Please type the name of the person you're calling GA Shall I say who is calling? GA Name or department to contact? GA OK ATh0 OK */ /* ATH1 OK ATh0 OK AT+MS=V21 OK AT+MS? +MS: V21,0,300,300,300,300 OK ATDT1800102920450004 CONNECT 9600 NGT ring ring NGT ring ring NGT Answered, please wait for connection NGT waiting for free relay assistant Connected to Text Relay, pls wait... hello GA Your message has been left. Thank you for using Text Relay. SK Recorded Message Hello, you are through to Text Relay Assist service. Please type the name of the person you're calling GA Shall I say who is calling? GA Name or department to contact? GA OK ATh0 OK ATh0 OK ath1 OK ath0 OK atd1800102920450002 CONNECT 9600 NGT The number you called is busy, please try later. NO CARRIER atd02920450002 NO CARRIER atd02920450002 BUSY atd02920 NO CARRIER ath0 OK ATh0 OK atd123456789 NO CARRIER ath1RRIER OK atdt02920450004 NO CARRIER ATDT02920450004 BUSY ATDT02920450004 BUSY atdt02920450004 NO CARRIER atdt02920450004 OK +++ath1 OK atdt02920450002 BUSY ath OK ath1 OK atdt02920450004 NO CARRIER +++ath OK RING RING ATDT1800102920450002 CONNECT 9600 NGT The number you called is busy, please try later. NO CARRIER ATDT02920210042 CONNECT 9600 NGT helpdesk please type: 1 for helpdesk, 2 for TextNumbers GA NGT waiting for free helpdesk advisor Hello Text Relay Helpdesk, how can I help? GA NGT Call has ended NO CARRIER RING RING RING ATH RING 1 OK ath OK ath RING RING ata RING CONNECT 9600 ▒ NO CARRIER */