mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #11720 from mtomczykmobica/ONME-4405
ATCmdParser: merge scanf and recv functionspull/11919/head
commit
2bde6581a6
|
@ -0,0 +1,409 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Arm Limited and affiliates.
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "ATCmdParser.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include "FileHandle_stub.h"
|
||||||
|
#include "mbed_poll_stub.h"
|
||||||
|
#include "Timer_stub.h"
|
||||||
|
|
||||||
|
using namespace mbed;
|
||||||
|
|
||||||
|
static bool expected_oob_callback = false;
|
||||||
|
|
||||||
|
void urc_callback()
|
||||||
|
{
|
||||||
|
EXPECT_TRUE(expected_oob_callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// AStyle ignored as the definition is not clear due to preprocessor usage
|
||||||
|
// *INDENT-OFF*
|
||||||
|
class test_ATCmdParser : public testing::Test {
|
||||||
|
protected:
|
||||||
|
|
||||||
|
void SetUp()
|
||||||
|
{
|
||||||
|
filehandle_stub_short_value_counter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TearDown()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// *INDENT-ON*
|
||||||
|
|
||||||
|
|
||||||
|
TEST_F(test_ATCmdParser, test_ATCmdParser_create)
|
||||||
|
{
|
||||||
|
FileHandle_stub fh1;
|
||||||
|
|
||||||
|
ATCmdParser *at = new ATCmdParser(&fh1, ",");
|
||||||
|
at->set_delimiter("\r");
|
||||||
|
at->set_timeout(5000);
|
||||||
|
at->debug_on(1);
|
||||||
|
|
||||||
|
delete at;
|
||||||
|
|
||||||
|
at = new ATCmdParser(&fh1, "\r");
|
||||||
|
|
||||||
|
EXPECT_TRUE(at != NULL);
|
||||||
|
delete at;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(test_ATCmdParser, test_ATCmdParser_set_timeout)
|
||||||
|
{
|
||||||
|
FileHandle_stub fh1;
|
||||||
|
|
||||||
|
ATCmdParser at(&fh1, ",");
|
||||||
|
at.set_timeout(8);
|
||||||
|
at.set_timeout(80);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
TEST_F(test_ATCmdParser, test_ATCmdParser_process_oob)
|
||||||
|
{
|
||||||
|
FileHandle_stub fh1;
|
||||||
|
|
||||||
|
ATCmdParser at(&fh1);
|
||||||
|
at.set_timeout(10);
|
||||||
|
|
||||||
|
at.process_oob();
|
||||||
|
|
||||||
|
filehandle_stub_short_value_counter = 1;
|
||||||
|
fh1.short_value = POLLIN;
|
||||||
|
at.oob("s", &urc_callback);
|
||||||
|
at.process_oob();
|
||||||
|
|
||||||
|
filehandle_stub_short_value_counter = 2;
|
||||||
|
at.process_oob();
|
||||||
|
|
||||||
|
char buf[5];
|
||||||
|
char table[] = "ssssssssssssssssssssssssssssssss\0";
|
||||||
|
filehandle_stub_table = table;
|
||||||
|
filehandle_stub_table_pos = 0;
|
||||||
|
mbed_poll_stub::revents_value = POLLIN;
|
||||||
|
mbed_poll_stub::int_value = 1;
|
||||||
|
at.read(buf, 5);
|
||||||
|
|
||||||
|
filehandle_stub_short_value_counter = 2;
|
||||||
|
expected_oob_callback = true;
|
||||||
|
at.process_oob();
|
||||||
|
expected_oob_callback = false;
|
||||||
|
|
||||||
|
timer_stub_value = 0;
|
||||||
|
filehandle_stub_table_pos = 0;
|
||||||
|
at.read(buf, 5);
|
||||||
|
|
||||||
|
filehandle_stub_short_value_counter = 1;
|
||||||
|
expected_oob_callback = true;
|
||||||
|
at.process_oob();
|
||||||
|
expected_oob_callback = false;
|
||||||
|
|
||||||
|
char table2[5];
|
||||||
|
table2[0] = '\r';
|
||||||
|
table2[1] = '\r';
|
||||||
|
table2[2] = '\n';
|
||||||
|
table2[3] = '\n';
|
||||||
|
table2[4] = 0;
|
||||||
|
filehandle_stub_table = table2;
|
||||||
|
|
||||||
|
timer_stub_value = 0;
|
||||||
|
filehandle_stub_table_pos = 0;
|
||||||
|
mbed_poll_stub::revents_value = POLLIN;
|
||||||
|
mbed_poll_stub::int_value = 1;
|
||||||
|
at.read(buf, 1);
|
||||||
|
|
||||||
|
filehandle_stub_short_value_counter = 1;
|
||||||
|
at.process_oob();
|
||||||
|
|
||||||
|
filehandle_stub_table = table;
|
||||||
|
|
||||||
|
filehandle_stub_short_value_counter = 0;
|
||||||
|
filehandle_stub_table_pos = 0;
|
||||||
|
filehandle_stub_table = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
TEST_F(test_ATCmdParser, test_ATCmdParser_flush)
|
||||||
|
{
|
||||||
|
FileHandle_stub fh1;
|
||||||
|
|
||||||
|
ATCmdParser at(&fh1, ",");
|
||||||
|
filehandle_stub_short_value_counter = 1;
|
||||||
|
fh1.short_value = POLLIN;
|
||||||
|
at.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(test_ATCmdParser, test_ATCmdParser_write)
|
||||||
|
{
|
||||||
|
FileHandle_stub fh1;
|
||||||
|
|
||||||
|
ATCmdParser at(&fh1, ",");
|
||||||
|
fh1.size_value = -1;
|
||||||
|
EXPECT_TRUE(-1 == at.write("help", 4));
|
||||||
|
|
||||||
|
mbed_poll_stub::revents_value = POLLOUT;
|
||||||
|
mbed_poll_stub::int_value = 1;
|
||||||
|
fh1.size_value = -1;
|
||||||
|
EXPECT_TRUE(-1 == at.write("help", 4));
|
||||||
|
|
||||||
|
mbed_poll_stub::revents_value = POLLOUT;
|
||||||
|
mbed_poll_stub::int_value = 1;
|
||||||
|
fh1.size_value = 7;
|
||||||
|
EXPECT_EQ(4, at.write("help", 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(test_ATCmdParser, test_ATCmdParser_set_delimiter)
|
||||||
|
{
|
||||||
|
FileHandle_stub fh1;
|
||||||
|
|
||||||
|
ATCmdParser at(&fh1, ",");
|
||||||
|
at.set_delimiter("+");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(test_ATCmdParser, test_ATCmdParser_read)
|
||||||
|
{
|
||||||
|
FileHandle_stub fh1;
|
||||||
|
filehandle_stub_table = NULL;
|
||||||
|
filehandle_stub_table_pos = 0;
|
||||||
|
|
||||||
|
ATCmdParser at(&fh1, ",");
|
||||||
|
char buf[6];
|
||||||
|
memset(buf, 0, 6);
|
||||||
|
|
||||||
|
// TEST EMPTY BUFFER
|
||||||
|
// Shouldn't read any byte since buffer is empty
|
||||||
|
EXPECT_TRUE(-1 == at.read(buf, 1));
|
||||||
|
// Return error due to error set to at handler by the above call on empty buffer
|
||||||
|
EXPECT_TRUE(-1 == at.read(buf, 1));
|
||||||
|
|
||||||
|
// TEST DATA IN BUFFER
|
||||||
|
char table1[] = "1234512345678OK\r\n\0";
|
||||||
|
filehandle_stub_table = table1;
|
||||||
|
filehandle_stub_table_pos = 0;
|
||||||
|
mbed_poll_stub::revents_value = POLLIN;
|
||||||
|
mbed_poll_stub::int_value = 1;
|
||||||
|
|
||||||
|
// Read 5 bytes
|
||||||
|
EXPECT_EQ(5, at.read(buf, 5));
|
||||||
|
EXPECT_TRUE(!memcmp(buf, table1, 5));
|
||||||
|
// get_char triggered above should have filled in the whole reading buffer
|
||||||
|
EXPECT_EQ(filehandle_stub_table_pos, (strlen(buf)));
|
||||||
|
// Read another 8 bytes
|
||||||
|
EXPECT_TRUE(8 == at.read(buf, 8) && !memcmp(buf, table1 + 5, 8));
|
||||||
|
// Reading more than the 4 bytes left -> ERROR
|
||||||
|
EXPECT_EQ(-1, at.read(buf, 5));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(test_ATCmdParser, test_ATCmdParser_debug_on)
|
||||||
|
{
|
||||||
|
FileHandle_stub fh1;
|
||||||
|
|
||||||
|
ATCmdParser at(&fh1, ",");
|
||||||
|
at.debug_on(true);
|
||||||
|
at.debug_on(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(test_ATCmdParser, test_ATCmdParser_abort)
|
||||||
|
{
|
||||||
|
FileHandle_stub fh1;
|
||||||
|
|
||||||
|
ATCmdParser at(&fh1, ",");
|
||||||
|
at.abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(test_ATCmdParser, test_ATCmdParser_printf)
|
||||||
|
{
|
||||||
|
FileHandle_stub fh1;
|
||||||
|
|
||||||
|
ATCmdParser at(&fh1);
|
||||||
|
at.flush();
|
||||||
|
at.debug_on(true);
|
||||||
|
|
||||||
|
const char * format = "TEST %d %s %x %c TEST \r\r\n\n";
|
||||||
|
mbed_poll_stub::revents_value = POLLOUT;
|
||||||
|
mbed_poll_stub::int_value = 1;
|
||||||
|
fh1.size_value = 64;
|
||||||
|
|
||||||
|
EXPECT_EQ(22, at.printf(format, 5, "t", 0x5, 't'));
|
||||||
|
|
||||||
|
fh1.size_value = -1;
|
||||||
|
EXPECT_EQ(-1, at.printf(format, 5, "t", 0x5, 't'));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(test_ATCmdParser, test_ATCmdParser_send)
|
||||||
|
{
|
||||||
|
FileHandle_stub fh1;
|
||||||
|
|
||||||
|
ATCmdParser at(&fh1);
|
||||||
|
at.flush();
|
||||||
|
at.debug_on(true);
|
||||||
|
|
||||||
|
const char * format = "TEST %d %s %x %c TEST \r\r\n\n";
|
||||||
|
mbed_poll_stub::revents_value = POLLOUT;
|
||||||
|
mbed_poll_stub::int_value = 1;
|
||||||
|
fh1.size_value = 64;
|
||||||
|
|
||||||
|
//VALID printf
|
||||||
|
EXPECT_TRUE(at.send(format, 5, "t", 0x5, 't'));
|
||||||
|
EXPECT_TRUE(at.send(""));
|
||||||
|
|
||||||
|
fh1.size_value = -1;
|
||||||
|
EXPECT_FALSE(at.send(format, 5, "t", 0x5, 't'));
|
||||||
|
EXPECT_FALSE(at.send(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(test_ATCmdParser, test_ATCmdParser_recv)
|
||||||
|
{
|
||||||
|
FileHandle_stub fh1;
|
||||||
|
ATCmdParser at(&fh1, "\r", 8);
|
||||||
|
|
||||||
|
//parse valid char
|
||||||
|
char table1[] = "s";
|
||||||
|
at.flush();
|
||||||
|
filehandle_stub_table = table1;
|
||||||
|
filehandle_stub_table_pos = 0;
|
||||||
|
mbed_poll_stub::revents_value = POLLIN;
|
||||||
|
mbed_poll_stub::int_value = 1;
|
||||||
|
char c;
|
||||||
|
EXPECT_TRUE(at.recv("%c", &c));
|
||||||
|
EXPECT_EQ(c, 's');
|
||||||
|
|
||||||
|
//too large response
|
||||||
|
char table2[] = "1234567890\n";
|
||||||
|
at.flush();
|
||||||
|
filehandle_stub_table = table2;
|
||||||
|
filehandle_stub_table_pos = 0;
|
||||||
|
mbed_poll_stub::revents_value = POLLIN;
|
||||||
|
mbed_poll_stub::int_value = 1;
|
||||||
|
EXPECT_FALSE(at.recv("123456789%c\n", &c));
|
||||||
|
|
||||||
|
//back to normal buffer
|
||||||
|
ATCmdParser at1(&fh1);
|
||||||
|
at1.flush();
|
||||||
|
filehandle_stub_table = table2;
|
||||||
|
filehandle_stub_table_pos = 0;
|
||||||
|
mbed_poll_stub::revents_value = POLLIN;
|
||||||
|
mbed_poll_stub::int_value = 1;
|
||||||
|
EXPECT_TRUE(at1.recv("123456789%c\n", &c));
|
||||||
|
|
||||||
|
char table3[] = "s\r\n\0";
|
||||||
|
at1.flush();
|
||||||
|
filehandle_stub_table = table3;
|
||||||
|
filehandle_stub_table_pos = 0;
|
||||||
|
mbed_poll_stub::revents_value = POLLIN;
|
||||||
|
mbed_poll_stub::int_value = 1;
|
||||||
|
EXPECT_TRUE(at.recv("%c", &c));
|
||||||
|
EXPECT_EQ(c, 's');
|
||||||
|
|
||||||
|
char table4[] = "s 1 E test\r\n";
|
||||||
|
char text[5];
|
||||||
|
int hexval;
|
||||||
|
int intval;
|
||||||
|
at1.flush();
|
||||||
|
filehandle_stub_table = table4;
|
||||||
|
filehandle_stub_table_pos = 0;
|
||||||
|
mbed_poll_stub::revents_value = POLLIN;
|
||||||
|
mbed_poll_stub::int_value = 1;
|
||||||
|
EXPECT_TRUE(at1.recv("%c %d %x %s", &c, &intval, &hexval, &text));
|
||||||
|
EXPECT_EQ(c, 's');
|
||||||
|
EXPECT_EQ(intval, 1);
|
||||||
|
EXPECT_EQ(hexval, 0xE);
|
||||||
|
EXPECT_EQ(!memcmp(text, "test", 4), 0);
|
||||||
|
|
||||||
|
char table5[] = "s 1 E test\r\nt 2 F tes2\r\n";
|
||||||
|
char c1;
|
||||||
|
char text1[5];
|
||||||
|
int hexval1;
|
||||||
|
int intval1;
|
||||||
|
at1.flush();
|
||||||
|
filehandle_stub_table = table5;
|
||||||
|
filehandle_stub_table_pos = 0;
|
||||||
|
mbed_poll_stub::revents_value = POLLIN;
|
||||||
|
mbed_poll_stub::int_value = 1;
|
||||||
|
|
||||||
|
expected_oob_callback = true;
|
||||||
|
at1.oob("s", &urc_callback);
|
||||||
|
EXPECT_TRUE(at1.recv("%c %d %x %s\r\n%c %d %x %s\r\n", &c, &intval, &hexval, &text));
|
||||||
|
expected_oob_callback = false;
|
||||||
|
EXPECT_EQ(c, 't');
|
||||||
|
EXPECT_EQ(intval, 2);
|
||||||
|
EXPECT_EQ(hexval, 0xF);
|
||||||
|
EXPECT_EQ(memcmp(text, "tes2", 4), 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(test_ATCmdParser, test_ATCmdParser_scanf)
|
||||||
|
{
|
||||||
|
FileHandle_stub fh1;
|
||||||
|
ATCmdParser at(&fh1, "\r");
|
||||||
|
|
||||||
|
//parse valid char
|
||||||
|
char table1[] = "s";
|
||||||
|
at.flush();
|
||||||
|
filehandle_stub_table = table1;
|
||||||
|
filehandle_stub_table_pos = 0;
|
||||||
|
mbed_poll_stub::revents_value = POLLIN;
|
||||||
|
mbed_poll_stub::int_value = 1;
|
||||||
|
char c;
|
||||||
|
EXPECT_TRUE(at.scanf("%c", &c));
|
||||||
|
EXPECT_EQ(c, 's');
|
||||||
|
|
||||||
|
//back to normal buffer
|
||||||
|
char table2[] = "1234567890\n";
|
||||||
|
at.flush();
|
||||||
|
filehandle_stub_table = table2;
|
||||||
|
filehandle_stub_table_pos = 0;
|
||||||
|
mbed_poll_stub::revents_value = POLLIN;
|
||||||
|
mbed_poll_stub::int_value = 1;
|
||||||
|
EXPECT_TRUE(at.scanf("123456789%c\n", &c));
|
||||||
|
|
||||||
|
char table3[] = "s\r\n\0";
|
||||||
|
at.flush();
|
||||||
|
filehandle_stub_table = table3;
|
||||||
|
filehandle_stub_table_pos = 0;
|
||||||
|
mbed_poll_stub::revents_value = POLLIN;
|
||||||
|
mbed_poll_stub::int_value = 1;
|
||||||
|
EXPECT_TRUE(at.scanf("%c", &c));
|
||||||
|
EXPECT_EQ(c, 's');
|
||||||
|
|
||||||
|
char table4[] = "s 1 E test\r\n";
|
||||||
|
char text[5];
|
||||||
|
memset(text, 0, 5);
|
||||||
|
int hexval;
|
||||||
|
int intval;
|
||||||
|
at.flush();
|
||||||
|
filehandle_stub_table = table4;
|
||||||
|
filehandle_stub_table_pos = 0;
|
||||||
|
mbed_poll_stub::revents_value = POLLIN;
|
||||||
|
mbed_poll_stub::int_value = 1;
|
||||||
|
EXPECT_TRUE(at.scanf("%c %d %x %s", &c, &intval, &hexval, &text));
|
||||||
|
EXPECT_EQ(c, 's');
|
||||||
|
EXPECT_EQ(intval, 1);
|
||||||
|
EXPECT_EQ(hexval, 0xE);
|
||||||
|
EXPECT_EQ(!memcmp(text, "test", 4), 0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
####################
|
||||||
|
# UNIT TESTS
|
||||||
|
####################
|
||||||
|
|
||||||
|
# Source files
|
||||||
|
set(unittest-sources
|
||||||
|
../platform/source/ATCmdParser.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
# Test files
|
||||||
|
set(unittest-test-sources
|
||||||
|
platform/ATCmdParser/test_ATCmdParser.cpp
|
||||||
|
stubs/FileHandle_stub.cpp
|
||||||
|
stubs/mbed_assert_stub.c
|
||||||
|
stubs/mbed_poll_stub.cpp
|
||||||
|
)
|
|
@ -1,420 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) , Arm Limited and affiliates.
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "ATCmdParser.h"
|
|
||||||
#include "mbed_poll.h"
|
|
||||||
#include "mbed_debug.h"
|
|
||||||
|
|
||||||
#ifdef LF
|
|
||||||
#undef LF
|
|
||||||
#define LF 10
|
|
||||||
#else
|
|
||||||
#define LF 10
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef CR
|
|
||||||
#undef CR
|
|
||||||
#define CR 13
|
|
||||||
#else
|
|
||||||
#define CR 13
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// getc/putc handling with timeouts
|
|
||||||
int ATCmdParser::putc(char c)
|
|
||||||
{
|
|
||||||
pollfh fhs;
|
|
||||||
fhs.fh = _fh;
|
|
||||||
fhs.events = POLLOUT;
|
|
||||||
|
|
||||||
int count = poll(&fhs, 1, _timeout);
|
|
||||||
if (count > 0 && (fhs.revents & POLLOUT)) {
|
|
||||||
return _fh->write(&c, 1) == 1 ? 0 : -1;
|
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int ATCmdParser::getc()
|
|
||||||
{
|
|
||||||
pollfh fhs;
|
|
||||||
fhs.fh = _fh;
|
|
||||||
fhs.events = POLLIN;
|
|
||||||
|
|
||||||
int count = poll(&fhs, 1, _timeout);
|
|
||||||
if (count > 0 && (fhs.revents & POLLIN)) {
|
|
||||||
unsigned char ch;
|
|
||||||
return _fh->read(&ch, 1) == 1 ? ch : -1;
|
|
||||||
} else {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ATCmdParser::flush()
|
|
||||||
{
|
|
||||||
while (_fh->readable()) {
|
|
||||||
unsigned char ch;
|
|
||||||
_fh->read(&ch, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// read/write handling with timeouts
|
|
||||||
int ATCmdParser::write(const char *data, int size)
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
for (; i < size; i++) {
|
|
||||||
if (putc(data[i]) < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ATCmdParser::read(char *data, int size)
|
|
||||||
{
|
|
||||||
int i = 0;
|
|
||||||
for (; i < size; i++) {
|
|
||||||
int c = getc();
|
|
||||||
if (c < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
data[i] = c;
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// printf/scanf handling
|
|
||||||
int ATCmdParser::vprintf(const char *format, va_list args)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (vsprintf(_buffer, format, args) < 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
for (; _buffer[i]; i++) {
|
|
||||||
if (putc(_buffer[i]) < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ATCmdParser::vscanf(const char *format, va_list args)
|
|
||||||
{
|
|
||||||
// Since format is const, we need to copy it into our buffer to
|
|
||||||
// add the line's null terminator and clobber value-matches with asterisks.
|
|
||||||
//
|
|
||||||
// We just use the beginning of the buffer to avoid unnecessary allocations.
|
|
||||||
int i = 0;
|
|
||||||
int offset = 0;
|
|
||||||
|
|
||||||
while (format[i]) {
|
|
||||||
if (format[i] == '%' && format[i + 1] != '%' && format[i + 1] != '*') {
|
|
||||||
_buffer[offset++] = '%';
|
|
||||||
_buffer[offset++] = '*';
|
|
||||||
i++;
|
|
||||||
} else {
|
|
||||||
_buffer[offset++] = format[i++];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scanf has very poor support for catching errors
|
|
||||||
// fortunately, we can abuse the %n specifier to determine
|
|
||||||
// if the entire string was matched.
|
|
||||||
_buffer[offset++] = '%';
|
|
||||||
_buffer[offset++] = 'n';
|
|
||||||
_buffer[offset++] = 0;
|
|
||||||
|
|
||||||
// To workaround scanf's lack of error reporting, we actually
|
|
||||||
// make two passes. One checks the validity with the modified
|
|
||||||
// format string that only stores the matched characters (%n).
|
|
||||||
// The other reads in the actual matched values.
|
|
||||||
//
|
|
||||||
// We keep trying the match until we succeed or some other error
|
|
||||||
// derails us.
|
|
||||||
int j = 0;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
// Ran out of space
|
|
||||||
if (j + 1 >= _buffer_size - offset) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Recieve next character
|
|
||||||
int c = getc();
|
|
||||||
if (c < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
_buffer[offset + j++] = c;
|
|
||||||
_buffer[offset + j] = 0;
|
|
||||||
|
|
||||||
// Check for match
|
|
||||||
int count = -1;
|
|
||||||
sscanf(_buffer + offset, _buffer, &count);
|
|
||||||
|
|
||||||
// We only succeed if all characters in the response are matched
|
|
||||||
if (count == j) {
|
|
||||||
// Store the found results
|
|
||||||
vsscanf(_buffer + offset, format, args);
|
|
||||||
return j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Command parsing with line handling
|
|
||||||
bool ATCmdParser::vsend(const char *command, va_list args)
|
|
||||||
{
|
|
||||||
// Create and send command
|
|
||||||
if (vsprintf(_buffer, command, args) < 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; _buffer[i]; i++) {
|
|
||||||
if (putc(_buffer[i]) < 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Finish with newline
|
|
||||||
for (size_t i = 0; _output_delimiter[i]; i++) {
|
|
||||||
if (putc(_output_delimiter[i]) < 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
debug_if(_dbg_on, "AT> %s\n", _buffer);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ATCmdParser::vrecv(const char *response, va_list args)
|
|
||||||
{
|
|
||||||
restart:
|
|
||||||
_aborted = false;
|
|
||||||
// Iterate through each line in the expected response
|
|
||||||
while (response[0]) {
|
|
||||||
// Since response is const, we need to copy it into our buffer to
|
|
||||||
// add the line's null terminator and clobber value-matches with asterisks.
|
|
||||||
//
|
|
||||||
// We just use the beginning of the buffer to avoid unnecessary allocations.
|
|
||||||
int i = 0;
|
|
||||||
int offset = 0;
|
|
||||||
bool whole_line_wanted = false;
|
|
||||||
|
|
||||||
while (response[i]) {
|
|
||||||
if (response[i] == '%' && response[i + 1] != '%' && response[i + 1] != '*') {
|
|
||||||
_buffer[offset++] = '%';
|
|
||||||
_buffer[offset++] = '*';
|
|
||||||
i++;
|
|
||||||
} else {
|
|
||||||
_buffer[offset++] = response[i++];
|
|
||||||
// Find linebreaks, taking care not to be fooled if they're in a %[^\n] conversion specification
|
|
||||||
if (response[i - 1] == '\n' && !(i >= 3 && response[i - 3] == '[' && response[i - 2] == '^')) {
|
|
||||||
whole_line_wanted = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scanf has very poor support for catching errors
|
|
||||||
// fortunately, we can abuse the %n specifier to determine
|
|
||||||
// if the entire string was matched.
|
|
||||||
_buffer[offset++] = '%';
|
|
||||||
_buffer[offset++] = 'n';
|
|
||||||
_buffer[offset++] = 0;
|
|
||||||
|
|
||||||
debug_if(_dbg_on, "AT? %s\n", _buffer);
|
|
||||||
// To workaround scanf's lack of error reporting, we actually
|
|
||||||
// make two passes. One checks the validity with the modified
|
|
||||||
// format string that only stores the matched characters (%n).
|
|
||||||
// The other reads in the actual matched values.
|
|
||||||
//
|
|
||||||
// We keep trying the match until we succeed or some other error
|
|
||||||
// derails us.
|
|
||||||
int j = 0;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
// Receive next character
|
|
||||||
int c = getc();
|
|
||||||
if (c < 0) {
|
|
||||||
debug_if(_dbg_on, "AT(Timeout)\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Simplify newlines (borrowed from retarget.cpp)
|
|
||||||
if ((c == CR && _in_prev != LF) ||
|
|
||||||
(c == LF && _in_prev != CR)) {
|
|
||||||
_in_prev = c;
|
|
||||||
c = '\n';
|
|
||||||
} else if ((c == CR && _in_prev == LF) ||
|
|
||||||
(c == LF && _in_prev == CR)) {
|
|
||||||
_in_prev = c;
|
|
||||||
// onto next character
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
_in_prev = c;
|
|
||||||
}
|
|
||||||
_buffer[offset + j++] = c;
|
|
||||||
_buffer[offset + j] = 0;
|
|
||||||
|
|
||||||
// Check for oob data
|
|
||||||
for (struct oob *oob = _oobs; oob; oob = oob->next) {
|
|
||||||
if ((unsigned)j == oob->len && memcmp(
|
|
||||||
oob->prefix, _buffer + offset, oob->len) == 0) {
|
|
||||||
debug_if(_dbg_on, "AT! %s\n", oob->prefix);
|
|
||||||
oob->cb();
|
|
||||||
|
|
||||||
if (_aborted) {
|
|
||||||
debug_if(_dbg_on, "AT(Aborted)\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// oob may have corrupted non-reentrant buffer,
|
|
||||||
// so we need to set it up again
|
|
||||||
goto restart;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check for match
|
|
||||||
int count = -1;
|
|
||||||
if (whole_line_wanted && c != '\n') {
|
|
||||||
// Don't attempt scanning until we get delimiter if they included it in format
|
|
||||||
// This allows recv("Foo: %s\n") to work, and not match with just the first character of a string
|
|
||||||
// (scanf does not itself match whitespace in its format string, so \n is not significant to it)
|
|
||||||
} else {
|
|
||||||
sscanf(_buffer + offset, _buffer, &count);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We only succeed if all characters in the response are matched
|
|
||||||
if (count == j) {
|
|
||||||
debug_if(_dbg_on, "AT= %s\n", _buffer + offset);
|
|
||||||
// Reuse the front end of the buffer
|
|
||||||
memcpy(_buffer, response, i);
|
|
||||||
_buffer[i] = 0;
|
|
||||||
|
|
||||||
// Store the found results
|
|
||||||
vsscanf(_buffer + offset, _buffer, args);
|
|
||||||
|
|
||||||
// Jump to next line and continue parsing
|
|
||||||
response += i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear the buffer when we hit a newline or ran out of space
|
|
||||||
// running out of space usually means we ran into binary data
|
|
||||||
if (c == '\n' || j + 1 >= _buffer_size - offset) {
|
|
||||||
debug_if(_dbg_on, "AT< %s", _buffer + offset);
|
|
||||||
j = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mapping to vararg functions
|
|
||||||
int ATCmdParser::printf(const char *format, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
va_start(args, format);
|
|
||||||
int res = vprintf(format, args);
|
|
||||||
va_end(args);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ATCmdParser::scanf(const char *format, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
va_start(args, format);
|
|
||||||
int res = vscanf(format, args);
|
|
||||||
va_end(args);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ATCmdParser::send(const char *command, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
va_start(args, command);
|
|
||||||
bool res = vsend(command, args);
|
|
||||||
va_end(args);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ATCmdParser::recv(const char *response, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
va_start(args, response);
|
|
||||||
bool res = vrecv(response, args);
|
|
||||||
va_end(args);
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
// oob registration
|
|
||||||
void ATCmdParser::oob(const char *prefix, Callback<void()> cb)
|
|
||||||
{
|
|
||||||
struct oob *oob = new struct oob;
|
|
||||||
oob->len = strlen(prefix);
|
|
||||||
oob->prefix = prefix;
|
|
||||||
oob->cb = cb;
|
|
||||||
oob->next = _oobs;
|
|
||||||
_oobs = oob;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ATCmdParser::abort()
|
|
||||||
{
|
|
||||||
_aborted = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ATCmdParser::process_oob()
|
|
||||||
{
|
|
||||||
if (!_fh->readable()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
while (true) {
|
|
||||||
// Receive next character
|
|
||||||
int c = getc();
|
|
||||||
if (c < 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
_buffer[i++] = c;
|
|
||||||
_buffer[i] = 0;
|
|
||||||
|
|
||||||
// Check for oob data
|
|
||||||
struct oob *oob = _oobs;
|
|
||||||
while (oob) {
|
|
||||||
if (i == (int)oob->len && memcmp(
|
|
||||||
oob->prefix, _buffer, oob->len) == 0) {
|
|
||||||
debug_if(_dbg_on, "AT! %s\r\n", oob->prefix);
|
|
||||||
oob->cb();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
oob = oob->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear the buffer when we hit a newline or ran out of space
|
|
||||||
// running out of space usually means we ran into binary data
|
|
||||||
if (i + 1 >= _buffer_size ||
|
|
||||||
strcmp(&_buffer[i - _output_delim_size], _output_delimiter) == 0) {
|
|
||||||
|
|
||||||
debug_if(_dbg_on, "AT< %s", _buffer);
|
|
||||||
i = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) , Arm Limited and affiliates.
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
#ifndef __AT_CMD_PARSER_H__
|
|
||||||
#define __AT_CMD_PARSER_H__
|
|
||||||
|
|
||||||
#include "mbed.h"
|
|
||||||
#include <cstdarg>
|
|
||||||
#include "FileHandle.h"
|
|
||||||
|
|
||||||
class ATCmdParser {
|
|
||||||
public:
|
|
||||||
ATCmdParser(mbed::FileHandle *fh, const char *output_delimiter = "\r",
|
|
||||||
int buffer_size = 256, int timeout = 8000, bool debug = false) {}
|
|
||||||
|
|
||||||
~ATCmdParser() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif //__AT_CMD_PARSER_H__
|
|
||||||
|
|
|
@ -79,6 +79,24 @@ private:
|
||||||
};
|
};
|
||||||
oob *_oobs;
|
oob *_oobs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Receive an AT response
|
||||||
|
*
|
||||||
|
* Receives a formatted response using scanf style formatting
|
||||||
|
* @see scanf
|
||||||
|
*
|
||||||
|
* Responses are parsed line at a time.
|
||||||
|
* If multiline is set to false parse only one line otherwise parse multiline response
|
||||||
|
* Any received data that does not match the response is ignored until
|
||||||
|
* a timeout occurs.
|
||||||
|
*
|
||||||
|
* @param response scanf-like format string of response to expect
|
||||||
|
* @param ... all scanf-like arguments to extract from response
|
||||||
|
* @param multiline determinate if parse one or multiple lines.
|
||||||
|
* @return number of bytes read or -1 on failure
|
||||||
|
*/
|
||||||
|
int vrecvscanf(const char *response, std::va_list args, bool multiline);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -124,68 +124,6 @@ int ATCmdParser::vprintf(const char *format, std::va_list args)
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ATCmdParser::vscanf(const char *format, std::va_list args)
|
|
||||||
{
|
|
||||||
// Since format is const, we need to copy it into our buffer to
|
|
||||||
// add the line's null terminator and clobber value-matches with asterisks.
|
|
||||||
//
|
|
||||||
// We just use the beginning of the buffer to avoid unnecessary allocations.
|
|
||||||
int i = 0;
|
|
||||||
int offset = 0;
|
|
||||||
|
|
||||||
while (format[i]) {
|
|
||||||
if (format[i] == '%' && format[i + 1] != '%' && format[i + 1] != '*') {
|
|
||||||
_buffer[offset++] = '%';
|
|
||||||
_buffer[offset++] = '*';
|
|
||||||
i++;
|
|
||||||
} else {
|
|
||||||
_buffer[offset++] = format[i++];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scanf has very poor support for catching errors
|
|
||||||
// fortunately, we can abuse the %n specifier to determine
|
|
||||||
// if the entire string was matched.
|
|
||||||
_buffer[offset++] = '%';
|
|
||||||
_buffer[offset++] = 'n';
|
|
||||||
_buffer[offset++] = 0;
|
|
||||||
|
|
||||||
// To workaround scanf's lack of error reporting, we actually
|
|
||||||
// make two passes. One checks the validity with the modified
|
|
||||||
// format string that only stores the matched characters (%n).
|
|
||||||
// The other reads in the actual matched values.
|
|
||||||
//
|
|
||||||
// We keep trying the match until we succeed or some other error
|
|
||||||
// derails us.
|
|
||||||
int j = 0;
|
|
||||||
|
|
||||||
while (true) {
|
|
||||||
// Ran out of space
|
|
||||||
if (j + 1 >= _buffer_size - offset) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Receive next character
|
|
||||||
int c = getc();
|
|
||||||
if (c < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
_buffer[offset + j++] = c;
|
|
||||||
_buffer[offset + j] = 0;
|
|
||||||
|
|
||||||
// Check for match
|
|
||||||
int count = -1;
|
|
||||||
sscanf(_buffer + offset, _buffer, &count);
|
|
||||||
|
|
||||||
// We only succeed if all characters in the response are matched
|
|
||||||
if (count == j) {
|
|
||||||
// Store the found results
|
|
||||||
vsscanf(_buffer + offset, format, args);
|
|
||||||
return j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Command parsing with line handling
|
// Command parsing with line handling
|
||||||
bool ATCmdParser::vsend(const char *command, std::va_list args)
|
bool ATCmdParser::vsend(const char *command, std::va_list args)
|
||||||
{
|
{
|
||||||
|
@ -211,7 +149,7 @@ bool ATCmdParser::vsend(const char *command, std::va_list args)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ATCmdParser::vrecv(const char *response, std::va_list args)
|
int ATCmdParser::vrecvscanf(const char *response, std::va_list args, bool multiline)
|
||||||
{
|
{
|
||||||
restart:
|
restart:
|
||||||
_aborted = false;
|
_aborted = false;
|
||||||
|
@ -228,10 +166,16 @@ restart:
|
||||||
|
|
||||||
while (response && response[i]) {
|
while (response && response[i]) {
|
||||||
if (response[i] == '%' && response[i + 1] != '%' && response[i + 1] != '*') {
|
if (response[i] == '%' && response[i + 1] != '%' && response[i + 1] != '*') {
|
||||||
|
if ((offset + 2) > _buffer_size) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
_buffer[offset++] = '%';
|
_buffer[offset++] = '%';
|
||||||
_buffer[offset++] = '*';
|
_buffer[offset++] = '*';
|
||||||
i++;
|
i++;
|
||||||
} else {
|
} else {
|
||||||
|
if ((offset + 1) > _buffer_size) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
_buffer[offset++] = response[i++];
|
_buffer[offset++] = response[i++];
|
||||||
// Find linebreaks, taking care not to be fooled if they're in a %[^\n] conversion specification
|
// Find linebreaks, taking care not to be fooled if they're in a %[^\n] conversion specification
|
||||||
if (response[i - 1] == '\n' && !(i >= 3 && response[i - 3] == '[' && response[i - 2] == '^')) {
|
if (response[i - 1] == '\n' && !(i >= 3 && response[i - 3] == '[' && response[i - 2] == '^')) {
|
||||||
|
@ -244,6 +188,9 @@ restart:
|
||||||
// Scanf has very poor support for catching errors
|
// Scanf has very poor support for catching errors
|
||||||
// fortunately, we can abuse the %n specifier to determine
|
// fortunately, we can abuse the %n specifier to determine
|
||||||
// if the entire string was matched.
|
// if the entire string was matched.
|
||||||
|
if ((offset + 3) > _buffer_size) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
_buffer[offset++] = '%';
|
_buffer[offset++] = '%';
|
||||||
_buffer[offset++] = 'n';
|
_buffer[offset++] = 'n';
|
||||||
_buffer[offset++] = 0;
|
_buffer[offset++] = 0;
|
||||||
|
@ -259,17 +206,24 @@ restart:
|
||||||
int j = 0;
|
int j = 0;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
// Ran out of space
|
||||||
|
if (j + 1 >= _buffer_size - offset) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
// If just peeking for OOBs, and at start of line, check
|
// If just peeking for OOBs, and at start of line, check
|
||||||
// readability
|
// readability
|
||||||
if (!response && j == 0 && !_fh->readable()) {
|
if (!response && j == 0 && !_fh->readable()) {
|
||||||
return false;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Receive next character
|
// Receive next character
|
||||||
int c = getc();
|
int c = getc();
|
||||||
if (c < 0) {
|
if (c < 0) {
|
||||||
debug_if(_dbg_on, "AT(Timeout)\n");
|
debug_if(_dbg_on, "AT(Timeout)\n");
|
||||||
return false;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simplify newlines (borrowed from retarget.cpp)
|
// Simplify newlines (borrowed from retarget.cpp)
|
||||||
if ((c == CR && _in_prev != LF) ||
|
if ((c == CR && _in_prev != LF) ||
|
||||||
(c == LF && _in_prev != CR)) {
|
(c == LF && _in_prev != CR)) {
|
||||||
|
@ -283,24 +237,30 @@ restart:
|
||||||
} else {
|
} else {
|
||||||
_in_prev = c;
|
_in_prev = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((offset + j + 1) > _buffer_size) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
_buffer[offset + j++] = c;
|
_buffer[offset + j++] = c;
|
||||||
_buffer[offset + j] = 0;
|
_buffer[offset + j] = 0;
|
||||||
|
|
||||||
// Check for oob data
|
// Check for oob data
|
||||||
for (struct oob *oob = _oobs; oob; oob = oob->next) {
|
if (multiline) {
|
||||||
if ((unsigned)j == oob->len && memcmp(
|
for (struct oob *oob = _oobs; oob; oob = oob->next) {
|
||||||
oob->prefix, _buffer + offset, oob->len) == 0) {
|
if ((unsigned)j == oob->len && memcmp(
|
||||||
debug_if(_dbg_on, "AT! %s\n", oob->prefix);
|
oob->prefix, _buffer + offset, oob->len) == 0) {
|
||||||
_oob_cb_count++;
|
debug_if(_dbg_on, "AT! %s\n", oob->prefix);
|
||||||
oob->cb();
|
_oob_cb_count++;
|
||||||
|
oob->cb();
|
||||||
|
|
||||||
if (_aborted) {
|
if (_aborted) {
|
||||||
debug_if(_dbg_on, "AT(Aborted)\n");
|
debug_if(_dbg_on, "AT(Aborted)\n");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
// oob may have corrupted non-reentrant buffer,
|
||||||
|
// so we need to set it up again
|
||||||
|
goto restart;
|
||||||
}
|
}
|
||||||
// oob may have corrupted non-reentrant buffer,
|
|
||||||
// so we need to set it up again
|
|
||||||
goto restart;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,6 +283,10 @@ restart:
|
||||||
// Store the found results
|
// Store the found results
|
||||||
vsscanf(_buffer + offset, _buffer, args);
|
vsscanf(_buffer + offset, _buffer, args);
|
||||||
|
|
||||||
|
if (!multiline) {
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
// Jump to next line and continue parsing
|
// Jump to next line and continue parsing
|
||||||
response += i;
|
response += i;
|
||||||
break;
|
break;
|
||||||
|
@ -337,7 +301,17 @@ restart:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ATCmdParser::vscanf(const char *format, std::va_list args)
|
||||||
|
{
|
||||||
|
return vrecvscanf(format, args, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ATCmdParser::vrecv(const char *response, std::va_list args)
|
||||||
|
{
|
||||||
|
return (vrecvscanf(response, args, true)) > 0 ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mapping to vararg functions
|
// Mapping to vararg functions
|
||||||
|
@ -354,7 +328,7 @@ int ATCmdParser::scanf(const char *format, ...)
|
||||||
{
|
{
|
||||||
std::va_list args;
|
std::va_list args;
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
int res = vscanf(format, args);
|
int res = vrecvscanf(format, args, false);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -372,9 +346,9 @@ bool ATCmdParser::recv(const char *response, ...)
|
||||||
{
|
{
|
||||||
std::va_list args;
|
std::va_list args;
|
||||||
va_start(args, response);
|
va_start(args, response);
|
||||||
bool res = vrecv(response, args);
|
int res = vrecvscanf(response, args, true);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
return res;
|
return (res > 0) ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// oob registration
|
// oob registration
|
||||||
|
|
Loading…
Reference in New Issue