Skip to content

Commit 76e0d36

Browse files
committed
Adding operater selection - AT+COPS - functionality.
1 parent f5682aa commit 76e0d36

File tree

2 files changed

+308
-12
lines changed

2 files changed

+308
-12
lines changed

src/SparkFun_LTE_Shield_Arduino_Library.cpp

Lines changed: 280 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ const char LTE_SHIELD_COMMAND_MNO[] = "+UMNOPROF"; // MNO (mobile network operat
5252
const char LTE_SHIELD_SIGNAL_QUALITY[] = "+CSQ";
5353
const char LTE_SHIELD_REGISTRATION_STATUS[] = "+CREG";
5454
const char LTE_SHIELD_MESSAGE_PDP_DEF[] = "+CGDCONT";
55+
const char LTE_SHIELD_MESSAGE_ENTER_PPP[] = "D";
56+
const char LTE_SHIELD_OPERATOR_SELECTION[] = "+COPS";
5557
// V24 control and V25ter (UART interface)
5658
const char LTE_SHIELD_COMMAND_BAUD[] = "+IPR"; // Baud rate
5759
// ### GPIO
@@ -577,7 +579,6 @@ boolean LTE_Shield::setNetwork(mobile_network_operator_t mno)
577579

578580
// Check currently set MNO
579581
if (getMno(&currentMno) != LTE_SHIELD_ERROR_SUCCESS) {
580-
Serial.println("Error getting MNO");
581582
return false;
582583
}
583584
if (currentMno == mno)
@@ -586,18 +587,15 @@ boolean LTE_Shield::setNetwork(mobile_network_operator_t mno)
586587
}
587588

588589
if (functionality(MINIMUM_FUNCTIONALITY) != LTE_SHIELD_ERROR_SUCCESS) {
589-
Serial.println("Error setting functionality");
590590
return false;
591591
}
592592

593593
if (setMno(mno) != LTE_SHIELD_ERROR_SUCCESS) {
594-
Serial.println("Error setting MNO");
595594
return false;
596595
}
597596

598597
if (reset() != LTE_SHIELD_ERROR_SUCCESS)
599598
{
600-
Serial.println("Error resetting");
601599
return false;
602600
}
603601

