1 #include 2 #include // for atoi 3 4 #include "getcmd.h" 5 #include "debug.h" 6 #include "modem_core.h" 7 8 char* mdm_responses[MDM_RESP_END_OF_LIST]; 9 10 void mdm_init(void) { 11 mdm_responses[MDM_RESP_OK] = "OK"; 12 mdm_responses[MDM_RESP_RING] = "RING"; 13 mdm_responses[MDM_RESP_ERROR] = "ERROR"; 14 mdm_responses[MDM_RESP_CONNECT] = "CONNECT"; 15 mdm_responses[MDM_RESP_NO_CARRIER] = "NO CARRIER"; 16 mdm_responses[MDM_RESP_CONNECT_1200] = "CONNECT 1200"; 17 mdm_responses[MDM_RESP_NO_DIALTONE] = "NO DIALTONE"; 18 mdm_responses[MDM_RESP_BUSY] = "BUSY"; 19 mdm_responses[MDM_RESP_NO_ANSWER] = "NO ANSWER"; 20 mdm_responses[MDM_RESP_CONNECT_0600] = "CONNECT 0600"; 21 mdm_responses[MDM_RESP_CONNECT_2400] = "CONNECT 2400"; 22 mdm_responses[MDM_RESP_CONNECT_4800] = "CONNECT 4800"; 23 mdm_responses[MDM_RESP_CONNECT_9600] = "CONNECT 9600"; 24 mdm_responses[MDM_RESP_CONNECT_7200] = "CONNECT 7200"; 25 mdm_responses[MDM_RESP_CONNECT_12000] = "CONNECT 12000"; 26 mdm_responses[MDM_RESP_CONNECT_14400] = "CONNECT 14400"; 27 mdm_responses[MDM_RESP_CONNECT_19200] = "CONNECT 19200"; 28 mdm_responses[MDM_RESP_CONNECT_38400] = "CONNECT 38400"; 29 mdm_responses[MDM_RESP_CONNECT_57600] = "CONNECT 57600"; 30 mdm_responses[MDM_RESP_CONNECT_115200] = "CONNECT 115200"; 31 mdm_responses[MDM_RESP_CONNECT_230400]= "CONNECT 230400"; 32 mdm_responses[MDM_RESP_CONNECT_460800] = "CONNECT 460800"; 33 mdm_responses[MDM_RESP_CONNECT_921600] = "CONNECT 921600"; 34 } 35 36 modem_response get_connect_response(int speed, int level) { 37 if(level == 0) { 38 return MDM_RESP_CONNECT; 39 } 40 switch (speed) { 41 case 921600: 42 return MDM_RESP_CONNECT_921600; 43 case 460800: 44 return MDM_RESP_CONNECT_460800; 45 case 230400: 46 return MDM_RESP_CONNECT_230400; 47 case 115200: 48 return MDM_RESP_CONNECT_115200; 49 case 57600: 50 return MDM_RESP_CONNECT_57600; 51 case 38400: 52 return MDM_RESP_CONNECT_38400; 53 case 19200: 54 return MDM_RESP_CONNECT_19200; 55 case 9600: 56 return MDM_RESP_CONNECT_9600; 57 case 4800: 58 return MDM_RESP_CONNECT_4800; 59 case 2400: 60 return MDM_RESP_CONNECT_2400; 61 case 1200: 62 return MDM_RESP_CONNECT_1200; 63 case 600: 64 return MDM_RESP_CONNECT_0600; 65 default: 66 return MDM_RESP_CONNECT; 67 } 68 } 69 70 void mdm_init_config(modem_config *cfg) { 71 int i = 0; 72 cfg->local_connect[0] = 0; 73 cfg->remote_connect[0] = 0; 74 cfg->local_answer[0] = 0; 75 cfg->remote_answer[0] = 0; 76 cfg->no_answer[0] = 0; 77 cfg->inactive[0] = 0; 78 cfg->direct_conn = FALSE; 79 cfg->direct_conn_num[0] = 0; 80 cfg->is_binary_negotiated = FALSE; 81 82 cfg->send_responses = TRUE; 83 cfg->connect_response = 0; 84 cfg->response_code_level = 4; 85 cfg->text_responses = TRUE; 86 cfg->is_echo = TRUE; 87 cfg->is_cmd_mode = TRUE; 88 cfg->conn_type = MDM_CONN_NONE; 89 cfg->is_off_hook = FALSE; 90 cfg->is_ringing = FALSE; 91 cfg->cur_line_idx = 0; 92 cfg->ring_ctr = 0; 93 94 for(i = 0; i < sizeof(cfg->s) / sizeof(cfg->s[0]); i++) { 95 cfg->s[i] = 0; 96 } 97 cfg->s[S_REG_BREAK] = 43; 98 cfg->s[S_REG_CR] = 13; 99 cfg->s[S_REG_LF] = 10; 100 cfg->s[S_REG_BS] = 8; 101 cfg->s[S_REG_BLIND_WAIT] = 2; 102 cfg->s[S_REG_CARRIER_WAIT] = 50; 103 cfg->s[S_REG_COMMA_PAUSE] = 2; 104 cfg->s[S_REG_CARRIER_TIME] = 6; 105 cfg->s[S_REG_CARRIER_LOSS] = 14; 106 cfg->s[S_REG_DTMF_TIME] = 95; 107 cfg->s[S_REG_GUARD_TIME] = 50; 108 109 cfg->crlf[0] = cfg->s[S_REG_CR]; 110 cfg->crlf[1] = cfg->s[S_REG_LF]; 111 cfg->crlf[2] = 0; 112 113 cfg->dial_type = 0; 114 cfg->last_dial_type = 0; 115 cfg->disconnect_delay = 0; 116 117 cfg->pre_break_delay = FALSE; 118 cfg->break_len = 0; 119 120 cfg->memory_dial = FALSE; 121 cfg->dsr_active = FALSE; 122 cfg->force_dsr = TRUE; 123 cfg->force_dcd = FALSE; 124 cfg->first_ch = 0; 125 cfg->is_cmd_started = FALSE; 126 cfg->allow_transmit = TRUE; 127 cfg->invert_dsr = FALSE; 128 cfg->invert_dcd = FALSE; 129 130 dce_init_config(&cfg->dce_data); 131 line_init_config(&cfg->line_data); 132 } 133 134 static int get_new_cts_state(modem_config *cfg) { 135 return DCE_CL_CTS; 136 } 137 138 static int get_new_dsr_state(modem_config *cfg) { 139 if(cfg->force_dsr || (cfg->conn_type != MDM_CONN_NONE)) { 140 return (cfg->invert_dsr ? 0 : DCE_CL_DSR); 141 } 142 return (cfg->invert_dsr ? DCE_CL_DSR : 0); 143 } 144 145 static int get_new_dcd_state(modem_config *cfg) { 146 if(cfg->force_dcd || (cfg->conn_type != MDM_CONN_NONE)) { 147 return (cfg->invert_dcd ? 0 : DCE_CL_DCD); 148 } 149 return (cfg->invert_dcd ? DCE_CL_DCD : 0); 150 } 151 152 static int get_new_ri_state(modem_config *cfg) { 153 return (cfg->is_ringing && (cfg->ring_ctr == 0) ? DCE_CL_RI : 0); 154 } 155 156 int mdm_set_control_lines(modem_config *cfg) { 157 int state = 0; 158 159 state |= get_new_cts_state(cfg); 160 state |= get_new_dsr_state(cfg); 161 state |= get_new_dcd_state(cfg); 162 state |= get_new_ri_state(cfg); 163 164 LOG(LOG_INFO, 165 "Control Lines: DSR:%d DCD:%d CTS:%d RI:%d", 166 ((state & DCE_CL_DSR) != 0 ? 1 : 0), 167 ((state & DCE_CL_DCD) != 0 ? 1 : 0), 168 ((state & DCE_CL_CTS) != 0 ? 1 : 0), 169 ((state & DCE_CL_RI) != 0 ? 1 : 0) 170 ); 171 172 dce_set_control_lines(&cfg->dce_data, state); 173 return 0; 174 } 175 176 void mdm_write_char(modem_config *cfg, unsigned char data) { 177 unsigned char str[1]; 178 179 str[0] = data; 180 mdm_write(cfg, str, 1); 181 } 182 183 void mdm_write(modem_config *cfg, unsigned char data[], int len) { 184 if(cfg->allow_transmit == TRUE) { 185 dce_write(&cfg->dce_data, data, len); 186 } 187 } 188 189 void mdm_send_response(int msg, modem_config *cfg) { 190 char msgID[17]; 191 192 LOG(LOG_DEBUG, "Sending %s response to modem", mdm_responses[msg]); 193 if(cfg->send_responses == TRUE) { 194 mdm_write(cfg, (unsigned char *)cfg->crlf, 2); 195 if(cfg->text_responses == TRUE) { 196 LOG(LOG_ALL, "Sending text response"); 197 mdm_write(cfg, (unsigned char *)mdm_responses[msg], strlen(mdm_responses[msg])); 198 } else { 199 LOG(LOG_ALL, "Sending numeric response"); 200 sprintf(msgID, "%d", msg); 201 mdm_write(cfg, (unsigned char *)msgID, strlen((char *)msgID)); 202 } 203 mdm_write(cfg, (unsigned char *)cfg->crlf, 2); 204 } 205 } 206 207 int mdm_print_speed(modem_config *cfg) { 208 int speed; 209 210 switch(cfg->connect_response) { 211 case 2: 212 speed = cfg->dce_data.port_speed; 213 break; 214 default: 215 speed = cfg->line_speed; 216 break; 217 218 } 219 mdm_send_response(get_connect_response(speed, cfg->response_code_level), cfg); 220 return 0; 221 } 222 223 static void off_hook(modem_config *cfg) { 224 LOG(LOG_INFO, "taking modem off hook"); 225 cfg->is_off_hook = TRUE; 226 line_off_hook(&cfg->line_data); 227 } 228 229 int mdm_off_hook(modem_config *cfg) { 230 off_hook(cfg); 231 if(cfg->is_ringing == TRUE) { 232 cfg->conn_type = MDM_CONN_INCOMING; 233 cfg->is_ringing = FALSE; 234 } 235 if(cfg->conn_type == MDM_CONN_INCOMING) { 236 mdm_set_control_lines(cfg); 237 } 238 return 0; 239 } 240 241 int mdm_answer(modem_config *cfg) { 242 if(cfg->is_ringing == TRUE) { 243 cfg->is_ringing = FALSE; 244 cfg->conn_type = MDM_CONN_INCOMING; 245 off_hook(cfg); 246 cfg->is_cmd_mode = FALSE; 247 mdm_set_control_lines(cfg); 248 mdm_print_speed(cfg); 249 } else if(cfg->conn_type != MDM_CONN_NONE) { 250 // we are connected, just go off hook. 251 off_hook(cfg); 252 cfg->is_cmd_mode = FALSE; 253 mdm_set_control_lines(cfg); 254 } else { 255 mdm_send_response(MDM_RESP_NO_CARRIER, cfg); 256 usleep(cfg->disconnect_delay * 1000); 257 //mdm_disconnect(cfg, FALSE); 258 } 259 return 0; 260 } 261 262 int mdm_connect(modem_config *cfg) { 263 off_hook(cfg); 264 cfg->is_cmd_mode = FALSE; 265 if(cfg->conn_type == MDM_CONN_NONE) { 266 if(line_connect(&cfg->line_data, cfg->dialno) == 0) { 267 cfg->conn_type = MDM_CONN_OUTGOING; 268 mdm_set_control_lines(cfg); 269 mdm_print_speed(cfg); 270 } else { 271 mdm_send_response(MDM_RESP_NO_CARRIER, cfg); 272 usleep(cfg->disconnect_delay * 1000); 273 } 274 } 275 return 0; 276 } 277 278 int mdm_listen(modem_config *cfg) { 279 return line_listen(&cfg->line_data); 280 } 281 282 int mdm_disconnect(modem_config* cfg, unsigned char force) { 283 int type; 284 285 LOG_ENTER(); 286 LOG(LOG_INFO, "Disconnecting modem"); 287 cfg->is_cmd_mode = TRUE; 288 cfg->is_off_hook = FALSE; 289 cfg->break_len = 0; 290 cfg->is_ringing = FALSE; 291 cfg->pre_break_delay = FALSE; 292 cfg->is_binary_negotiated = FALSE; 293 if(cfg->direct_conn && !force) { 294 LOG(LOG_INFO, "Direct connection active, maintaining link"); 295 } else { 296 line_disconnect(&cfg->line_data); 297 type = cfg->conn_type; 298 cfg->conn_type = MDM_CONN_NONE; 299 mdm_set_control_lines(cfg); 300 if(type != MDM_CONN_NONE) { 301 mdm_send_response(MDM_RESP_NO_CARRIER, cfg); 302 usleep(cfg->disconnect_delay * 1000); 303 } else { 304 // ath0 after just off hook 305 mdm_send_response(MDM_RESP_OK, cfg); 306 usleep(cfg->disconnect_delay * 1000); 307 } 308 cfg->s[S_REG_RING_COUNT] = 0; 309 mdm_listen(cfg); 310 } 311 LOG_EXIT(); 312 return 0; 313 } 314 315 int mdm_parse_cmd(modem_config* cfg) { 316 int done = FALSE; 317 int index = 0; 318 int num = 0; 319 int start = 0; 320 int end = 0; 321 int cmd = AT_CMD_NONE; 322 char *command = cfg->cur_line; 323 int len = cfg->cur_line_idx; 324 char tmp[256]; 325 326 LOG_ENTER(); 327 LOG(LOG_DEBUG, "Evaluating AT%s", command); 328 329 while(TRUE != done ) { 330 if(cmd != AT_CMD_ERR) { 331 cmd = getcmd(command, len, &index, &num, &start, &end); 332 LOG(LOG_DEBUG, 333 "Command: %c (%d), Flags: %d, index=%d, num=%d, data=%d-%d", 334 (cmd > -1 ? cmd & 0xff : ' '), 335 cmd, 336 cmd >> 8, 337 index, 338 num, 339 start, 340 end 341 ); 342 } 343 switch(cmd) { 344 case AT_CMD_ERR: 345 mdm_send_response(MDM_RESP_ERROR, cfg); 346 done = TRUE; 347 break; 348 case AT_CMD_END: 349 if(cfg->is_cmd_mode == TRUE) 350 mdm_send_response(MDM_RESP_OK, cfg); 351 done = TRUE; 352 break; 353 case AT_CMD_NONE: 354 done = TRUE; 355 break; 356 case 'O': 357 case 'A': 358 mdm_answer(cfg); 359 cmd = AT_CMD_END; 360 done = TRUE; 361 break; 362 case 'B': // 212A versus V.22 connection 363 if(num > 1) { 364 cmd = AT_CMD_ERR; 365 } else { 366 //cfg->connect_1200 = num; 367 } 368 break; 369 case 'D': 370 if(end > start) { 371 strncpy(cfg->dialno, (char *)command + start, end - start); 372 cfg->dialno[end - start] = '\0'; 373 cfg->dial_type = (unsigned char)num; 374 cfg->last_dial_type = (unsigned char)num; 375 strncpy((char *)cfg->last_dialno, (char *)command+start, end - start); 376 cfg->last_dialno[end - start] = '\0'; 377 cfg->memory_dial = FALSE; 378 } else if (num == 'L') { 379 strncpy(cfg->dialno, cfg->last_dialno, strlen(cfg->last_dialno)); 380 cfg->dial_type = cfg->last_dial_type; 381 cfg->memory_dial = TRUE; 382 mdm_write(cfg, (unsigned char *)cfg->crlf, 2); 383 mdm_write(cfg, (unsigned char *)cfg->dialno, strlen(cfg->dialno)); 384 } else { 385 cfg->dialno[0] = 0; 386 cfg->last_dialno[0] = 0; 387 cfg->dial_type = 0; 388 cfg->last_dial_type = 0; 389 } 390 if (strlen(cfg->dialno) > 0) { 391 mdm_connect(cfg); 392 } else { 393 mdm_off_hook(cfg); 394 cfg->is_cmd_mode = FALSE; 395 } 396 done = TRUE; 397 break; 398 case 'E': // still need to define #2 399 if(num == 0) 400 cfg->is_echo = FALSE; 401 else if(num == 1) 402 cfg->is_echo = TRUE; 403 else { 404 cmd = AT_CMD_ERR; 405 } 406 break; 407 case 'H': 408 if(num == 0) { 409 mdm_disconnect(cfg, FALSE); 410 } else if(num == 1) { 411 mdm_off_hook(cfg); 412 } else 413 cmd = AT_CMD_ERR; 414 break; 415 case 'I': // Information. 416 break; 417 case 'L': // Speaker volume 418 if(num < 1 || num > 3) 419 cmd = AT_CMD_ERR; 420 else { 421 //cfg->volume = num; 422 } 423 break; 424 case 'M': // speaker settings 425 if(num > 3) 426 cmd=AT_CMD_ERR; 427 else { 428 //cfg->speaker_setting = num; 429 } 430 break; 431 case 'N': // automode negotiate 432 if(num > 1) 433 cmd=AT_CMD_ERR; 434 else { 435 //cfg->auto_mode=num; 436 } 437 break; 438 case 'P': // defaut to pulse dialing 439 //cfg->default_dial_type=MDM_DT_PULSE; 440 break; 441 case 'Q': // still need to define #2 442 if(num == 0) 443 cfg->send_responses = TRUE; 444 else if(num == 1) 445 cfg->send_responses = FALSE; 446 else if(num == 2) // this should be yes orig/no answer. 447 cfg->send_responses = TRUE; 448 else { 449 cmd = AT_CMD_ERR; 450 } 451 break; 452 case 'S': 453 strncpy(tmp, command + start, end - start); 454 tmp[end - start] = '\0'; 455 if(num < sizeof(cfg->s)) { 456 cfg->s[num] = atoi(tmp); // TODO do not assume this is always a number... 457 switch(num) { 458 case S_REG_CR: 459 cfg->crlf[0] = cfg->s[S_REG_CR]; 460 break; 461 case S_REG_LF: 462 cfg->crlf[1] = cfg->s[S_REG_LF]; 463 break; 464 } 465 } else { 466 LOG(LOG_DEBUG, "Ignoring S register %d=%s", num, tmp); 467 } 468 break; 469 case AT_CMD_FLAG_QUERY | 'S': 470 sprintf(tmp, "%s%3.3d", cfg->crlf, cfg->s[num]); 471 mdm_write(cfg, (unsigned char *)tmp, strlen(tmp)); 472 break; 473 case 'T': // defaut to tone dialing 474 //cfg->default_dial_type = MDM_DT_TONE; 475 break; 476 case 'V': // done 477 if(num == 0) 478 cfg->text_responses = FALSE; 479 else if(num == 1) 480 cfg->text_responses = TRUE; 481 else { 482 cmd=AT_CMD_ERR; 483 } 484 break; 485 case 'W': 486 if(num > -1 && num < 3) 487 cfg->connect_response = num; 488 else 489 cmd = AT_CMD_ERR; 490 break; 491 case 'X': 492 if(num > -1 && num < 5) 493 cfg->response_code_level = num; 494 else 495 cmd = AT_CMD_ERR; 496 break; 497 case 'Y': // long space disconnect. 498 if(num > 1) 499 cmd = AT_CMD_ERR; 500 else { 501 //cfg->long_disconnect = num; 502 } 503 break; 504 case 'Z': // long space disconnect. 505 if(num > 1) 506 cmd = AT_CMD_ERR; 507 else { 508 // set config0 to cur_line and go. 509 } 510 break; 511 case AT_CMD_FLAG_EXT + 'C': 512 switch(num) { 513 case 0: 514 cfg->force_dcd = TRUE; 515 mdm_set_control_lines(cfg); 516 break; 517 case 1: 518 cfg->force_dcd = FALSE; 519 mdm_set_control_lines(cfg); 520 break; 521 default: 522 cmd = AT_CMD_ERR; 523 break; 524 } 525 break; 526 case AT_CMD_FLAG_EXT + 'K': 527 // flow control. 528 switch (num) { 529 case 0: 530 dce_set_flow_control(&cfg->dce_data, 0); 531 break; 532 case 3: 533 dce_set_flow_control(&cfg->dce_data, MDM_FC_RTS); 534 break; 535 case 4: 536 dce_set_flow_control(&cfg->dce_data, MDM_FC_XON); 537 break; 538 case 5: 539 dce_set_flow_control(&cfg->dce_data, MDM_FC_XON); 540 // need to add passthrough.. Not sure how. 541 break; 542 case 6: 543 dce_set_flow_control(&cfg->dce_data, MDM_FC_XON | MDM_FC_RTS); 544 break; 545 default: 546 cmd=AT_CMD_ERR; 547 break; 548 } 549 break; 550 default: 551 break; 552 } 553 } 554 cfg->last_line_idx = cfg->cur_line_idx; 555 cfg->cur_line_idx = 0; 556 return cmd; 557 } 558 559 /* 560 * interestingly, at least the hayes modem I have has the following behavior 561 * concerning the AT command: 562 * 563 * AaaaaaT works (rule is that the first A found is considered the A char, and the 564 * trailing T has the same case, so this works 565 * 566 * abcdefat also works (first 'a' starts the sequence, next letters starts over, 567 * and then the last 'a' is paired up with the 't' 568 * 569 * At and aT will not work (the modem uses AT to determine parity, but mixed case 570 * messes with the algorithm 571 * 572 * If a sequence is started (AT sent) but then the user backspaces, the backspace 573 * is echoed to the sender, but then a 'T' is sent if the user has erased all of the 574 * command 575 * 576 * A real modem will complain about incorrect data in the command string. TCPSER 577 * will silently ignore such issues, as it creates more compatibility to ignore 578 * unknown commands. 579 */ 580 581 int mdm_handle_char(modem_config *cfg, unsigned char ch) { 582 char ch_raw = ch & 0x7f; 583 584 if(cfg->is_echo == TRUE) 585 dce_write_char_raw(&cfg->dce_data, ch); 586 if(cfg->is_cmd_started == TRUE) { // we previously got an 'AT' 587 if(ch_raw == (cfg->s[S_REG_BS])) { 588 if(cfg->cur_line_idx == 0 && cfg->is_echo == TRUE) { 589 mdm_write_char(cfg, 'T'); 590 } else { 591 cfg->cur_line_idx--; 592 } 593 } else if(ch_raw == (unsigned char)(cfg->s[S_REG_CR])) { 594 // we have a line, process. 595 cfg->cur_line[cfg->cur_line_idx] = 0; 596 mdm_parse_cmd(cfg); 597 cfg->first_ch = 0; 598 cfg->is_cmd_started = FALSE; 599 } else { 600 cfg->cur_line[cfg->cur_line_idx++ % sizeof(cfg->cur_line)] = ch_raw; 601 } 602 } else if(cfg->first_ch) { // we already got our first char 603 // if we received a 't' and the case of both chars is the same, start 604 if(((ch_raw & 0x5f) == 'T') && ((cfg->first_ch & 0x20) == (ch_raw & 0x20))) { 605 cfg->is_cmd_started = TRUE; 606 dce_detect_parity(&cfg->dce_data, cfg->first_ch, ch); 607 LOG(LOG_ALL,"'T' parsed in serial stream, switching to command parse mode"); 608 } else if(ch_raw == '/') { 609 LOG(LOG_ALL,"'/' parsed in the serial stream, replaying last command"); 610 cfg->cur_line_idx = cfg->last_line_idx; 611 mdm_parse_cmd(cfg); 612 cfg->is_cmd_started = FALSE; 613 } else if((ch_raw & 0x5f) != 'A') { 614 cfg->first_ch = 0; 615 } 616 } else if((ch_raw & 0x5f) == 'A') { 617 LOG(LOG_ALL, "'A' parsed in serial stream"); 618 cfg->first_ch = ch; 619 } 620 return 0; 621 } 622 623 int mdm_clear_break(modem_config* cfg) { 624 cfg->break_len = 0; 625 cfg->pre_break_delay = FALSE; 626 return 0; 627 } 628 629 int mdm_handle_timeout(modem_config *cfg) { 630 if(cfg->pre_break_delay == TRUE && cfg->break_len == 3) { 631 // pre and post break. 632 LOG(LOG_INFO, "Break condition detected"); 633 cfg->is_cmd_mode = TRUE; 634 mdm_send_response(MDM_RESP_OK, cfg); 635 mdm_clear_break(cfg); 636 } else if(cfg->pre_break_delay == FALSE) { 637 // pre break wait over. 638 LOG(LOG_DEBUG, "Initial Break Delay detected"); 639 cfg->pre_break_delay = TRUE; 640 } else if(cfg->pre_break_delay == TRUE && cfg->break_len > 0) { 641 LOG(LOG_ALL, "Inter-break-char delay time exceeded"); 642 mdm_clear_break(cfg); 643 } else if(cfg->s[S_REG_INACTIVITY_TIME] != 0) { 644 // timeout... 645 LOG(LOG_INFO, "DTE communication inactivity timeout"); 646 mdm_disconnect(cfg, FALSE); 647 } 648 return 0; 649 } 650 651 int mdm_send_ring(modem_config *cfg) { 652 LOG(LOG_DEBUG, "Sending 'RING' to modem"); 653 cfg->is_ringing = TRUE; 654 mdm_set_control_lines(cfg); 655 mdm_send_response(MDM_RESP_RING, cfg); 656 cfg->s[S_REG_RING_COUNT]++; 657 LOG(LOG_ALL,"Sent #%d ring", cfg->s[S_REG_RING_COUNT]); 658 if(cfg->is_cmd_mode == FALSE || (cfg->s[S_REG_RINGS] != 0 && cfg->s[S_REG_RING_COUNT] >= cfg->s[S_REG_RINGS])) { 659 mdm_answer(cfg); 660 } 661 return 0; 662 } 663 664 int mdm_parse_data(modem_config *cfg, unsigned char *data, int len) { 665 int i; 666 667 if(cfg->is_cmd_mode == TRUE) { 668 for(i = 0; i < len; i++) { 669 mdm_handle_char(cfg, data[i]); 670 } 671 } else { 672 line_write(&cfg->line_data, data, len); 673 if(cfg->pre_break_delay == TRUE) { 674 for(i = 0; i < len; i++) { 675 if(dce_strip_parity(&cfg->dce_data, data[i]) == (unsigned char)cfg->s[S_REG_BREAK]) { 676 LOG(LOG_DEBUG, "Break character received"); 677 cfg->break_len++; 678 if(cfg->break_len > 3) { // more than 3, considered invalid 679 cfg->pre_break_delay = FALSE; 680 cfg->break_len = 0; 681 } 682 } else { 683 LOG(LOG_ALL, "Found non-break character, cancelling break"); 684 // chars past +++ 685 mdm_clear_break(cfg); 686 } 687 } 688 } 689 } 690 return 0; 691 } 692 693 int mdm_read(modem_config *cfg, unsigned char *data, int len) { 694 int res; 695 696 if(cfg->is_cmd_mode == TRUE) { 697 // read one char in raw mode 698 res = dce_read_char_raw(&cfg->dce_data); 699 if(res > 0) { // we have a character 700 data[0] = (unsigned char)res; // fixup 701 res = 1; 702 } 703 } else { 704 res = dce_read(&cfg->dce_data, data, sizeof(data)); 705 } 706 return res; 707 }