The functionality described in this document applies only to card form-factor Super SIMs shipped after September 2021.
Every Super SIM, like all SIMs, includes a list of operator-preferred networks. This list, part of the 3GPP standard, is called the OPLMN (Operator-controlled Public Land Mobile Network) table and it sets the order in which the SIM's host cellular module contacts visible networks to request a network connection.
For example, Super SIM-empowered modems in the US first attempt to connect to AT&T because that's the first network (and only) listed in the OPLMN for the US. For Super SIM, the operator is, of course, Twilio. Other carriers are set as the Twilio-preferred network for other countries. The Super SIM OPLMN contains a single preferred network for each country.
Card form-factor Super SIMs issued after September 2021 allow you to override Twilio's OPLMN. This technique takes advantage of another 3GPP-standard SIM table: an optional list of user-preferred networks. This is the UPLMN (User-controlled Public Land Mobile Network) table. The cellular module must always select any network set in its SIM's UPLMN table, if it has one, over those in the OPLMN table. If it can't connect to the first user-preferred network, it tries the next one. If the UPLMN lacks an entry for any network visible to the modem, the SIM falls back on the OPLMN.
With just a few AT commands, your application can set its Super SIM's UPLMN table to list the networks you would like the SIM to use in preference to those specified by Twilio. This guide will show you how.
The OPLMN is formally known as the 'OPLMNwAcT', and the UPLMN as the 'PLMNwAcT'. The 'wAcT' in each case is short for 'with Access Technology'. Here we'll stick with OPLMN and UPLMN, but you will see the other terms in 3GPP documentation. For full details of the encoding, please see ETSI Technical Specification 131 102.
First, let's consider why you might want to implement a UPLMN table. For the majority of customers, the network choices we have made are fine, but a small number of customers may discover during testing that an alternative network for the initial connection gives their particular choice of hardware better start-up performance. Or they are deploying in an area where Twilio's preferred network offers poorer coverage than another network. They can then set the UPLMN table in each of their Super SIMs so that their devices will favor that network.
For example, you might code your application to check the signal strength and backhaul bandwidth of each visible network at a device's location. The app might find that, say, the T-Mobile signal there is much stronger than the signal shown by OPLMN-prioritized AT&T. Or that though the AT&T signal is stronger, its backhaul is saturated so that the weaker signal T-Mobile tower delivers better throughput. In such cases, the application could write the UPLMN table to prioritize T-Mobile for that device.
Alternatively, you might want your devices in a given country to go straight to your NAP-selected network. By setting this network at the start of the UPLMN, you ensure the modem will go to it first and thus eliminate the time spent attempting to connect to other networks and in case failing because those networks are blocked by your NAP.
It's important to note, however, that better performance with a network not included in the OPLMN is often the result of where the test device is located, and may not be experienced by products that are rolled out more widely than the test area. Twilio's OPLMN choices are based on broad network coverage, not highly local coverage. Signal quality and network coverage may vary at any time, particularly when the device is moved or is in motion.
That said, your application may be location aware and therefore able to override the OPLMN with a UPLMN in certain cases where this is beneficial. Thorough testing and analysis will help you select the best network selection strategy to employ for your use case.
You choose which networks to allow your devices to attach to, and which networks to block, using a given Fleet resource's Network Access Profile (NAP). Your network choices are enforced by the cell tower: networks blocked by your NAP will not allow the device to attach, even if that network is included in the UPLMN and/or OPLMN tables. The NAP cannot be used to create a list of networks to try in a particular order. The UPLMN is used solely to determine the order in which networks are contacted to request attachment. If there is no UPLMN, the modem will engage with the networks specified by the OPLMN. If a network is blocked by NAP, but is present in the UPLMN, the device will still try to attach to that network if it fails to connect to higher-priority networks. There is a small, but potentially significant latency in making such 'known to fail' attachment attempts, so you may wish to align your SIMs' UPLMNs to your NAP.
Here's the basic flow:
To read and update a SIM's data files, including the OPLMN and UPLMN tables, you use the standard AT command +CRSM
.
SIM commands are issued as data structures called Application Protocol Data Units (APDUs). We won't cover the full data structure here — for that, we recommend you check out ETSI Technical Specification 102 221 — but essentially it contains an instruction-type byte, a number of instruction-specific parameter values, and the number of data bytes being read or written, if any.
+CRSM
allows you to send the key elements of an APDU to the SIM: as the AT command's parameters. To demonstrate this, let's use +CRSM
to read a Super SIM's OPLMN.
The OPLMN is stored in an 'Elementary File' (EF) on the SIM. The file is said to be 'transparent'. In other words, it consists of a sequence of bytes. Transparent files are read using the Read Binary SIM command.
We'll assume you know how to issue AT commands to a cellular module. If you're not sure, this is how we did it for this guide. We connected a Sixfab 3G-4G/LTE Base Hat and Tellit ME910C1-WW module to a Raspberry 400 Linux computer, and used the minicom serial communications tool to talk to the module. See our Super SIM Getting Started Guide for more details.
Get the first network in the OPLMN with
AT+CRSM=176,28513,0,0,5
What does this mean? Let's decode each of the command's parameters in turn:
176
which is the Read Binary instruction.
28513
which is the ID of the OPLMN. In standards documentation this is usually given in its hexadecimal value,
0x6F61
. Likewise, the formal name of the file containing the OPLMN is the EFOPLMNwAcT.
0
.
0
.
5
bytes, enough for one record. OPLMN and UPLMN network records are five bytes long: three for the Mobile Country Code (MCC)/Mobile Network Code (MNU) combination that identifies the network, and two bytes for the Radio Access Technology (RAT) used.
Issuing the AT command above returns:
1+CRSM: 144,0,130014408023OK
Again, let's decode each of the response's parts:
144
(
0x90
) indicates success.
0
on success, but can indicate a specific cause if the first status code indicates an error.
The PLMN is coded as follows. Numbering the hex octets 1 to 6, from left to right:
MCC = octet 2 * 100 + octet 1 * 10 + octet 4, so, 130
decodes to 310 (US)
MNC = octet 6 * 100 + octet 5 * 10 + octet 3, so 014
decodes to 410 (AT&T)
The standard encoding is based on three-digit MCCs and MNCs. For two-digit values, a placeholder third digit is added: the character F
. For example, the MNC 81
is encoded as 81F
.
You can use this short Python script to convert a PLMN coding to MCC and MNC values:
1# Get a PLMN coding2plmn = input("Enter a PLMN coding: ")3if len(plmn) != 6:4print("ERROR -- PLMN must be 6 hex digits")5else:6# Rearrange octets and output7mcc = (plmn[1] + plmn[0] + plmn[3]).replace("F", "")8mnc = (plmn[5] + plmn[4] + plmn[2]).replace("F", "")9print("MCC:", mcc)10print("MNC:", mnc)11
For a complete utility that makes use of this code, see Super SIM UPLMN Codec, below.
You can find a good list of MCCs and MNCs here.
The two-byte RAT value is encoded this way. The first two digits are the hex value 40
(64), which indicates a preference for E-UTRAN (4G). The second two digits are the hex value 80
(128), which indicates GSM as a secondary radio technology preference. For full details of the encoding, please see ETSI Technical Specification 131 102.
Like the OPLMN table, the UPLMN table is placed in an Elementary File: EFPLMNwAcT, with the ID 0x6F60
(28512). The file must be 40 bytes size minimum, i.e., eight network entries formatted as described above. If that's too many entries for your needs, fill up the remaining bytes with 0xFF
. On a new Super SIM, the table already contains 40 such bytes, so you need only overwrite some of them the desired records. But bear in mind that subsequent attempts to update the UPLMN with a shorter list will need to clear any unwanted network records with FFFFFFFFFF
.
You can use this short Python script to convert entered MCC and MNC values into PLMN record hex octets:
1# Get MCC and MNC values2mcc = input("Enter an MCC: ")3mnc = input("Enter an MNC: ")45# Assemble string6# NOTE Use 'F' for unused columns, ie. '81' -> '81F'7if len(mnc) < 3: mnc += "FFF"[:3 - len(mnc)]8if len(mcc) < 3: mcc += "FFF"[:3 - len(mcc)]9plmn = mcc + mnc1011# Rearrange octets and output12plmn = plmn[1] + plmn[0] + plmn[5] + plmn[2] + plmn[4] + plmn[3]13print("UPLMN Encoding:", plmn)14
For a complete utility that makes use of this code, see Super SIM UPLMN Codec, below.
Let's set the UPLMN table to T-Mobile and AT&T. The data for AT&T we already have, from reading the OPLMN: 130014
. T-Mobile US's MNC is 260. Encoding its MCC/MNC combination as described above yields 130062
. Using the same RAT as above, 4080
, we get:
13006240801300144080
which we write to the UPLMN with the APDU Update Binary instruction, 214
. The File ID in decimal is 28512
. We're writing at the start of the file so the two offset bytes are once more both zero, but this time we're writing ten bytes — the sequence above shows hexadecimal octets, not a decimal value — so the final parameter is 10
:
AT+CRSM=214,28512,0,0,10,"13006240801300144080"
If the data is written correctly, you'll see:
1+CRSM: 144,023OK
in response.
Check the write by reading back all of the UPLMN:
AT+CRSM=176,28512,0,0,10
The response is:
1+CRSM: 144,0,32F405408032F451408023OK
We've issued the above AT commands directly to the cellular module, just as your application might do on start-up after checking a flag to see whether it has already set the UPLMN table. Alternatively, depending on the module you're using, you may be able to issue the necessary AT commands by way of SMS messages. Not all modules support this feature, however, so please check your device's documentation first if this approach appeals to you.
There is a potentially easier method for setting the UPLMN table than the one outlined above, 'potentially' because it's not available on all cellular modules so you will need to check the documentation for your chosen modem to see if you'll be able to use it. This alternative approach uses the +CPOL
AT command. It stands for "Preferred Operator List", and it allows you to update the UPLMN table directly. You pass a table index value, a format marker for the next parameter, a cellular operator identifier, and the RATs enabled for it. The format marker tells the module whether the following cellular identifier is a short or long string, or a numerical code.
You can read the current UPLMN with AT+CPOL?
, but you'll receive an error if it does not yet exist — no entries have been written to it.
To get a (long) list of operator codes, issue AT+COPN
.
Some modems — the u-blox SARA-R5 is one example — allow you to specify which table — UPLMN, OPLMN or the HPLMN (Home Public Land Mobile Network) — +CPOL
will write to or read from. By default it will be the former, but you can set it to another, though attempting to write to the OPLMN or HPLMN tables will result in an error. The command to change the target table is +CPLS
. Pass 0
for the UPLMN, 1
for the OPLMN or 2
for the HPLMN.
For example, the call AT+CPLS=1;+CPOL?;+CPLS=0
will set the OPLMN as the +CPOL
target, read the table, and then set the target back to the UPLMN.
For more details on using +CPOL
, please see your modem's documentation.
As noted earlier, only card form-factor Super SIMs which shipped after September 2021 include a UPLMN table to which you can add preferred networks. Earlier Super SIMs lack this table, and attempts to update it will fail so with the response:
ERROR
However, attempts to read the UPLMN, i.e., issuing AT+CRSM=176,28512,0,0,0
, will elicit a seemingly successful response:
1+CRSM: 106,13023OK
In fact 106
(0x6A
) is an APDU failure code indicating a bad parameter. The second value, 130
(0x82
), narrows this down to "file not found" — there is no UPLMN table, file EFPLMNwAcT, on this SIM.
Your application code can use this pair of values to check whether its cellular module contains an older Super SIM without a UPLMN table. Do not rely on a direct error response from the modem. ETSI Technical Specification 131 102 list the possible error codes you may encounter.
You can read the OPLMN table on any Super SIM with AT+CRSM=176,28513,0,0,0
.
You can find a complete utility to help you encode MCC-MNC pairs into UPLMN table entries, and to decode entries into MCC, MNC and RAT values, in our public GitHub repo. The utility is written in Python 3 without further dependencies so will run on any system with Python 3 installed.