@@ -651,11 +649,285 @@ LTE_Shield_error_t LTE_Shield::setAPN(String apn, uint8_t cid, LTE_Shield_pdp_ty
651649

652650
err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, NULL,
653651
LTE_SHIELD_STANDARD_RESPONSE_TIMEOUT);
654-
//Serial.println("Set APN: " + String(command));
652+
653+
free(command);
654+
655+
return err;
656+
}
657+
658+
LTE_Shield_error_t LTE_Shield::getAPN(String * apn, IPAddress * ip)
659+
{
660+
LTE_Shield_error_t err;
661+
char * command;
662+
char * response;
663+
char * searchPtr;
664+
uint8_t ipOctets[4];
665+
666+
command = lte_calloc_char(strlen(LTE_SHIELD_MESSAGE_PDP_DEF) + 3);
667+
if (command == NULL) return LTE_SHIELD_ERROR_OUT_OF_MEMORY;
668+
sprintf(command, "%s?", LTE_SHIELD_MESSAGE_PDP_DEF);
669+
670+
response = lte_calloc_char(128);
671+
if (response == NULL)
672+
{
673+
free(command);
674+
return LTE_SHIELD_ERROR_OUT_OF_MEMORY;
675+
}
676+
677+
err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, response,
678+
LTE_SHIELD_STANDARD_RESPONSE_TIMEOUT);
679+
680+
if (err == LTE_SHIELD_ERROR_SUCCESS)
681+
{
682+
// Example: +CGDCONT: 1,"IP","hologram","10.170.241.191",0,0,0,0
683+
searchPtr = strstr(response, "+CGDCONT: ");
684+
if (searchPtr != NULL)
685+
{
686+
searchPtr += strlen("+CGDCONT: ");
687+
// Search to the third double-quote
688+
for (int i = 0; i < 3; i ++)
689+
{
690+
searchPtr = strchr(++searchPtr, '\"');
691+
}
692+
if (searchPtr != NULL)
693+
{
694+
// Fill in the APN:
695+
searchPtr = strchr(searchPtr, '\"'); // Move to first quote
696+
while ((*(++searchPtr) != '\"') && (searchPtr != '\0'))
697+
{
698+
apn->concat(*(searchPtr));
699+
}
700+
// Now get the IP:
701+
if (searchPtr != NULL)
702+
{
703+
int scanned = sscanf(searchPtr, "\",\"%hhu.%hhu.%hhu.%hhu\"",
704+
&ipOctets[0], &ipOctets[1], &ipOctets[2], &ipOctets[3]);
705+
if (scanned == 4)
706+
{
707+
for (int octet = 0; octet < 4; octet++)
708+
{
709+
(*ip)[octet] = ipOctets[octet];
710+
}
711+
}
712+
}
713+
}
714+
}
715+
else
716+
{
717+
err = LTE_SHIELD_ERROR_UNEXPECTED_RESPONSE;
718+
}
719+
}
720+
721+
free(command);
722+
free(response);
723+
724+
return err;
725+
}
726+
727+
const char * PPP_L2P[5] = {
728+
"",
729+
"PPP",
730+
"M-HEX",
731+
"M-RAW_IP",
732+
"M-OPT-PPP",
733+
};
734+
735+
LTE_Shield_error_t LTE_Shield::enterPPP(uint8_t cid, char dialing_type_char,
736+
unsigned long dialNumber, LTE_Shield::LTE_Shield_l2p_t l2p)
737+
{
738+
LTE_Shield_error_t err;
739+
char * command;
740+
741+
if ((dialing_type_char != 0) && (dialing_type_char != 'T') &&
742+
(dialing_type_char != 'P'))
743+
{
744+
return LTE_SHIELD_ERROR_UNEXPECTED_PARAM;
745+
}
746+
747+
command = lte_calloc_char(strlen(LTE_SHIELD_MESSAGE_ENTER_PPP) + 32);
748+
if (command == NULL) return LTE_SHIELD_ERROR_OUT_OF_MEMORY;
749+
if (dialing_type_char != 0)
750+
{
751+
sprintf(command, "%s%c*%lu**%s*%hhu#", LTE_SHIELD_MESSAGE_ENTER_PPP, dialing_type_char,
752+
dialNumber, PPP_L2P[l2p], cid);
753+
}
754+
else
755+
{
756+
sprintf(command, "%s*%lu**%s*%hhu#", LTE_SHIELD_MESSAGE_ENTER_PPP,
757+
dialNumber, PPP_L2P[l2p], cid);
758+
}
759+
760+
err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, NULL,
761+
LTE_SHIELD_STANDARD_RESPONSE_TIMEOUT);
762+
763+
free(command);
764+
return err;
765+
}
766+
767+
uint8_t LTE_Shield::getOperators(struct operator_stats * opRet, int maxOps)
768+
{
769+
LTE_Shield_error_t err;
770+
char * command;
771+
char * response;
772+
uint8_t opsSeen = 0;
773+
774+
command = lte_calloc_char(strlen(LTE_SHIELD_OPERATOR_SELECTION) + 3);
775+
if (command == NULL) return LTE_SHIELD_ERROR_OUT_OF_MEMORY;
776+
sprintf(command, "%s=?", LTE_SHIELD_OPERATOR_SELECTION);
777+
778+
response = lte_calloc_char(maxOps*48 + 16);
779+
if (response == NULL)
780+
{
781+
free (command);
782+
return LTE_SHIELD_ERROR_OUT_OF_MEMORY;
783+
}
784+
785+
// AT+COPS maximum response time is 3 minutes (180000 ms)
786+
err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, response,
787+
180000);
788+
789+
// Sample responses:
790+
// +COPS: (3,"Verizon Wireless","VzW","311480",8),,(0,1,2,3,4),(0,1,2)
791+
// +COPS: (1,"313 100","313 100","313100",8),(2,"AT&T","AT&T","310410",8),(3,"311 480","311 480","311480",8),,(0,1,2,3,4),(0,1,2)
792+
793+
if (err == LTE_SHIELD_ERROR_SUCCESS)
794+
{
795+
char * opBegin;
796+
char * opEnd;
797+
int op = 0;
798+
int sscanRead = 0;
799+
int stat;
800+
char longOp[26];
801+
char shortOp[11];
802+
uint8_t act;
803+
unsigned long numOp;
804+
805+
opBegin = response;
806+
807+
for (; op < maxOps; op++)
808+
{
809+
opBegin = strchr(opBegin, '(');
810+
if (opBegin == NULL) break;
811+
opEnd = strchr(opBegin, ')');
812+
if (opEnd == NULL) break;
813+
814+
int sscanRead = sscanf(opBegin, "(%d,\"%[^\"]\",\"%[^\"]\",\"%lu\",%d)%*s",
815+
&stat, longOp, shortOp, &numOp, &act);
816+
if (sscanRead == 5)
817+
{
818+
opRet[op].stat = stat;
819+
opRet[op].longOp = (String)(longOp);
820+
opRet[op].shortOp = (String)(shortOp);
821+
opRet[op].numOp = numOp;
822+
opRet[op].act = act;
823+
opsSeen += 1;
824+
}
825+
// TODO: Search for other possible patterns here
826+
else
827+
{
828+
break; // Break out if pattern doesn't match.
829+
}
830+
opBegin = opEnd + 1; // Move opBegin to beginning of next value
831+
}
832+
}
833+
834+
free(command);
835+
free(response);
836+
837+
return opsSeen;
838+
}
839+
840+
LTE_Shield_error_t LTE_Shield::registerOperator(struct operator_stats oper)
841+
{
842+
LTE_Shield_error_t err;
843+
char * command;
844+
845+
command = lte_calloc_char(strlen(LTE_SHIELD_OPERATOR_SELECTION) + 24);
846+
if (command == NULL) return LTE_SHIELD_ERROR_OUT_OF_MEMORY;
847+
sprintf(command, "%s=1,2,\"%lu\"", LTE_SHIELD_OPERATOR_SELECTION, oper.numOp);
848+
849+
// AT+COPS maximum response time is 3 minutes (180000 ms)
850+
err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, NULL,
851+
180000);
655852

