1 //
2 // Copyright (c) 2010-2024 Antmicro
3 //
4 // This file is licensed under the MIT License.
5 // Full license text is available in 'licenses/MIT.txt'.
6 //
7 using Antmicro.Renode.Core;
8 using Antmicro.Renode.Logging;
9 using Antmicro.Renode.Utilities;
10 
11 namespace Antmicro.Renode.Peripherals.Network
12 {
13     public class Quectel_BG96 : QuectelModem
14     {
Quectel_BG96(IMachine machine, string imeiNumber = DefaultImeiNumber, string softwareVersionNumber = DefaultSoftwareVersionNumber, string serialNumber = DefaultSerialNumber)15         public Quectel_BG96(IMachine machine, string imeiNumber = DefaultImeiNumber,
16             string softwareVersionNumber = DefaultSoftwareVersionNumber,
17             string serialNumber = DefaultSerialNumber) : base(machine, imeiNumber, softwareVersionNumber, serialNumber)
18         {
19         }
20 
21         // CEREG - EPS Network Registration Status
22         [AtCommand("AT+CEREG", CommandType.Write)]
CeregWrite(NetworkRegistrationUrcType type)23         protected override Response CeregWrite(NetworkRegistrationUrcType type)
24         {
25             // EMM cause information is not supported on this modem
26             if(type == NetworkRegistrationUrcType.StatLocationEmmCause ||
27                 type == NetworkRegistrationUrcType.StatLocationEmmCausePsm)
28             {
29                 return Error;
30             }
31             return base.CeregWrite(type);
32         }
33 
34         // CREG - Network Registration
35         [AtCommand("AT+CREG", CommandType.Write)]
CregWrite(NetworkRegistrationUrcType type)36         protected override Response CregWrite(NetworkRegistrationUrcType type)
37         {
38             if(type > NetworkRegistrationUrcType.StatLocation)
39             {
40                 this.Log(LogLevel.Warning, "AT+CREG: Argument <n> set to {0}, not supported by this modem", (int)type);
41                 return Error;
42             }
43             return base.CregWrite(type);
44         }
45 
46         // CESQ - Extended Signal Quality
47         // CESQ is not supported by this modem. We override Cesq without marking it with [AtCommand]
48         // in order to remove it from the command set (including the test command, AT+CESQ=?).
Cesq()49         protected override Response Cesq() => Error;
50 
51         // CGDCONT - Define PDP Context
52         [AtCommand("AT+CGDCONT", CommandType.Read)]
Cgdcont()53         protected override Response Cgdcont() => Ok.WithParameters($"+CGDCONT: 1,\"IP\",\"{pdpContextApn}\",\"{NetworkIp}\",0,0"); // stub
54 
55         // CGMI - Request Manufacturer Identification
56         [AtCommand("AT+CGMI")]
Cgmi()57         protected override Response Cgmi() => Ok.WithParameters(Vendor);
58 
59         // CGSN - Request Product Serial Number
60         // CGSN only supports reading the IMEI on this modem and is available only as an execution command
61         // Also, it returns only the IMEI itself instead of "+CGSN: <imei>"
62         [AtCommand("AT+CGSN")]
Cgsn()63         protected override Response Cgsn() => Ok.WithParameters(imeiNumber);
64 
65         [AtCommand("AT+CGSN", CommandType.Write)]
CgsnWrite(SerialNumberType serialNumberType = SerialNumberType.Device)66         protected override Response CgsnWrite(SerialNumberType serialNumberType = SerialNumberType.Device) => Error;
67 
68         // CMEE - Report Mobile Termination Error
69         [AtCommand("AT+CMEE", CommandType.Write)]
Cmee(MobileTerminationResultCodeMode mode = MobileTerminationResultCodeMode.Numeric)70         protected override Response Cmee(MobileTerminationResultCodeMode mode = MobileTerminationResultCodeMode.Numeric)
71         {
72             return base.Cmee(mode);
73         }
74 
75         // CSCON - Signaling Connection Status
76         // Not supported
Cscon(int enable = 0)77         protected override Response Cscon(int enable = 0) => Error;
78 
79         // QBAND - Get and Set Mobile Operation Band
80         // Not supported
Qband(int numberOfBands, params int[] bands)81         protected override Response Qband(int numberOfBands, params int[] bands) => Error;
82 
83         // QCCID - USIM Card Identification
84         // Not supported
Qccid()85         protected override Response Qccid() => Error;
86 
87         // CCLK - Set and Get Current Date and Time
88         [AtCommand("AT+CCLK", CommandType.Read)]
CclkRead()89         protected virtual Response CclkRead()
90         {
91             return Ok.WithParameters("+CCLK: " + machine.RealTimeClockDateTime.ToString("yy/MM/dd,HH:mm:sszz").SurroundWith("\""));
92         }
93 
94         // QCFG - System Configuration
95         [AtCommand("AT+QCFG", CommandType.Write)]
Qcfg(string function, params int[] args)96         protected override Response Qcfg(string function, params int[] args)
97         {
98             switch(function)
99             {
100                 case "ledmode": // NETLIGHT output Mode
101                 {
102                     if(args.Length == 1)
103                     {
104                         return SetNetLightMode(args[0]);
105                     }
106                     return base.Qcfg(function, args);
107                 }
108                 case "apready": // AP_READY Pin
109                 case "band": // band configuration
110                 case "celevel": // get LTE Cat NB1 coverage enhancement level
111                 case "cmux/urcport": // URC output port for CMUX
112                 case "ims": // IMS function control
113                 case "iotopmode": // network category to be searched under LTE RAT
114                 case "msc": // MSC release version configuration
115                 case "nb1/bandprior": // band scan priority under LTE Cat NB1
116                 case "nwscanmode": // RAT(s) to be searched
117                 case "nwscanseq": // RAT searching sequence
118                 case "pdp/duplicatechk": // establish multi PDNs with the same APN
119                 case "psm/enter": // trigger PSM immediately
120                 case "psm/urc": // enable/disable PSM entry indication
121                 case "risignaltype": // RI signal output carrier
122                 case "roamservice": // roam service configuration
123                 case "servicedomain": // service domain configuration
124                 case "sgsn": // SGSN release version configuration
125                 case "urc/delay": // delay URC indication
126                 case "urc/ri/other": // RI behavior when other URCs are presented
127                 case "urc/ri/ring": // RI behavior when RING URC is presented
128                 case "urc/ri/smsincoming": // RI behavior when incoming SMS URCs are presented
129                     this.Log(LogLevel.Warning, "Config value '{0}' set to {1}, not implemented", function, string.Join(", ", args));
130                     break;
131                 default:
132                     return base.Qcfg(function, args);
133             }
134             return Ok;
135         }
136 
137         // QENG - Engineering Mode
138         // Not supported
Qeng(int mode)139         protected override Response Qeng(int mode) => Error;
140 
141         // QIACT - Activate a PDP Context
142         [AtCommand("AT+QIACT", CommandType.Write)]
Qiact(int contextId)143         protected Response Qiact(int contextId)
144         {
145             if(!IsValidContextId(contextId))
146             {
147                 return Error;
148             }
149             return Ok; // stub
150         }
151 
152         // QICFG - Configure Optional TCP/IP Parameters
153         [AtCommand("AT+QICFG", CommandType.Write)]
Qicfg(string parameter, params int[] args)154         protected override Response Qicfg(string parameter, params int[] args)
155         {
156             if(args.Length < 1)
157             {
158                 return Error;
159             }
160 
161             switch(parameter)
162             {
163                 case "dataformat":
164                     if(args.Length < 2)
165                     {
166                         return Error;
167                     }
168                     sendDataFormat = args[0] != 0 ? DataFormat.Hex : DataFormat.Text;
169                     receiveDataFormat = args[1] != 0 ? DataFormat.Hex : DataFormat.Text;
170                     break;
171                 case "viewmode":
172                     dataOutputSeparator = args[0] != 0 ? "," : CrLf;
173                     break;
174                 case "transpktsize": // packet size for transparent mode
175                 case "transwaittm": // wait time for transparent mode
176                 case "tcp/retranscfg": //  maximum interval time and number for TCP retransmissions
177                 case "dns/cache": // enable the DNS cache
178                 case "qisend/timeout": // input data timeout
179                 case "passiveclosed": // passive close of TCP connection when the server is closed
180                     this.Log(LogLevel.Warning, "TCP/IP config value '{0}' set to {1}, not implemented", parameter, args.Stringify());
181                     break;
182                 default:
183                     return base.Qicfg(parameter, args);
184             }
185             return Ok;
186         }
187 
188         // QICLOSE - Close a Socket Service
189         [AtCommand("AT+QICLOSE", CommandType.Write)]
Qiclose(int connectionId, int timeout = 10)190         protected /* override */ Response Qiclose(int connectionId, int timeout = 10)
191         {
192             return base.Qiclose(connectionId);
193         }
194 
195         // QICSGP - Configure Parameters of a TCP/IP Context
196         [AtCommand("AT+QICSGP", CommandType.Write)]
Qicsgp(int contextId, ProtocolType contextType = ProtocolType.IpV4, string apn = R, string username = R, string password = R, AuthenticationMethod authenticationType = AuthenticationMethod.None)197         protected virtual Response Qicsgp(int contextId, ProtocolType contextType = ProtocolType.IpV4,
198             string apn = "", string username = "", string password = "",
199             AuthenticationMethod authenticationType = AuthenticationMethod.None)
200         {
201             if(!IsValidContextId(contextId))
202             {
203                 return Error;
204             }
205             return Ok; // stub
206         }
207 
208         // QIDEACT - Deactivate a PDP Context
209         [AtCommand("AT+QIDEACT", CommandType.Write)]
Qideact(int contextId)210         protected virtual Response Qideact(int contextId)
211         {
212             if(!IsValidContextId(contextId))
213             {
214                 return Error;
215             }
216             return Ok; // stub
217         }
218 
219         // QISEND - Send Hex/Text String Data
220         [AtCommand("AT+QISEND", CommandType.Write)]
Qisend(int connectionId, int? sendLength = null, string data = null, int? raiMode = null)221         protected override Response Qisend(int connectionId, int? sendLength = null, string data = null, int? raiMode = null)
222         {
223             // The BG96 doesn't support non-data mode in AT+QISEND
224             if(data != null)
225             {
226                 return Error;
227             }
228 
229             return base.Qisend(connectionId, sendLength, data);
230         }
231 
232         // QNBIOTEVENT - Enable/Disable NB-IoT Related Event Report
233         // Not supported
Qnbiotevent(int enable = 0, int eventType = 1)234         protected override Response Qnbiotevent(int enable = 0, int eventType = 1) => Error;
235 
236         // QNBIOTRAI - NB-IoT Release Assistance Indication
237         // Not supported
Qnbiotrai(int raiMode = 0)238         protected override Response Qnbiotrai(int raiMode = 0) => Error;
239 
240         // QRST - Module Reset
241         // Not supported
QrstWrite(int mode = 1)242         protected override Response QrstWrite(int mode = 1) => Error;
243 
244         protected override string Vendor => "Quectel";
245         protected override string ModelName => "BG96";
246         protected override string Revision => "Revision: BG96MAR01A01M1G";
247         protected override string ManufacturerRevision => "BG96MAR01A01M1G";
248         protected override string SoftwareRevision => "01.008.01.008";
249 
250         private const string DefaultImeiNumber = "866818039921444";
251         private const string DefaultSoftwareVersionNumber = "31";
252         private const string DefaultSerialNumber = "<serial number>";
253 
254         protected enum ProtocolType
255         {
256             IpV4 = 1,
257             IpV4V6,
258         }
259 
260         protected enum AuthenticationMethod
261         {
262             None,
263             Pap,
264             Chap,
265             PapOrChap,
266         }
267     }
268 }
269