Hello everyone,
I’m currently working on integrating a Sierra Wireless MC7340 module into a Digi WR21 router and am facing some configuration and provisioning challenges with the GPS, the modem works but i cannot get the GPS to work. I would appreciate any guidance or advice from the community to help resolve these issues.
Background: I have upgraded the cellular module in our Digi WR21 to a Sierra Wireless MC7340. The existing provisioning script, originally designed for a different module, uses a variety of AT commands and custom settings, and I need to ensure these are compatible or suitably updated for the MC7340.
' provision.sb
'
' This sends a series of configuration commands to the GPRS modem.
' In this case, the configuration commands are those used for provisioning
' the CMotech CDMA modems.
' Usage:
' bas provision.sb <IMSI> <NAI> <NAIPW>
'
' The script automatically works out which ASY port from the modemcc 0 asy_add setting
' It also deactivates the PPP instance just in case it's in use.
'
' Version2: for ICE/NMT PRI, added MDN (based on MIN), home SID/NID list etc
' Version2: also ICE/NMT PRI, added programming of ACCOLC via DM port
' version for NMT (Sweden)
' home sid/nid now programmed via DM port due to possible bug in CMotech AT command
' MCC and MNC are now correcly encoded following revelation from CMotech that these
' values are written unencoded to NVRAM (unlike the MIN which is correctly encoded).
' Version 4 for Norway, Sweden and Denmark
' Version 5 allows a directory number to be specified. If the a_key parameter is less
' than 20 digits, it is assumed to be a directory number and overrides builtin setting
' include "pppfcs.sb"
' 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"
' set to 1 to allow dprint messages
global_debug = 0
' Enter an error message in the event log and exit
' Also prints message to console output
'
function errexit(msg)
print "ERROR: " & msg & nl
junk = system("setevent \"" & msg & "\"" & " 6")
print "ERROR: provisioning failed" & nl
stop
end function
' Enter an error message in the event log
' Also prints message to console output
'
function eventmsg(msg)
print msg, nl
junk = system("setevent \"" & msg & "\"" & " 0")
end function
function dprint(msg)
if global_debug <> 0 then print msg & nl
end function
' From http://en.wikipedia.org/wiki/Computation_of_CRC
' // Least significant bit first (little-endian)
' // x^16+x^12+x^5+1 = 1000 0100 0000 1000 (1) = 0x8408
' Add FCS to GLOBAL array buf of length GLOBAL msglen
'
function addfcs
local remainder, i, j
remainder = 0xffff
for i = 1 to msglen
remainder = remainder xor buf[i]
for j = 1 to 8
if (remainder and 0x0001) <> 0 then
remainder = (remainder \ 2) xor 0x8408
else
remainder = remainder \ 2
endif
next j
next i
' print "\r\nFCS = 0x", format("%04X", remainder), "\r\n"
remainder = (NOT remainder) AND 0xffff
' print "\r\nInverted FCS = 0x", format("%04X", remainder), "\r\n"
buf[msglen+1] = remainder AND 255
buf[msglen+2] = remainder\256
msglen += 2
end function
' calculate the FCS for a string buffer
'
function calculate_fcs(string_data_buf, data_len)
local remainder, i, j
remainder = 0xffff
for i = 1 to data_len
remainder = remainder xor asc(mid(string_data_buf,i,1))
for j = 1 to 8
if (remainder and 0x0001) <> 0 then
remainder = (remainder \ 2) xor 0x8408
else
remainder = remainder \ 2
endif
next j
next i
remainder = (NOT remainder) AND 0xffff
calculate_fcs = remainder
end function
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
' Return the value of Sarian parameter in rsp
' strCmd needs to be of form "<entity name> <instance no> <parameter name> ?"
' 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
' ******** SERIAL IO FUNCTIONS ********
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
rxbuf = ""
junk = setevent(0)
junk = setevent(mc75in)
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
getchar = FALSE
tstart = ticks
while ticks-tstart < 1000
if len(rxbuf) <> 0 then
rsp = left(rxbuf, 1)
rxbuf = mid(rxbuf, 2)
getchar = TRUE
exit function
endif
if waitevents(1000) = mc75in then
junk = sockinfo(mc75in, sinfo)
' print "Bytes available = ", sinfo[2], nl
if sinfo[2] <> 0 then
rxbuf = input(sinfo[2], mc75in)
endif
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
function getRespline(rspline)
local i, myline
getRespline = FALSE
for i = 1 to 10
if getline(myline) <> TRUE then exit function
if (instr(myline, "OK") <> undef) or (instr(myline, "ERROR") <> undef) then
getRespline = TRUE
rspline = myline
exit function
endif
next i
end function
' send the DM command containing the given parameters
' Note that buf and msglen are GLOBAL (used by addfcs)
' The packet is sent to the GLOBAL file handle infoout
'
function send_dm(params, paramlen)
local i, ostr
for i = 1 to paramlen
buf[i] = params[i]
next i
msglen = paramlen
addfcs
' copy to the string ostr, adding framing and escape characters
'
ostr = ""
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)
' dump_packet(ostr, "Sending")
print #infoout, ostr
end function
'
' Receive a DM response and check the FCS
' The packet is read from the GLOBAL file handle infoin
'
function recv_dm(pkt)
local i, junk, complete, infoinbuf, pktbuf, infostat, unescstr, fcsval, actualfcs
recv_dm = FALSE
pktbuf = ""
i = 5
complete = FALSE
while i > 0 AND complete = FALSE
sleep(1)
junk = sockinfo(infoin, infostat)
dprint "bytes received = " & infostat[2]
if infostat[2] <> 0 then
infoinbuf = input(infostat[2], infoin)
pktbuf = pktbuf & infoinbuf
if asc(right(infoinbuf, 1)) = 0x7e then
complete = TRUE
unescstr = decode_escapes(pktbuf)
fcsval = calculate_fcs(unescstr, len(unescstr)-3)
dprint "Calculated FCS = 0x" & format("%04X", fcsval)
actualfcs = asc(mid(unescstr, len(unescstr)-2, 1)) + asc(mid(unescstr, len(unescstr)-1, 1))*256
dprint "Actual FCS = 0x" & format("%04X", actualfcs)
endif
endif
i -= 1
wend
if complete = FALSE then
dprint "No response"
exit function
endif
if fcsval <> actualfcs then
dprint "FCS error"
exit function
endif
recv_dm = TRUE
pkt = unescstr
end function
' Write the ACCOLC value. We have to do it with an NV write because CMotech's
' command NVW ACCOLC=<nam>,<value> doesn't work.
'
function write_accolc(accolc)
local i, dmbuf, pkt
write_accolc = FALSE
eventmsg "write_accolc(" & accolc & ")"
dmbuf[1] = 0x27
dmbuf[2] = 0x25
dmbuf[3] = 0x00
for i = 1 to 130
dmbuf[i+3] = 0
next i
dmbuf[5] = accolc
dmbuf[6] = accolc
send_dm(dmbuf, 133)
if recv_dm(pkt) = FALSE then exit function
write_accolc = TRUE
end function
' Write the HOME_SID_NID value. We have to do it with an NV write to item 0x103 because CMotech's
' command NVW HOME_SID_NID writes incorrect values
'
function write_home_sid_nid
local i, dmbuf, pkt
write_home_sid_nid = FALSE
' NV write command
dmbuf[1] = 0x27
' NV Item
dmbuf[2] = 0x03
dmbuf[3] = 0x01
for i = 1 to 130
dmbuf[i+3] = 0
next i
for i = 1 to home_sid_nid_len
' low byte
dmbuf[i*2+3] = home_sid_nid_list[i] AND 255
' high byte
dmbuf[i*2+4] = home_sid_nid_list[i] \ 256
next i
send_dm(dmbuf, 133)
if recv_dm(pkt) = FALSE then exit function
write_home_sid_nid = TRUE
end function
' write NV item 176 (0x00B0) containing the MCC (2 bytes)
'
function write_mcc(mccval)
local i, dmbuf, pkt
write_mcc = FALSE
eventmsg "write_mcc(" & mccval & ")"
dmbuf[1] = 0x27
dmbuf[2] = 0xB0
dmbuf[3] = 0x00
for i = 1 to 130
dmbuf[i+3] = 0
next i
dmbuf[5] = mccval AND 255
dmbuf[6] = mccval \ 256
send_dm(dmbuf, 133)
if recv_dm(pkt) = FALSE then exit function
write_mcc = TRUE
end function
' write NV item 177 (0x00B1) containing the MNC (1 byte)
'
function write_mnc(mncval)
local i, dmbuf, pkt
write_mnc = FALSE
eventmsg "write_mnc(" & mncval & ")"
dmbuf[1] = 0x27
dmbuf[2] = 0xB1
dmbuf[3] = 0x00
for i = 1 to 130
dmbuf[i+3] = 0
next i
dmbuf[5] = mncval
send_dm(dmbuf, 133)
if recv_dm(pkt) = FALSE then exit function
write_mnc = TRUE
end function
function restorecfg
local res
res = execute("modemcc 0 asy_add " & asystr, 0, resstr)
res = execute("modemcc 0 info_asy_add " & infoasystr, 0, resstr)
end function
' ******** MAIN PROGRAM STARTS HERE ********
errcnt = 0
split command() by " " to imsi, nai, naipw, a_key
print "\r\n"
if isundef(imsi) or isundef(nai) or isundef(naipw) then
errexit "Incorrect usage: provision.sb <IMSI> <NAI> <NAIPW>"
exit sub
endif
dirnum = ""
akey = ""
if isdefined(a_key) then
dprint "A_KEY supplied"
if len(a_key) > 20 or len(a_key) < 10 then errexit "Incorrect A_KEY length: should be 10-20 digits"
for i = 1 to len(a_key)
chval = asc(mid(a_key,i,1))
if chval < 0x30 or chval > 0x39 then errexit "A_KEY contains non-digit character(s)"
next i
dprint "A_KEY OK(" & a_key & ")"
if len(a_key) = 20 then
akey = a_key
else
dirnum = a_key
endif
else
dprint "A_KEY will not be programmed"
endif
if len(imsi) <> 15 then errexit "Incorrect IMSI length: should be 15 digits"
for i = 1 to 15
chval = asc(mid(imsi,i,1))
if chval < 0x30 or chval > 0x39 then errexit "IMSI contains non-digit character(s)"
next i
' the 3 digit MCC and 2 digit MNC need to be converted before writing using the AT command
'
mcc = mid(imsi, 1, 3)
mcc1 = val(mid(mcc,1,1))
mcc2 = val(mid(mcc,2,1))
mcc3 = val(mid(mcc,3,1))
if mcc1 = 0 then mcc1 = 10
if mcc2 = 0 then mcc2 = 10
if mcc3 = 0 then mcc3 = 10
mcc24 = mcc1*100 + mcc2*10 + mcc3 - 111
mnc = mid(imsi, 4, 2)
mnc1 = val(mid(mnc,1,1))
mnc2 = val(mid(mnc,2,1))
if mnc1 = 0 then mnc1 = 10
if mnc2 = 0 then mnc2 = 10
mnc16 = mnc1*10 + mnc2 - 11
' Initial default settings for Sweden
'
NbConfigStrings = 9
ConfigStrings[1] = "at$$spc=000000"
' ConfigStrings[2] = "at$$nvw mcc=0," & mcc24
' ConfigStrings[3] = "at$$nvw mnc=0," & mnc16
ConfigStrings[2] = "at$$nvw min=0," & mid(imsi, 6, 10)
ConfigStrings[3] = "at$$nvw dir_number=0,46" & mid(imsi, 6, 10)
ConfigStrings[4] = "at$$nvw home_reg=0,1"
ConfigStrings[5] = "at$$nvw for_sid=0,1"
ConfigStrings[6] = "at$$nvw for_nid=0,1"
ConfigStrings[7] = "at$$nvw sys_pref=0,3"
ConfigStrings[8] = "at$$hdr_nai=" & nai
ConfigStrings[9] = "at$$hdr_password=" & naipw
' ConfigStrings[12] = "at$$nvw a_key=0," & a_key
ResetString = "at$$reset"
AKeyString = "at$$nvw a_key=0," & akey
home_sid_nid_list[1] = 24
home_sid_nid_list[2] = 2
home_sid_nid_list[3] = 13
home_sid_nid_list[4] = 1
home_sid_nid_list[5] = 35
home_sid_nid_list[6] = 3
home_sid_nid_list[7] = 46
home_sid_nid_list[8] = 4
home_sid_nid_len = 8
' country specific settings for Norway
'
if mcc = "242" then
ConfigStrings[3] = "at$$nvw dir_number=0,47" & mid(imsi, 6, 10)
home_sid_nid_list[1] = 13
home_sid_nid_list[2] = 1
home_sid_nid_list[3] = 24
home_sid_nid_list[4] = 2
endif
' country specific settings for Denmark
'
if mcc = "238" then
ConfigStrings[3] = "at$$nvw dir_number=0,45" & mid(imsi, 6, 10)
home_sid_nid_list[1] = 35
home_sid_nid_list[2] = 3
home_sid_nid_list[5] = 24
home_sid_nid_list[6] = 2
endif
' Network specific settings for Ediscom
'
if mcc = "262" and mnc = "19" then
home_sid_nid_list[1] = 22110
home_sid_nid_list[2] = 0
home_sid_nid_list[3] = 0
home_sid_nid_list[4] = 0
home_sid_nid_list[5] = 0
home_sid_nid_list[6] = 0
home_sid_nid_list[7] = 0
home_sid_nid_list[8] = 0
endif
' Override directory number if specified separately
'
if dirnum <> "" then ConfigStrings[3] = "at$$nvw dir_number=0," & dirnum
' Find out what ASY port is used by modemcc for GPRS
'
if getParam("modemcc 0 asy_add ?", asystr) = TRUE then
dprint "modemcc 0 asy_add is: " & asystr
else
errexit "Failed to get modemcc 0 asy_add"
endif
if asystr = "255" or asystr = "0" or asystr = "" then
errexit "Modemcc asy_add incorrectly configured: try again after muxon"
endif
' Find out what INFO ASY port is used by modemcc for GPRS
'
if getParam("modemcc 0 info_asy_add ?", infoasystr) = TRUE then
dprint "modemcc 0 info_asy_add is: " & infoasystr
else
errexit "Failed to get modemcc 0 info_asy_add"
endif
if infoasystr = "0" or infoasystr = "" then
errexit "Modemcc info_asy_add incorrectly configured: try again after muxon"
endif
' Find out which PPP instance is configured for GPRS
'
got_gprs_ppp = get_gprs_ppp_instance(gprs_ppp_instance)
if got_gprs_ppp then
dprint "PPP " & gprs_ppp_instance & " is configured for GPRS"
res = execute("ppp " & gprs_ppp_instance & " deact_rq", 0, resstr)
sleep(1)
else
dprint "No PPP instances configured for GPRS"
endif
res = execute("modemcc 0 asy_add 255", 0, resstr)
res = execute("modemcc 0 info_asy_add 0", 0, resstr)
' initialise the serial port
AsyPortName = "ASY" & asystr
mc75asyport = AsyPortName
dprint "AsyPortName = " & AsyPortName
init_mc75io()
eventmsg "Connecting to modem on " & AsyPortName & "..."
' 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
dprint "Sending AT..."
print #mc75out, "AT\r"
if getOKline() = true then GotOK = true
wend
if GotOK = false then
restorecfg()
errexit "Cannot AT device on " & AsyPortName
endif
dprint "Connected to modem on " & AsyPortName
' First, do a reset in case logging has been enabled
' This will turn off excessive messages on the DM interface
'
print #mc75out, ResetString, "\r"
dprint "Sent " & ResetString
rslt = getRespline(rspline)
if rslt = true then
dprint "Got response: " & rspline
else
dprint "No response to reset command"
endif
sleep(2)
' And 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
dprint "Sending AT..."
print #mc75out, "AT\r"
if getOKline() = true then GotOK = true
wend
if GotOK = false then
restorecfg()
errexit "Cannot AT device on " & AsyPortName
endif
dprint "Reconnected to modem on " & AsyPortName
for i = 1 to NbConfigStrings
' skip MDN for unknown countries if not overridden
if i = 3 and mcc <> "240" and mcc <> "238" and mcc <> "242" and dirnum = "" then goto continue
print #mc75out, ConfigStrings[i], "\r"
eventmsg "Sent " & ConfigStrings[i]
rslt = getRespline(rspline)
if rslt = true then
if rspline <> "OK" then
restorecfg()
errexit "Got bad response: " & rspline
endif
dprint "Got response: " & rspline
else
restorecfg()
errexit "No response to command"
endif
continue:
next i
if akey <> "" then
print #mc75out, AKeyString, "\r"
eventmsg "Sent " & AKeyString
rslt = getRespline(rspline)
if rslt = true then
if rspline <> "OK" then
restorecfg()
errexit "Got bad response: " & rspline
endif
dprint "Got response: " & rspline
else
restorecfg()
errexit "No response to command"
endif
endif
' now set up the info port for the DM operations
InfoAsyPortName = "ASY" & infoasystr
infoout = 0
infoin = 0
open InfoAsyPortName for output as infoout
open InfoAsyPortName for input as infoin
if write_accolc(val(right(imsi,1))) = FALSE then
restorecfg()
errexit "writing accolc failed"
endif
' only set home sid nid list for Sweden, Norway, and Denmark
if mcc = "240" or mcc = "242" or mcc = "238" or (mcc = "262" and mnc = "19") then
i = 0
while i < 5 and write_home_sid_nid() = FALSE
sleep(1)
i += 1
wend
endif
if write_mcc(mcc24) = FALSE then
restorecfg()
errexit "writing MCC failed"
endif
if write_mnc(mnc16) = FALSE then
restorecfg()
errexit "writing MNC failed"
endif
close(infoin)
close(infoout)
' Finally, do a reset
'
print #mc75out, ResetString, "\r"
eventmsg "Sent " & ResetString
rslt = getRespline(rspline)
if rslt = true then
eventmsg "Got response: " & rspline
else
dprint "No response to reset command"
endif
' close the serial port and restore the modem connection
'
close(mc75out)
close(mc75in)
sleep(1)
restorecfg()
eventmsg "SUCCESS: provisioning complete"
stop
ErrorLabel:
'print "Got error code: ", error(), "(", error$, ")", nl
if error() = 22 and errcnt < 10 then
dprint "Retrying connection ..."
sleep(1)
errcnt = errcnt + 1
on error goto ErrorLabel
resume
endif
restorecfg()
errexit error$
Specific Challenges:
- AT Command Compatibility: The script uses several AT commands that I need to confirm are supported by the MC7340 or identify alternatives. The script includes commands related to network registration, modem initialization, and setting various cellular parameters.
- Port Configuration: I need to determine the appropriate ASY port configuration for both modem communications and GPS functionality. Currently, it’s unclear if “asy 2” should be used for GPS with the MC7340 installed in the Digi WR21.
gps 0 asy_add 3
gps 0 gpson ON
gps 0 init_str "$GPS_START"
- Provisioning Process: The provisioning process needs to be reviewed to ensure it correctly sets up the MC7340 for operation, including setting network parameters, configuring profiles, and handling any carrier-specific requirements.
Questions:
- Has anyone integrated an MC7340 with a Digi WR21? If so, how did you handle the AT command updates?
- What considerations should be made for ASY port assignments on the MC7340, especially concerning GPS functionality?
- Are there specific settings or commands in Sierra Wireless modules that I should adjust in the provisioning script to accommodate the MC7340?
Any scripts, configuration tips, or insights into handling Sierra modules in Digi routers would be highly appreciated. Thank you in advance for your help!