656853
return err;
657854
}
658855

856+
LTE_Shield_error_t LTE_Shield::getOperator(String * oper)
857+
{
858+
LTE_Shield_error_t err;
859+
char * command;
860+
char * response;
861+
char * searchPtr;
862+
char mode;
863+
864+
command = lte_calloc_char(strlen(LTE_SHIELD_OPERATOR_SELECTION) + 3);
865+
if (command == NULL) return LTE_SHIELD_ERROR_OUT_OF_MEMORY;
866+
sprintf(command, "%s?", LTE_SHIELD_OPERATOR_SELECTION);
867+
868+
response = lte_calloc_char(64);
869+
if (response == NULL)
870+
{
871+
free(command);
872+
return LTE_SHIELD_ERROR_OUT_OF_MEMORY;
873+
}
874+
875+
// AT+COPS maximum response time is 3 minutes (180000 ms)
876+
err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, response,
877+
180000);
878+
879+
if (err == LTE_SHIELD_ERROR_SUCCESS)
880+
{
881+
searchPtr = strstr(response, "+COPS: ");
882+
if (searchPtr != NULL)
883+
{
884+
searchPtr += strlen("+COPS: "); // Move searchPtr to first char
885+
mode = *searchPtr; // Read first char -- should be mode
886+
if (mode == '2') // Check for de-register
887+
{
888+
err = LTE_SHIELD_ERROR_DEREGISTERED;
889+
}
890+
// Otherwise if it's default, manual, set-only, or automatic
891+
else if ((mode == '0') || (mode == '1') || (mode == '3') || (mode == '4'))
892+
{
893+
*oper = "";
894+
searchPtr = strchr(searchPtr, '\"'); // Move to first quote
895+
if (searchPtr == NULL)
896+
{
897+
err = LTE_SHIELD_ERROR_DEREGISTERED;
898+
}
899+
else
900+
{
901+
while ((*(++searchPtr) != '\"') && (searchPtr != '\0'))
902+
{
903+
oper->concat(*(searchPtr));
904+
}
905+
}
906+
//Serial.println("Operator: " + *oper);
907+
//oper->concat('\0');
908+
}
909+
}
910+
}
911+
912+
free(response);
913+
free(command);
914+
return err;
915+
}
916+
917+
LTE_Shield_error_t LTE_Shield::deregisterOperator(void)
918+
{
919+
LTE_Shield_error_t err;
920+
char * command;
921+
922+
command = lte_calloc_char(strlen(LTE_SHIELD_OPERATOR_SELECTION) + 4);
923+
if (command == NULL) return LTE_SHIELD_ERROR_OUT_OF_MEMORY;
924+
sprintf(command, "%s=2", LTE_SHIELD_OPERATOR_SELECTION);
925+
926+
err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, NULL,
927+
LTE_SHIELD_STANDARD_RESPONSE_TIMEOUT);
928+
929+
return err;
930+
}
659931

660932
LTE_Shield_error_t LTE_Shield::setSMSMessageFormat(lte_shield_message_format_t textMode)
661933
{
@@ -1230,6 +1502,8 @@ LTE_Shield_error_t LTE_Shield::getMno(mobile_network_operator_t * mno)
12301502
LTE_Shield_error_t err;
12311503
char * command;
12321504
char * response;
1505+
const char * mno_keys = "0123456"; // Valid MNO responses
1506+
int i;
12331507

12341508
command = lte_calloc_char(strlen(LTE_SHIELD_COMMAND_MNO) + 2);
12351509
if (command == NULL) return LTE_SHIELD_ERROR_OUT_OF_MEMORY;
@@ -1240,11 +1514,8 @@ LTE_Shield_error_t LTE_Shield::getMno(mobile_network_operator_t * mno)
12401514

12411515
err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK,
12421516
response, LTE_SHIELD_STANDARD_RESPONSE_TIMEOUT);
1243-
12441517
if (err != LTE_SHIELD_ERROR_SUCCESS) return err;
12451518

1246-
const char * mno_keys = "0123456"; // Valid MNO responses
1247-
int i;
12481519
i = strcspn(response, mno_keys); // Find first occurence of MNO key
12491520
if (i == strlen(response))
12501521
{
@@ -1321,7 +1592,7 @@ LTE_Shield_error_t LTE_Shield::waitForResponse(char * expectedResponse, uint16_t
13211592

13221593
LTE_Shield_error_t LTE_Shield::sendCommandWithResponse(
13231594
const char * command, char * expectedResponse, char * responseDest,
1324-
uint16_t commandTimeout, boolean at)
1595+
unsigned long commandTimeout, boolean at)
13251596
{
13261597
unsigned long timeIn;
13271598
boolean found = false;

0 commit comments

Comments
 (0)