SIM900
Loading...
Searching...
No Matches
sim900.cpp
1/*
2 * This file is part of the SIM900 Arduino Shield library.
3 * Copyright (c) 2023 Nathanne Isip
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 * THE SOFTWARE.
22 */
23
24#include <sim900.h>
25#include <SoftwareSerial.h>
26
27void SIM900::sendCommand(String message) {
28 this->sim900->println(message);
29}
30
31String SIM900::getResponse() {
32 delay(500);
33
34 if(this->sim900->available() > 0) {
35 String response = this->sim900->readString();
36 response.trim();
37
38 return response;
39 }
40
41 return "";
42}
43
44String SIM900::getReturnedMode() {
45 String response = this->getResponse();
46 return response.substring(response.lastIndexOf('\n') + 1);
47}
48
49bool SIM900::isSuccessCommand() {
50 return this->getReturnedMode() == F("OK");
51}
52
53String SIM900::rawQueryOnLine(uint16_t line) {
54 String response = this->getResponse();
55 String result = "";
56
57 uint16_t currentLine = 0;
58 for(int i = 0; i < response.length(); i++)
59 if(currentLine == line && response[i] != '\n')
60 result += response[i];
61 else if(response[i] == '\n') {
62 currentLine++;
63
64 if(currentLine > line)
65 break;
66 }
67
68 return result;
69}
70
71String SIM900::queryResult() {
72 String response = this->getResponse();
73 String result = F("");
74
75 int idx = response.indexOf(": ");
76 if(idx != -1)
77 result = response.substring(
78 idx + 2,
79 response.indexOf('\n', idx)
80 );
81
82 return result;
83}
84
85SIM900::SIM900(SoftwareSerial *_sim900):
86 sim900(_sim900) {
87 this->sim900->begin(9600);
88}
89
91 this->sendCommand(F("AT"));
92 return this->isSuccessCommand();
93}
94
96 this->sendCommand(F("AT+CPIN?"));
97 return this->isSuccessCommand();
98}
99
100bool SIM900::changeCardPin(uint8_t pin) {
101 if(pin > 9999)
102 return false;
103
104 this->sendCommand("AT+CPIN=\"" + String(pin) + "\"");
105 return this->isSuccessCommand();
106}
107
110 signal.rssi = signal.bit_error_rate = 0;
111 this->sendCommand("AT+CSQ");
112
113 String response = this->queryResult();
114 uint8_t delim = response.indexOf(',');
115
116 if(delim == -1)
117 return signal;
118
119 signal.rssi = (uint8_t) response.substring(0, delim).toInt();
120 signal.bit_error_rate = (uint8_t) response.substring(delim + 1).toInt();
121
122 return signal;
123}
124
126 this->sim900->end();
127}
128
129SIM900DialResult SIM900::dialUp(String number) {
130 this->sendCommand("ATD+ " + number + ";");
131
132 SIM900DialResult result = SIM900_DIAL_RESULT_ERROR;
133 String mode = this->getReturnedMode();
134
135 if(mode == F("NO DIALTONE"))
136 result = SIM900_DIAL_RESULT_NO_DIALTONE;
137 else if(mode == F("BUSY"))
138 result = SIM900_DIAL_RESULT_BUSY;
139 else if(mode == F("NO CARRIER"))
140 result = SIM900_DIAL_RESULT_NO_CARRIER;
141 else if(mode == F("NO ANSWER"))
142 result = SIM900_DIAL_RESULT_NO_ANSWER;
143 else if(mode == F("OK"))
144 result = SIM900_DIAL_RESULT_OK;
145
146 return result;
147}
148
149SIM900DialResult SIM900::redialUp() {
150 this->sendCommand(F("ATDL"));
151
152 SIM900DialResult result = SIM900_DIAL_RESULT_ERROR;
153 String mode = this->getReturnedMode();
154
155 if(mode == F("NO DIALTONE"))
156 result = SIM900_DIAL_RESULT_NO_DIALTONE;
157 else if(mode == F("BUSY"))
158 result = SIM900_DIAL_RESULT_BUSY;
159 else if(mode == F("NO CARRIER"))
160 result = SIM900_DIAL_RESULT_NO_CARRIER;
161 else if(mode == F("NO ANSWER"))
162 result = SIM900_DIAL_RESULT_NO_ANSWER;
163 else if(mode == F("OK"))
164 result = SIM900_DIAL_RESULT_OK;
165
166 return result;
167}
168
169SIM900DialResult SIM900::acceptIncomingCall() {
170 this->sendCommand(F("ATA"));
171
172 SIM900DialResult result = SIM900_DIAL_RESULT_ERROR;
173 String mode = this->getReturnedMode();
174
175 if(mode == F("NO CARRIER"))
176 result = SIM900_DIAL_RESULT_NO_CARRIER;
177 else if(mode == F("OK"))
178 result = SIM900_DIAL_RESULT_OK;
179
180 return result;
181}
182
184 this->sendCommand(F("ATH"));
185 return this->isSuccessCommand();
186}
187
188bool SIM900::sendSMS(String number, String message) {
189 this->handshake();
190
191 this->sendCommand(F("AT+CMGF=1"));
192 delay(500);
193 this->sendCommand("AT+CMGS=\"" + number + "\"");
194 delay(500);
195 this->sendCommand(message);
196 delay(500);
197 this->sim900->write(0x1a);
198
199 return this->getReturnedMode().startsWith(">");
200}
201
203 SIM900Operator simOperator;
204 simOperator.mode = 0;
205 simOperator.format = 0;
206 simOperator.name = "";
207
208 this->sendCommand(F("AT+COPS?"));
209
210 String response = this->queryResult();
211 uint8_t delim1 = response.indexOf(','),
212 delim2 = response.indexOf(',', delim1 + 1);
213
214 simOperator.mode = (uint8_t) response.substring(0, delim1).toInt();
215 simOperator.format = (uint8_t) response.substring(delim1 + 1, delim2).toInt();
216 simOperator.name = response.substring(delim2 + 2, response.length() - 2);
217
218 return simOperator;
219}
220
222 this->sendCommand(F("AT+CMGF=1"));
223 if(!this->isSuccessCommand())
224 return false;
225
226 this->sendCommand(F("AT+CGATT=1"));
227 if(!this->isSuccessCommand())
228 return false;
229
230 this->sendCommand(
231 "AT+CSTT=\"" + apn.apn +
232 "\",\"" + apn.username +
233 "\",\"" + apn.password + "\""
234 );
235
236 return (this->hasAPN = this->isSuccessCommand());
237}
238
240 if(!this->hasAPN)
241 return false;
242
243 this->sendCommand(F("AT+CIICR"));
244 delay(1000);
245
246 return this->isSuccessCommand();
247}
248
250 SIM900HTTPResponse response;
251 response.status = -1;
252
253 if(!this->hasAPN)
254 return response;
255
256 this->sendCommand(
257 "AT+CIPSTART=\"TCP\",\"" + request.domain +
258 "\"," + String(request.port)
259 );
260
261 String resp = this->getResponse();
262 resp.trim();
263
264 delay(1500);
265 if(!resp.endsWith(F("CONNECT OK")))
266 return response;
267
268 String requestStr = request.method + " " +
269 request.resource + " HTTP/1.0\r\nHost: " +
270 request.domain + "\r\n";
271
272 for(int i = 0; i < request.header_count; i++)
273 requestStr += request.headers[i].key + ": " +
274 request.headers[i].value + "\r\n";
275
276 if(request.data != "" || request.data != NULL)
277 requestStr += request.data + "\r\n";
278
279 requestStr += F("\r\n");
280 this->sendCommand(requestStr);
281
282 // TODO
283 return response;
284}
285
287 this->sendCommand(
288 "AT+CCLK=\"" + String(config.year <= 9 ? "0" : "") + String(config.year) +
289 "/" + String(config.month <= 9 ? "0" : "") + String(config.month) +
290 "/" + String(config.day <= 9 ? "0" : "") + String(config.day) +
291 "," + String(config.hour <= 9 ? "0" : "") + String(config.hour) +
292 ":" + String(config.minute <= 9 ? "0" : "") + String(config.minute) +
293 ":" + String(config.second <= 9 ? "0" : "") + String(config.second) +
294 "+" + String(config.gmt <= 9 ? "0" : "") + String(config.gmt) + "\""
295 );
296
297 return this->isSuccessCommand();
298}
299
302 rtc.year = rtc.month = rtc.day =
303 rtc.hour = rtc.minute = rtc.second =
304 rtc.gmt = 0;
305
306 this->sendCommand(F("AT+CMGF=1"));
307 if(!this->isSuccessCommand())
308 return rtc;
309
310 this->sendCommand(F("AT+CENG=3"));
311 if(!this->isSuccessCommand())
312 return rtc;
313 this->sendCommand(F("AT+CCLK?"));
314
315 String time = this->queryResult();
316 time = time.substring(1, time.length() - 2);
317
318 uint8_t delim1 = time.indexOf('/'),
319 delim2 = time.indexOf('/', delim1 + 1),
320 delim3 = time.indexOf(',', delim2),
321 delim4 = time.indexOf(':', delim3),
322 delim5 = time.indexOf(':', delim4 + 1),
323 delim6 = time.indexOf('+', delim5);
324
325 rtc.year = (uint8_t) time.substring(0, delim1).toInt();
326 rtc.month = (uint8_t) time.substring(delim1 + 1, delim2).toInt();
327 rtc.day = (uint8_t) time.substring(delim2 + 1, delim3).toInt();
328 rtc.hour = (uint8_t) time.substring(delim3 + 1, delim4).toInt();
329 rtc.minute = (uint8_t) time.substring(delim4 + 1, delim5).toInt();
330 rtc.second = (uint8_t) time.substring(delim5 + 1, delim6).toInt();
331 rtc.gmt = (uint8_t) time.substring(delim6 + 1).toInt();
332
333 return rtc;
334}
335
336bool SIM900::savePhonebook(uint8_t index, SIM900CardAccount account) {
337 this->sendCommand(
338 "AT+CPBW=" + String(index) +
339 ",\"" + account.number +
340 "\"," + account.numberType +
341 ",\"" + account.name + "\""
342 );
343 return this->isSuccessCommand();
344}
345
347 this->sendCommand("AT+CPBR=" + String(index));
348
349 SIM900CardAccount accountInfo;
350 accountInfo.numberType = 0;
351
352 String response = this->queryResult();
353 response = response.substring(response.indexOf(',') + 1);
354
355 uint8_t delim1 = response.indexOf(','),
356 delim2 = response.indexOf(',', delim1 + 1);
357
358 accountInfo.number = response.substring(1, delim1 - 1);
359
360 uint8_t type = (uint8_t) response.substring(delim1 + 1, delim2).toInt();
361 if(type == 129 || type == 145)
362 accountInfo.numberType = type;
363 else accountInfo.numberType = 0;
364
365 accountInfo.name = response.substring(delim2 + 2, response.length() - 2);
366 return accountInfo;
367}
368
369bool SIM900::deletePhonebook(uint8_t index) {
370 this->sendCommand("AT+CPBW=" + String(index));
371 return this->isSuccessCommand();
372}
373
376 capacity.used = capacity.max = 0;
377 capacity.memoryType = F("");
378
379 this->sendCommand("AT+CPBS?");
380
381 String response = this->queryResult();
382 uint8_t delim1 = response.indexOf(','),
383 delim2 = response.indexOf(',', delim1 + 1);
384
385 capacity.memoryType = response.substring(1, delim1 - 1);
386 capacity.used = (uint8_t) response.substring(delim1 + 1, delim2).toInt();
387 capacity.max = (uint8_t) response.substring(delim2 + 1).toInt();
388
389 return capacity;
390}
391
393 this->sendCommand(F("AT+CNUM"));
394
395 SIM900CardAccount account;
396 account.name = F("");
397
398 String response = this->queryResult();
399 if(response == F(""))
400 return account;
401
402 uint8_t delim1 = response.indexOf(','),
403 delim2 = response.indexOf(',', delim1 + 1),
404 delim3 = response.indexOf(',', delim2 + 1),
405 delim4 = response.indexOf(',', delim3 + 1);
406
407 account.name = response.substring(1, delim1 - 1);
408 account.number = response.substring(delim1 + 2, delim2 - 1);
409 account.type = (uint8_t) response.substring(delim2 + 1, delim3).toInt();
410 account.speed = (uint8_t) response.substring(delim3 + 1, delim4).toInt();
411 account.service = (uint8_t) response.substring(delim4 + 1).toInt();
412 account.numberType = 0;
413
414 return account;
415}
416
418 this->sendCommand(F("AT+GMI"));
419 return this->rawQueryOnLine(2);
420}
421
423 this->sendCommand(F("AT+GMR"));
424
425 String result = this->rawQueryOnLine(2);
426 result = result.substring(result.lastIndexOf(F(":")) + 1);
427
428 return result;
429}
430
431String SIM900::imei() {
432 this->sendCommand(F("AT+GSN"));
433 return this->rawQueryOnLine(2);
434}
435
437 this->sendCommand(F("AT+GMM"));
438 return this->rawQueryOnLine(2);
439}
440
442 this->sendCommand(F("AT+GOI"));
443 return this->rawQueryOnLine(2);
444}
445
447 this->sendCommand(F("AT+CIFSR"));
448 return this->rawQueryOnLine(2);
449}
bool savePhonebook(uint8_t index, SIM900CardAccount account)
Save a contact in the SIM card's phonebook.
Definition sim900.cpp:336
String manufacturer()
Get the manufacturer name of the SIM900 module.
Definition sim900.cpp:417
SIM900DialResult redialUp()
Redial the last outgoing call.
Definition sim900.cpp:149
String chipName()
Get the chip name of the SIM900 module.
Definition sim900.cpp:441
SIM900PhonebookCapacity phonebookCapacity()
Get information about the capacity of the SIM card's phonebook.
Definition sim900.cpp:374
SIM900DialResult acceptIncomingCall()
Accept an incoming call.
Definition sim900.cpp:169
SIM900DialResult dialUp(String number)
Initiate an outgoing call to a phone number.
Definition sim900.cpp:129
bool enableGPRS()
Enable the General Packet Radio Service (GPRS) for data communication.
Definition sim900.cpp:239
String ipAddress()
Get the IP address assigned to the SIM900 module.
Definition sim900.cpp:446
SIM900CardAccount cardNumber()
Get the SIM card number.
Definition sim900.cpp:392
String chipModel()
Get the chip model of the SIM900 module.
Definition sim900.cpp:436
bool deletePhonebook(uint8_t index)
Delete a contact from the SIM card's phonebook.
Definition sim900.cpp:369
SIM900Operator networkOperator()
Get information about the current network operator.
Definition sim900.cpp:202
bool sendSMS(String number, String message)
Send an SMS (Short Message Service).
Definition sim900.cpp:188
bool updateRtc(SIM900RTC config)
Update the SIM900 module's real-time clock (RTC).
Definition sim900.cpp:286
String softwareRelease()
Get the software release version of the SIM900 module.
Definition sim900.cpp:422
void close()
Close the communication with the SIM900 module.
Definition sim900.cpp:125
bool hangUp()
Hang up an active call.
Definition sim900.cpp:183
SIM900(SoftwareSerial *_sim900)
Constructor for the SIM900 class.
Definition sim900.cpp:85
bool connectAPN(SIM900APN apn)
Connect to an Access Point Name (APN) for mobile data.
Definition sim900.cpp:221
bool changeCardPin(uint8_t pin)
Change the PIN code of the SIM card.
Definition sim900.cpp:100
SIM900RTC rtc()
Get the real-time clock (RTC) information.
Definition sim900.cpp:300
bool handshake()
Initialize communication with the SIM900 module and perform a handshake.
Definition sim900.cpp:90
bool isCardReady()
Check if the SIM card is ready.
Definition sim900.cpp:95
String imei()
Get the International Mobile Equipment Identity (IMEI) number of the SIM900 module.
Definition sim900.cpp:431
SIM900CardAccount retrievePhonebook(uint8_t index)
Retrieve a contact from the SIM card's phonebook.
Definition sim900.cpp:346
SIM900Signal signal()
Get the signal strength and bit error rate of the network connection.
Definition sim900.cpp:108
SIM900HTTPResponse request(SIM900HTTPRequest request)
Send an HTTP request to a remote server.
Definition sim900.cpp:249
A structure representing Access Point Name (APN) configuration for mobile data.
A structure representing a card account, including name, number, type, and service information.
A structure representing an HTTP request.
A structure representing an HTTP response.
A structure representing mobile network operator information.
A structure representing the capacity of a phonebook memory type.
A structure representing real-time clock (RTC) information.
A structure representing signal strength and bit error rate information.