' activate.sb ' ' This runs through the Over-The-Air Service Provisioning procedure ' for the Verizon and Sprint networks on a Sierra Wireless MC5725/7 CDMA module. ' Usage: ' ' bas activate.sb ' ' The Sarian should be rebooted when the operation is completed. ' The script automatically works out which ASY ports from the modemcc 0 asy_add and info_asy_add settings ' It also deactivates the PPP instance in case it's in use. ' Progress and final result is reported in the eventlog ' Progress is also logged to a RAM file called sstat.txt ' Web files sstat.asp and sstat1.asp are also generated to allow progress ' to be observed at the web interface ' the following line makes all string comparisons case insensitive ' OPTION COMPARE sbCaseInsensitive ' set up the error handler ' on error goto ErrorLabel const nl = "\r\n" ' Enter an error message in the event log ' Also prints message to console output ' And appends the message to the web log file ' function eventmsg(msg) print #aspout, msg, nl print msg, nl junk = system("setevent \"" & msg & "\"" & " 0") end function ' Appends the message to the web log file ' function logmsg(msg) print #aspout, msg, nl end function ' Generate the log files for monitoring progress at the web interface ' function init_log_files local fh fh = 0 open "sstat.asp" for output as fh print #fh, "\r\n" print #fh, "\r\n" print #fh, "Provisioning Status\r\n" print #fh, "\r\n" print #fh, "\r\n" print #fh, "\r\n" print #fh, "\r\n" print #fh, "\r\n" print #fh, "\r\n" print #fh, "\r\n" print #fh, "\r\n" print #fh, "\r\n" close fh fh = 0 open "sstat1.asp" for output as fh print #fh, "\r\n" print #fh, "\r\n" print #fh, "Provisioning Status\r\n" print #fh, "\r\n" print #fh, "\r\n" print #fh, "\r\n" print #fh, "\r\n" print #fh, "
\r\n" print #fh, "

Activation started. See below for progress

\r\n" print #fh, "

Click here to cancel

\r\n" print #fh, "
\r\n" print #fh, "\r\n" print #fh, "\r\n" close fh aspout=0 open "sstat.txt" for output as aspout end function ' Generate a final status message which can be displayed at the web interface ' This re-writes the top sstat1 frame page function log_status(log_msg) local fh fh = 0 open "sstat1.asp" for output as fh print #fh, "\r\n" print #fh, "\r\n" print #fh, "Provisioning Status\r\n" print #fh, "\r\n" print #fh, "\r\n" print #fh, "\r\n" print #fh, "\r\n" print #fh, "
\r\n" print #fh, "

" & log_msg & "

\r\n" print #fh, "

Please reboot the router, " print #fh, "or click here to retry.

