freematics-traccar-encrypted/esp32/libraries/FreematicsPlus/FreematicsNetwork.cpp

937 lines
24 KiB
C++
Raw Permalink Normal View History

2024-06-30 18:59:23 -06:00
/*************************************************************************
* Helper classes for various network communication devices
* Distributed under BSD license
* Visit https://freematics.com for more inform
on
* (C)2012-2021 Developed by Stanley Huang <stanley@freematics.com.au>
*************************************************************************/
#include <Arduino.h>
#include "FreematicsBase.h"
#include "FreematicsNetwork.h"
String HTTPClient::genHeader(HTTP_METHOD method, const char* path, bool keepAlive, const char* payload, int payloadSize)
{
String header;
// generate a simplest HTTP header
header = method == METHOD_GET ? "GET " : "POST ";
header += path;
header += " HTTP/1.1\r\nConnection: ";
header += keepAlive ? "keep-alive" : "close";
header += "\r\nHost: ";
header += m_host;
if (method != METHOD_GET) {
header += "\r\nContent-length: ";
header += String(payloadSize);
}
header += "\r\n\r\n";
return header;
}
/*******************************************************************************
Implementation for WiFi (on top of Arduino WiFi library)
*******************************************************************************/
bool ClientWIFI::setup(unsigned int timeout)
{
for (uint32_t t = millis(); millis() - t < timeout;) {
if (WiFi.status() == WL_CONNECTED) {
return true;
}
delay(50);
}
return false;
}
String ClientWIFI::getIP()
{
return WiFi.localIP().toString();
}
bool ClientWIFI::begin(const char* ssid, const char* password)
{
//listAPs();
WiFi.begin(ssid, password);
#ifndef ARDUINO_ESP32C3_DEV
WiFi.setTxPower(WIFI_POWER_8_5dBm);
#endif
return true;
}
void ClientWIFI::end()
{
WiFi.disconnect(true);
}
void ClientWIFI::listAPs()
{
int n = WiFi.scanNetworks();
if (n <= 0) {
Serial.println("No WiFi AP found");
} else {
Serial.println("Nearby WiFi APs:");
for (int i = 0; i < n; ++i) {
// Print SSID and RSSI for each network found
Serial.print(i + 1);
Serial.print(": ");
Serial.print(WiFi.SSID(i));
Serial.print(" (");
Serial.print(WiFi.RSSI(i));
Serial.println("dB)");
}
}
}
bool WifiUDP::open(const char* host, uint16_t port)
{
if (udp.beginPacket(host, port)) {
udpIP = udp.remoteIP();
udpPort = port;
if (udp.endPacket()) {
return true;
}
}
return false;
}
bool WifiUDP::send(const char* data, unsigned int len)
{
if (udp.beginPacket(udpIP, udpPort)) {
if (udp.write((uint8_t*)data, len) == len && udp.endPacket()) {
return true;
}
}
return false;
}
int WifiUDP::receive(char* buffer, int bufsize, unsigned int timeout)
{
uint32_t t = millis();
do {
int bytes = udp.parsePacket();
if (bytes > 0) {
bytes = udp.read(buffer, bufsize);
return bytes;
}
delay(1);
} while (millis() - t < timeout);
return 0;
}
String WifiUDP::queryIP(const char* host)
{
return udpIP.toString();
}
void WifiUDP::close()
{
udp.stop();
}
bool WifiHTTP::open(const char* host, uint16_t port)
{
if (!host) return true;
if (client.connect(host, port)) {
m_state = HTTP_CONNECTED;
m_host = host;
return true;
} else {
m_state = HTTP_ERROR;
return false;
}
}
void WifiHTTP::close()
{
client.stop();
m_state = HTTP_DISCONNECTED;
}
bool WifiHTTP::send(HTTP_METHOD method, const char* path, bool keepAlive, const char* payload, int payloadSize)
{
String header = genHeader(method, path, keepAlive, payload, payloadSize);
int len = header.length();
if (client.write(header.c_str(), len) != len) {
m_state = HTTP_DISCONNECTED;
return false;
}
if (payloadSize) {
if (client.write(payload, payloadSize) != payloadSize) {
m_state = HTTP_ERROR;
return false;
}
}
m_state = HTTP_SENT;
return true;
}
char* WifiHTTP::receive(char* buffer, int bufsize, int* pbytes, unsigned int timeout)
{
int bytes = 0;
int contentBytes = 0;
int contentLen = 0;
char* content = 0;
bool keepAlive = true;
for (uint32_t t = millis(); millis() - t < timeout && bytes < bufsize; ) {
if (!client.available()) {
delay(1);
continue;
}
buffer[bytes++] = client.read();
buffer[bytes] = 0;
if (content) {
if (++contentBytes == contentLen) break;
} else if (strstr(buffer, "\r\n\r\n")) {
// parse HTTP header
char *p = strstr(buffer, "/1.1 ");
if (!p) p = strstr(buffer, "/1.0 ");
if (p) {
if (p) m_code = atoi(p + 5);
}
keepAlive = strstr(buffer, ": close\r\n") == 0;
p = strstr(buffer, "Content-Length: ");
if (!p) p = strstr(buffer, "Content-length: ");
if (p) {
contentLen = atoi(p + 16);
}
content = buffer + bytes;
}
}
if (!content) {
m_state = HTTP_ERROR;
return 0;
}
m_state = HTTP_CONNECTED;
if (pbytes) *pbytes = contentBytes;
if (!keepAlive) close();
return content;
}
/*******************************************************************************
SIM7600/SIM7070/SIM5360
*******************************************************************************/
bool CellSIMCOM::begin(CFreematics* device)
{
getBuffer();
m_device = device;
for (byte n = 0; n < 30; n++) {
device->xbTogglePower(200);
device->xbPurge();
if (!check(2000)) continue;
if (sendCommand("ATE0\r") && sendCommand("ATI\r")) {
// retrieve module info
//Serial.print(m_buffer);
char *p = strstr(m_buffer, "Model:");
if (!p) {
sendCommand("AT+SIMCOMATI\r");
p = strstr(m_buffer, "QCN:");
if (p) {
char *q = strchr(p += 4, '_');
if (q) {
int l = q - p;
if (l >= sizeof(m_model)) l = sizeof(m_model) - 1;
memcpy(m_model, p, l);
m_model[l] = 0;
}
}
m_type = CELL_SIM7070;
} else {
p = strchr(p, '_');
if (p++) {
int i = 0;
while (i < sizeof(m_model) - 1 && p[i] && p[i] != '\r' && p[i] != '\n') {
m_model[i] = p[i];
i++;
}
m_model[i] = 0;
}
m_type = strstr(m_model, "5360") ? CELL_SIM5360 : CELL_SIM7600;
}
p = strstr(m_buffer, "IMEI:");
if (p) strncpy(IMEI, p[5] == ' ' ? p + 6 : p + 5, sizeof(IMEI) - 1);
return true;
}
}
end();
return false;
}
void CellSIMCOM::end()
{
setGPS(false);
if (m_type == CELL_SIM7070) {
if (!sendCommand("AT+CPOWD=1\r", 1000, "NORMAL POWER DOWN")) {
if (m_device) m_device->xbTogglePower(2510);
}
} else {
if (!sendCommand("AT+CPOF\r")) {
if (m_device) m_device->xbTogglePower(2510);
}
}
}
bool CellSIMCOM::setup(const char* apn, const char* username, const char* password, unsigned int timeout)
{
uint32_t t = millis();
bool success = false;
if (m_type == CELL_SIM7070) {
do {
do {
success = false;
sendCommand("AT+CFUN=1\r");
do {
delay(500);
if (sendCommand("AT+CGREG?\r",1000, "+CGREG: 0,")) {
char *p = strstr(m_buffer, "+CGREG: 0,");
if (p) {
char ret = *(p + 10);
success = ret == '1' || ret == '5';
}
}
} while (!success && millis() - t < timeout);
if (!success) break;
success = sendCommand("AT+CGACT?\r", 1000, "+CGACT: 1,");
break;
} while (millis() - t < timeout);
if (!success) break;
sendCommand("AT+CGNAPN\r");
if (apn && *apn) {
if (username && password) {
sprintf(m_buffer, "AT+CNCFG=0,0,\"%s\",\"%s\",\"%s\",3\r", apn, username, password);
} else {
sprintf(m_buffer, "AT+CNCFG=0,0,\"%s\"\r", apn);
}
sendCommand(m_buffer);
}
sendCommand("AT+CNACT=0,1\r");
sendCommand("AT+CNSMOD?\r");
sendCommand("AT+CSCLK=0\r");
} while(0);
} else {
do {
do {
m_device->xbWrite("AT+CPSI?\r");
m_buffer[0] = 0;
const char* answers[] = {"NO SERVICE", ",Online", ",Offline", ",Low Power Mode"};
int ret = m_device->xbReceive(m_buffer, RECV_BUF_SIZE, 500, answers, 4);
if (ret == 2) {
success = true;
break;
}
if (ret == -1 || ret == 4) break;
delay(500);
} while (millis() - t < timeout);
if (!success) break;
success = false;
do {
delay(100);
if (sendCommand("AT+CREG?\r", 1000, "+CREG: 0,")) {
char *p = strstr(m_buffer, "+CREG: 0,");
success = (p && (*(p + 9) == '1' || *(p + 9) == '5'));
}
} while (!success && millis() - t < timeout);
if (!success) break;
if (m_type == CELL_SIM7600) {
success = false;
do {
delay(100);
if (sendCommand("AT+CGREG?\r",1000, "+CGREG: 0,")) {
char *p = strstr(m_buffer, "+CGREG: 0,");
success = (p && (*(p + 10) == '1' || *(p + 10) == '5'));
}
} while (!success && millis() - t < timeout);
if (!success) break;
}
if (apn && *apn) {
sprintf(m_buffer, "AT+CGSOCKCONT=1,\"IP\",\"%s\"\r", apn);
sendCommand(m_buffer);
if (username && password) {
sprintf(m_buffer, "AT+CSOCKAUTH=1,1,\"%s\",\"%s\"\r", username, password);
sendCommand(m_buffer);
}
}
sendCommand("AT+CSOCKSETPN=1\r");
sendCommand("AT+CIPMODE=0\r");
sendCommand("AT+NETOPEN\r");
} while(0);
}
if (!success) Serial.println(m_buffer);
return success;
}
bool CellSIMCOM::setGPS(bool on)
{
if (on) {
if (m_type == CELL_SIM7070) {
sendCommand("AT+CGNSPWR=1\r");
sendCommand("AT+CGNSMOD=1,1,0,0,0\r");
if (sendCommand("AT+CGNSINF\r", 1000, "+CGNSINF:")) {
if (!m_gps) {
m_gps = new GPS_DATA;
memset(m_gps, 0, sizeof(GPS_DATA));
}
return true;
}
} else {
sendCommand("AT+CVAUXV=61\r", 100);
sendCommand("AT+CVAUXS=1\r", 100);
for (byte n = 0; n < 3; n++) {
if ((sendCommand("AT+CGPS=1,1\r") && sendCommand("AT+CGPSINFO=1\r")) || sendCommand("AT+CGPS?\r", 100, "+CGPS: 1")) {
if (!m_gps) {
m_gps = new GPS_DATA;
memset(m_gps, 0, sizeof(GPS_DATA));
}
return true;
}
sendCommand("AT+CGPS=0\r", 100);
}
}
} else if (m_gps) {
if (m_type == CELL_SIM7070) {
sendCommand("AT+CGNSPWR=0\r");
} else {
//sendCommand("AT+CVAUXS=0\r");
sendCommand("AT+CGPS=0\r", 100);
}
GPS_DATA *g = m_gps;
m_gps = 0;
delete g;
return true;
}
return false;
}
bool CellSIMCOM::getLocation(GPS_DATA** pgd)
{
if (m_gps) {
if (pgd) *pgd = m_gps;
return m_gps->ts != 0;
} else {
return false;
}
}
String CellSIMCOM::getIP()
{
if (m_type == CELL_SIM7070) {
sendCommand("AT+CNACT=0,1\r");
for (int i = 0; i < 30; i++) {
delay(500);
if (sendCommand("AT+CNACT?\r", 1000)) {
char *ip = strstr(m_buffer, "+CNACT:");
if (ip) {
ip = strchr(ip, '\"');
if (ip++ && *ip != '0') {
char *q = strchr(ip, '\"');
if (q) *q = 0;
return ip;
}
}
}
}
} else {
uint32_t t = millis();
do {
if (sendCommand("AT+IPADDR\r", 3000, "\r\nOK\r\n")) {
char *p = strstr(m_buffer, "+IPADDR:");
if (p) {
char *ip = p + 9;
if (*ip != '0') {
char *q = strchr(ip, '\r');
if (q) *q = 0;
return ip;
}
}
}
delay(500);
} while (millis() - t < 15000);
}
return "";
}
int CellSIMCOM::RSSI()
{
if (sendCommand("AT+CSQ\r")) {
char *p = strchr(m_buffer, ':');
if (p) {
int csq = atoi(p + 2);
if (csq != 99) {
return csq * 2 - 113;
}
}
}
return 0;
}
String CellSIMCOM::getOperatorName()
{
if (sendCommand("AT+COPS?\r")) {
char *p = strstr(m_buffer, ",\"");
if (p) {
p += 2;
char *s = strchr(p, '\"');
if (s) *s = 0;
return p;
}
}
return "";
}
bool CellSIMCOM::check(unsigned int timeout)
{
uint32_t t = millis();
do {
if (sendCommand("AT\r", 250)) return true;
} while (millis() - t < timeout);
return false;
}
bool CellSIMCOM::checkSIM(const char* pin)
{
bool success;
if (pin && *pin) {
snprintf(m_buffer, RECV_BUF_SIZE, "AT+CPIN=\"%s\"\r", pin);
sendCommand(m_buffer);
}
for (byte n = 0; n < 20 && !(success = sendCommand("AT+CPIN?\r", 500, ": READY")); n++);
return success;
}
String CellSIMCOM::queryIP(const char* host)
{
if (m_type == CELL_SIM7070) {
sprintf(m_buffer, "AT+CDNSGIP=\"%s\",1,3000\r", host);
if (sendCommand(m_buffer, 10000, "+CDNSGIP:")) {
char *p = strstr(m_buffer, host);
if (p) {
p = strstr(p, "\",\"");
if (p) {
char *ip = p + 3;
p = strchr(ip, '\"');
if (p) *p = 0;
return ip;
}
}
}
} else {
sprintf(m_buffer, "AT+CDNSGIP=\"%s\"\r", host);
if (sendCommand(m_buffer, 10000)) {
char *p = strstr(m_buffer, host);
if (p) {
p = strstr(p, ",\"");
if (p) {
char *ip = p + 2;
p = strchr(ip, '\"');
if (p) *p = 0;
return ip;
}
}
}
}
return "";
}
bool CellSIMCOM::sendCommand(const char* cmd, unsigned int timeout, const char* expected)
{
if (cmd) {
m_device->xbWrite(cmd);
delay(10);
}
m_buffer[0] = 0;
const char* answers[] = {"\r\nOK", "\r\nERROR"};
byte ret = m_device->xbReceive(m_buffer, RECV_BUF_SIZE, timeout, expected ? &expected : answers, expected ? 1 : 2);
inbound();
return ret == 1;
}
float CellSIMCOM::parseDegree(const char* s)
{
char *p;
unsigned long left = atol(s);
unsigned long tenk_minutes = (left % 100UL) * 100000UL;
if ((p = strchr(s, '.')))
{
unsigned long mult = 10000;
while (isdigit(*++p))
{
tenk_minutes += mult * (*p - '0');
mult /= 10;
}
}
return (left / 100) + (float)tenk_minutes / 6 / 1000000;
}
void CellSIMCOM::checkGPS()
{
if (!m_gps) return;
// check and parse GPS data
if (m_type == CELL_SIM7070) {
if (sendCommand("AT+CGNSINF\r", 100, "+CGNSINF:")) do {
char *p;
if (!(p = strchr(m_buffer, ':'))) break;
p += 2;
if (strncmp(p, "1,1,", 4)) break;
p += 4;
m_gps->time = atol(p + 8) * 100 + atoi(p + 15);
*(p + 8) = 0;
int day = atoi(p + 6);
*(p + 6) = 0;
int month = atoi(p + 4);
*(p + 4) = 0;
int year = atoi(p + 2);
m_gps->date = year + month * 100 + day * 10000;
if (!(p = strchr(p + 9, ','))) break;
m_gps->lat = atof(++p);
if (!(p = strchr(p, ','))) break;
m_gps->lng = atof(++p);
if (!(p = strchr(p, ','))) break;
m_gps->alt = atof(++p);
if (!(p = strchr(p, ','))) break;
m_gps->speed = atof(++p) * 1000 / 1852;
if (!(p = strchr(p, ','))) break;
m_gps->heading = atoi(++p);
m_gps->ts = millis();
} while (0);
}
}
void CellSIMCOM::inbound()
{
if (m_type == CELL_SIM7070) {
if (strstr(m_buffer, "+CADATAIND: 0") || strstr(m_buffer, "+SHREAD:")) {
m_incoming = 1;
}
} else {
char *p;
if (m_gps && (p = strstr(m_buffer, "+CGPSINFO:"))) do {
if (!(p = strchr(p, ':'))) break;
if (*(++p) == ',') break;
m_gps->lat = parseDegree(p);
if (!(p = strchr(p, ','))) break;
if (*(++p) == 'S') m_gps->lat = -m_gps->lat;
if (!(p = strchr(p, ','))) break;
m_gps->lng = parseDegree(++p);
if (!(p = strchr(p, ','))) break;
if (*(++p) == 'W') m_gps->lng = -m_gps->lng;
if (!(p = strchr(p, ','))) break;
m_gps->date = atoi(++p);
if (!(p = strchr(p, ','))) break;
m_gps->time = atof(++p) * 100;
if (!(p = strchr(p, ','))) break;
m_gps->alt = atof(++p);
if (!(p = strchr(p, ','))) break;
m_gps->speed = atof(++p);
if (!(p = strchr(p, ','))) break;
m_gps->heading = atoi(++p);
m_gps->ts = millis();
} while (0);
if (strstr(m_buffer, "+IPD") || strstr(m_buffer, "RECV EVENT")) {
Serial.println("[CELL] Incoming data");
m_incoming = 1;
}
}
}
char* CellSIMCOM::getBuffer()
{
if (!m_buffer) m_buffer = (char*)malloc(RECV_BUF_SIZE);
return m_buffer;
}
bool CellUDP::open(const char* host, uint16_t port)
{
if (host) {
udpIP = queryIP(host);
if (!udpIP.length()) {
udpIP = host;
}
udpPort = port;
}
if (!udpIP.length()) return false;
if (m_type == CELL_SIM7070) {
sendCommand("AT+CNACT=0,1\r");
sendCommand("AT+CACID=0\r");
sprintf(m_buffer, "AT+CAOPEN=0,0,\"UDP\",\"%s\",%u\r", udpIP.c_str(), udpPort);
if (!sendCommand(m_buffer, 3000)) {
Serial.println(m_buffer);
return false;
}
return true;
} else {
sprintf(m_buffer, "AT+CIPOPEN=0,\"UDP\",\"%s\",%u,8000\r", udpIP.c_str(), udpPort);
if (!sendCommand(m_buffer, 3000)) {
Serial.println(m_buffer);
return false;
}
return true;
}
}
bool CellUDP::close()
{
if (m_type == CELL_SIM7070) {
sendCommand("AT+CACLOSE=0\r");
return sendCommand("AT+CNACT=0,0\r");
} else {
return sendCommand("AT+CIPCLOSE=0\r");
}
}
bool CellUDP::send(const char* data, unsigned int len)
{
if (m_type == CELL_SIM7070) {
sendCommand("AT+CASTATE?\r");
sprintf(m_buffer, "AT+CASEND=0,%u\r", len);
sendCommand(m_buffer, 100, "\r\n>");
if (sendCommand(data, 1000)) return true;
} else {
int n = sprintf(m_buffer, "AT+CIPSEND=0,%u,\"%s\",%u\r", len, udpIP.c_str(), udpPort);
m_device->xbWrite(m_buffer, n);
delay(10);
m_device->xbWrite(data, len);
const char* answers[] = {"\r\nERROR", "OK\r\n\r\n+CIPSEND:", "\r\nRECV FROM:"};
byte ret = m_device->xbReceive(m_buffer, RECV_BUF_SIZE, 1000, answers, 3);
if (ret > 1) return true;
}
return false;
}
char* CellUDP::receive(int* pbytes, unsigned int timeout)
{
if (m_type == CELL_SIM7070) {
if (!m_incoming && timeout) sendCommand(0, timeout, "+CADATAIND: 0");
if (!m_incoming) return 0;
m_incoming = 0;
if (sendCommand("AT+CARECV=0,384\r", timeout)) {
char *p = strstr(m_buffer, "+CARECV: ");
if (p) {
if (pbytes) *pbytes = atoi(p + 9);
p = strchr(m_buffer, ',');
return p ? p + 1 : m_buffer;
}
}
} else {
if (!m_incoming && timeout) sendCommand(0, timeout, "+IPD");
if (m_incoming) {
m_incoming = 0;
char *p = strstr(m_buffer, "+IPD");
if (p) {
*p = '-'; // mark this datagram as checked
int len = atoi(p + 4);
if (pbytes) *pbytes = len;
p = strchr(p, '\n');
if (p) {
if (strlen(++p) > len) *(p + len) = 0;
return p;
}
}
}
}
return 0;
}
void CellHTTP::init()
{
if (m_type != CELL_SIM7070) {
sendCommand("AT+CHTTPSSTOP\r");
sendCommand("AT+CHTTPSSTART\r");
}
}
bool CellHTTP::open(const char* host, uint16_t port)
{
if (m_type == CELL_SIM7070) {
sendCommand("AT+CNACT=0,1\r");
sendCommand("AT+CACID=0\r");
bool useSSL = (port == 443);
if (useSSL) {
sendCommand("AT+SHSSL=1,\"\"\r");
sendCommand("AT+CSSLCFG=\"ignorertctime\",1,1\r");
sendCommand("AT+CSSLCFG=\"SSLVERSION\",1,3\r");
sprintf(m_buffer, "AT+CSSLCFG=\"sni\",1,\"%s\"\r", host);
sendCommand(m_buffer);
}
sprintf(m_buffer, "AT+SHCONF=\"URL\",\"%s://%s:%u\"\r", useSSL ? "https" : "http", host, port);
if (!sendCommand(m_buffer)) {
return false;
}
sendCommand("AT+SHCONF=\"HEADERLEN\",256\r");
sendCommand("AT+SHCONF=\"BODYLEN\",1024\r");
sendCommand("AT+SHCONN\r", HTTP_CONN_TIMEOUT);
if (sendCommand("AT+SHSTATE?\r")) {
if (strstr(m_buffer, "+SHSTATE: 1")) {
m_state = HTTP_CONNECTED;
m_host = host;
sendCommand("AT+SHCHEAD\r");
sendCommand("AT+SHAHEAD=\"User-Agent\",\"curl/7.47.0\"\r");
sendCommand("AT+SHAHEAD=\"Cache-control\",\"no-cache\"\r");
sendCommand("AT+SHAHEAD=\"Connection\",\"keep-alive\"\r");
sendCommand("AT+SHAHEAD=\"Accept\",\"*/*\"\r");
m_state = HTTP_CONNECTED;
return true;
}
}
} else {
memset(m_buffer, 0, RECV_BUF_SIZE);
sprintf(m_buffer, "AT+CHTTPSOPSE=\"%s\",%u,%u\r", host, port, port == 443 ? 2: 1);
if (sendCommand(m_buffer, 1000)) {
if (sendCommand(0, HTTP_CONN_TIMEOUT, "+CHTTPSOPSE:")) {
m_state = HTTP_CONNECTED;
m_host = host;
return true;
}
}
}
Serial.println(m_buffer);
m_state = HTTP_ERROR;
return false;
}
bool CellHTTP::close()
{
m_state = HTTP_DISCONNECTED;
if (m_type == CELL_SIM7070) {
return sendCommand("AT+SHDISC\r");
} else if (m_type == CELL_SIM5360) {
return sendCommand("AT+CHTTPSCLSE\r", 1000, "+CHTTPSCLSE:");
} else {
return sendCommand("AT+CIPCLOSE=0\r");
}
}
bool CellHTTP::send(HTTP_METHOD method, const char* path, bool keepAlive, const char* payload, int payloadSize)
{
if (m_type == CELL_SIM7070) {
if (method == METHOD_POST) {
sprintf(m_buffer, "AT+SHBOD=%u,1000\r", payloadSize);
if (sendCommand(m_buffer, 1000, "\r\n>")) {
sendCommand(payload);
}
}
snprintf(m_buffer, RECV_BUF_SIZE, "AT+SHREQ=\"%s\",%u\r", path, method == METHOD_GET ? 1 : 3);
if (sendCommand(m_buffer, HTTP_CONN_TIMEOUT)) {
char *p;
int len = 0;
if (strstr(m_buffer, "+SHREQ:") || sendCommand(0, HTTP_CONN_TIMEOUT, "+SHREQ:")) {
if ((p = strstr(m_buffer, "+SHREQ:")) && (p = strchr(p, ','))) {
m_code = atoi(++p);
if ((p = strchr(p, ','))) len = atoi(++p);
}
}
if (len > 0) {
if (len > RECV_BUF_SIZE - 16) len = RECV_BUF_SIZE - 16;
sprintf(m_buffer, "AT+SHREAD=0,%u\r", len);
if (sendCommand(m_buffer)) {
m_state = HTTP_SENT;
return true;
}
}
}
} else {
String header = genHeader(method, path, keepAlive, payload, payloadSize);
int len = header.length();
sprintf(m_buffer, "AT+CHTTPSSEND=%u\r", len + payloadSize);
if (!sendCommand(m_buffer, 100, ">")) {
m_state = HTTP_DISCONNECTED;
return false;
}
// send HTTP header
m_device->xbWrite(header.c_str());
// send POST payload if any
if (payload) m_device->xbWrite(payload, payloadSize);
if (sendCommand(0, 200, "+CHTTPSSEND:")) {
m_state = HTTP_SENT;
return true;
}
}
Serial.println(m_buffer);
m_state = HTTP_ERROR;
return false;
}
char* CellHTTP::receive(int* pbytes, unsigned int timeout)
{
if (m_type == CELL_SIM7070) {
if (!m_incoming && timeout) sendCommand(0, timeout, "+SHREAD:");
if (!m_incoming) return 0;
m_incoming = 0;
m_state = HTTP_CONNECTED;
char *p = strstr(m_buffer, "+SHREAD:");
if (p) {
int bytes = atoi(p += 9);
if (pbytes) *pbytes = bytes;
p = strchr(p, '\n');
if (p++) {
*(p + bytes) = 0;
return p;
}
}
return 0;
} else {
// start receiving
int received = 0;
char* payload = 0;
bool keepalive;
if (!m_incoming && timeout) sendCommand(0, timeout, "RECV EVENT");
if (!m_incoming) return 0;
m_incoming = 0;
// to be compatible with SIM5360
bool legacy = false;
char *p = strstr(m_buffer, "RECV EVENT");
if (p && *(p - 1) == ' ') legacy = true;
/*
+CHTTPSRECV:XX\r\n
[payload]\r\n
+CHTTPSRECV:0\r\n
*/
// TODO: implement for multiple chunks of data
// only process first chunk now
sprintf(m_buffer, "AT+CHTTPSRECV=%u\r", RECV_BUF_SIZE - 36);
if (sendCommand(m_buffer, timeout, legacy ? "\r\n+CHTTPSRECV: 0" : "\r\n+CHTTPSRECV:0")) {
char *p = strstr(m_buffer, "\r\n+CHTTPSRECV: DATA");
if (p) {
if ((p = strchr(p, ','))) {
received = atoi(p + 1);
char *q = strchr(p, '\n');
payload = q ? (q + 1) : p;
if (m_buffer + RECV_BUF_SIZE - payload > received) {
payload[received] = 0;
}
}
}
}
if (received == 0) {
m_state = HTTP_ERROR;
return 0;
}
p = strstr(payload, "/1.1 ");
if (!p) p = strstr(payload, "/1.0 ");
if (p) {
if (p) m_code = atoi(p + 5);
}
keepalive = strstr(m_buffer, ": close\r\n") == 0;
m_state = HTTP_CONNECTED;
if (!keepalive) close();
if (pbytes) *pbytes = received;
return payload;
}
}