' prlupdate.sb ' ' Does a PRL update from a file ' ' 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, "PRL Update 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, "PRL Update 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, "

PRL update started. See below for progress

\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, "PRL Update 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 ' 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) if asyportchanged <> 0 then res = execute("modemcc 0 asy_add " & asystr, 0, resstr) else res = execute("modemconn", 0, resstr) endif 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) if do_restore <> 0 then restorecfg() log_status(msg) print #aspout, msg, nl print msg, nl print "Please reboot the router", nl junk = system("setevent \"" & msg & "\"" & " 6") 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 retuned 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 ' 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 ' sends a command to the modem and returns the reponse lines ' function modem_cmd_lines(cmd_str, rsplines) local i, j, nlines, rlines modem_cmd_lines = 0 print #mc75out, cmd_str & "\r" nlines = getResplines(rlines) if nlines = 0 then eventmsg "No response to " & cmd_str exit function endif j = 0 for i = 0 to nlines-1 if rlines[i] <> "" AND rlines[i] <> cmd_str then rsplines[j] = rlines[i] j += 1 endif next i modem_cmd_lines = j 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 ' 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 get 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 ' 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 ' 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 ' return <0 if there's something wrong with it, otherwise the length of the CnS payload data ' function check_cns_packet(rsppkt, optype, objid) local plenhi, plenlo, plen, msgid, pobjidhi, pobjidlo, pobjid, poptype, payloadlen ' check for empty packet if rsppkt = "" then print "No CnS reply\r\n" check_cns_packet = -1 exit function endif ' 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 len(rsppkt) <> plen+6 then print "Bad HIP payload length\r\n" check_cns_packet = -2 exit function endif if msgid <> 0x6B then print "Unknown Message ID\r\n" check_cns_packet = -3 exit function endif ' check the CnS packet pobjidhi = asc(mid(rsppkt, 6, 1)) pobjidlo = asc(mid(rsppkt, 7, 1)) pobjid = pobjidhi*256 + pobjidlo poptype = asc(mid(rsppkt, 8, 1)) payloadlen = asc(mid(rsppkt, 15, 1)) print "CnS header: Objid=0x", format("%04X", pobjid), ", Optype=0x", format("%02X", poptype), ", Payloadlen=", payloadlen, "\r\n" if (poptype and 0x80) <> 0 then print "Got CnS Error response: ", mid(rsppkt, 16, payloadlen), "\r\n" check_cns_packet = -4 exit function endif if pobjid <> objid then print "Unexpected Object ID\r\n" check_cns_packet = -5 exit function endif if poptype <> optype then print "Unexpected Operation type\r\n" check_cns_packet = -6 exit function endif if payloadlen+10 <> plen then print "Bad CnS payload length\r\n" check_cns_packet = -7 exit function endif check_cns_packet = payloadlen end function function recv_cns(rsppkt, optype, objid) local payloadlen, rslt rsppkt = get_cns_response1(5) rslt = check_cns_packet(rsppkt, optype, objid) ' we can extract the message from an error response if rslt = -4 then payloadlen = asc(mid(rsppkt, 15, 1)) if payloadlen <> 0 then eventmsg "Received CnS error response: " & mid(rsppkt, CNS_PAYLOAD_INDEX, payloadlen) endif recv_cns = rslt end function ' opens a file for reading ' returns the file handle, or -1 on error function openfile(filename) local fh openfile = -1 fh = 0 on error goto openfileerror open filename for input as fh openfile = fh exit function openfileerror: print "Error opening the file\r\n" end function ' get the size in bytes of the given file ' return 0 if we can't open it ' function getfilesize(filename) local fh, n, total_bytes, buf getfilesize = 0 total_bytes = 0 fh = openfile(filename) if fh = -1 then exit function while not eof(fh) buf = input(120, fh) n = len(buf) total_bytes += n wend getfilesize = total_bytes close(fh) end function function decode_prl_write_result(rcode) if rcode = 0 then decode_prl_write_result = "Success" else if rcode = 1 then decode_prl_write_result = "SPC is locked" else if rcode = 2 then decode_prl_write_result = "PRL size not set" else if rcode = 3 then decode_prl_write_result = "incorrect NAM set" else if rcode = 4 then decode_prl_write_result = "incorrect block sequence" else if rcode = 5 then decode_prl_write_result = "incorrect block size" else if rcode = 6 then decode_prl_write_result = "invalid PRL (CRC failure)" else if rcode = 7 then decode_prl_write_result = "invalid write" else decode_prl_write_result = "Unknown reason (" & rcode & ")" endif end function ' unlock an activation session using the two step activation validation sequence ' function do_unlock(msl_string) local t0, t1, scd, scr, srd, srr, cnsbuf, rsp, rslt do_unlock = false ' construct and send 8 Secure Challenge Digits (scd) ' t0 = rnd() % 100 if t0 = 0 then t0 += 1 scd = str(t0 * msl_string) while len(scd) < 8 scd = "0" & scd wend cnsbuf[0] = asc(mid(scd, 1, 1)) cnsbuf[1] = asc(mid(scd, 2, 1)) cnsbuf[2] = asc(mid(scd, 3, 1)) cnsbuf[3] = asc(mid(scd, 4, 1)) cnsbuf[4] = asc(mid(scd, 5, 1)) cnsbuf[5] = asc(mid(scd, 6, 1)) cnsbuf[6] = asc(mid(scd, 7, 1)) cnsbuf[7] = asc(mid(scd, 8, 1)) send_cns(CNS_SET_COMMAND, 0x1015, cnsbuf, 8) ' receive 10 digit Secure Challenge Response (scr) ' rslt = recv_cns(rsp, CNS_SET_ACKNOWLEDGE, 0x1015) if rslt <> 10 then eventmsg "Bad response to secure challenge" exit function endif scr = mid(rsp, CNS_PAYLOAD_INDEX, 10) ' construct and send 4 Secure Rebuttal Digits (srd) ' t1 = scr\scd - 1 srd = str(t1 * t0) while len(srd) < 4 srd = "0" & srd wend cnsbuf[0] = asc(mid(srd, 1, 1)) cnsbuf[1] = asc(mid(srd, 2, 1)) cnsbuf[2] = asc(mid(srd, 3, 1)) cnsbuf[3] = asc(mid(srd, 4, 1)) send_cns(CNS_SET_COMMAND, 0x1016, cnsbuf, 4) ' receive UINT16 Secure Rebuttal Response (srr) ' rslt = recv_cns(rsp, CNS_SET_ACKNOWLEDGE, 0x1016) if rslt <> 2 then eventmsg "Bad response to secure rebuttal" eventmsg "T0:" & t0 & " SCD:" & scd & " SCR:" & scr & " SRD:" & srd exit function endif srr = asc(mid(rsp, CNS_PAYLOAD_INDEX, 1))*256 + asc(mid(rsp, CNS_PAYLOAD_INDEX+1, 1)) if srr = 1 or srr = 2 then do_unlock = true exit function endif eventmsg "Activation challenge failed: possible incorrect MSL" eventmsg "T0:" & t0 & " SCD:" & scd & " SCR:" & scr & " SRD:" & srd & " SRR:" & srr end function ' This runs through the PRL Update procedure for Sierra Wireless modules ' function do_prlupdate local CnsPortName, rsp, rslt, cnsbuf, prlversion, prlsize, prlfile, prlfh, prlbuf, n, i, prlrslt eventmsg "PRL update started" ' Get the parameters. ' First check the command line, as this can override the configured parameters ' Then check the provisioning config settings. These are: ' ' string1: the MSL ' string20: the PRL filename ' split command() by " " to msl_str, prlfile if isundef(msl_str) or isundef(prlfile) then if getParam("provision 0 string1 ?", msl_str) = TRUE then if getParam("provision 0 string20 ?", prlfile) = TRUE then else errexit "failed to get prlfile\r\n" endif else errexit "failed to get msl_str\r\n" endif ' print "\nUsage: prlupdate.sb \r\n" ' errexit "PRL update failed: missing parameters" ' exit sub endif print "msl_str=", msl_str, ", prlfile=", prlfile, "\r\n" if msl_str = "" then errexit "PRL update failed: missing MSL parameter" if prlfile = "" then errexit "PRL update failed: missing PRL file parameter" fsize = getfilesize(prlfile) if fsize = 0 then errexit "PRL update failed: couldn't get PRL filesize" ' 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 if do_unlock(msl_str) = false then errexit "PRL update failed: cannot unlock modem" eventmsg "Modem unlocked successfully" ' Get the current PRL version ' send_cns(CNS_GET_REQUEST, 0x1008, undef, 0) rslt = recv_cns(rsp, CNS_GET_REPLY, 0x1008) if rslt < 0 then errexit "PRL update failed: bad response getting current PRL version" prlversion = asc(mid(rsp, CNS_PAYLOAD_INDEX, 1))*256 + asc(mid(rsp, CNS_PAYLOAD_INDEX+1, 1)) eventmsg "Current PRL Version is " & prlversion ' Get the current PRL size ' ' UINT16 parameter: NAM cnsbuf[0] = 0 cnsbuf[1] = 0 send_cns(CNS_GET_REQUEST, 0x1052, cnsbuf, 2) rslt = recv_cns(rsp, CNS_GET_REPLY, 0x1052) if rslt < 0 then errexit "PRL update failed: bad response getting current PRL size" prlsize = asc(mid(rsp, CNS_PAYLOAD_INDEX+4, 1))*256 + asc(mid(rsp, CNS_PAYLOAD_INDEX+5, 1)) eventmsg "Current PRL size is " & prlsize print "PRL file size is ", fsize, nl ' now try setting the PRL size just to see what error we get ' ' parameters are NAM (UINT16), PRL Size (UINT32) cnsbuf[0] = 0 cnsbuf[1] = 0 cnsbuf[2] = 0 cnsbuf[3] = 0 cnsbuf[4] = fsize\256 cnsbuf[5] = fsize AND 255 send_cns(CNS_SET_COMMAND, 0x1052, cnsbuf, 6) rslt = recv_cns(rsp, CNS_SET_ACKNOWLEDGE, 0x1052) if rslt < 0 then errexit "PRL update failed: bad response setting the PRL size" ' now try writing the PRL file to see the responses ' we write in 120 byte chunks ' prlfh = openfile(prlfile) if prlfh = -1 then errexit "PRL update failed: couldn't open PRL file" prlblk = 0 while not eof(prlfh) prlbuf = input(120, prlfh) n = len(prlbuf) ' parameters are: NAM (UINT16), Block number (UINT16), Block size (UINT16), Block data cnsbuf[0] = 0 cnsbuf[1] = 0 cnsbuf[2] = 0 cnsbuf[3] = prlblk cnsbuf[4] = 0 cnsbuf[5] = n for i = 1 to n cnsbuf[i+5] = asc(mid(prlbuf, i, 1)) next i send_cns(CNS_SET_COMMAND, 0x1054, cnsbuf, 6+n) rslt = recv_cns(rsp, CNS_SET_ACKNOWLEDGE, 0x1054) if rslt <> 2 then errexit "PRL update failed: bad response to PRL block write request" prlrslt = asc(mid(rsp, CNS_PAYLOAD_INDEX, 1))*256 + asc(mid(rsp, CNS_PAYLOAD_INDEX+1, 1)) if prlrslt <> 0 then errexit "PRL update failed: " & decode_prl_write_result(prlrslt) prlblk += 1 wend close(prlfh) errexit "PRL Update 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 ' This runs through the PRL Update procedure for Motorola modules ' function do_moto_prlupdate local modind_cmd, modci_cmd, ticks_end, iota_done, modindline, mpos, mcode ' command to enable unsolicited progress reports modind_cmd = "AT+MODIND=1" ' command to start client initiated PRL update modci_cmd = "AT+MODCI=1" eventmsg "Sent " & modind_cmd print #mc75out, modind_cmd, "\r" if getOKline() = false then errexit "PRL update failed: MODIND command failed" eventmsg "Sent " & modci_cmd print #mc75out, modci_cmd, "\r" if getOKline() = false then errexit "PRL update failed: MODCI command failed" ' now sit and wait for progress reports ' log all output received ' ' Typical sequence of reports is as follows (see decode_modind for meanings): ' +MODIND: 4 ' +MODIND: 9 ' +MODIND: 10 ' +MODIND: 13 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 = 8 or mcode = 11 or mcode = 15 or mcode = 17 then errexit "PRL update failed" if mcode = 13 then iota_done = TRUE endif endif endif wend if iota_done = FALSE then errexit "PRL update failed: timeout awaiting completion" ' 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" errexit "PRL update SUCCESSFUL" end function ' Do an automatic PRL update ' This is done using the "AT+PRL=2" command, and monitoring progress using "AT+OMADM=?" ' GOBI modules appear to reboot themselves at the end, so we try to detect this ' function do_gobi_auto local res, resstr, i local omadm_cmd, omadmstatus_cmd, rsp, nrsp, prev_rsp, prev_nrsp, tstart, ticks_end, omadm_done, state_changed ' errexit "Automatic update not yet implemented" ' reset the modem and disable the driver ' res = execute("modemoff", 0, resstr) eventmsg "Resetting modem..." for i = 1 to 5 sleep(1) next i ' and release only the AT port, not the info port ' res = execute("modemcc 0 asy_add 255", 0, resstr) asyportchanged = 1 for i = 1 to 35 sleep(1) 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 wend if GotOK = false then restorecfg() errexit "PRL update failed: cannot AT device on " & AsyPortName endif clear_mc75io() eventmsg "Automatic provisioning starting" omadm_cmd = "AT+PRL=2" omadmstatus_cmd = "AT+OMADM=?" ' get the initial status ' eventmsg "Getting initial status" init_nrsp = modem_cmd_lines(omadmstatus_cmd, init_rsp) if init_nrsp <> 0 then for i = 0 to init_nrsp-1 eventmsg init_rsp[i] next i else restorecfg() errexit "PRL update failed: failed to get initial status" endif ' Start up the OMADM session ' eventmsg "Sent " & omadm_cmd print #mc75out, omadm_cmd, "\r" if getOKline() = false then restorecfg() errexit "PRL update failed: bad response to " & omadm_cmd endif eventmsg "Monitoring status (up to 5 mins)..." ' set the end time. ticks are units of 10ms ' 5 mins normally ' ticks_end = ticks + 5*60*100 ' 60 secs for debugging tstart = ticks ticks_end = ticks + 60*100 ' now monitor the status ' prev_nrsp = 0 omadm_done = FALSE while ticks <= ticks_end and omadm_done = FALSE sleep(1) nrsp = modem_cmd_lines(omadmstatus_cmd, rsp) if nrsp <> 0 then ' check to see if state info has changed state_changed = 0 if nrsp <> prev_nrsp then state_changed = 1 else for i = 0 to nrsp-1 if prev_rsp[i] <> rsp[i] then state_changed = 1 endif next i endif ' and only report state if it has changed if state_changed <> 0 then for i = 0 to nrsp-1 eventmsg rsp[i] prev_rsp[i] = rsp[i] next i prev_nrsp = nrsp endif ' difficult to determine completion because it will ' probably always say "Device is programmed". ' So for now we just look for "None" after "Current device config session status:" ' ' first check to see if state info has changed from initial state init_state_changed = false if nrsp <> init_nrsp then init_state_changed = true else for i = 0 to nrsp-1 if init_rsp[i] <> rsp[i] then init_state_changed = true endif next i endif if (init_state_changed = false) and ((ticks-tstart) < 500) then ' hold off checking for the first 5 secs if there is no state change else for i = 0 to nrsp-1 if instr(rsp[i], "None") > 0 then omadm_done = TRUE endif next i endif endif wend if omadm_done = FALSE then restorecfg() errexit "PRL update failed: timeout awaiting completion" endif restorecfg() errexit "Automatic PRL update session finished" end function ' do a manual prl update ' this is done using the built in command "qmiprlupd" ' function do_gobi_manual local res res = execute("qmiprlupd", 130, resstr) if instr(resstr, "PRL update successful") > 0 then errexit "PRL successfully programmed" else errexit "PRL update failed: " & resstr end if end function ' For the GOBI module, we can do either automatic or manual update ' The method used depends on whether or not the MSL and PRL file parameters are given ' function do_gobi_prlupdate local msl_str, prlfile ' Get the parameters. ' ' string1: the MSL ' string20: the PRL filename ' if getParam("provision 0 string1 ?", msl_str) = TRUE then if getParam("provision 0 string20 ?", prlfile) = TRUE then else errexit "failed to get prlfile parameter\r\n" end if else errexit "failed to get msl_str parameter\r\n" end if print "msl_str=", msl_str, ", prlfile=", prlfile, "\r\n" ' do automatic update if MSL and PRL file are empty if msl_str = "" AND prlfile = "" then do_gobi_auto() exit function end if ' otherwise we need both for a manual update if msl_str = "" then errexit "PRL update failed: missing MSL parameter" if prlfile = "" then errexit "PRL update failed: missing PRL file parameter" do_gobi_manual() end function ' returns true if we are running GOBI CDMA firmware ' function gobi_module_detected local res, tmp gobi_module_detected = false res = execute("tags", 0, tmp) if res = true then if InStr(tmp, "QUALCOMM_GOBI_CDMA") > 0 then gobi_module_detected = true endif endif end function ' ******** MAIN PROGRAM STARTS HERE ******** errcnt = 0 socketopened = 0 cnsopened = 0 atopened = 0 do_restore = 0 asyportchanged = 0 init_log_files() tnow = now() and 0x7fffffff eventmsg "PRL update script started at " & FormatDate("0D-MON-YY 0H:0m:0s",tnow) gobi_module = gobi_module_detected() ' 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 "PRL update cannot start: unable to get modemcc 0 asy_add" endif if asystr = "255" or asystr = "0" or asystr = "" then errexit "PRL update 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 "PRL update cannot start: unable to get modemcc 0 info_asy_add" endif if infoasystr = "0" or infoasystr = "" then errexit "PRL update 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 if gobi_module then do_gobi_prlupdate() stop endif ' now reset the modem and disable the driver ' res = execute("modemoff", 0, resstr) eventmsg "Connecting to modem..." for i = 1 to 5 sleep(1) next i ' the modemdisc command releases the modemports and disables the driver ' res = execute("modemdisc", 0, resstr) do_restore = 1 for i = 1 to 15 sleep(1) 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 wend if GotOK = false then errexit "PRL update failed: cannot AT device on " & AsyPortName manufacturer = modem_cmd("AT+GMI") eventmsg "Manufacturer is: " & manufacturer if instr(manufacturer, "Motorola") <> undef then eventmsg "Motorola module specific PRL update starting" do_moto_prlupdate() else eventmsg "Sierra Wireless module specific PRL update starting" do_prlupdate() 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 errexit(error$)