" print #fh, "
\r\n" print #fh, "\r\n" print #fh, "\r\n" close fh end function ' Enter an error message in the event log and exit ' Also prints message to console output ' And updates the web status page ' function errexit(msg) log_status(msg) print #aspout, msg, nl print msg, nl print "Please reboot the router", nl junk = system("setevent \"" & msg & "\"" & " 6") junk = mibset("provision.0.userstring2", msg) stop end function ' Return the value of Sarian parameter in rsp ' strCmd needs to be of form " ?" ' e.g. "ppp 0 ans ?" function getParam(strCmd,rsp) local res, tmp, tmpPos, x, pos2 getParam = false res = execute(strCmd, 0, tmp) if res = true then tmpPos = InStr(tmp, nl & "OK" & nl) if tmpPos > 0 then For x = tmpPos To 1 Step -1 pos2 = InStr(tmp, nl, x - 3) If pos2 > 0 and pos2 <> tmpPos then x = 1 endif next x if pos2 > 0 and pos2 <> tmpPos then rsp = mid(tmp, pos2 + 2, tmpPos - pos2 - 2) getParam = true endif endif endif end function ' find the first PPP instance configured for GPRS ' returns TRUE if we found one, and put the instance number into num ' otherwise returns FALSE ' function get_gprs_ppp_instance(num) local mdmstr, i get_gprs_ppp_instance = false for i = 0 to 4 if getParam("ppp " & i & " use_modem ?", mdmstr) = TRUE then ' print "PPP ", i, " use_modem = ", mdmstr, nl if mdmstr = "1" or mdmstr = "4" or mdmstr = "5" then get_gprs_ppp_instance = true num = i exit function endif else print "Failed to get PPP ", i, " use_modem", nl endif next i end function ' init_mc75io - opens a serial port and initialises a receive buffer for it ' Sets the following GLOBAL vars: ' mc75in - the input file handle ' mc75out - the output file handle ' mc75rxbuf - the receive buffer ' Parameter required is a GLOBAL variable mc75asyport, eg "ASY5" ' function init_mc75io ' open the serial port used for the MC75 ' two handles, one for input and one for output mc75in = 0 open mc75asyport for input as mc75in ' if error() <> 0 then ' print "error opening asy port", nl ' endif mc75out = 0 open mc75asyport for output as mc75out mc75rxbuf = "" junk = setevent(0) junk = setevent(mc75in) end function ' clear the receive buffer ' function clear_mc75io local junk, infobuf, tbuf mx75rxbuf = "" if waitevents(1000) = mc75in then junk = sockinfo(mc75in, infobuf) if infobuf[2] <> 0 then tbuf = input(infobuf[2], mc75in) endif endif end function ' gets a character from mc75in ' timeout is fixed at 10 secs for now ' Return TRUE if successful, otherwise FALSE ' If TRUE, then character is retuned in the rsp parameter ' function getchar(rsp) local tstart, junk, sinfo getchar = FALSE tstart = ticks while ticks-tstart < 1000 if len(mc75rxbuf) <> 0 then rsp = left(mc75rxbuf, 1) mc75rxbuf = mid(mc75rxbuf, 2) getchar = TRUE exit function endif junk = sockinfo(mc75in, sinfo) ' print "Bytes available = ", sinfo[2], nl if sinfo[2] <> 0 then ' print "Reading ", sinfo[2], " Bytes", nl mc75rxbuf = input(sinfo[2], mc75in) ' else ' sleep(1) endif wend end function ' Get a line from mc75in ' Return TRUE if successful, otherwise FALSE ' If TRUE, then line is returned in the rsp parameter ' function getline(rsp) local junk, sinfo, tbuf, tchr getline = FALSE tbuf = "" while TRUE if getchar(tchr) <> TRUE then exit function ' see if we received a LF (our end of line) if asc(tchr) = 0x0a then rsp = tbuf getline = TRUE exit function endif ' ignore CR, append all other chars if asc(tchr) <> 0x0d then tbuf = tbuf & tchr endif wend end function function getOKline local i, myline getOKline = FALSE for i = 1 to 10 if getline(myline) <> TRUE then exit function if myline = "OK" then getOKline = TRUE exit function endif next i end function ' ' Collect a number of lines into an array ' Stop at OK, ERROR or timeout ' return the number of lines received. ' function getResplines(rsplines) local nlines, i, myline nlines = 0 getResplines = 0 for i = 1 to 10 if getline(myline) <> TRUE then exit function rsplines[nlines] = myline nlines += 1 getResplines = nlines if (instr(myline, "OK") <> undef) or (instr(myline, "ERROR") <> undef) then exit function endif next i end function ' extract a line from an array obtained from getResplines ' function extract_result(rsp_lines, nlines, search_str) local i extract_result = "" for i = 0 to nlines-1 if instr(rsp_lines[i], search_str) <> undef then extract_result = mid(rsp_lines[i], len(search_str)+1) exit function endif next i end function ' hex and ascii dump of a string ' function dump_packet(pkt) local i, j, n, ll, chval, astr n = len(pkt) print "Received ", n, " bytes\r\n" i = 1 while n > 0 if n >= 16 then ll = 16 else ll = n endif for j = i to i+ll-1 print format("%02X", asc(mid(pkt,j,1))), " " next j astr = string((16-ll)*3+4, " ") for j = i to i+ll-1 chval = asc(mid(pkt,j,1)) if chval >= 0x20 and chval <= 0x7e then astr = astr & mid(pkt,j,1) else astr = astr & "." endif next j print astr, "\r\n" n -= 16 i += 16 wend end function ' remove escape character sequences from a received packet ' function decode_escapes(string_data_buf) local ostr, n, i, c ostr = "" n = len(string_data_buf) for i = 1 to n-1 c = asc(mid(string_data_buf,i,1)) if c = 0x7D then i += 1 c = asc(mid(string_data_buf,i,1)) c = c XOR 0x20 endif ostr = ostr & chr(c) next i ' add the last character ostr = ostr & right(string_data_buf, 1) decode_escapes = ostr end function ' get a response from the cns port, or timeout ' after the specified number of seconds ' Returns the recieved packet as a string variable, ' or an empty string in the case of a timeout ' We also decode the PPP escape sequences ' function get_cns_response(timeout) local i, pktbuf, complete, junk, infostat, cnsinbuf, unescstr get_cns_response = "" pktbuf = "" i = timeout complete = FALSE while i > 0 AND complete = FALSE junk = sockinfo(cnsin, infostat) print "CnS bytes received = ", infostat[2], "\r\n" if infostat[2] <> 0 then cnsinbuf = input(infostat[2], cnsin) pktbuf = pktbuf & cnsinbuf if asc(right(cnsinbuf, 1)) = 0x7e then complete = TRUE unescstr = decode_escapes(pktbuf) dump_packet(unescstr) get_cns_response = unescstr exit function endif endif i -= 1 sleep(1) wend end function ' gets a character from cnsin ' Return TRUE if successful, otherwise FALSE ' If TRUE, then character is retuned in the rsp parameter ' Data is buffered in the global string variable cnsrxbuf ' timeout is specified in units of secs ' function getCnSchar(rsp, timeout) local tstart, junk, sinfo, ttimeout getCnSchar = FALSE tstart = ticks ttimeout = timeout * 100 while ticks-tstart < ttimeout if len(cnsrxbuf) <> 0 then rsp = left(cnsrxbuf, 1) cnsrxbuf = mid(cnsrxbuf, 2) getCnSchar = TRUE ' print "getCnsChar returning ", asc(rsp), "\r\n" exit function endif junk = sockinfo(cnsin, sinfo) if sinfo[2] <> 0 then cnsrxbuf = input(sinfo[2], cnsin) endif sleep(1) wend end function ' experimental version that splits up multiple packets ' function get_cns_response1(timeout) local pktbuf, tchr, unescstr get_cns_response1 = "" pktbuf = "" while TRUE if getCnSchar(tchr, timeout) <> TRUE then exit function ' see if we received 0x7e (our start/end of packet) ' if asc(tchr) = 0x7e then pktbuf = pktbuf & tchr ' print "Added 7E, length is now ", len(pktbuf), "\r\n" ' we got 7e - see if it's the end of a packet ' if len(pktbuf) > 1 then unescstr = decode_escapes(pktbuf) dump_packet(unescstr) get_cns_response1 = unescstr exit function endif else ' ' not 7e - append to buffer if it's not the first byte ' ' print "Got other char, length is ", len(pktbuf), "\r\n" if len(pktbuf) >= 1 then pktbuf = pktbuf & tchr endif endif wend end function ' check the HIP header and CnS operation type for a valid, non-error response ' function is_valid_cns_packet(rsppkt) local plenhi, plenlo, plen, msgid, pobjidhi, pobjidlo, pobjid, payloadlen is_valid_cns_packet = FALSE ' check the HIP header plenhi = asc(mid(rsppkt, 2, 1)) plenlo = asc(mid(rsppkt, 3, 1)) plen = plenhi*256 + plenlo msgid = asc(mid(rsppkt, 4, 1)) print "HIP header: payload len=", plen, ", msgid=0x", format("%02X", msgid), "\r\n" if plen <> len(rsppkt)-6 then print "Bad HIP payload length\r\n" exit function endif if msgid <> 0x6B then print "Unknown Message ID\r\n" exit function endif ' check the CnS packet pobjidhi = asc(mid(rsppkt, 6, 1)) pobjidlo = asc(mid(rsppkt, 7, 1)) pobjid = pobjidhi*256 + pobjidlo optype = asc(mid(rsppkt, 8, 1)) payloadlen = asc(mid(rsppkt, 15, 1)) print "CnS header: Objid=0x", format("%04X", pobjid), ", Optype=0x", format("%02X", optype), ", Payloadlen=", payloadlen, "\r\n" if (optype and 0x80) <> 0 then print "Got CnS Error response: ", mid(rsppkt, 16, payloadlen), "\r\n" exit function endif is_valid_cns_packet = TRUE end function ' checks for a valid notification enable response packet ' function check_enable_response(rsppkt, objid) local pobjidhi, pobjidlo, pobjid, optype check_enable_response = FALSE if is_valid_cns_packet(rsppkt) = FALSE then exit function endif ' check the CnS packet pobjidhi = asc(mid(rsppkt, 6, 1)) pobjidlo = asc(mid(rsppkt, 7, 1)) pobjid = pobjidhi*256 + pobjidlo optype = asc(mid(rsppkt, 8, 1)) ' make sure it is an enable response operation type if optype <> 0x6 then print "Expected Enable Response (6), got ", optype, "\r\n" exit function endif ' make sure the object id matches if pobjid <> objid then print "Expected objid ", objid, ", got ", pobjid, "\r\n" exit function endif check_enable_response = TRUE end function ' checks for a valid get response packet ' function check_get_response(rsppkt, objid) local pobjidhi, pobjidlo, pobjid, optype check_get_response = FALSE if is_valid_cns_packet(rsppkt) = FALSE then exit function endif ' check the CnS packet pobjidhi = asc(mid(rsppkt, 6, 1)) pobjidlo = asc(mid(rsppkt, 7, 1)) pobjid = pobjidhi*256 + pobjidlo optype = asc(mid(rsppkt, 8, 1)) ' make sure it is a get response operation type if optype <> 0x2 then print "Expected Get Response (2), got ", optype, "\r\n" exit function endif ' make sure the object id matches if pobjid <> objid then print "Expected objid ", objid, ", got ", pobjid, "\r\n" exit function endif check_get_response = TRUE end function function decode_call_disc(discpkt, cnslen) local callstate, discreason, discstr if cnslen < 4 then exit function callstate = asc(mid(discpkt, 16, 1))*256 + asc(mid(discpkt, 17, 1)) discreason = asc(mid(discpkt, 18, 1))*256 + asc(mid(discpkt, 19, 1)) if discreason = 0 then discstr = "Modem offine" elseif discreason = 1 then discstr = "Modem CDMA locked until power cycle" elseif discreason = 2 then discstr = "No service" else discstr = "code " & discreason endif eventmsg "OTASP call disconnected, reason: " & discstr end function ' checks for a valid OTASP notification ' if so, we check to see if we got an OTASP notification indicating successful NVRAM commit ' function check_otasp_done(rsppkt, objid) local inthi, intlo, pobjid, optype, cnslen, otaspstate, otaspsuccess check_otasp_done = FALSE if is_valid_cns_packet(rsppkt) = FALSE then exit function endif ' check the CnS packet inthi = asc(mid(rsppkt, 6, 1)) intlo = asc(mid(rsppkt, 7, 1)) pobjid = inthi*256 + intlo optype = asc(mid(rsppkt, 8, 1)) cnslen = asc(mid(rsppkt, 15, 1)) ' make sure it is a notification operation type (7) if optype <> 0x7 then print "Expected Notification (7), got ", optype, "\r\n" exit function endif ' see if it's a call disconnect notification (0x300C) if pobjid = 0x300C then decode_call_disc(rsppkt, cnslen) exit function endif ' make sure the object id matches if pobjid <> objid then print "Expected objid ", objid, ", got ", pobjid, "\r\n" exit function endif if cnslen < 4 then print "Expected OTASP length 4, got ", cnslen, "\r\n" endif inthi = asc(mid(rsppkt, 16, 1)) intlo = asc(mid(rsppkt, 17, 1)) otaspstate = inthi*256 + intlo inthi = asc(mid(rsppkt, 18, 1)) intlo = asc(mid(rsppkt, 19, 1)) otaspsuccess = inthi*256 + intlo if otaspstate = 8 and otaspsuccess = 1 then check_otasp_done = TRUE endif otaspstatestr = "unknown" if otaspstate = 1 then otaspstatestr = "SPL unlock" elseif otaspstate = 2 then otaspstatestr = "AKey exchange" elseif otaspstate = 3 then otaspstatestr = "SSD update" elseif otaspstate = 4 then otaspstatestr = "NAM download" elseif otaspstate = 5 then otaspstatestr = "MDM download" elseif otaspstate = 6 then otaspstatestr = "IMSI download" elseif otaspstate = 7 then otaspstatestr = "PRL download" elseif otaspstate = 8 then otaspstatestr = "NVRAM commit" endif eventmsg "Got OTASP state=" & otaspstate & "(" & otaspstatestr & "), success=" & otaspsuccess end function ' Close i/o handles and try to put the config back the way it was ' If using a TCP socket we only have one handle to close. function restorecfg local res, resstr if atopened <> 0 then if socketopened = 0 then close(mc75out) endif close(mc75in) endif if cnsopened <> 0 then close(cnsout) close(cnsin) endif sleep(1) res = execute("modemconn", 0, resstr) end function ' sends a command to the modem and returns the first reponse line ' function modem_cmd(cmd_str) local i, nlines, rsplines modem_cmd = "" print #mc75out, cmd_str & "\r" nlines = getResplines(rsplines) if nlines = 0 then eventmsg "No response to " & cmd_str exit function endif if rsplines[nlines-1] <> "OK" then eventmsg cmd_str & " did not return OK, got " & rsplines[nlines-1] exit function endif ' for i = 0 to nlines-1 ' eventmsg "Got line: " & rsplines[i] ' next i for i = 0 to nlines-1 if rsplines[i] <> "" AND rsplines[i] <> cmd_str then modem_cmd = rsplines[i] exit function endif next i end function ' check to see if the user clicked cancel ' The web form handler signals this to us by setting the MIB variable ' provision.0.userstring1 = ABORT ' function check_user_abort if mib_val("provision.0.userstring1") = "ABORT" then restorecfg() errexit "Activation cancelled by user" endif end function ' CnS operation codes const CNS_GET_REQUEST = 1 const CNS_GET_REPLY = 2 const CNS_SET_COMMAND = 3 const CNS_SET_ACKNOWLEDGE = 4 const CNS_NOTIFICATION_ENABLE = 5 const CNS_ENABLE_RESPONSE = 6 const CNS_NOTIFICATION = 7 const CNS_NOTIFICATION_DISABLE = 8 const CNS_FORWARD_DISABLE_ACKNOWLEDGE = 9 ' the index of the first Cns payload byte in a received packet const CNS_PAYLOAD_INDEX = 16 ' Send a CnS request message for the given object id ' ' optype: the CnS operation type: ' 1: Get request ' 3: Set request ' 5: Notification enable ' 8: Notification disable ' objid: the Cns object ID ' payloaddata: an array containing the Cns payload data starting at index 0 ' payloadlen: the number of bytes in the payload data ' ' Uses the global file handle cnsout to send the data ' function send_cns(optype, objid, payloaddata, payloadlen) local i, buf, msglen, ostr ' HIP header: payload len hi, payload len lo, message id (host to modem), parameter i = payloadlen+10 buf[1] = i\256 buf[2] = i AND 255 buf[3] = 0x2b buf[4] = 0 ' CnS message buf[5] = objid\256 buf[6] = objid AND 255 buf[7] = optype buf[8] = 0 buf[9] = 0 buf[10] = 0 buf[11] = 0 buf[12] = 0 buf[13] = payloadlen\256 buf[14] = payloadlen AND 255 if payloadlen <> 0 then for i = 0 to payloadlen-1 buf[15+i] = payloaddata[i] next i endif msglen = payloadlen + 14 ' add framing and escape characters ostr = chr(0x7e) for i = 1 to msglen if buf[i] = 0x7e or buf[i] = 0x7d then ostr = ostr & chr(0x7d) ostr = ostr & chr(buf[i] XOR 0x20) else ostr = ostr & chr(buf[i]) endif next i ostr = ostr & chr(0x7e) print #cnsout, ostr end function ' Gets the modem model. ' We need to use CnS here because of a bug in the AT command on the MC5727 ' function get_modem_model local CnsPortName, rsp, cnslen, inthi, intlo, modemtype get_modem_model = "" ' open the CnS port ' errcnt = 0 CnsPortName = "ASY" & infoasystr cnsout = 0 cnsin = 0 open CnsPortName for output as cnsout open CnsPortName for input as cnsin cnsrxbuf = "" cnsopened = 1 send_cns(CNS_GET_REQUEST, 0x000A, undef, 0) rsp = get_cns_response1(5) if rsp = "" then restorecfg() errexit "Activation failed: no response to CnS model ID request" endif if check_get_response(rsp, 0x000A) = FALSE then restorecfg() errexit "Activation failed: bad response to CnS model ID request" endif cnslen = asc(mid(rsp, 15, 1)) if cnslen < 4 then restorecfg() errexit "Expected CnS length at least 4, got " & cnslen endif inthi = asc(mid(rsp, 18, 1)) intlo = asc(mid(rsp, 19, 1)) modemtype = inthi*256 + intlo eventmsg "Got modem model " & modemtype close(cnsout) close(cnsin) cnsopened = 0 if modemtype = 0x11 then get_modem_model = "MC5725" else if modemtype = 0x25 then get_modem_model = "MC5727" endif end function ' This runs through the Over-The-Air Service Provisioning procedure ' for the Verizon network. ' function do_verizon local CnsPortName, rsp, ticks_end, otasp_done, i, GotOK, mdn, rslt eventmsg "Verizon OTASP provisioning started" ' open the CnS port ' errcnt = 0 CnsPortName = "ASY" & infoasystr cnsout = 0 cnsin = 0 open CnsPortName for output as cnsout open CnsPortName for input as cnsin cnsrxbuf = "" cnsopened = 1 ' try the call notification status objects too ' ' send_cns(CNS_NOTIFICATION_ENABLE, 0x300E, undef, 0) ' rsp = get_cns_response1(5) ' send_cns(CNS_NOTIFICATION_ENABLE, 0x3011, undef, 0) ' rsp = get_cns_response1(5) ' send_cns(CNS_NOTIFICATION_ENABLE, 0x300A, undef, 0) ' rsp = get_cns_response1(5) ' send_cns(CNS_NOTIFICATION_ENABLE, 0x3004, undef, 0) ' rsp = get_cns_response1(5) ' send_cns(CNS_NOTIFICATION_ENABLE, 0x3012, undef, 0) ' rsp = get_cns_response1(5) ' enable call disconnected object (0x300C) ' send_cns(CNS_NOTIFICATION_ENABLE, 0x300c, undef, 0) rsp = get_cns_response1(5) if rsp = "" then restorecfg() errexit "OTASP failed: no response to CnS request" endif if check_enable_response(rsp, 0x300C) = FALSE then restorecfg() errexit "OTASP failed: bad response to CnS request" endif ' enable OTASP notification messages (objid 0x3014) ' send_cns(CNS_NOTIFICATION_ENABLE, 0x3014, undef, 0) rsp = get_cns_response1(5) if rsp = "" then restorecfg() errexit "OTASP failed: no response to CnS request" endif if check_enable_response(rsp, 0x3014) = FALSE then restorecfg() errexit "OTASP failed: bad response to CnS request" endif ' Now initiate the provisioning call (we don't expect a response from this command) ' eventmsg "Sent AT+CDV*22899" print #mc75out, "AT+CDV*22899\r" eventmsg "Monitoring progress (up to 5 mins)..." ' set the end time. ticks are units of 10ms ' 5 mins normally ticks_end = ticks + 5*60*100 ' 15 secs for debugging ' ticks_end = ticks + 15*100 ' now sit and wait for OTASP notifications ' otasp_done = FALSE while ticks <= ticks_end and otasp_done = FALSE rsp = get_cns_response1(5) if rsp <> "" then if check_otasp_done(rsp, 0x3014) = TRUE then otasp_done = TRUE endif endif check_user_abort() wend if otasp_done = FALSE then restorecfg() errexit "OTASP failed: timeout awaiting NVRAM commit" endif ' Looks like provisioning worked. Let's try reading back the MDN ' ' First AT the modem again clear_mc75io() i = 0 GotOK = false while i < 10 and GotOK = false i += 1 print "Sending AT...", nl print #mc75out, "AT\r" if getOKline() = true then GotOK = true wend ' now query the MIN/MDN ' We should get something like this: ' ' at~namval?0 ' MDN: 2023292944 ' MIN: 2023292944 ' SID: 18 ' NID: 65535 print #mc75out, "AT~NAMVAL?0\r" mdn = "" rslt = getResplines(rsplines) if rslt <> 0 then mdn = extract_result(rsplines, rslt, "MDN: ") endif ' send a reset command. Don't worry about the reply as we'll be rebooting anyway ' ' eventmsg "Sent AT!RESET" ' print #mc75out, "AT!RESET\r" ' Restore the modem connection ' restorecfg() errexit "Verizon OTASP SUCCESSFUL (MDN=" & mdn & ")" end function ' This runs through the Over-The-Air Service Provisioning procedure ' for the Sprint network. ' function do_sprint local i, msl_str, mdn_str, min_str, reset_cmd, iota_cmd, namlck_cmd, namval_cmd, namval0_cmd local iota_done, ticks_end, iotaline eventmsg "Sprint activation started" ' Get the optional parameters. ' First check the command line, as this can override the configured parameters ' Then check the provisioning config settings. These are: ' ' string1: the MSL ' string2: the MDN ' string3: the MIN/MSID ' split command() by " " to msl_str, mdn_str, min_str if isundef(msl_str) or isundef(mdn_str) or isundef(min_str) then if getParam("provision 0 string1 ?", msl_str) = TRUE then if getParam("provision 0 string2 ?", mdn_str) = TRUE then if getParam("provision 0 string3 ?", min_str) = TRUE then else errexit "failed to get min_str\r\n" endif else errexit "failed to get mdn_str\r\n" endif else errexit "failed to get msl_str\r\n" endif ' print "\nUsage: sprint.sb \n" ' errexit "Sprint activation failed: missing parameters" ' exit sub endif print "msl_str=", msl_str, ", mdn_str=", mdn_str, ", min_str=", min_str, "\r\n" ' We allow the MSL to be omitted, but if it is present then the PTN and MSID must also be provided ' if msl_str = "" then eventmsg "MSL parameter not present: MDN and MSID will not be programmed " else if mdn_str = "" then errexit "Sprint activation failed: missing PTN parameter" endif if min_str = "" then errexit "Sprint activation failed: missing MSID parameter" endif endif ' Now reconnect to the module via a TCP connection ' We need to do this because the Sprint provisioning process can generate ' large bursts of data (typical outout is 33Kbytes). The serial interface has ' a limited receive buffer size, whereas the TCP interface can handle this. ' close(mc75in) close(mc75out) mc75in = 0 mc75port = 4000 + val(asystr) open "127.0.0.1:" & mc75port for socket as mc75in mc75out = mc75in mc75rxbuf = "" socketopened = 1 junk = setevent(0) junk = setevent(mc75in) eventmsg "Sprint: connected to modem on " & AsyPortName reset_cmd = "AT!RESET" iota_cmd = "AT!IOTASTART" if left(modem_model, 6) = "MC5727" then iota_cmd = "AT!DMDC=2" endif ' only write the account activation data if it was supplied ' if msl_str <> "" then namlck_cmd = "AT~NAMLCK=" & msl_str namval_cmd = "AT~NAMVAL=0," & mdn_str & "," & min_str & ",0,0" namval0_cmd = "AT~NAMVAL=0" ' Enter the MSL to unlock the modem ' eventmsg "Sent " & namlck_cmd print #mc75out, namlck_cmd, "\r" if getOKline() = false then restorecfg() errexit "Sprint activation failed: NAMLCK failed" endif ' Enter phonenumber etc ' eventmsg "Sent " & namval_cmd print #mc75out, namval_cmd, "\r" if getOKline() = false then restorecfg() errexit "Sprint activation failed: NAMVAL failed" endif ' Set the NAM ' eventmsg "Sent " & namval0_cmd print #mc75out, namval0_cmd, "\r" if getOKline() = false then restorecfg() errexit "Sprint activation failed: NAMVAL failed" endif ' Send a reset ' eventmsg "Sent " & reset_cmd print #mc75out, reset_cmd, "\r" if getOKline() = false then restorecfg() errexit "Sprint activation failed: RESET failed" endif ' close the socket while we wait for a reset ' close(mc75in) socketopened = 0 eventmsg "Waiting 30 secs for modem reset" sleep(30) ' now reopen the socket ' mc75in = 0 open "127.0.0.1:" & mc75port for socket as mc75in mc75out = mc75in mc75rxbuf = "" socketopened = 1 junk = setevent(0) junk = setevent(mc75in) ' ' First AT the modem again clear_mc75io() i = 0 GotOK = false while i < 10 and GotOK = false i += 1 print "Sending AT...", nl print #mc75out, "AT\r" if getOKline() = true then GotOK = true wend if GotOK = false then restorecfg() errexit "Sprint activation failed: AT failed after RESET" endif endif ' now start up the IOTA session ' eventmsg "Sent " & iota_cmd print #mc75out, iota_cmd, "\r" ' set the end time. ticks are units of 10ms ' 5 mins normally ticks_end = ticks + 5*60*100 ' 15 secs for debugging ' ticks_end = ticks + 15*100 ' now sit and wait for an OK response ' log all output received ' iota_done = FALSE while ticks <= ticks_end and iota_done = FALSE if getline(iotaline) = TRUE then logmsg iotaline if iotaline = "ERROR" then restorecfg() errexit "Sprint activation failed: ERROR result received" endif if iotaline = "OK" then iota_done = TRUE endif endif wend if iota_done = FALSE then restorecfg() errexit "Sprint activation failed: timeout awaiting OK result" endif ' send a reset command. Don't worry about the reply as we'll be rebooting anyway ' eventmsg "Sent AT!RESET" print #mc75out, "AT!RESET\r" ' Restore the modem connection ' restorecfg() errexit "Sprint activation SUCCESSFUL" end function ' decode a MODIND update progress code ' function decode_modind(mcode) local mcodestr if mcode = 1 then mcodestr = "Network Initiated, INFORMATIVE" elseif mcode = 2 then mcodestr = "CIDC Started" elseif mcode = 3 then mcodestr = "Network Initiated, BACKGROUND" elseif mcode = 4 then mcodestr = "CIPRL Started" elseif mcode = 5 then mcodestr = "HFA Started" elseif mcode = 6 then mcodestr = "Checking for DC Update" elseif mcode = 7 then mcodestr = "Updating DC" elseif mcode = 8 then mcodestr = "No provisioning update available" elseif mcode = 9 then mcodestr = "Checking for PRL Update" elseif mcode = 10 then mcodestr = "Updating PRL" elseif mcode = 11 then mcodestr = "No PRL update available" elseif mcode = 12 then mcodestr = "DC Update Complete" elseif mcode = 13 then mcodestr = "PRL Update Complete" elseif mcode = 14 then mcodestr = "HFA Update Complete" elseif mcode = 15 then mcodestr = "Update Failed Error xxx" elseif mcode = 16 then mcodestr = "Retry Re-Establish Session" elseif mcode = 17 then mcodestr = "Session Aborted" elseif mcode = 18 then mcodestr = "Network Initiated, Complete" else mcodestr = "Unknown" endif eventmsg "DM status: " & mcodestr end function ' ' Runs the OMA DM provisioning on a Motorola C24 (normally for Sprint) ' function do_motorola_oma_dm local moddc_cmd, modind_cmd, modci_cmd, ticks_end, iota_done, modindline, mpos, mcode ' command to enable device configuration moddc_cmd = "AT+MODDC=1" ' command to enable unsolicited progress reports modind_cmd = "AT+MODIND=1" ' command to start client initiated device configuration modci_cmd = "AT+MODCI=0" eventmsg "Sent " & moddc_cmd print #mc75out, moddc_cmd, "\r" if getOKline() = false then restorecfg() errexit "Activation failed: MODDC command failed" endif eventmsg "Sent " & modind_cmd print #mc75out, modind_cmd, "\r" if getOKline() = false then restorecfg() errexit "Activation failed: MODIND command failed" endif eventmsg "Sent " & modci_cmd print #mc75out, modci_cmd, "\r" if getOKline() = false then restorecfg() errexit "Activation failed: MODCI command failed" endif ' now sit and wait for progress reports ' log all output received ' eventmsg "Monitoring progress (up to 5 mins)..." ' set the end time. ticks are units of 10ms ' 5 mins normally ticks_end = ticks + 5*60*100 ' 15 secs for debugging ' ticks_end = ticks + 15*100 iota_done = FALSE while ticks <= ticks_end and iota_done = FALSE if getline(modindline) = TRUE then if modindline <> "" then eventmsg "Received: " & modindline mpos = instr(modindline, "+MODIND: ") if mpos > 0 then mcode = val(mid(modindline, mpos+9)) decode_modind(mcode) if mcode = 15 or mcode = 17 then restorecfg() errexit "Activation failed" endif if mcode = 12 or mcode = 18 then iota_done = TRUE endif endif endif wend if iota_done = FALSE then restorecfg() errexit "Activation failed: timeout awaiting completion" endif ' send a reset command. Don't worry about the reply as we'll be rebooting anyway ' eventmsg "Sent AT$SPRESET" print #mc75out, "AT$SPRESET\r" ' Restore the modem connection ' restorecfg() errexit "Activation SUCCESSFUL" end function ' This function uses the mib() function to read ' a MIB variable. It then breaks up the resultant ' string and returns the value of the variable. ' function mib_val(var_name) local a, ps mib_val = "" a = chomp(mib(var_name)) ps = instr(a, " = ") if ps > 0 then mib_val = mid(a, ps+3) endif end function ' ******** MAIN PROGRAM STARTS HERE ******** errcnt = 0 socketopened = 0 cnsopened = 0 atopened = 0 init_log_files() eventmsg "Activation script started at " & FormatDate("0D-MON-YY 0H:0m:0s",tnow) ' clear the abort signal ' junk = mibset("provision.0.userstring1", "") ' clear the last exit message ' junk = mibset("provision.0.userstring2", "Started at " & FormatDate("0D-MON-YY 0H:0m:0s",tnow)) ' Find out what ASY port is used by modemcc for GPRS ' if getParam("modemcc 0 asy_add ?", asystr) = TRUE then print "modemcc 0 asy_add is: ", asystr, nl else errexit "Activation cannot start: unable to get modemcc 0 asy_add" endif if asystr = "255" or asystr = "0" or asystr = "" then errexit "Activation cannot start: invalid modemcc asy_add (try muxon)" endif ' Find out what INFO ASY port is used by modemcc for GPRS ' if getParam("modemcc 0 info_asy_add ?", infoasystr) = TRUE then print "modemcc 0 info_asy_add is: ", infoasystr, nl else errexit "Activation cannot start: unable to get modemcc 0 info_asy_add" endif if infoasystr = "0" or infoasystr = "" then errexit "Activation cannot start: invalid modemcc info_asy_add (try muxon)" endif ' Find out which PPP instance is configured for GPRS ' got_gprs_ppp = get_gprs_ppp_instance(gprs_ppp_instance) ' deactivate PPP ' if got_gprs_ppp then print "PPP ", gprs_ppp_instance, " is configured for GPRS", nl res = execute("ppp " & gprs_ppp_instance & " deact_rq", 0, resstr) sleep(1) else print "No PPP instances configured for GPRS", nl endif ' now reset the modem and disable the driver ' res = execute("modemoff", 0, resstr) eventmsg "Resetting modem..." for i = 1 to 5 sleep(1) check_user_abort() next i ' the modemdisc command releases the modemports and disables the driver ' res = execute("modemdisc", 0, resstr) for i = 1 to 15 sleep(1) check_user_abort() next i ' initialise the AT serial port IO ' AsyPortName = "ASY" & asystr mc75asyport = AsyPortName print "AsyPortName = ", AsyPortName, nl init_mc75io() atopened = 1 ' First make sure we can talk to the device by ATing it ' until we get OK back ' i = 0 GotOK = false while i < 10 and GotOK = false i += 1 print "Sending AT...", nl print #mc75out, "AT\r" if getOKline() = true then GotOK = true check_user_abort() wend if GotOK = false then restorecfg() errexit "Activation failed: cannot AT device on " & AsyPortName endif manufacturer = modem_cmd("AT+GMI") eventmsg "Manufacturer is: " & manufacturer if instr(manufacturer, "Motorola") <> undef then eventmsg "Motorola module specific provisioning starting" do_motorola_oma_dm() else eventmsg "Sierra Wireless module specific provisioning starting" carrierid = modem_cmd("AT+CARRIERID?") eventmsg "Carrier ID is: " & carrierid ' modem_model = modem_cmd("AT+GMM") ' eventmsg "Modem model is: " & modem_model modem_model = get_modem_model() eventmsg "Modem model is: " & modem_model check_user_abort() ' now go to the carrier specific functions ' if carrierid = "5" then eventmsg "Module is configured for Verizon" do_verizon() else if carrierid = "2" then eventmsg "Module is configured for Sprint" do_sprint() else restorecfg() errexit "Cannot start activation: unrecognised carrier ID" endif endif stop ErrorLabel: 'print "Got error code: ", error(), "(", error$, ")", nl if error() = 22 and errcnt < 20 then print "Retrying connection ...", nl sleep(1) errcnt = errcnt + 1 on error goto ErrorLabel resume endif restorecfg() errexit(error$)