mirror of https://github.com/ARMmbed/mbed-os.git
Merge branch 'master' of https://github.com/mbedmicro/mbed
commit
b42dacb13d
|
@ -49,7 +49,7 @@
|
||||||
#define USBHOST_MOUSE 1
|
#define USBHOST_MOUSE 1
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enable USBHostSerial
|
* Enable USBHostSerial or USBHostMultiSerial (if set > 1)
|
||||||
*/
|
*/
|
||||||
#define USBHOST_SERIAL 1
|
#define USBHOST_SERIAL 1
|
||||||
|
|
||||||
|
|
|
@ -18,17 +18,35 @@
|
||||||
#define USB_DEBUG_H
|
#define USB_DEBUG_H
|
||||||
|
|
||||||
//Debug is disabled by default
|
//Debug is disabled by default
|
||||||
#define DEBUG 0
|
#define DEBUG 3 /*INFO,ERR,WARN*/
|
||||||
#define DEBUG_TRANSFER 0
|
#define DEBUG_TRANSFER 0
|
||||||
#define DEBUG_EP_STATE 0
|
#define DEBUG_EP_STATE 0
|
||||||
#define DEBUG_EVENT 0
|
#define DEBUG_EVENT 0
|
||||||
|
|
||||||
#if (DEBUG)
|
#if (DEBUG > 3)
|
||||||
#define USB_DBG(x, ...) std::printf("[USB_DBG: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
|
#define USB_DBG(x, ...) std::printf("[USB_DBG: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
|
||||||
#else
|
#else
|
||||||
#define USB_DBG(x, ...)
|
#define USB_DBG(x, ...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if (DEBUG > 2)
|
||||||
|
#define USB_INFO(x, ...) std::printf("[USB_INFO: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
|
||||||
|
#else
|
||||||
|
#define USB_INFO(x, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (DEBUG > 1)
|
||||||
|
#define USB_WARN(x, ...) std::printf("[USB_WARNING: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
|
||||||
|
#else
|
||||||
|
#define USB_WARN(x, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (DEBUG > 0)
|
||||||
|
#define USB_ERR(x, ...) std::printf("[USB_ERR: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
|
||||||
|
#else
|
||||||
|
#define USB_ERR(x, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
#if (DEBUG_TRANSFER)
|
#if (DEBUG_TRANSFER)
|
||||||
#define USB_DBG_TRANSFER(x, ...) std::printf("[USB_TRANSFER: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
|
#define USB_DBG_TRANSFER(x, ...) std::printf("[USB_TRANSFER: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
|
||||||
#else
|
#else
|
||||||
|
@ -41,9 +59,6 @@
|
||||||
#define USB_DBG_EVENT(x, ...)
|
#define USB_DBG_EVENT(x, ...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define USB_INFO(x, ...) std::printf("[USB_INFO: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
|
|
||||||
#define USB_WARN(x, ...) std::printf("[USB_WARNING: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
|
|
||||||
#define USB_ERR(x, ...) std::printf("[USB_ERR: %s:%d]" x "\r\n", __FILE__, __LINE__, ##__VA_ARGS__);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -20,27 +20,17 @@
|
||||||
|
|
||||||
#include "dbg.h"
|
#include "dbg.h"
|
||||||
|
|
||||||
#define SET_LINE_CODING 0x20
|
#define CHECK_INTERFACE(cls,subcls,proto) \
|
||||||
|
(((cls == 0xFF) && (subcls == 0xFF) && (proto == 0xFF)) /* QUALCOM CDC */ || \
|
||||||
|
((cls == SERIAL_CLASS) && (subcls == 0x00) && (proto == 0x00)) /* STANDARD CDC */ )
|
||||||
|
|
||||||
USBHostSerial::USBHostSerial(): circ_buf() {
|
#if (USBHOST_SERIAL <= 1)
|
||||||
|
|
||||||
|
USBHostSerial::USBHostSerial()
|
||||||
|
{
|
||||||
host = USBHost::getHostInst();
|
host = USBHost::getHostInst();
|
||||||
size_bulk_in = 0;
|
ports_found = 0;
|
||||||
size_bulk_out = 0;
|
|
||||||
init();
|
|
||||||
}
|
|
||||||
|
|
||||||
void USBHostSerial::init() {
|
|
||||||
dev = NULL;
|
|
||||||
bulk_in = NULL;
|
|
||||||
bulk_out = NULL;
|
|
||||||
dev_connected = false;
|
dev_connected = false;
|
||||||
serial_intf = -1;
|
|
||||||
serial_device_found = false;
|
|
||||||
line_coding.baudrate = 9600;
|
|
||||||
line_coding.data_bits = 8;
|
|
||||||
line_coding.parity = None;
|
|
||||||
line_coding.stop_bits = 1;
|
|
||||||
circ_buf.flush();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool USBHostSerial::connected()
|
bool USBHostSerial::connected()
|
||||||
|
@ -48,49 +38,219 @@ bool USBHostSerial::connected()
|
||||||
return dev_connected;
|
return dev_connected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void USBHostSerial::disconnect(void)
|
||||||
|
{
|
||||||
|
ports_found = 0;
|
||||||
|
dev = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
bool USBHostSerial::connect() {
|
bool USBHostSerial::connect() {
|
||||||
|
|
||||||
if (dev_connected) {
|
if (dev)
|
||||||
|
{
|
||||||
|
for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++)
|
||||||
|
{
|
||||||
|
USBDeviceConnected* d = host->getDevice(i);
|
||||||
|
if (dev == d)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++) {
|
disconnect();
|
||||||
if ((dev = host->getDevice(i)) != NULL) {
|
}
|
||||||
|
for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++)
|
||||||
|
{
|
||||||
|
USBDeviceConnected* d = host->getDevice(i);
|
||||||
|
if (d != NULL) {
|
||||||
|
|
||||||
USB_DBG("Trying to connect serial device \r\n");
|
USB_DBG("Trying to connect serial device \r\n");
|
||||||
|
if(host->enumerate(d, this))
|
||||||
if(host->enumerate(dev, this))
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (serial_device_found) {
|
USBEndpoint* bulk_in = d->getEndpoint(port_intf, BULK_ENDPOINT, IN);
|
||||||
bulk_in = dev->getEndpoint(serial_intf, BULK_ENDPOINT, IN);
|
USBEndpoint* bulk_out = d->getEndpoint(port_intf, BULK_ENDPOINT, OUT);
|
||||||
bulk_out = dev->getEndpoint(serial_intf, BULK_ENDPOINT, OUT);
|
if (bulk_in && bulk_out)
|
||||||
|
{
|
||||||
|
USBHostSerialPort::connect(host,d,port_intf,bulk_in, bulk_out);
|
||||||
|
dev = d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dev != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (!bulk_in || !bulk_out)
|
/*virtual*/ void USBHostSerial::setVidPid(uint16_t vid, uint16_t pid)
|
||||||
break;
|
{
|
||||||
|
// we don't check VID/PID for MSD driver
|
||||||
|
}
|
||||||
|
|
||||||
USB_INFO("New Serial device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, serial_intf);
|
/*virtual*/ bool USBHostSerial::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
|
||||||
dev->setName("Serial", serial_intf);
|
{
|
||||||
host->registerDriver(dev, serial_intf, this, &USBHostSerial::init);
|
if ((ports_found < USBHOST_MAXSERIAL) &&
|
||||||
|
CHECK_INTERFACE(intf_class, intf_subclass, intf_protocol)) {
|
||||||
baud(9600);
|
port_intf = intf_nb;
|
||||||
|
ports_found = true;
|
||||||
size_bulk_in = bulk_in->getSize();
|
|
||||||
size_bulk_out = bulk_out->getSize();
|
|
||||||
|
|
||||||
bulk_in->attach(this, &USBHostSerial::rxHandler);
|
|
||||||
bulk_out->attach(this, &USBHostSerial::txHandler);
|
|
||||||
|
|
||||||
host->bulkRead(dev, bulk_in, buf, size_bulk_in, false);
|
|
||||||
dev_connected = true;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
init();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBHostSerial::rxHandler() {
|
/*virtual*/ bool USBHostSerial::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
|
||||||
|
{
|
||||||
|
if (ports_found && (intf_nb == port_intf)) {
|
||||||
|
if (type == BULK_ENDPOINT)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // (USBHOST_SERIAL > 1)
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
USBHostMultiSerial::USBHostMultiSerial()
|
||||||
|
{
|
||||||
|
host = USBHost::getHostInst();
|
||||||
|
dev = NULL;
|
||||||
|
memset(ports, NULL, sizeof(ports));
|
||||||
|
ports_found = 0;
|
||||||
|
dev_connected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
USBHostMultiSerial::~USBHostMultiSerial()
|
||||||
|
{
|
||||||
|
disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool USBHostMultiSerial::connected()
|
||||||
|
{
|
||||||
|
return dev_connected;
|
||||||
|
}
|
||||||
|
|
||||||
|
void USBHostMultiSerial::disconnect(void)
|
||||||
|
{
|
||||||
|
for (int port = 0; port < USBHOST_SERIAL; port ++)
|
||||||
|
{
|
||||||
|
if (ports[port])
|
||||||
|
{
|
||||||
|
delete ports[port];
|
||||||
|
ports[port] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ports_found = 0;
|
||||||
|
dev = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool USBHostMultiSerial::connect() {
|
||||||
|
|
||||||
|
if (dev)
|
||||||
|
{
|
||||||
|
for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++)
|
||||||
|
{
|
||||||
|
USBDeviceConnected* d = host->getDevice(i);
|
||||||
|
if (dev == d)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
disconnect();
|
||||||
|
}
|
||||||
|
for (uint8_t i = 0; i < MAX_DEVICE_CONNECTED; i++)
|
||||||
|
{
|
||||||
|
USBDeviceConnected* d = host->getDevice(i);
|
||||||
|
if (d != NULL) {
|
||||||
|
|
||||||
|
USB_DBG("Trying to connect serial device \r\n");
|
||||||
|
if(host->enumerate(d, this))
|
||||||
|
break;
|
||||||
|
|
||||||
|
for (int port = 0; port < ports_found; port ++)
|
||||||
|
{
|
||||||
|
USBEndpoint* bulk_in = d->getEndpoint(port_intf[port], BULK_ENDPOINT, IN);
|
||||||
|
USBEndpoint* bulk_out = d->getEndpoint(port_intf[port], BULK_ENDPOINT, OUT);
|
||||||
|
if (bulk_in && bulk_out)
|
||||||
|
{
|
||||||
|
ports[port] = new USBHostSerialPort();
|
||||||
|
if (ports[port])
|
||||||
|
{
|
||||||
|
ports[port]->connect(host,d,port_intf[port],bulk_in, bulk_out);
|
||||||
|
dev = d;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return dev != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*virtual*/ void USBHostMultiSerial::setVidPid(uint16_t vid, uint16_t pid)
|
||||||
|
{
|
||||||
|
// we don't check VID/PID for MSD driver
|
||||||
|
}
|
||||||
|
|
||||||
|
/*virtual*/ bool USBHostMultiSerial::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
|
||||||
|
{
|
||||||
|
if ((ports_found < USBHOST_SERIAL) &&
|
||||||
|
CHECK_INTERFACE(intf_class, intf_subclass, intf_protocol)) {
|
||||||
|
port_intf[ports_found++] = intf_nb;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*virtual*/ bool USBHostMultiSerial::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
|
||||||
|
{
|
||||||
|
if ((ports_found > 0) && (intf_nb == port_intf[ports_found-1])) {
|
||||||
|
if (type == BULK_ENDPOINT)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#define SET_LINE_CODING 0x20
|
||||||
|
|
||||||
|
USBHostSerialPort::USBHostSerialPort(): circ_buf()
|
||||||
|
{
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void USBHostSerialPort::init(void)
|
||||||
|
{
|
||||||
|
host = NULL;
|
||||||
|
dev = NULL;
|
||||||
|
serial_intf = NULL;
|
||||||
|
size_bulk_in = 0;
|
||||||
|
size_bulk_out = 0;
|
||||||
|
bulk_in = NULL;
|
||||||
|
bulk_out = NULL;
|
||||||
|
line_coding.baudrate = 9600;
|
||||||
|
line_coding.data_bits = 8;
|
||||||
|
line_coding.parity = None;
|
||||||
|
line_coding.stop_bits = 1;
|
||||||
|
circ_buf.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
void USBHostSerialPort::connect(USBHost* _host, USBDeviceConnected * _dev,
|
||||||
|
uint8_t _serial_intf, USBEndpoint* _bulk_in, USBEndpoint* _bulk_out)
|
||||||
|
{
|
||||||
|
host = _host;
|
||||||
|
dev = _dev;
|
||||||
|
serial_intf = _serial_intf;
|
||||||
|
bulk_in = _bulk_in;
|
||||||
|
bulk_out = _bulk_out;
|
||||||
|
|
||||||
|
USB_INFO("New Serial device: VID:%04x PID:%04x [dev: %p - intf: %d]", dev->getVid(), dev->getPid(), dev, serial_intf);
|
||||||
|
dev->setName("Serial", serial_intf);
|
||||||
|
host->registerDriver(dev, serial_intf, this, &USBHostSerialPort::init);
|
||||||
|
//baud(9600);
|
||||||
|
size_bulk_in = bulk_in->getSize();
|
||||||
|
size_bulk_out = bulk_out->getSize();
|
||||||
|
bulk_in->attach(this, &USBHostSerialPort::rxHandler);
|
||||||
|
bulk_out->attach(this, &USBHostSerialPort::txHandler);
|
||||||
|
host->bulkRead(dev, bulk_in, buf, size_bulk_in, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void USBHostSerialPort::rxHandler() {
|
||||||
if (bulk_in) {
|
if (bulk_in) {
|
||||||
int len = bulk_in->getLengthTransferred();
|
int len = bulk_in->getLengthTransferred();
|
||||||
if (bulk_in->getState() == USB_TYPE_IDLE) {
|
if (bulk_in->getState() == USB_TYPE_IDLE) {
|
||||||
|
@ -103,7 +263,7 @@ void USBHostSerial::rxHandler() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBHostSerial::txHandler() {
|
void USBHostSerialPort::txHandler() {
|
||||||
if (bulk_out) {
|
if (bulk_out) {
|
||||||
if (bulk_out->getState() == USB_TYPE_IDLE) {
|
if (bulk_out->getState() == USB_TYPE_IDLE) {
|
||||||
tx.call();
|
tx.call();
|
||||||
|
@ -111,7 +271,7 @@ void USBHostSerial::txHandler() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int USBHostSerial::_putc(int c) {
|
int USBHostSerialPort::_putc(int c) {
|
||||||
if (bulk_out) {
|
if (bulk_out) {
|
||||||
if (host->bulkWrite(dev, bulk_out, (uint8_t *)&c, 1) == USB_TYPE_OK) {
|
if (host->bulkWrite(dev, bulk_out, (uint8_t *)&c, 1) == USB_TYPE_OK) {
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -120,12 +280,12 @@ int USBHostSerial::_putc(int c) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBHostSerial::baud(int baudrate) {
|
void USBHostSerialPort::baud(int baudrate) {
|
||||||
line_coding.baudrate = baudrate;
|
line_coding.baudrate = baudrate;
|
||||||
format(line_coding.data_bits, (Parity)line_coding.parity, line_coding.stop_bits);
|
format(line_coding.data_bits, (Parity)line_coding.parity, line_coding.stop_bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
void USBHostSerial::format(int bits, Parity parity, int stop_bits) {
|
void USBHostSerialPort::format(int bits, Parity parity, int stop_bits) {
|
||||||
line_coding.data_bits = bits;
|
line_coding.data_bits = bits;
|
||||||
line_coding.parity = parity;
|
line_coding.parity = parity;
|
||||||
line_coding.stop_bits = (stop_bits == 1) ? 0 : 2;
|
line_coding.stop_bits = (stop_bits == 1) ? 0 : 2;
|
||||||
|
@ -137,7 +297,7 @@ void USBHostSerial::format(int bits, Parity parity, int stop_bits) {
|
||||||
0, serial_intf, (uint8_t *)&line_coding, 7);
|
0, serial_intf, (uint8_t *)&line_coding, 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
int USBHostSerial::_getc() {
|
int USBHostSerialPort::_getc() {
|
||||||
uint8_t c = 0;
|
uint8_t c = 0;
|
||||||
if (bulk_in == NULL) {
|
if (bulk_in == NULL) {
|
||||||
init();
|
init();
|
||||||
|
@ -148,37 +308,36 @@ int USBHostSerial::_getc() {
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int USBHostSerialPort::writeBuf(const char* b, int s)
|
||||||
|
{
|
||||||
|
int c = 0;
|
||||||
|
if (bulk_out)
|
||||||
|
{
|
||||||
|
while (c < s)
|
||||||
|
{
|
||||||
|
int i = (s < size_bulk_out) ? s : size_bulk_out;
|
||||||
|
if (host->bulkWrite(dev, bulk_out, (uint8_t *)(b+c), i) == USB_TYPE_OK)
|
||||||
|
c += i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t USBHostSerial::available() {
|
int USBHostSerialPort::readBuf(char* b, int s)
|
||||||
|
{
|
||||||
|
int i = 0;
|
||||||
|
if (bulk_in)
|
||||||
|
{
|
||||||
|
for (i = 0; i < s; )
|
||||||
|
b[i++] = getc();
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t USBHostSerialPort::available() {
|
||||||
return circ_buf.available();
|
return circ_buf.available();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*virtual*/ void USBHostSerial::setVidPid(uint16_t vid, uint16_t pid)
|
|
||||||
{
|
|
||||||
// we don't check VID/PID for MSD driver
|
|
||||||
}
|
|
||||||
|
|
||||||
/*virtual*/ bool USBHostSerial::parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) //Must return true if the interface should be parsed
|
|
||||||
{
|
|
||||||
if ((serial_intf == -1) &&
|
|
||||||
(intf_class == SERIAL_CLASS) &&
|
|
||||||
(intf_subclass == 0x00) &&
|
|
||||||
(intf_protocol == 0x00)) {
|
|
||||||
serial_intf = intf_nb;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*virtual*/ bool USBHostSerial::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
|
|
||||||
{
|
|
||||||
if (intf_nb == serial_intf) {
|
|
||||||
if (type == BULK_ENDPOINT) {
|
|
||||||
serial_device_found = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -28,12 +28,12 @@
|
||||||
/**
|
/**
|
||||||
* A class to communicate a USB virtual serial port
|
* A class to communicate a USB virtual serial port
|
||||||
*/
|
*/
|
||||||
class USBHostSerial : public IUSBEnumerator, public Stream {
|
class USBHostSerialPort : public Stream {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
USBHostSerial();
|
USBHostSerialPort();
|
||||||
|
|
||||||
enum IrqType {
|
enum IrqType {
|
||||||
RxIrq,
|
RxIrq,
|
||||||
|
@ -48,19 +48,8 @@ public:
|
||||||
Space
|
Space
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
void connect(USBHost* _host, USBDeviceConnected * _dev,
|
||||||
* Check if a virtual serial port is connected
|
uint8_t _serial_intf, USBEndpoint* _bulk_in, USBEndpoint* _bulk_out);
|
||||||
*
|
|
||||||
* @returns true if a serial device is connected
|
|
||||||
*/
|
|
||||||
bool connected();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Try to connect a serial device
|
|
||||||
*
|
|
||||||
* @return true if connection was successful
|
|
||||||
*/
|
|
||||||
bool connect();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check the number of bytes available.
|
* Check the number of bytes available.
|
||||||
|
@ -111,34 +100,29 @@ public:
|
||||||
/** Set the transmission format used by the Serial port
|
/** Set the transmission format used by the Serial port
|
||||||
*
|
*
|
||||||
* @param bits The number of bits in a word (default = 8)
|
* @param bits The number of bits in a word (default = 8)
|
||||||
* @param parity The parity used (USBHostSerial::None, USBHostSerial::Odd, USBHostSerial::Even, USBHostSerial::Mark, USBHostSerial::Space; default = USBHostSerial::None)
|
* @param parity The parity used (USBHostSerialPort::None, USBHostSerialPort::Odd, USBHostSerialPort::Even, USBHostSerialPort::Mark, USBHostSerialPort::Space; default = USBHostSerialPort::None)
|
||||||
* @param stop The number of stop bits (1 or 2; default = 1)
|
* @param stop The number of stop bits (1 or 2; default = 1)
|
||||||
*/
|
*/
|
||||||
void format(int bits = 8, Parity parity = USBHostSerial::None, int stop_bits = 1);
|
void format(int bits = 8, Parity parity = USBHostSerialPort::None, int stop_bits = 1);
|
||||||
|
virtual int writeBuf(const char* b, int s);
|
||||||
|
virtual int readBuf(char* b, int s);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
//From IUSBEnumerator
|
|
||||||
virtual void setVidPid(uint16_t vid, uint16_t pid);
|
|
||||||
virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
|
|
||||||
virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
|
|
||||||
|
|
||||||
virtual int _getc();
|
virtual int _getc();
|
||||||
virtual int _putc(int c);
|
virtual int _putc(int c);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
USBHost * host;
|
USBHost * host;
|
||||||
USBDeviceConnected * dev;
|
USBDeviceConnected * dev;
|
||||||
|
|
||||||
USBEndpoint * bulk_in;
|
USBEndpoint * bulk_in;
|
||||||
USBEndpoint * bulk_out;
|
USBEndpoint * bulk_out;
|
||||||
uint32_t size_bulk_in;
|
uint32_t size_bulk_in;
|
||||||
uint32_t size_bulk_out;
|
uint32_t size_bulk_out;
|
||||||
|
|
||||||
bool dev_connected;
|
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
MtxCircBuffer<uint8_t, 64> circ_buf;
|
MtxCircBuffer<uint8_t, 128> circ_buf;
|
||||||
|
|
||||||
uint8_t buf[64];
|
uint8_t buf[64];
|
||||||
|
|
||||||
|
@ -156,11 +140,92 @@ private:
|
||||||
FunctionPointer rx;
|
FunctionPointer rx;
|
||||||
FunctionPointer tx;
|
FunctionPointer tx;
|
||||||
|
|
||||||
int serial_intf;
|
uint8_t serial_intf;
|
||||||
bool serial_device_found;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if (USBHOST_SERIAL <= 1)
|
||||||
|
|
||||||
|
class USBHostSerial : public IUSBEnumerator, public USBHostSerialPort
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
USBHostSerial();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to connect a serial device
|
||||||
|
*
|
||||||
|
* @return true if connection was successful
|
||||||
|
*/
|
||||||
|
bool connect();
|
||||||
|
|
||||||
|
void disconnect();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a any serial port is connected
|
||||||
|
*
|
||||||
|
* @returns true if a serial device is connected
|
||||||
|
*/
|
||||||
|
bool connected();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
USBHost* host;
|
||||||
|
USBDeviceConnected* dev;
|
||||||
|
uint8_t port_intf;
|
||||||
|
int ports_found;
|
||||||
|
|
||||||
|
//From IUSBEnumerator
|
||||||
|
virtual void setVidPid(uint16_t vid, uint16_t pid);
|
||||||
|
virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
|
||||||
|
virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool dev_connected;
|
||||||
|
};
|
||||||
|
|
||||||
|
#else // (USBHOST_SERIAL > 1)
|
||||||
|
|
||||||
|
class USBHostMultiSerial : public IUSBEnumerator {
|
||||||
|
public:
|
||||||
|
USBHostMultiSerial();
|
||||||
|
virtual ~USBHostMultiSerial();
|
||||||
|
|
||||||
|
USBHostSerialPort* getPort(int port)
|
||||||
|
{
|
||||||
|
return port < USBHOST_SERIAL ? ports[port] : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Try to connect a serial device
|
||||||
|
*
|
||||||
|
* @return true if connection was successful
|
||||||
|
*/
|
||||||
|
bool connect();
|
||||||
|
|
||||||
|
void disconnect();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a any serial port is connected
|
||||||
|
*
|
||||||
|
* @returns true if a serial device is connected
|
||||||
|
*/
|
||||||
|
bool connected();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
USBHost* host;
|
||||||
|
USBDeviceConnected* dev;
|
||||||
|
USBHostSerialPort* ports[USBHOST_SERIAL];
|
||||||
|
uint8_t port_intf[USBHOST_SERIAL];
|
||||||
|
int ports_found;
|
||||||
|
|
||||||
|
//From IUSBEnumerator
|
||||||
|
virtual void setVidPid(uint16_t vid, uint16_t pid);
|
||||||
|
virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol); //Must return true if the interface should be parsed
|
||||||
|
virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool dev_connected;
|
||||||
|
};
|
||||||
|
#endif // (USBHOST_SERIAL <= 1)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -63,13 +63,15 @@ int ATCommandsInterface::open()
|
||||||
}
|
}
|
||||||
|
|
||||||
//Initialize AT link & start events processing
|
//Initialize AT link & start events processing
|
||||||
int ATCommandsInterface::init()
|
int ATCommandsInterface::init(bool reset /* = true*/)
|
||||||
{
|
{
|
||||||
DBG("Sending ATZ E1 V1");
|
|
||||||
|
|
||||||
//Lock transaction mutex
|
//Lock transaction mutex
|
||||||
m_transactionMtx.lock();
|
m_transactionMtx.lock();
|
||||||
|
|
||||||
|
if (reset)
|
||||||
|
{
|
||||||
|
DBG("Sending ATZ E1 V1");
|
||||||
//Should we flush m_pStream at this point ???
|
//Should we flush m_pStream at this point ???
|
||||||
int err;
|
int err;
|
||||||
int tries = 5;
|
int tries = 5;
|
||||||
|
@ -88,6 +90,7 @@ int ATCommandsInterface::init()
|
||||||
m_transactionMtx.unlock();
|
m_transactionMtx.unlock();
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//Enable events handling and execute events enabling commands
|
//Enable events handling and execute events enabling commands
|
||||||
enableEvents();
|
enableEvents();
|
||||||
|
|
|
@ -77,7 +77,7 @@ public:
|
||||||
int open();
|
int open();
|
||||||
|
|
||||||
//Initialize AT link
|
//Initialize AT link
|
||||||
int init();
|
int init(bool reset = true);
|
||||||
|
|
||||||
//Close connection
|
//Close connection
|
||||||
int close();
|
int close();
|
||||||
|
|
|
@ -50,22 +50,15 @@ extern "C" {
|
||||||
#include "netif/ppp/ppp.h"
|
#include "netif/ppp/ppp.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
PPPIPInterface::PPPIPInterface(IOStream* pStream, const char* msisdn) : LwIPInterface(), m_linkStatusSphre(1), m_pppErrCode(0), m_pStream(pStream), m_streamAvail(true), m_pppd(-1)
|
PPPIPInterface::PPPIPInterface(IOStream* pStream) : LwIPInterface(), m_linkStatusSphre(1), m_pppErrCode(0), m_pStream(pStream), m_streamAvail(true), m_pppd(-1)
|
||||||
{
|
{
|
||||||
m_connectCmd = new char[strlen(CONNECT_CMD_PREFIX) + strlen(msisdn) + strlen(CONNECT_CMD_SUFFIX) + 1];
|
|
||||||
sprintf(m_connectCmd, "%s%s%s", CONNECT_CMD_PREFIX, msisdn, CONNECT_CMD_SUFFIX);
|
|
||||||
m_expectedResp = new char[strlen(m_connectCmd) + strlen(EXPECTED_RESP_SUFFIX) + 1];
|
|
||||||
sprintf(m_expectedResp, "%s%s", m_connectCmd, EXPECTED_RESP_SUFFIX);
|
|
||||||
m_expectedRespDatarate = new char[strlen(m_connectCmd) + strlen(EXPECTED_RESP_DATARATE_SUFFIX) + 1];
|
|
||||||
sprintf(m_expectedRespDatarate, "%s%s", m_connectCmd, EXPECTED_RESP_DATARATE_SUFFIX);
|
|
||||||
m_linkStatusSphre.wait();
|
m_linkStatusSphre.wait();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*virtual*/ PPPIPInterface::~PPPIPInterface()
|
/*virtual*/ PPPIPInterface::~PPPIPInterface()
|
||||||
{
|
{
|
||||||
delete m_connectCmd;
|
|
||||||
delete m_expectedResp;
|
|
||||||
delete m_expectedRespDatarate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*virtual*/ int PPPIPInterface::init() //Init PPP-specific stuff, create the right bindings, etc
|
/*virtual*/ int PPPIPInterface::init() //Init PPP-specific stuff, create the right bindings, etc
|
||||||
|
@ -78,10 +71,11 @@ PPPIPInterface::PPPIPInterface(IOStream* pStream, const char* msisdn) : LwIPInte
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PPPIPInterface::setup(const char* user, const char* pw)
|
int PPPIPInterface::setup(const char* user, const char* pw, const char* msisdn)
|
||||||
{
|
{
|
||||||
DBG("Configuring PPP authentication method");
|
DBG("Configuring PPP authentication method");
|
||||||
pppSetAuth(PPPAUTHTYPE_ANY, user, pw);
|
pppSetAuth(PPPAUTHTYPE_ANY, user, pw);
|
||||||
|
m_msisdn = msisdn;
|
||||||
DBG("Done");
|
DBG("Done");
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
@ -89,22 +83,22 @@ int PPPIPInterface::setup(const char* user, const char* pw)
|
||||||
/*virtual*/ int PPPIPInterface::connect()
|
/*virtual*/ int PPPIPInterface::connect()
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
char cmd[32];
|
||||||
|
int cmdLen;
|
||||||
char buf[32];
|
char buf[32];
|
||||||
size_t len;
|
size_t len;
|
||||||
DBG("Trying to connect with PPP");
|
DBG("Trying to connect with PPP");
|
||||||
|
|
||||||
cleanupLink();
|
cleanupLink();
|
||||||
|
|
||||||
DBG("Sending %s", m_connectCmd);
|
cmdLen = sprintf(cmd, "%s%s%s", CONNECT_CMD_PREFIX, m_msisdn, CONNECT_CMD_SUFFIX);
|
||||||
|
DBG("Sending %s", cmd);
|
||||||
ret = m_pStream->write((uint8_t*)m_connectCmd, strlen(m_connectCmd), osWaitForever);
|
ret = m_pStream->write((uint8_t*)cmd, cmdLen, osWaitForever);
|
||||||
if( ret != OK )
|
if( ret != OK )
|
||||||
{
|
{
|
||||||
return NET_UNKNOWN;
|
return NET_UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
DBG("Expect %s", m_expectedResp);
|
|
||||||
|
|
||||||
len = 0;
|
len = 0;
|
||||||
size_t readLen;
|
size_t readLen;
|
||||||
ret = m_pStream->read((uint8_t*)buf + len, &readLen, EXPECTED_RESP_MIN_LEN, 10000);
|
ret = m_pStream->read((uint8_t*)buf + len, &readLen, EXPECTED_RESP_MIN_LEN, 10000);
|
||||||
|
@ -128,7 +122,11 @@ int PPPIPInterface::setup(const char* user, const char* pw)
|
||||||
DBG("Got %s[len %d]", buf, len);
|
DBG("Got %s[len %d]", buf, len);
|
||||||
|
|
||||||
int datarate = 0;
|
int datarate = 0;
|
||||||
if( (sscanf(buf, m_expectedRespDatarate, &datarate ) != 1) && (strcmp(m_expectedResp, buf) != 0) )
|
strcpy(&cmd[cmdLen], EXPECTED_RESP_DATARATE_SUFFIX);
|
||||||
|
if( (sscanf(buf, cmd, &datarate ) != 1))
|
||||||
|
{
|
||||||
|
strcpy(&cmd[cmdLen], EXPECTED_RESP_SUFFIX);
|
||||||
|
if (strcmp(cmd, buf) != 0)
|
||||||
{
|
{
|
||||||
//Discard buffer
|
//Discard buffer
|
||||||
do //Clear buf
|
do //Clear buf
|
||||||
|
@ -137,6 +135,7 @@ int PPPIPInterface::setup(const char* user, const char* pw)
|
||||||
} while( (ret == OK) && (len > 0) );
|
} while( (ret == OK) && (len > 0) );
|
||||||
return NET_CONN;
|
return NET_CONN;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DBG("Transport link open");
|
DBG("Transport link open");
|
||||||
if(datarate != 0)
|
if(datarate != 0)
|
||||||
|
|
|
@ -40,11 +40,11 @@ using namespace rtos;
|
||||||
class PPPIPInterface : public LwIPInterface
|
class PPPIPInterface : public LwIPInterface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PPPIPInterface(IOStream* pStream, const char* msisdn);
|
PPPIPInterface(IOStream* pStream);
|
||||||
virtual ~PPPIPInterface();
|
virtual ~PPPIPInterface();
|
||||||
|
|
||||||
int init(); //Init PPP-specific stuff, create the right bindings, etc
|
int init(); //Init PPP-specific stuff, create the right bindings, etc
|
||||||
int setup(const char* user, const char* pw); //Setup authentication
|
int setup(const char* user, const char* pw, const char* msisdn); //Setup authentication
|
||||||
virtual int connect();
|
virtual int connect();
|
||||||
virtual int disconnect();
|
virtual int disconnect();
|
||||||
|
|
||||||
|
@ -57,16 +57,13 @@ private:
|
||||||
|
|
||||||
IOStream* m_pStream; //Serial stream
|
IOStream* m_pStream; //Serial stream
|
||||||
bool m_streamAvail;
|
bool m_streamAvail;
|
||||||
|
const char* m_msisdn;
|
||||||
|
|
||||||
int m_pppd;
|
int m_pppd;
|
||||||
|
|
||||||
friend u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len);
|
friend u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len);
|
||||||
friend u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len);
|
friend u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len);
|
||||||
friend void sio_read_abort(sio_fd_t fd);
|
friend void sio_read_abort(sio_fd_t fd);
|
||||||
|
|
||||||
char* m_connectCmd;
|
|
||||||
char* m_expectedResp;
|
|
||||||
char* m_expectedRespDatarate;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* PPPIPINTERFACE_H_ */
|
#endif /* PPPIPINTERFACE_H_ */
|
||||||
|
|
|
@ -0,0 +1,253 @@
|
||||||
|
/* IOSerialStream.cpp */
|
||||||
|
/* Copyright (C) 2012 mbed.org, MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||||
|
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||||
|
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||||
|
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or
|
||||||
|
* substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||||
|
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||||
|
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define __DEBUG__ 0 //Maximum verbosity
|
||||||
|
#ifndef __MODULE__
|
||||||
|
#define __MODULE__ "IOSerialStream.cpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "core/fwk.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "IOSerialStream.h"
|
||||||
|
|
||||||
|
#define UART_X ((LPC_UART_TypeDef *)(UART_1))
|
||||||
|
|
||||||
|
IOSerialStream::IOSerialStream(mbed::RawSerial& serial) : m_serial(serial), m_serialTxFifoEmpty(true),
|
||||||
|
m_availableSphre(1), m_spaceSphre(1), m_inBuf(), m_outBuf()
|
||||||
|
{
|
||||||
|
m_availableSphre.wait();
|
||||||
|
m_spaceSphre.wait();
|
||||||
|
//Attach interrupts
|
||||||
|
m_serial.attach(this, &IOSerialStream::readable, mbed::SerialBase::RxIrq);
|
||||||
|
m_serial.attach(this, &IOSerialStream::writeable, mbed::SerialBase::TxIrq);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*virtual*/ IOSerialStream::~IOSerialStream()
|
||||||
|
{
|
||||||
|
m_serial.attach(NULL, mbed::SerialBase::RxIrq);
|
||||||
|
m_serial.attach(NULL, mbed::SerialBase::TxIrq);
|
||||||
|
}
|
||||||
|
|
||||||
|
//0 for non-blocking (returns immediately), osWaitForever for infinite blocking
|
||||||
|
/*virtual*/ int IOSerialStream::read(uint8_t* buf, size_t* pLength, size_t maxLength, uint32_t timeout/*=osWaitForever*/)
|
||||||
|
{
|
||||||
|
DBG("Trying to read at most %d chars", maxLength);
|
||||||
|
int ret = waitAvailable(timeout);
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
WARN("Error %d while waiting for incoming data", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
int readLen = MIN( available(), maxLength );
|
||||||
|
*pLength = readLen;
|
||||||
|
setupReadableISR(false);
|
||||||
|
while(readLen--)
|
||||||
|
{
|
||||||
|
m_inBuf.dequeue(buf);
|
||||||
|
buf++;
|
||||||
|
}
|
||||||
|
setupReadableISR(true);
|
||||||
|
DBG("Read %d chars successfully", *pLength);
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*virtual*/ size_t IOSerialStream::available()
|
||||||
|
{
|
||||||
|
setupReadableISR(false); //m_inBuf.available() is not reentrant
|
||||||
|
size_t len = m_inBuf.available();
|
||||||
|
setupReadableISR(true);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*virtual*/ int IOSerialStream::waitAvailable(uint32_t timeout/*=osWaitForever*/) //Wait for data to be available
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
if(available()) //Is data already available?
|
||||||
|
{
|
||||||
|
m_availableSphre.wait(0); //Clear the queue as data is available
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBG("Waiting for data availability %d ms (-1 is infinite)", timeout);
|
||||||
|
ret = m_availableSphre.wait(timeout); //Wait for data to arrive or for abort
|
||||||
|
if(ret <= 0)
|
||||||
|
{
|
||||||
|
DBG("Timeout");
|
||||||
|
return NET_TIMEOUT;
|
||||||
|
}
|
||||||
|
if(!available()) //Even if abort has been called, return that data is available
|
||||||
|
{
|
||||||
|
DBG("Aborted");
|
||||||
|
return NET_INTERRUPTED;
|
||||||
|
}
|
||||||
|
DBG("Finished waiting");
|
||||||
|
m_availableSphre.wait(0); //Clear the queue as data is available
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*virtual*/ int IOSerialStream::abortRead() //Abort current reading (or waiting) operation
|
||||||
|
{
|
||||||
|
if( !available() ) //If there is data pending, no need to abort
|
||||||
|
{
|
||||||
|
m_availableSphre.release(); //Force exiting the waiting state; kludge to pass a RC directly
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBG("Serial is readable"); ;
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IOSerialStream::setupReadableISR(bool en)
|
||||||
|
{
|
||||||
|
if(en)
|
||||||
|
{
|
||||||
|
UART_X->IER |= 1 << 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UART_X->IER &= ~(1 << 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IOSerialStream::readable() //Callback from m_serial when new data is available
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
m_inBuf.queue(m_serial.getc());
|
||||||
|
} while(m_serial.readable());
|
||||||
|
m_availableSphre.release(); //Force exiting the waiting state
|
||||||
|
}
|
||||||
|
|
||||||
|
//0 for non-blocking (returns immediately), osWaitForever for infinite blocking
|
||||||
|
/*virtual*/ int IOSerialStream::write(uint8_t* buf, size_t length, uint32_t timeout/*=osWaitForever*/)
|
||||||
|
{
|
||||||
|
DBG("Trying to write %d chars", length);
|
||||||
|
int ret = waitSpace(timeout);
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
WARN("Error %d while waiting for space", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
DBG("Writing %d chars", length);
|
||||||
|
setupWriteableISR(false);
|
||||||
|
while(length)
|
||||||
|
{
|
||||||
|
m_outBuf.queue(*buf);
|
||||||
|
buf++;
|
||||||
|
length--;
|
||||||
|
if(length && !space())
|
||||||
|
{
|
||||||
|
DBG("Waiting to write remaining %d chars", length);
|
||||||
|
setupWriteableISR(true);
|
||||||
|
ret = waitSpace(timeout);
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
WARN("Error %d while waiting for space", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
setupWriteableISR(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//If m_serial tx fifo is empty we need to manually tx a byte in order to trigger the interrupt
|
||||||
|
if( m_outBuf.available() && m_serialTxFifoEmpty )
|
||||||
|
{
|
||||||
|
m_serialTxFifoEmpty = false;
|
||||||
|
uint8_t c;
|
||||||
|
m_outBuf.dequeue(&c);
|
||||||
|
m_serial.putc((char)c);
|
||||||
|
}
|
||||||
|
setupWriteableISR(true);
|
||||||
|
DBG("Write successful");
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*virtual*/ size_t IOSerialStream::space()
|
||||||
|
{
|
||||||
|
setupWriteableISR(false); //m_outBuf.available() is not reentrant
|
||||||
|
size_t len = CIRCBUF_SIZE - m_outBuf.available();
|
||||||
|
setupWriteableISR(true);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*virtual*/ int IOSerialStream::waitSpace(uint32_t timeout/*=osWaitForever*/) //Wait for space to be available
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
if(space()) //Is still space already left?
|
||||||
|
{
|
||||||
|
m_spaceSphre.wait(0); //Clear the queue as space is available
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBG("Waiting for data space %d ms (-1 is infinite)", timeout);
|
||||||
|
ret = m_spaceSphre.wait(timeout); //Wait for space to be made or for abort
|
||||||
|
if(ret <= 0)
|
||||||
|
{
|
||||||
|
DBG("Timeout");
|
||||||
|
return NET_TIMEOUT;
|
||||||
|
}
|
||||||
|
if(!space()) //Even if abort has been called, return that space is available
|
||||||
|
{
|
||||||
|
DBG("Aborted");
|
||||||
|
return NET_INTERRUPTED;
|
||||||
|
}
|
||||||
|
m_spaceSphre.wait(0); //Clear the queue as space is available
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*virtual*/ int IOSerialStream::abortWrite() //Abort current writing (or waiting) operation
|
||||||
|
{
|
||||||
|
if( !space() ) //If there is space left, no need to abort
|
||||||
|
{
|
||||||
|
m_spaceSphre.release(); //Force exiting the waiting state
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IOSerialStream::setupWriteableISR(bool en)
|
||||||
|
{
|
||||||
|
if(en)
|
||||||
|
{
|
||||||
|
UART_X->IER |= 1 << 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
UART_X->IER &= ~(1 << 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IOSerialStream::writeable() //Callback from m_serial when new space is available
|
||||||
|
{
|
||||||
|
if(m_outBuf.isEmpty())
|
||||||
|
{
|
||||||
|
m_serialTxFifoEmpty = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
while(m_serial.writeable() && !m_outBuf.isEmpty())
|
||||||
|
{
|
||||||
|
uint8_t c;
|
||||||
|
m_outBuf.dequeue(&c);
|
||||||
|
m_serial.putc((char)c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_spaceSphre.release(); //Force exiting the waiting state
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
/* IOSerialStream.h */
|
||||||
|
/* Copyright (C) 2012 mbed.org, MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||||
|
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||||
|
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||||
|
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or
|
||||||
|
* substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||||
|
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||||
|
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
#ifndef IOSERIALSTREAM_H_
|
||||||
|
#define IOSERIALSTREAM_H_
|
||||||
|
|
||||||
|
#include "core/fwk.h"
|
||||||
|
|
||||||
|
#include "RawSerial.h"
|
||||||
|
|
||||||
|
#include "rtos.h"
|
||||||
|
#include "core/MtxCircBuffer.h"
|
||||||
|
|
||||||
|
/** Input Serial Stream for physical serial interfaces (UART...)
|
||||||
|
This class is not thread-safe, except for the *Abort() methods that can be called by any thread/ISR
|
||||||
|
*/
|
||||||
|
class IOSerialStream : public IOStream
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum { CIRCBUF_SIZE = 255 };
|
||||||
|
IOSerialStream(mbed::RawSerial& serial);
|
||||||
|
/*virtual*/ ~IOSerialStream();
|
||||||
|
|
||||||
|
//0 for non-blocking (returns immediately), osWaitForever for infinite blocking
|
||||||
|
virtual int read(uint8_t* buf, size_t* pLength, size_t maxLength, uint32_t timeout=osWaitForever);
|
||||||
|
virtual size_t available();
|
||||||
|
virtual int waitAvailable(uint32_t timeout=osWaitForever); //Wait for data to be available
|
||||||
|
virtual int abortRead(); //Abort current reading (or waiting) operation
|
||||||
|
|
||||||
|
|
||||||
|
//0 for non-blocking (returns immediately), osWaitForever for infinite blocking
|
||||||
|
virtual int write(uint8_t* buf, size_t length, uint32_t timeout=osWaitForever);
|
||||||
|
virtual size_t space();
|
||||||
|
virtual int waitSpace(uint32_t timeout=osWaitForever); //Wait for space to be available
|
||||||
|
virtual int abortWrite(); //Abort current writing (or waiting) operation
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
mbed::RawSerial& m_serial;
|
||||||
|
volatile bool m_serialTxFifoEmpty;
|
||||||
|
|
||||||
|
void setupReadableISR(bool en);
|
||||||
|
void readable(); //Callback from m_serial when new data is available
|
||||||
|
|
||||||
|
Semaphore m_availableSphre; //Used for signalling
|
||||||
|
|
||||||
|
void setupWriteableISR(bool en);
|
||||||
|
void writeable(); //Callback from m_serial when new space is available
|
||||||
|
|
||||||
|
Semaphore m_spaceSphre; //Used for signalling
|
||||||
|
|
||||||
|
MtxCircBuffer<uint8_t, CIRCBUF_SIZE + 1> m_inBuf;
|
||||||
|
MtxCircBuffer<uint8_t, CIRCBUF_SIZE + 1> m_outBuf;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* IOSERIALSTREAM_H_ */
|
|
@ -32,10 +32,11 @@
|
||||||
/* Input Serial Stream for USB virtual serial ports interfaces
|
/* Input Serial Stream for USB virtual serial ports interfaces
|
||||||
This class is not thread-safe, except for the *Abort() methods that can be called by any thread/ISR
|
This class is not thread-safe, except for the *Abort() methods that can be called by any thread/ISR
|
||||||
*/
|
*/
|
||||||
#define CIRCBUF_SIZE 127
|
|
||||||
class USBSerialStream : public IOStream, IUSBHostSerialListener
|
class USBSerialStream : public IOStream, IUSBHostSerialListener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
enum { CIRCBUF_SIZE = 127 };
|
||||||
USBSerialStream(IUSBHostSerial& serial);
|
USBSerialStream(IUSBHostSerial& serial);
|
||||||
/*virtual*/ ~USBSerialStream();
|
/*virtual*/ ~USBSerialStream();
|
||||||
|
|
||||||
|
|
|
@ -109,6 +109,6 @@ int UbloxCDMAModemInitializer::getSerialPortCount()
|
||||||
|
|
||||||
/*virtual*/ int UbloxCDMAModemInitializer::getType()
|
/*virtual*/ int UbloxCDMAModemInitializer::getType()
|
||||||
{
|
{
|
||||||
return WAN_DONGLE_TYPE_UBLOXC200;
|
return WAN_DONGLE_TYPE_UBLOX_LISAC200;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
WAN_DONGLE_TYPE_UBLOXC200
|
WAN_DONGLE_TYPE_UBLOX_LISAC200 = 0xC200,
|
||||||
};
|
};
|
||||||
|
|
||||||
class UbloxCDMAModemInitializer : public WANDongleInitializer
|
class UbloxCDMAModemInitializer : public WANDongleInitializer
|
||||||
|
|
|
@ -126,6 +126,6 @@ int UbloxGSMModemInitializer::getSerialPortCount()
|
||||||
|
|
||||||
/*virtual*/ int UbloxGSMModemInitializer::getType()
|
/*virtual*/ int UbloxGSMModemInitializer::getType()
|
||||||
{
|
{
|
||||||
return WAN_DONGLE_TYPE_UBX;
|
return WAN_DONGLE_TYPE_UBLOX_LISAU200;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
WAN_DONGLE_TYPE_UBX
|
WAN_DONGLE_TYPE_UBLOX_LISAU200 = 0x0200
|
||||||
};
|
};
|
||||||
|
|
||||||
//-----------------------------------------------------------------------
|
//-----------------------------------------------------------------------
|
||||||
|
|
|
@ -0,0 +1,471 @@
|
||||||
|
/* UbloxModem.cpp */
|
||||||
|
/* Copyright (C) 2012 mbed.org, MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||||
|
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||||
|
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||||
|
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or
|
||||||
|
* substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||||
|
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||||
|
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define __DEBUG__ 3
|
||||||
|
#ifndef __MODULE__
|
||||||
|
#define __MODULE__ "UbloxModem.cpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "core/fwk.h"
|
||||||
|
#include "sms/GSMSMSInterface.h"
|
||||||
|
#include "sms/CDMASMSInterface.h"
|
||||||
|
|
||||||
|
#include "UbloxModem.h"
|
||||||
|
|
||||||
|
UbloxModem::UbloxModem(IOStream* atStream, IOStream* pppStream) :
|
||||||
|
m_at(atStream), // Construct ATCommandsInterface with the AT serial channel
|
||||||
|
m_CdmaSms(&m_at), // Construct SMSInterface with the ATCommandsInterface
|
||||||
|
m_GsmSms(&m_at), // Construct SMSInterface with the ATCommandsInterface
|
||||||
|
m_ussd(&m_at), // Construct USSDInterface with the ATCommandsInterface
|
||||||
|
m_linkMonitor(&m_at), // Construct LinkMonitor with the ATCommandsInterface
|
||||||
|
m_ppp(pppStream ? pppStream : atStream), // Construct PPPIPInterface with the PPP serial channel
|
||||||
|
m_ipInit(false), // PPIPInterface connection is initially down
|
||||||
|
m_smsInit(false), // SMSInterface starts un-initialised
|
||||||
|
m_ussdInit(false), // USSDInterface starts un-initialised
|
||||||
|
m_linkMonitorInit(false), // LinkMonitor subsystem starts un-initialised
|
||||||
|
m_atOpen(false), // ATCommandsInterface starts in a closed state
|
||||||
|
m_onePort(pppStream == NULL),
|
||||||
|
m_gsm(true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
class CREGProcessor : public IATCommandsProcessor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CREGProcessor(bool gsm) : status(STATUS_REGISTERING)
|
||||||
|
{
|
||||||
|
m_gsm = gsm;
|
||||||
|
}
|
||||||
|
enum REGISTERING_STATUS { STATUS_REGISTERING, STATUS_OK, STATUS_FAILED };
|
||||||
|
REGISTERING_STATUS getStatus()
|
||||||
|
{
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
const char* getAtCommand()
|
||||||
|
{
|
||||||
|
return m_gsm ? "AT+CREG?" : "AT+CSS?";
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
if (m_gsm)
|
||||||
|
{
|
||||||
|
if( sscanf(line, "+CREG: %*d,%d", &r) == 1 )
|
||||||
|
{
|
||||||
|
status = (r == 1 || r == 5) ? STATUS_OK :
|
||||||
|
(r == 0 || r == 2) ? STATUS_REGISTERING :
|
||||||
|
// (r == 3) ? STATUS_FAILED :
|
||||||
|
STATUS_FAILED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char bc[3] = "";
|
||||||
|
if(sscanf(line, "%*s %*c,%2s,%*d",bc)==1)
|
||||||
|
{
|
||||||
|
status = (strcmp("Z", bc) == 0) ? STATUS_REGISTERING : STATUS_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
virtual int onNewEntryPrompt(ATCommandsInterface* pInst)
|
||||||
|
{
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
volatile REGISTERING_STATUS status;
|
||||||
|
bool m_gsm;
|
||||||
|
};
|
||||||
|
|
||||||
|
int UbloxModem::connect(const char* apn, const char* user, const char* password)
|
||||||
|
{
|
||||||
|
if( !m_ipInit )
|
||||||
|
{
|
||||||
|
m_ipInit = true;
|
||||||
|
m_ppp.init();
|
||||||
|
}
|
||||||
|
m_ppp.setup(user, password, m_gsm ? DEFAULT_MSISDN_GSM : DEFAULT_MSISDN_CDMA);
|
||||||
|
|
||||||
|
int ret = init();
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_onePort)
|
||||||
|
{
|
||||||
|
m_smsInit = false; //SMS status reset
|
||||||
|
m_ussdInit = false; //USSD status reset
|
||||||
|
m_linkMonitorInit = false; //Link monitor status reset
|
||||||
|
}
|
||||||
|
|
||||||
|
ATCommandsInterface::ATResult result;
|
||||||
|
|
||||||
|
if(apn != NULL)
|
||||||
|
{
|
||||||
|
char cmd[48];
|
||||||
|
int tries = 30;
|
||||||
|
sprintf(cmd, "AT+CGDCONT=1,\"IP\",\"%s\"", apn);
|
||||||
|
do //Try 30 times because for some reasons it can fail *a lot* with the K3772-Z dongle
|
||||||
|
{
|
||||||
|
ret = m_at.executeSimple(cmd, &result);
|
||||||
|
DBG("Result of command: Err code=%d", ret);
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
Thread::wait(500);
|
||||||
|
}
|
||||||
|
} while(ret && --tries);
|
||||||
|
DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
|
||||||
|
DBG("APN set to %s", apn);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Connect
|
||||||
|
DBG("Connecting");
|
||||||
|
if (m_onePort)
|
||||||
|
{
|
||||||
|
m_at.close(); // Closing AT parser
|
||||||
|
m_atOpen = false; //Will need to be reinitialized afterwards
|
||||||
|
}
|
||||||
|
|
||||||
|
DBG("Connecting PPP");
|
||||||
|
|
||||||
|
ret = m_ppp.connect();
|
||||||
|
DBG("Result of connect: Err code=%d", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int UbloxModem::disconnect()
|
||||||
|
{
|
||||||
|
DBG("Disconnecting from PPP");
|
||||||
|
int ret = m_ppp.disconnect();
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
ERR("Disconnect returned %d, still trying to disconnect", ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Ugly but leave dongle time to recover
|
||||||
|
Thread::wait(500);
|
||||||
|
|
||||||
|
if (m_onePort)
|
||||||
|
{
|
||||||
|
//ATCommandsInterface::ATResult result;
|
||||||
|
DBG("Starting AT thread");
|
||||||
|
ret = m_at.open();
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DBG("Trying to hangup");
|
||||||
|
|
||||||
|
if (m_onePort)
|
||||||
|
{
|
||||||
|
//Reinit AT parser
|
||||||
|
ret = m_at.init(false);
|
||||||
|
DBG("Result of command: Err code=%d\n", ret);
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
m_at.close(); // Closing AT parser
|
||||||
|
DBG("AT Parser closed, could not complete disconnection");
|
||||||
|
return NET_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int UbloxModem::sendSM(const char* number, const char* message)
|
||||||
|
{
|
||||||
|
int ret = init();
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ISMSInterface* sms;
|
||||||
|
if (m_gsm) sms = &m_GsmSms;
|
||||||
|
else sms = &m_CdmaSms;
|
||||||
|
if(!m_smsInit)
|
||||||
|
{
|
||||||
|
ret = sms->init();
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
m_smsInit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = sms->send(number, message);
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int UbloxModem::getSM(char* number, char* message, size_t maxLength)
|
||||||
|
{
|
||||||
|
int ret = init();
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ISMSInterface* sms;
|
||||||
|
if (m_gsm) sms = &m_GsmSms;
|
||||||
|
else sms = &m_CdmaSms;
|
||||||
|
if(!m_smsInit)
|
||||||
|
{
|
||||||
|
ret = sms->init();
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
m_smsInit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = sms->get(number, message, maxLength);
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int UbloxModem::getSMCount(size_t* pCount)
|
||||||
|
{
|
||||||
|
int ret = init();
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ISMSInterface* sms;
|
||||||
|
if (m_gsm) sms = &m_GsmSms;
|
||||||
|
else sms = &m_CdmaSms;
|
||||||
|
if(!m_smsInit)
|
||||||
|
{
|
||||||
|
ret = sms->init();
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
m_smsInit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = sms->getCount(pCount);
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ATCommandsInterface* UbloxModem::getATCommandsInterface()
|
||||||
|
{
|
||||||
|
return &m_at;
|
||||||
|
}
|
||||||
|
|
||||||
|
int UbloxModem::init()
|
||||||
|
{
|
||||||
|
if(m_atOpen)
|
||||||
|
{
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBG("Starting AT thread if needed");
|
||||||
|
int ret = m_at.open();
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBG("Sending initialisation commands");
|
||||||
|
ret = m_at.init(false);
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ATCommandsInterface::ATResult result;
|
||||||
|
CREGProcessor cregProcessor(m_gsm);
|
||||||
|
//Wait for network registration
|
||||||
|
do
|
||||||
|
{
|
||||||
|
DBG("Waiting for network registration");
|
||||||
|
ret = m_at.execute(cregProcessor.getAtCommand(), &cregProcessor, &result);
|
||||||
|
DBG("Result of command: Err code=%d\n", ret);
|
||||||
|
DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
|
||||||
|
if(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING)
|
||||||
|
{
|
||||||
|
Thread::wait(3000);
|
||||||
|
}
|
||||||
|
} while(cregProcessor.getStatus() == CREGProcessor::STATUS_REGISTERING);
|
||||||
|
if(cregProcessor.getStatus() == CREGProcessor::STATUS_FAILED)
|
||||||
|
{
|
||||||
|
ERR("Registration denied");
|
||||||
|
return NET_AUTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_atOpen = true;
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int UbloxModem::cleanup()
|
||||||
|
{
|
||||||
|
if(m_ppp.isConnected())
|
||||||
|
{
|
||||||
|
WARN("Data connection is still open"); //Try to encourage good behaviour from the user
|
||||||
|
m_ppp.disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_smsInit = false;
|
||||||
|
m_ussdInit = false;
|
||||||
|
m_linkMonitorInit = false;
|
||||||
|
//We don't reset m_ipInit as PPPIPInterface::init() only needs to be called once
|
||||||
|
|
||||||
|
if(m_atOpen)
|
||||||
|
{
|
||||||
|
m_at.close();
|
||||||
|
m_atOpen = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int UbloxModem::sendUSSD(const char* command, char* result, size_t maxLength)
|
||||||
|
{
|
||||||
|
int ret = init();
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!m_ussdInit)
|
||||||
|
{
|
||||||
|
ret = m_ussd.init();
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
m_ussdInit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = m_ussd.send(command, result, maxLength);
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int UbloxModem::getLinkState(int* pRssi, LinkMonitor::REGISTRATION_STATE* pRegistrationState, LinkMonitor::BEARER* pBearer)
|
||||||
|
{
|
||||||
|
int ret = init();
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!m_linkMonitorInit)
|
||||||
|
{
|
||||||
|
ret = m_linkMonitor.init();
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
m_linkMonitorInit = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = m_linkMonitor.getState(pRssi, pRegistrationState, pBearer);
|
||||||
|
if(ret)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "USBHost.h"
|
||||||
|
#include "UbloxGSMModemInitializer.h"
|
||||||
|
#include "UbloxCDMAModemInitializer.h"
|
||||||
|
|
||||||
|
UbloxUSBModem::UbloxUSBModem() :
|
||||||
|
UbloxModem(&m_atStream, &m_pppStream),
|
||||||
|
m_dongle(), // Construct WANDongle: USB interface with two serial channels to the modem (USBSerialStream objects)
|
||||||
|
m_atStream(m_dongle.getSerial(1)), // AT commands are sent down one serial channel.
|
||||||
|
m_pppStream(m_dongle.getSerial(0)), // PPP connections are managed via another serial channel.
|
||||||
|
m_dongleConnected(false) // Dongle is initially not ready for anything
|
||||||
|
{
|
||||||
|
USBHost* host = USBHost::getHostInst();
|
||||||
|
m_dongle.addInitializer(new UbloxGSMModemInitializer(host));
|
||||||
|
m_dongle.addInitializer(new UbloxCDMAModemInitializer(host));
|
||||||
|
}
|
||||||
|
|
||||||
|
int UbloxUSBModem::init()
|
||||||
|
{
|
||||||
|
if( !m_dongleConnected )
|
||||||
|
{
|
||||||
|
m_dongleConnected = true;
|
||||||
|
while( !m_dongle.connected() )
|
||||||
|
{
|
||||||
|
m_dongle.tryConnect();
|
||||||
|
Thread::wait(10);
|
||||||
|
}
|
||||||
|
if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBLOX_LISAU200)
|
||||||
|
{
|
||||||
|
INFO("Using a u-blox LISA-U200 3G/WCDMA Modem");
|
||||||
|
}
|
||||||
|
else if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBLOX_LISAC200)
|
||||||
|
{
|
||||||
|
INFO("Using a u-blox LISA-C200 CDMA Modem");
|
||||||
|
m_gsm = false;
|
||||||
|
m_onePort = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
WARN("Using an Unknown Dongle");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UbloxModem::init();
|
||||||
|
}
|
||||||
|
|
||||||
|
int UbloxUSBModem::cleanup()
|
||||||
|
{
|
||||||
|
UbloxModem::cleanup();
|
||||||
|
m_dongle.disconnect();
|
||||||
|
m_dongleConnected = false;
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
UbloxSerModem::UbloxSerModem() :
|
||||||
|
UbloxModem(&m_atStream, NULL),
|
||||||
|
m_Serial(P0_15,P0_16),
|
||||||
|
m_atStream(m_Serial)
|
||||||
|
{
|
||||||
|
m_Serial.baud(115200);
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,168 @@
|
||||||
|
/* VodafoneUSBModem.h */
|
||||||
|
/* Copyright (C) 2012 mbed.org, MIT License
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||||
|
* and associated documentation files (the "Software"), to deal in the Software without restriction,
|
||||||
|
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
|
||||||
|
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in all copies or
|
||||||
|
* substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
|
||||||
|
* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||||
|
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef UBLOXMODEM_H_
|
||||||
|
#define UBLOXMODEM_H_
|
||||||
|
|
||||||
|
#include "core/fwk.h"
|
||||||
|
|
||||||
|
#include "at/ATCommandsInterface.h"
|
||||||
|
#include "ip/PPPIPInterface.h"
|
||||||
|
#include "sms/GSMSMSInterface.h"
|
||||||
|
#include "sms/CDMASMSInterface.h"
|
||||||
|
#include "ussd/USSDInterface.h"
|
||||||
|
#include "link/LinkMonitor.h"
|
||||||
|
#include "CellularModem.h"
|
||||||
|
|
||||||
|
/** u-blox WCDMA modem (LISA-U200)
|
||||||
|
*/
|
||||||
|
class UbloxModem: public CellularModem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** Create u-blox API instance
|
||||||
|
@param powerGatingPin Optional pin commanding a power gating transistor on the modem's power line
|
||||||
|
@param powerGatingOnWhenPinHigh true if the pin needs to be high to power the dongle, defaults to true
|
||||||
|
*/
|
||||||
|
UbloxModem(IOStream* atStream, IOStream* pppStream);
|
||||||
|
|
||||||
|
//Internet-related functions
|
||||||
|
|
||||||
|
/** Open a 3G internet connection
|
||||||
|
@return 0 on success, error code on failure
|
||||||
|
*/
|
||||||
|
virtual int connect(const char* apn = NULL, const char* user = NULL, const char* password = NULL);
|
||||||
|
|
||||||
|
/** Close the internet connection
|
||||||
|
@return 0 on success, error code on failure
|
||||||
|
*/
|
||||||
|
virtual int disconnect();
|
||||||
|
|
||||||
|
|
||||||
|
/** Send a SM
|
||||||
|
@param number The receiver's phone number
|
||||||
|
@param message The message to send
|
||||||
|
@return 0 on success, error code on failure
|
||||||
|
*/
|
||||||
|
virtual int sendSM(const char* number, const char* message);
|
||||||
|
|
||||||
|
|
||||||
|
/** Receive a SM
|
||||||
|
@param number Pointer to a buffer to store the sender's phone number (must be at least 17 characters-long, including the sapce for the null-terminating char)
|
||||||
|
@param message Pointer to a buffer to store the the incoming message
|
||||||
|
@param maxLength Maximum message length that can be stored in buffer (including null-terminating character)
|
||||||
|
@return 0 on success, error code on failure
|
||||||
|
*/
|
||||||
|
virtual int getSM(char* number, char* message, size_t maxLength);
|
||||||
|
|
||||||
|
/** Get the number of SMs in the incoming box
|
||||||
|
@param pCount pointer to store the number of unprocessed SMs on
|
||||||
|
@return 0 on success, error code on failure
|
||||||
|
*/
|
||||||
|
virtual int getSMCount(size_t* pCount);
|
||||||
|
|
||||||
|
/** Send a USSD command & wait for its result
|
||||||
|
@param command The command to send
|
||||||
|
@param result Buffer in which to store the result
|
||||||
|
@param maxLength Maximum result length that can be stored in buffer (including null-terminating character)
|
||||||
|
@return 0 on success, error code on failure
|
||||||
|
*/
|
||||||
|
int sendUSSD(const char* command, char* result, size_t maxLength);
|
||||||
|
|
||||||
|
/** Get link state
|
||||||
|
@param pRssi pointer to store the current RSSI in dBm, between -51 dBm and -113 dBm if known; -51 dBm means -51 dBm or more; -113 dBm means -113 dBm or less; 0 if unknown
|
||||||
|
@param pRegistrationState pointer to store the current registration state
|
||||||
|
@param pBearer pointer to store the current bearer
|
||||||
|
@return 0 on success, error code on failure
|
||||||
|
*/
|
||||||
|
int getLinkState(int* pRssi, LinkMonitor::REGISTRATION_STATE* pRegistrationState, LinkMonitor::BEARER* pBearer);
|
||||||
|
|
||||||
|
/** Get the ATCommandsInterface instance
|
||||||
|
@return Pointer to the ATCommandsInterface instance
|
||||||
|
*/
|
||||||
|
virtual ATCommandsInterface* getATCommandsInterface();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
/** Initialise dongle.
|
||||||
|
* The following actions are performed:
|
||||||
|
* 1) Start AT interface thread
|
||||||
|
* 2) Wait for network registration
|
||||||
|
*/
|
||||||
|
virtual int init();
|
||||||
|
|
||||||
|
/** De-initialise dongle.
|
||||||
|
* The following actions are performed:
|
||||||
|
* 1) Tear down PPP session
|
||||||
|
* 2) Set SMS,USSD, and LinkMonitor subsystems to un-initialised
|
||||||
|
* 3) Close the AT commands interface
|
||||||
|
*/
|
||||||
|
virtual int cleanup();
|
||||||
|
|
||||||
|
private:
|
||||||
|
ATCommandsInterface m_at; //< Interface to AT commands processing
|
||||||
|
|
||||||
|
CDMASMSInterface m_CdmaSms; //< Interface to SMS manager (send/receive etc)
|
||||||
|
GSMSMSInterface m_GsmSms; //< Interface to SMS manager (send/receive etc)
|
||||||
|
USSDInterface m_ussd; //< Interface to USSD manager (send etc)
|
||||||
|
LinkMonitor m_linkMonitor; //< Interface to link monitor (RSSI)
|
||||||
|
|
||||||
|
PPPIPInterface m_ppp; //< Interface to PPP conection manager (IP assignment etc)
|
||||||
|
|
||||||
|
bool m_ipInit; //< Has PPIPInterface object (m_ppp) been initialised? true/false
|
||||||
|
bool m_smsInit; //< Has SMSInterface object (m_sms) been initialised? true/false
|
||||||
|
bool m_ussdInit; //< Has USSDInterface object (m_ussd) been initialised? true/false
|
||||||
|
bool m_linkMonitorInit; //< Has LinkMonitor object (m_linkMonitor) been initialised? true/false
|
||||||
|
bool m_atOpen; //< Is the interface to the ATCommandsInterface open? true/false
|
||||||
|
protected:
|
||||||
|
bool m_onePort;
|
||||||
|
bool m_gsm;
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "WANDongle.h"
|
||||||
|
#include "serial/usb/USBSerialStream.h"
|
||||||
|
|
||||||
|
class UbloxUSBModem: public UbloxModem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UbloxUSBModem();
|
||||||
|
virtual int init();
|
||||||
|
virtual int cleanup();
|
||||||
|
virtual int power(bool enable) { return 1; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
WANDongle m_dongle; //< Interface to USB connected WAN dongle
|
||||||
|
|
||||||
|
USBSerialStream m_atStream; //< Serial interface to AT channel on modem
|
||||||
|
USBSerialStream m_pppStream; //< Serial interface to PPP channel on modem
|
||||||
|
|
||||||
|
bool m_dongleConnected; //< Is the dongle physically connected (does the USB stack respond)? true/false
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "serial/io/IOSerialStream.h"
|
||||||
|
|
||||||
|
class UbloxSerModem: public UbloxModem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
UbloxSerModem();
|
||||||
|
virtual int power(bool enable) { return 1; }
|
||||||
|
private:
|
||||||
|
RawSerial m_Serial;
|
||||||
|
IOSerialStream m_atStream; //< Serial interface to AT channel on modem
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* UBLOXMODEM_H_ */
|
|
@ -33,7 +33,7 @@
|
||||||
UbloxUSBCDMAModem::UbloxUSBCDMAModem(PinName powerGatingPin /*= NC*/, bool powerGatingOnWhenPinHigh /* = true*/, int serial /* 0 */) : m_dongle(),
|
UbloxUSBCDMAModem::UbloxUSBCDMAModem(PinName powerGatingPin /*= NC*/, bool powerGatingOnWhenPinHigh /* = true*/, int serial /* 0 */) : m_dongle(),
|
||||||
m_stream(m_dongle.getSerial(serial)),
|
m_stream(m_dongle.getSerial(serial)),
|
||||||
m_at(&m_stream),
|
m_at(&m_stream),
|
||||||
m_sms(&m_at), m_ppp(&m_stream, DEFAULT_MSISDN_CDMA),
|
m_sms(&m_at), m_ppp(&m_stream),
|
||||||
m_dongleConnected(false), m_ipInit(false), m_smsInit(false), m_atOpen(false),
|
m_dongleConnected(false), m_ipInit(false), m_smsInit(false), m_atOpen(false),
|
||||||
m_powerGatingPin(powerGatingPin), m_powerGatingOnWhenPinHigh(powerGatingOnWhenPinHigh)
|
m_powerGatingPin(powerGatingPin), m_powerGatingOnWhenPinHigh(powerGatingOnWhenPinHigh)
|
||||||
{
|
{
|
||||||
|
@ -88,7 +88,7 @@ int UbloxUSBCDMAModem::connect(const char* apn, const char* user, const char* pa
|
||||||
m_ipInit = true;
|
m_ipInit = true;
|
||||||
m_ppp.init();
|
m_ppp.init();
|
||||||
}
|
}
|
||||||
m_ppp.setup(user, password);
|
m_ppp.setup(user, password, DEFAULT_MSISDN_CDMA);
|
||||||
|
|
||||||
int ret = init();
|
int ret = init();
|
||||||
if(ret)
|
if(ret)
|
||||||
|
@ -341,7 +341,7 @@ int UbloxUSBCDMAModem::init()
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBLOXC200)
|
if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBLOX_LISAC200)
|
||||||
{
|
{
|
||||||
INFO("Using a UBLOX C200 Dongle");
|
INFO("Using a UBLOX C200 Dongle");
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ UbloxUSBGSMModem::UbloxUSBGSMModem(PinName powerGatingPin /*= NC*/, bool powerGa
|
||||||
m_sms(&m_at), // Construct SMSInterface with the ATCommandsInterface
|
m_sms(&m_at), // Construct SMSInterface with the ATCommandsInterface
|
||||||
m_ussd(&m_at), // Construct USSDInterface with the ATCommandsInterface
|
m_ussd(&m_at), // Construct USSDInterface with the ATCommandsInterface
|
||||||
m_linkMonitor(&m_at), // Construct LinkMonitor with the ATCommandsInterface
|
m_linkMonitor(&m_at), // Construct LinkMonitor with the ATCommandsInterface
|
||||||
m_ppp(&m_pppStream, DEFAULT_MSISDN_GSM), // Construct PPPIPInterface with the PPP serial channel
|
m_ppp(&m_pppStream), // Construct PPPIPInterface with the PPP serial channel
|
||||||
m_dongleConnected(false), // Dongle is initially not ready for anything
|
m_dongleConnected(false), // Dongle is initially not ready for anything
|
||||||
m_ipInit(false), // PPIPInterface connection is initially down
|
m_ipInit(false), // PPIPInterface connection is initially down
|
||||||
m_smsInit(false), // SMSInterface starts un-initialised
|
m_smsInit(false), // SMSInterface starts un-initialised
|
||||||
|
@ -185,7 +185,7 @@ int UbloxUSBGSMModem::connect(const char* apn, const char* user, const char* pas
|
||||||
m_ipInit = true;
|
m_ipInit = true;
|
||||||
m_ppp.init();
|
m_ppp.init();
|
||||||
}
|
}
|
||||||
m_ppp.setup(user, password);
|
m_ppp.setup(user, password, DEFAULT_MSISDN_GSM);
|
||||||
|
|
||||||
int ret = init();
|
int ret = init();
|
||||||
if(ret)
|
if(ret)
|
||||||
|
@ -543,7 +543,7 @@ int UbloxUSBGSMModem::init()
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBX)
|
if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBLOX_LISAU200)
|
||||||
{
|
{
|
||||||
INFO("Using a u-blox LISA-U");
|
INFO("Using a u-blox LISA-U");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue