static bool gn_atem_cpi_set(char **buf, struct gn_atem_op *op, char *val) { switch (gn_atem_num_get(buf)) { case 0: /* Disable */ strcpy(val, "0"); break; case 1: /* Enable */ strcpy(val, "1"); break; case 2: /* Status */ strcpy(val, "2"); break; case 3: /* Append cause and ALS bearer state to unsolicited results */ strcpy(val, "3"); break; case 4: /* Append Advance Cause Code */ strcpy(val, "4"); break; default: return (true); } return (false); }
/* Handle AT# commands */ bool gn_atem_command_diesis(char **buf) { int number; char buffer[MAX_LINE_LENGTH]; if (strncasecmp(*buf, "CID", 3) == 0) { buf[0] += 3; switch (**buf) { case '?': buf[0]++; gsprintf(buffer, MAX_LINE_LENGTH, "%d\r\n", CallerIDMode); gn_atem_string_out(buffer); return (false); case '=': buf[0]++; if (**buf == '?') { buf[0]++; gn_atem_string_out("0,1\r\n"); return (false); } else { number = gn_atem_num_get(buf); if ( number == 0 || number == 1 ) { CallerIDMode = number; return (false); } } } } return (true); }
static bool gn_atem_cfun_set(char **buf, struct gn_atem_op *op, char *val) { /* Format is <fun>[,<Rst] */ switch (gn_atem_num_get(buf)) { /* Ignore the Reset argument */ case 0: /* Minimum functionality */ strcpy(val, "0"); return (false); case 1: /* Full functionality */ strcpy(val, "1"); return (false); case 2: /* Disable phone transmit RF circuits only */ strcpy(val, "2"); return (false); case 3: /* Disable phone receive RF circuits only */ strcpy(val, "3"); return (false); case 4: /* Disable phone both transmit and receive RF circuits */ strcpy(val, "4"); return (false); } return (true); }
static bool gn_atem_creg_set(char **buf, struct gn_atem_op *op, char *val) { /* <stat> values are: * 0 not registered, MT is not currently searching a * new operator to register to * 1 registered, home network * 2 not registered, but MT is currently searching a * new operator to register to * 3 registration denied * 4 unknown * 5 registered, roaming */ switch (gn_atem_num_get(buf)) { case 0: /* No unsolicited +CREG. */ strcpy(val, "0,1"); return (false); case 1: /* +CREG Syntax is <stat> when there's a change in network * registration status. */ strcpy(val, "1,1"); return (false); case 2: /* +CREG Syntax is <stat>[,<lac>,<ci>[,<AcT>]] when we've (MT) * succesfully registered in the network cell. */ strcpy(val, "2,1"); return (false); } return (true); }
static bool gn_atem_colp_set(char **buf, struct gn_atem_op *op, char *val) { switch (gn_atem_num_get(buf)) { case 0: strcpy(val, "0,1"); /* COLP provisioned in this network */ return (false); case 1: strcpy(val, "1,1"); /* COLP provisioned in this network */ return (false); } return (true); }
static bool gn_atem_cmee_set(char **buf, struct gn_atem_op *op, char *val) { switch (gn_atem_num_get(buf)) { case 0: strcpy(val, "0"); return (false); case 1: strcpy(val, "1"); return (false); case 2: strcpy(val, "2"); return (false); } return (true); }
static bool gn_atem_band_set(char **buf, struct gn_atem_op *op, char *val) { /* Syntax is <band>[,<mode>] */ switch (gn_atem_num_get(buf)) { case 0: /* Automatic */ strcpy(val, "0"); break; case 1: /* Manual */ strcpy(val, "1"); break; default: return (true); } return (false); }
static bool gn_atem_cops_set(char **buf, struct gn_atem_op *op, char *val) { data.network_change_notification = gn_atem_network_msg; /* Syntax is <mode>[,<format>[,<oper>]] */ switch (gn_atem_num_get(buf)) { /* Parse <mode> */ case 0: case 1: case 4: if (gn_sm_functions(GN_OP_NetworkRegister, &data, sm) != GN_ERR_NONE) break; return (false); case 2: if (gn_sm_functions(GN_OP_NetworkUnregister, &data, sm) != GN_ERR_NONE) break; return (false); case 3: /* Only sets <format>, TODO */ return (false); } return (true); }
/* Parser for standard AT commands. cmd_buffer must be null terminated. */ void gn_atem_at_parse(char *cmd_buffer) { char *buf; int regno, val; char str[256]; if (!cmd_buffer[0]) return; if (strncasecmp (cmd_buffer, "AT", 2) != 0) { gn_atem_modem_result(MR_ERROR); return; } for (buf = &cmd_buffer[2]; *buf;) { switch (toupper(*buf)) { case 'Z': /* Reset modem */ buf++; switch (gn_atem_num_get(&buf)) { case -1: case 0: /* reset and load stored profile 0 */ case 1: /* reset and load stored profile 1 */ gn_atem_hangup_phone(); gn_atem_registers_init(); break; default: gn_atem_modem_result(MR_ERROR); return; } break; case 'A': /* Answer call */ buf++; gn_atem_answer_phone(); return; break; case 'D': /* Dial Data :-) */ /* FIXME - should parse this better */ /* For now we'll also initialise the datapump + rlp code again */ dp_Initialise(PtyRDFD, PtyWRFD); buf++; if (toupper(*buf) == 'T' || toupper(*buf) == 'P') buf++; while (*buf == ' ') buf++; data.call_notification = dp_CallPassup; gn_sm_functions(GN_OP_SetCallNotification, &data, sm); snprintf(data.call_info->number, sizeof(data.call_info->number), "%s", buf); if (ModemRegisters[S35] == 0) data.call_info->type = GN_CALL_DigitalData; else data.call_info->type = GN_CALL_NonDigitalData; data.call_info->send_number = GN_CALL_Default; CommandMode = false; if (gn_sm_functions(GN_OP_MakeCall, &data, sm) != GN_ERR_NONE) { CommandMode = true; dp_CallPassup(GN_CALL_RemoteHangup, NULL, NULL, NULL); } else { IncomingCallNo = data.call_info->call_id; gn_sm_loop(10, sm); } return; break; case 'H': /* Hang Up */ buf++; switch (gn_atem_num_get(&buf)) { case -1: case 0: /* hook off the phone */ gn_atem_hangup_phone(); break; case 1: /* hook on the phone */ break; default: gn_atem_modem_result(MR_ERROR); return; } break; case 'S': /* Change registers */ buf++; regno = gn_atem_num_get(&buf); if (regno < 0 || regno >= MAX_MODEM_REGISTERS) { gn_atem_modem_result(MR_ERROR); return; } if (*buf == '=') { buf++; val = gn_atem_num_get(&buf); if (val < 0 || val > 255) { gn_atem_modem_result(MR_ERROR); return; } ModemRegisters[regno] = val; } else if (*buf == '?') { buf++; snprintf(str, sizeof(str), "%d\r\n", ModemRegisters[regno]); gn_atem_string_out(str); } else { gn_atem_modem_result(MR_ERROR); return; } break; case 'E': /* E - Turn Echo on/off */ buf++; switch (gn_atem_num_get(&buf)) { case -1: case 0: ModemRegisters[REG_ECHO] &= ~BIT_ECHO; break; case 1: ModemRegisters[REG_ECHO] |= BIT_ECHO; break; default: gn_atem_modem_result(MR_ERROR); return; } break; case 'Q': /* Q - Turn Quiet on/off */ buf++; switch (gn_atem_num_get(&buf)) { case -1: case 0: ModemRegisters[REG_QUIET] &= ~BIT_QUIET; break; case 1: ModemRegisters[REG_QUIET] |= BIT_QUIET; break; default: gn_atem_modem_result(MR_ERROR); return; } break; case 'V': /* V - Turn Verbose on/off */ buf++; switch (gn_atem_num_get(&buf)) { case -1: case 0: ModemRegisters[REG_VERBOSE] &= ~BIT_VERBOSE; break; case 1: ModemRegisters[REG_VERBOSE] |= BIT_VERBOSE; break; default: gn_atem_modem_result(MR_ERROR); return; } break; case 'X': /* X - Set verbosity of the result messages */ buf++; switch (gn_atem_num_get(&buf)) { case -1: case 0: val = 0x00; break; case 1: val = 0x40; break; case 2: val = 0x50; break; case 3: val = 0x60; break; case 4: val = 0x70; break; case 5: val = 0x10; break; default: gn_atem_modem_result(MR_ERROR); return; } ModemRegisters[S22] = (ModemRegisters[S22] & 0x8f) | val; break; case 'I': /* I - info */ buf++; switch (gn_atem_num_get(&buf)) { case -1: case 0: /* terminal id */ snprintf(str, sizeof(str), "%d\r\n", ModemRegisters[39]); gn_atem_string_out(str); break; case 1: /* serial number (IMEI) */ snprintf(str, sizeof(str), "%s\r\n", imei); gn_atem_string_out(str); break; case 2: /* phone revision */ snprintf(str, sizeof(str), "%s\r\n", revision); gn_atem_string_out(str); break; case 3: /* modem revision */ gn_atem_string_out("gnokiid " VERSION "\r\n"); break; case 4: /* OEM string */ snprintf(str, sizeof(str), "%s %s\r\n", manufacturer, model); gn_atem_string_out(str); break; default: gn_atem_modem_result(MR_ERROR); return; } break; /* Handle AT* commands (Nokia proprietary I think) */ case '*': buf++; if (!strcasecmp(buf, "NOKIATEST")) { gn_atem_modem_result(MR_OK); /* FIXME? */ return; } else { if (!strcasecmp(buf, "C")) { gn_atem_modem_result(MR_OK); Parser = gn_atem_sms_parse; return; } } break; /* + is the precursor to another set of commands */ case '+': buf++; switch (toupper(*buf)) { case 'C': buf++; /* Returns true if error occured */ if (gn_atem_command_plusc(&buf) == true) { gn_atem_modem_result(MR_ERROR); return; } break; case 'G': buf++; /* Returns true if error occured */ if (gn_atem_command_plusg(&buf) == true) { gn_atem_modem_result(MR_ERROR); return; } break; default: gn_atem_modem_result(MR_ERROR); return; } break; /* # is the precursor to another set of commands */ case '#': buf++; /* Returns true if error occured */ if (gn_atem_command_diesis(&buf) == true) { gn_atem_modem_result(MR_ERROR); return; } break; default: gn_atem_modem_result(MR_ERROR); return; } } gn_atem_modem_result(MR_OK); }
bool gn_atem_parse_option(char **buf, struct gn_atem_op *op, char *val) { char buffer[MAX_LINE_LENGTH], **strval; int len; if (*val == 0) strcpy(val, op->default_val); if ((*buf)[0] == 0 || ((*buf)[0] == '?' && (*buf)[1] == 0)) { *buf += strlen(*buf); gsprintf(buffer, MAX_LINE_LENGTH, "%s: %s\r\n", op->op, val); gn_atem_string_out(buffer); return (false); } if (*(*buf) ++ != '=') return (true); if (!strcasecmp(*buf, "?")) { (*buf) ++; len = gsprintf(buffer, MAX_LINE_LENGTH, "%s: ", op->op); switch (op->type) { case gn_var_string: strval = op->string_val; len += gsprintf(buffer + len, MAX_LINE_LENGTH - len, "\"%s\"", *strval++); while (*strval) len += gsprintf(buffer + len, MAX_LINE_LENGTH - len, ",\"%s\"", *strval++); break; case gn_var_numbers: strval = op->string_val; len += gsprintf(buffer + len, MAX_LINE_LENGTH - len, "\"%s\"", *strval++); /* TODO */ break; case gn_var_bool: len += gsprintf(buffer + len, MAX_LINE_LENGTH - len, "(0,1)"); break; } gsprintf(buffer + len, MAX_LINE_LENGTH - len, "\r\n"); return (false); } if (!op->writable) return (true); if (op->set_val) return op->set_val(buf, op, val); switch (op->type) { case gn_var_string: for (strval = op->string_val; *strval; strval++) if (!strcasecmp(*buf, *strval)) { gsprintf(val, MAX_LINE_LENGTH, "\"%s\"", *strval); *buf += strlen(*buf); return (false); } break; case gn_var_bool: switch (gn_atem_num_get(buf)) { case 0: strcpy(val, "0"); return (false); case 1: strcpy(val, "1"); return (false); } break; default: break; } return (true); }