mirror of https://github.com/ARMmbed/mbed-os.git
Merge branch 'master' of git://github.com/mbedmicro/mbed into bugfix-STM32-vectors
commit
6ae1e9e360
|
@ -1,5 +1,11 @@
|
|||
*.py[cod]
|
||||
|
||||
# Distribution dir
|
||||
dist
|
||||
|
||||
# MANIFEST file
|
||||
MANIFEST
|
||||
|
||||
# Private settings
|
||||
private_settings.py
|
||||
|
||||
|
@ -53,4 +59,4 @@ uVision Project/
|
|||
debug.log
|
||||
|
||||
# Ignore OS X Desktop Services Store files
|
||||
.DS_Store
|
||||
.DS_Store
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
# file GENERATED by distutils, do NOT edit
|
||||
LICENSE
|
||||
setup.py
|
||||
workspace_tools/__init__.py
|
||||
workspace_tools/__init__.pyc
|
||||
workspace_tools/autotest.py
|
||||
workspace_tools/build.py
|
||||
workspace_tools/build_api.py
|
||||
workspace_tools/build_release.py
|
||||
workspace_tools/client.py
|
||||
workspace_tools/export_test.py
|
||||
workspace_tools/hooks.py
|
||||
workspace_tools/libraries.py
|
||||
workspace_tools/make.py
|
||||
workspace_tools/options.py
|
||||
workspace_tools/patch.py
|
||||
workspace_tools/paths.py
|
||||
workspace_tools/project.py
|
||||
workspace_tools/server.py
|
||||
workspace_tools/settings.py
|
||||
workspace_tools/size.py
|
||||
workspace_tools/syms.py
|
||||
workspace_tools/synch.py
|
||||
workspace_tools/targets.py
|
||||
workspace_tools/tests.py
|
||||
workspace_tools/utils.py
|
||||
workspace_tools/data/__init__.py
|
||||
workspace_tools/data/example_test_spec.json
|
||||
workspace_tools/data/support.py
|
||||
workspace_tools/data/rpc/RPCClasses.h
|
||||
workspace_tools/data/rpc/class.cpp
|
||||
workspace_tools/dev/__init__.py
|
||||
workspace_tools/dev/dsp_fir.py
|
||||
workspace_tools/dev/rpc_classes.py
|
||||
workspace_tools/export/__init__.py
|
||||
workspace_tools/export/codered.py
|
||||
workspace_tools/export/codered_lpc1768_cproject.tmpl
|
||||
workspace_tools/export/codered_lpc1768_project.tmpl
|
||||
workspace_tools/export/codered_lpc4088_cproject.tmpl
|
||||
workspace_tools/export/codered_lpc4088_project.tmpl
|
||||
workspace_tools/export/codesourcery.py
|
||||
workspace_tools/export/codesourcery_lpc1768.tmpl
|
||||
workspace_tools/export/ds5_5.py
|
||||
workspace_tools/export/ds5_5_lpc11u24.cproject.tmpl
|
||||
workspace_tools/export/ds5_5_lpc11u24.launch.tmpl
|
||||
workspace_tools/export/ds5_5_lpc11u24.project.tmpl
|
||||
workspace_tools/export/ds5_5_lpc1768.cproject.tmpl
|
||||
workspace_tools/export/ds5_5_lpc1768.launch.tmpl
|
||||
workspace_tools/export/ds5_5_lpc1768.project.tmpl
|
||||
workspace_tools/export/exporters.py
|
||||
workspace_tools/export/gcc_arm_lpc1768.tmpl
|
||||
workspace_tools/export/gccarm.py
|
||||
workspace_tools/export/iar.ewp.tmpl
|
||||
workspace_tools/export/iar.eww.tmpl
|
||||
workspace_tools/export/iar.py
|
||||
workspace_tools/export/uvision4.py
|
||||
workspace_tools/export/uvision4_kl25z.uvopt.tmpl
|
||||
workspace_tools/export/uvision4_kl25z.uvproj.tmpl
|
||||
workspace_tools/export/uvision4_lpc1114.uvopt.tmpl
|
||||
workspace_tools/export/uvision4_lpc1114.uvproj.tmpl
|
||||
workspace_tools/export/uvision4_lpc11c24.uvopt.tmpl
|
||||
workspace_tools/export/uvision4_lpc11c24.uvproj.tmpl
|
||||
workspace_tools/export/uvision4_lpc11u24.uvopt.tmpl
|
||||
workspace_tools/export/uvision4_lpc11u24.uvproj.tmpl
|
||||
workspace_tools/export/uvision4_lpc1347.uvopt.tmpl
|
||||
workspace_tools/export/uvision4_lpc1347.uvproj.tmpl
|
||||
workspace_tools/export/uvision4_lpc1768.uvopt.tmpl
|
||||
workspace_tools/export/uvision4_lpc1768.uvproj.tmpl
|
||||
workspace_tools/export/uvision4_lpc4088.uvopt.tmpl
|
||||
workspace_tools/export/uvision4_lpc4088.uvproj.tmpl
|
||||
workspace_tools/export/uvision4_lpc812.uvopt.tmpl
|
||||
workspace_tools/export/uvision4_lpc812.uvproj.tmpl
|
||||
workspace_tools/host_tests/__init__.py
|
||||
workspace_tools/host_tests/echo.py
|
||||
workspace_tools/host_tests/host_test.py
|
||||
workspace_tools/host_tests/mbedrpc.py
|
||||
workspace_tools/host_tests/net_test.py
|
||||
workspace_tools/host_tests/rpc.py
|
||||
workspace_tools/host_tests/tcpecho_client.py
|
||||
workspace_tools/host_tests/tcpecho_server.py
|
||||
workspace_tools/host_tests/tcpecho_server_loop.py
|
||||
workspace_tools/host_tests/udpecho_client.py
|
||||
workspace_tools/host_tests/udpecho_server.py
|
||||
workspace_tools/host_tests/example/BroadcastReceive.py
|
||||
workspace_tools/host_tests/example/BroadcastSend.py
|
||||
workspace_tools/host_tests/example/MulticastReceive.py
|
||||
workspace_tools/host_tests/example/MulticastSend.py
|
||||
workspace_tools/host_tests/example/TCPEchoClient.py
|
||||
workspace_tools/host_tests/example/TCPEchoServer.py
|
||||
workspace_tools/host_tests/example/UDPEchoClient.py
|
||||
workspace_tools/host_tests/example/UDPEchoServer.py
|
||||
workspace_tools/host_tests/example/__init__.py
|
||||
workspace_tools/toolchains/__init__.py
|
||||
workspace_tools/toolchains/arm.py
|
||||
workspace_tools/toolchains/gcc.py
|
||||
workspace_tools/toolchains/iar.py
|
|
@ -0,0 +1,2 @@
|
|||
graft workspace_tools
|
||||
include __init__.py LICENSE
|
|
@ -30,6 +30,10 @@
|
|||
|
||||
#include "IUSBHostSerialListener.h"
|
||||
|
||||
// This is needed by some versions of GCC
|
||||
#undef putc
|
||||
#undef getc
|
||||
|
||||
class IUSBHostSerial {
|
||||
public:
|
||||
|
||||
|
|
|
@ -25,8 +25,8 @@
|
|||
#define __MODULE__ "WANDongle.cpp"
|
||||
#endif
|
||||
|
||||
#include "core/dbg.h"
|
||||
#include <cstdint>
|
||||
#include "dbg.h"
|
||||
#include <stdint.h>
|
||||
#include "rtos.h"
|
||||
|
||||
#include "WANDongle.h"
|
||||
|
@ -47,7 +47,7 @@ bool WANDongle::tryConnect()
|
|||
{
|
||||
//FIXME should run on USB thread
|
||||
|
||||
DBG("Trying to connect device");
|
||||
USB_DBG("Trying to connect device");
|
||||
|
||||
if (dev_connected) {
|
||||
return true;
|
||||
|
@ -61,23 +61,23 @@ bool WANDongle::tryConnect()
|
|||
{
|
||||
m_pInitializer = NULL; //Will be set in setVidPid callback
|
||||
|
||||
DBG("Enumerate");
|
||||
USB_DBG("Enumerate");
|
||||
int ret = host->enumerate(dev, this);
|
||||
if(ret)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DBG("Device has VID:%04x PID:%04x", dev->getVid(), dev->getPid());
|
||||
USB_DBG("Device has VID:%04x PID:%04x", dev->getVid(), dev->getPid());
|
||||
|
||||
if(m_pInitializer) //If an initializer has been found
|
||||
{
|
||||
DBG("m_pInitializer=%p", m_pInitializer);
|
||||
DBG("m_pInitializer->getSerialVid()=%04x", m_pInitializer->getSerialVid());
|
||||
DBG("m_pInitializer->getSerialPid()=%04x", m_pInitializer->getSerialPid());
|
||||
USB_DBG("m_pInitializer=%p", m_pInitializer);
|
||||
USB_DBG("m_pInitializer->getSerialVid()=%04x", m_pInitializer->getSerialVid());
|
||||
USB_DBG("m_pInitializer->getSerialPid()=%04x", m_pInitializer->getSerialPid());
|
||||
if ((dev->getVid() == m_pInitializer->getSerialVid()) && (dev->getPid() == m_pInitializer->getSerialPid()))
|
||||
{
|
||||
DBG("The dongle is in virtual serial mode");
|
||||
USB_DBG("The dongle is in virtual serial mode");
|
||||
host->registerDriver(dev, 0, this, &WANDongle::init);
|
||||
m_serialCount = m_pInitializer->getSerialPortCount();
|
||||
if( m_serialCount > WANDONGLE_MAX_SERIAL_PORTS )
|
||||
|
@ -86,13 +86,13 @@ bool WANDongle::tryConnect()
|
|||
}
|
||||
for(int j = 0; j < m_serialCount; j++)
|
||||
{
|
||||
DBG("Connecting serial port #%d", j+1);
|
||||
DBG("Ep %p", m_pInitializer->getEp(dev, j, false));
|
||||
DBG("Ep %p", m_pInitializer->getEp(dev, j, true));
|
||||
USB_DBG("Connecting serial port #%d", j+1);
|
||||
USB_DBG("Ep %p", m_pInitializer->getEp(dev, j, false));
|
||||
USB_DBG("Ep %p", m_pInitializer->getEp(dev, j, true));
|
||||
m_serial[j].connect( dev, m_pInitializer->getEp(dev, j, false), m_pInitializer->getEp(dev, j, true) );
|
||||
}
|
||||
|
||||
DBG("Device connected");
|
||||
USB_DBG("Device connected");
|
||||
|
||||
dev_connected = true;
|
||||
|
||||
|
@ -101,16 +101,16 @@ bool WANDongle::tryConnect()
|
|||
}
|
||||
else if ((dev->getVid() == m_pInitializer->getMSDVid()) && (dev->getPid() == m_pInitializer->getMSDPid()))
|
||||
{
|
||||
DBG("Vodafone K3370 dongle detected in MSD mode");
|
||||
USB_DBG("Vodafone K3370 dongle detected in MSD mode");
|
||||
//Try to switch
|
||||
if( m_pInitializer->switchMode(dev) )
|
||||
{
|
||||
DBG("Switched OK");
|
||||
USB_DBG("Switched OK");
|
||||
return false; //Will be connected on a next iteration
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR("Could not switch mode");
|
||||
USB_ERR("Could not switch mode");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -168,21 +168,21 @@ void WANDongle::init()
|
|||
{
|
||||
WANDongleInitializer* initializer;
|
||||
|
||||
for(unsigned i = 0; i < m_totalInitializers; i++)
|
||||
for(int i = 0; i < m_totalInitializers; i++)
|
||||
{
|
||||
initializer = m_Initializers[i];
|
||||
DBG("initializer=%p", initializer);
|
||||
DBG("initializer->getSerialVid()=%04x", initializer->getSerialVid());
|
||||
DBG("initializer->getSerialPid()=%04x", initializer->getSerialPid());
|
||||
USB_DBG("initializer=%p", initializer);
|
||||
USB_DBG("initializer->getSerialVid()=%04x", initializer->getSerialVid());
|
||||
USB_DBG("initializer->getSerialPid()=%04x", initializer->getSerialPid());
|
||||
if ((dev->getVid() == initializer->getSerialVid()) && (dev->getPid() == initializer->getSerialPid()))
|
||||
{
|
||||
DBG("The dongle is in virtual serial mode");
|
||||
USB_DBG("The dongle is in virtual serial mode");
|
||||
m_pInitializer = initializer;
|
||||
break;
|
||||
}
|
||||
else if ((dev->getVid() == initializer->getMSDVid()) && (dev->getPid() == initializer->getMSDPid()))
|
||||
{
|
||||
DBG("Dongle detected in MSD mode");
|
||||
USB_DBG("Dongle detected in MSD mode");
|
||||
m_pInitializer = initializer;
|
||||
break;
|
||||
}
|
||||
|
@ -229,7 +229,7 @@ bool WANDongle::addInitializer(WANDongleInitializer* pInitializer)
|
|||
|
||||
WANDongle::~WANDongle()
|
||||
{
|
||||
for(unsigned i = 0; i < m_totalInitializers; i++)
|
||||
for(int i = 0; i < m_totalInitializers; i++)
|
||||
delete m_Initializers[i];
|
||||
}
|
||||
|
||||
|
|
|
@ -23,9 +23,7 @@
|
|||
|
||||
#ifdef USBHOST_3GMODULE
|
||||
|
||||
#include <cstdint>
|
||||
using std::uint16_t;
|
||||
using std::uint32_t;
|
||||
#include <stdint.h>
|
||||
|
||||
#include "USBHost.h"
|
||||
#include "IUSBEnumerator.h"
|
||||
|
@ -44,6 +42,7 @@ protected:
|
|||
uint8_t m_serialIntfMap[WANDONGLE_MAX_SERIAL_PORTS];
|
||||
|
||||
public:
|
||||
virtual ~WANDongleInitializer() {}
|
||||
virtual uint16_t getMSDVid() = 0;
|
||||
virtual uint16_t getMSDPid() = 0;
|
||||
|
||||
|
|
|
@ -25,8 +25,8 @@
|
|||
#define __MODULE__ "WANDongleSerialPort.cpp"
|
||||
#endif
|
||||
|
||||
#include "core/dbg.h"
|
||||
#include <cstdint>
|
||||
#include "dbg.h"
|
||||
#include <stdint.h>
|
||||
#include "rtos.h"
|
||||
|
||||
#include "WANDongleSerialPort.h"
|
||||
|
@ -65,31 +65,31 @@ void WANDongleSerialPort::reset()
|
|||
|
||||
int WANDongleSerialPort::readPacket()
|
||||
{
|
||||
DBG("Read packet on %p", this);
|
||||
USB_DBG("Read packet on %p", this);
|
||||
rx_mtx.lock();
|
||||
if(lock_rx)
|
||||
{
|
||||
ERR("Fail");
|
||||
USB_ERR("Fail");
|
||||
rx_mtx.unlock();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( bulk_in == NULL )
|
||||
{
|
||||
WARN("Port is disconnected");
|
||||
USB_WARN("Port is disconnected");
|
||||
rx_mtx.unlock();
|
||||
return -1;
|
||||
}
|
||||
|
||||
lock_rx = true; //Receiving
|
||||
rx_mtx.unlock();
|
||||
// DBG("readPacket");
|
||||
// USB_DBG("readPacket");
|
||||
//lock_rx.lock();
|
||||
USB_TYPE res = host->bulkRead(dev, (USBEndpoint *)bulk_in, buf_in, ((USBEndpoint *)bulk_in)->getSize(), false); //Queue transfer
|
||||
if(res != USB_TYPE_PROCESSING)
|
||||
{
|
||||
//lock_rx.unlock();
|
||||
ERR("host->bulkRead() returned %d", res);
|
||||
USB_ERR("host->bulkRead() returned %d", res);
|
||||
Thread::wait(100);
|
||||
return -1;
|
||||
}
|
||||
|
@ -101,28 +101,28 @@ int WANDongleSerialPort::writePacket()
|
|||
tx_mtx.lock();
|
||||
if(lock_tx)
|
||||
{
|
||||
ERR("Fail");
|
||||
USB_ERR("Fail");
|
||||
tx_mtx.unlock();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( bulk_out == NULL )
|
||||
{
|
||||
WARN("Port is disconnected");
|
||||
USB_WARN("Port is disconnected");
|
||||
tx_mtx.unlock();
|
||||
return -1;
|
||||
}
|
||||
|
||||
lock_tx = true; //Transmitting
|
||||
tx_mtx.unlock();
|
||||
// DBG("writePacket");
|
||||
// USB_DBG("writePacket");
|
||||
|
||||
//lock_tx.lock();
|
||||
USB_TYPE res = host->bulkWrite(dev, (USBEndpoint *)bulk_out, buf_out, buf_out_len, false); //Queue transfer
|
||||
if(res != USB_TYPE_PROCESSING)
|
||||
{
|
||||
//lock_tx.unlock();
|
||||
ERR("host->bulkWrite() returned %d", res);
|
||||
USB_ERR("host->bulkWrite() returned %d", res);
|
||||
Thread::wait(100);
|
||||
return -1;
|
||||
}
|
||||
|
@ -142,7 +142,7 @@ int WANDongleSerialPort::putc(int c)
|
|||
}
|
||||
else
|
||||
{
|
||||
ERR("CAN'T WRITE!");
|
||||
USB_ERR("CAN'T WRITE!");
|
||||
}
|
||||
tx_mtx.unlock();
|
||||
return c;
|
||||
|
@ -162,7 +162,7 @@ int WANDongleSerialPort::getc()
|
|||
}
|
||||
else
|
||||
{
|
||||
ERR("CAN'T READ!");
|
||||
USB_ERR("CAN'T READ!");
|
||||
}
|
||||
rx_mtx.unlock();
|
||||
return c;
|
||||
|
@ -305,7 +305,7 @@ void WANDongleSerialPort::rxHandler()
|
|||
else //Error, try reading again
|
||||
{
|
||||
//lock_rx.unlock();
|
||||
DBG("Trying again");
|
||||
USB_DBG("Trying again");
|
||||
readPacket();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,9 +22,7 @@
|
|||
|
||||
#include "gpio_api.h"
|
||||
#include "gpio_irq_api.h"
|
||||
|
||||
#include "FunctionPointer.h"
|
||||
#include "CallChain.h"
|
||||
|
||||
namespace mbed {
|
||||
|
||||
|
@ -73,197 +71,59 @@ public:
|
|||
/** Attach a function to call when a rising edge occurs on the input
|
||||
*
|
||||
* @param fptr A pointer to a void function, or 0 to set as none
|
||||
*
|
||||
* @returns
|
||||
* The function object created for 'fptr'
|
||||
*/
|
||||
pFunctionPointer_t rise(void (*fptr)(void));
|
||||
|
||||
/** Add a function to be called when a rising edge occurs at the end of the call chain
|
||||
*
|
||||
* @param fptr the function to add
|
||||
*
|
||||
* @returns
|
||||
* The function object created for 'fptr'
|
||||
*/
|
||||
pFunctionPointer_t rise_add(void (*fptr)(void)) {
|
||||
return rise_add_common(fptr);
|
||||
}
|
||||
|
||||
/** Add a function to be called when a rising edge occurs at the beginning of the call chain
|
||||
*
|
||||
* @param fptr the function to add
|
||||
*
|
||||
* @returns
|
||||
* The function object created for 'fptr'
|
||||
*/
|
||||
pFunctionPointer_t rise_add_front(void (*fptr)(void)) {
|
||||
return rise_add_common(fptr, true);
|
||||
}
|
||||
void rise(void (*fptr)(void));
|
||||
|
||||
/** Attach a member function to call when a rising edge occurs on the input
|
||||
*
|
||||
* @param tptr pointer to the object to call the member function on
|
||||
* @param mptr pointer to the member function to be called
|
||||
*
|
||||
* @returns
|
||||
* The function object created for 'tptr' and 'mptr'
|
||||
*/
|
||||
template<typename T>
|
||||
pFunctionPointer_t rise(T* tptr, void (T::*mptr)(void)) {
|
||||
_rise.clear();
|
||||
pFunctionPointer_t pf = _rise.add(tptr, mptr);
|
||||
void rise(T* tptr, void (T::*mptr)(void)) {
|
||||
_rise.attach(tptr, mptr);
|
||||
gpio_irq_set(&gpio_irq, IRQ_RISE, 1);
|
||||
return pf;
|
||||
}
|
||||
|
||||
/** Add a function to be called when a rising edge occurs at the end of the call chain
|
||||
*
|
||||
* @param tptr pointer to the object to call the member function on
|
||||
* @param mptr pointer to the member function to be called
|
||||
*
|
||||
* @returns
|
||||
* The function object created for 'tptr' and 'mptr'
|
||||
*/
|
||||
template<typename T>
|
||||
pFunctionPointer_t rise_add(T* tptr, void (T::*mptr)(void)) {
|
||||
return rise_add_common(tptr, mptr);
|
||||
}
|
||||
|
||||
/** Add a function to be called when a rising edge occurs at the beginning of the call chain
|
||||
*
|
||||
* @param tptr pointer to the object to call the member function on
|
||||
* @param mptr pointer to the member function to be called
|
||||
*
|
||||
* @returns
|
||||
* The function object created for 'tptr' and 'mptr'
|
||||
*/
|
||||
template<typename T>
|
||||
pFunctionPointer_t rise_add_front(T* tptr, void (T::*mptr)(void)) {
|
||||
return rise_add_common(tptr, mptr, true);
|
||||
}
|
||||
|
||||
/** Remove a function from the list of functions to be called when a rising edge occurs
|
||||
*
|
||||
* @param pf the function object to remove
|
||||
*
|
||||
* @returns
|
||||
* true if the function was found and removed, false otherwise
|
||||
*/
|
||||
bool rise_remove(pFunctionPointer_t pf);
|
||||
|
||||
/** Attach a function to call when a falling edge occurs on the input
|
||||
*
|
||||
* @param fptr A pointer to a void function, or 0 to set as none
|
||||
*
|
||||
* @returns
|
||||
* The function object created for 'fptr'
|
||||
*/
|
||||
pFunctionPointer_t fall(void (*fptr)(void));
|
||||
|
||||
/** Add a function to be called when a falling edge occurs at the end of the call chain
|
||||
*
|
||||
* @param fptr the function to add
|
||||
*
|
||||
* @returns
|
||||
* The function object created for 'fptr'
|
||||
*/
|
||||
pFunctionPointer_t fall_add(void (*fptr)(void)) {
|
||||
return fall_add_common(fptr);
|
||||
}
|
||||
|
||||
/** Add a function to be called when a falling edge occurs at the beginning of the call chain
|
||||
*
|
||||
* @param fptr the function to add
|
||||
*
|
||||
* @returns
|
||||
* The function object created for 'fptr'
|
||||
*/
|
||||
pFunctionPointer_t fall_add_front(void (*fptr)(void)) {
|
||||
return fall_add_common(fptr, true);
|
||||
}
|
||||
void fall(void (*fptr)(void));
|
||||
|
||||
/** Attach a member function to call when a falling edge occurs on the input
|
||||
*
|
||||
* @param tptr pointer to the object to call the member function on
|
||||
* @param mptr pointer to the member function to be called
|
||||
*
|
||||
* @returns
|
||||
* The function object created for 'tptr' and 'mptr'
|
||||
*/
|
||||
template<typename T>
|
||||
pFunctionPointer_t fall(T* tptr, void (T::*mptr)(void)) {
|
||||
_fall.clear();
|
||||
pFunctionPointer_t pf = _fall.add(tptr, mptr);
|
||||
void fall(T* tptr, void (T::*mptr)(void)) {
|
||||
_fall.attach(tptr, mptr);
|
||||
gpio_irq_set(&gpio_irq, IRQ_FALL, 1);
|
||||
return pf;
|
||||
}
|
||||
|
||||
/** Add a function to be called when a falling edge occurs at the end of the call chain
|
||||
*
|
||||
* @param tptr pointer to the object to call the member function on
|
||||
* @param mptr pointer to the member function to be called
|
||||
*
|
||||
* @returns
|
||||
* The function object created for 'tptr' and 'mptr'
|
||||
*/
|
||||
template<typename T>
|
||||
pFunctionPointer_t fall_add(T* tptr, void (T::*mptr)(void)) {
|
||||
return fall_add_common(tptr, mptr);
|
||||
}
|
||||
|
||||
/** Add a function to be called when a falling edge occurs at the beginning of the call chain
|
||||
*
|
||||
* @param tptr pointer to the object to call the member function on
|
||||
* @param mptr pointer to the member function to be called
|
||||
*
|
||||
* @returns
|
||||
* The function object created for 'tptr' and 'mptr'
|
||||
*/
|
||||
template<typename T>
|
||||
pFunctionPointer_t fall_add_front(T* tptr, void (T::*mptr)(void)) {
|
||||
return fall_add_common(tptr, mptr, true);
|
||||
}
|
||||
|
||||
/** Remove a function from the list of functions to be called when a falling edge occurs
|
||||
*
|
||||
* @param pf the function object to remove
|
||||
*
|
||||
* @returns
|
||||
* true if the function was found and removed, false otherwise
|
||||
*/
|
||||
bool fall_remove(pFunctionPointer_t pf);
|
||||
|
||||
/** Set the input pin mode
|
||||
*
|
||||
* @param mode PullUp, PullDown, PullNone
|
||||
*/
|
||||
void mode(PinMode pull);
|
||||
|
||||
/** Enable IRQ
|
||||
*/
|
||||
void enable_irq();
|
||||
|
||||
/** Disable IRQ
|
||||
*/
|
||||
void disable_irq();
|
||||
|
||||
static void _irq_handler(uint32_t id, gpio_irq_event event);
|
||||
|
||||
protected:
|
||||
pFunctionPointer_t rise_add_common(void (*fptr)(void), bool front=false);
|
||||
pFunctionPointer_t fall_add_common(void (*fptr)(void), bool front=false);
|
||||
|
||||
template<typename T>
|
||||
pFunctionPointer_t rise_add_common(T* tptr, void (T::*mptr)(void), bool front=false) {
|
||||
pFunctionPointer_t pf = front ? _rise.add_front(tptr, mptr) : _rise.add(tptr, mptr);
|
||||
gpio_irq_set(&gpio_irq, IRQ_RISE, 1);
|
||||
return pf;
|
||||
}
|
||||
template<typename T>
|
||||
pFunctionPointer_t fall_add_common(T* tptr, void (T::*mptr)(void), bool front=false) {
|
||||
pFunctionPointer_t pf = front ? _fall.add_front(tptr, mptr) : _fall.add(tptr, mptr);
|
||||
gpio_irq_set(&gpio_irq, IRQ_FALL, 1);
|
||||
return pf;
|
||||
}
|
||||
|
||||
gpio_t gpio;
|
||||
gpio_irq_t gpio_irq;
|
||||
|
||||
CallChain _rise;
|
||||
CallChain _fall;
|
||||
FunctionPointer _rise;
|
||||
FunctionPointer _fall;
|
||||
};
|
||||
|
||||
} // namespace mbed
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2006-2013 ARM Limited
|
||||
*
|
||||
* 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 MBED_RAW_SERIAL_H
|
||||
#define MBED_RAW_SERIAL_H
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#if DEVICE_SERIAL
|
||||
|
||||
#include "SerialBase.h"
|
||||
#include "serial_api.h"
|
||||
|
||||
namespace mbed {
|
||||
|
||||
/** A serial port (UART) for communication with other serial devices
|
||||
* This is a variation of the Serial class that doesn't use streams,
|
||||
* thus making it safe to use in interrupt handlers with the RTOS.
|
||||
*
|
||||
* Can be used for Full Duplex communication, or Simplex by specifying
|
||||
* one pin as NC (Not Connected)
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* // Send a char to the PC
|
||||
*
|
||||
* #include "mbed.h"
|
||||
*
|
||||
* RawSerial pc(USBTX, USBRX);
|
||||
*
|
||||
* int main() {
|
||||
* pc.putc('A');
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
class RawSerial: public SerialBase {
|
||||
|
||||
public:
|
||||
/** Create a RawSerial port, connected to the specified transmit and receive pins
|
||||
*
|
||||
* @param tx Transmit pin
|
||||
* @param rx Receive pin
|
||||
*
|
||||
* @note
|
||||
* Either tx or rx may be specified as NC if unused
|
||||
*/
|
||||
RawSerial(PinName tx, PinName rx);
|
||||
|
||||
/** Write a char to the serial port
|
||||
*
|
||||
* @param c The char to write
|
||||
*
|
||||
* @returns The written char or -1 if an error occured
|
||||
*/
|
||||
int putc(int c);
|
||||
|
||||
/** Read a char from the serial port
|
||||
*
|
||||
* @returns The char read from the serial port
|
||||
*/
|
||||
int getc();
|
||||
};
|
||||
|
||||
} // namespace mbed
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -21,9 +21,8 @@
|
|||
#if DEVICE_SERIAL
|
||||
|
||||
#include "Stream.h"
|
||||
#include "FunctionPointer.h"
|
||||
#include "SerialBase.h"
|
||||
#include "serial_api.h"
|
||||
#include "CallChain.h"
|
||||
|
||||
namespace mbed {
|
||||
|
||||
|
@ -45,7 +44,7 @@ namespace mbed {
|
|||
* }
|
||||
* @endcode
|
||||
*/
|
||||
class Serial : public Stream {
|
||||
class Serial : public SerialBase, public Stream {
|
||||
|
||||
public:
|
||||
/** Create a Serial port, connected to the specified transmit and receive pins
|
||||
|
@ -58,167 +57,9 @@ public:
|
|||
*/
|
||||
Serial(PinName tx, PinName rx, const char *name=NULL);
|
||||
|
||||
/** Set the baud rate of the serial port
|
||||
*
|
||||
* @param baudrate The baudrate of the serial port (default = 9600).
|
||||
*/
|
||||
void baud(int baudrate);
|
||||
|
||||
enum Parity {
|
||||
None = 0,
|
||||
Odd,
|
||||
Even,
|
||||
Forced1,
|
||||
Forced0
|
||||
};
|
||||
|
||||
enum IrqType {
|
||||
RxIrq = 0,
|
||||
TxIrq
|
||||
};
|
||||
|
||||
/** Set the transmission format used by the Serial port
|
||||
*
|
||||
* @param bits The number of bits in a word (5-8; default = 8)
|
||||
* @param parity The parity used (Serial::None, Serial::Odd, Serial::Even, Serial::Forced1, Serial::Forced0; default = Serial::None)
|
||||
* @param stop The number of stop bits (1 or 2; default = 1)
|
||||
*/
|
||||
void format(int bits=8, Parity parity=Serial::None, int stop_bits=1);
|
||||
|
||||
/** Determine if there is a character available to read
|
||||
*
|
||||
* @returns
|
||||
* 1 if there is a character available to read,
|
||||
* 0 otherwise
|
||||
*/
|
||||
int readable();
|
||||
|
||||
/** Determine if there is space available to write a character
|
||||
*
|
||||
* @returns
|
||||
* 1 if there is space to write a character,
|
||||
* 0 otherwise
|
||||
*/
|
||||
int writeable();
|
||||
|
||||
/** Attach a function to call whenever a serial interrupt is generated
|
||||
*
|
||||
* @param fptr A pointer to a void function, or 0 to set as none
|
||||
* @param type Which serial interrupt to attach the member function to (Seriall::RxIrq for receive, TxIrq for transmit buffer empty)
|
||||
*
|
||||
* @returns
|
||||
* The function object created for 'fptr'
|
||||
*/
|
||||
pFunctionPointer_t attach(void (*fptr)(void), IrqType type=RxIrq);
|
||||
|
||||
/** Add a function to be called when a serial interrupt is generated at the end of the call chain
|
||||
*
|
||||
* @param fptr the function to add
|
||||
* @param type Which serial interrupt to attach the member function to (Seriall::RxIrq for receive, TxIrq for transmit buffer empty)
|
||||
*
|
||||
* @returns
|
||||
* The function object created for 'fptr'
|
||||
*/
|
||||
pFunctionPointer_t add_handler(void (*fptr)(void), IrqType type=RxIrq) {
|
||||
return add_handler_helper(fptr, type);
|
||||
}
|
||||
|
||||
/** Add a function to be called when a serial interrupt is generated at the beginning of the call chain
|
||||
*
|
||||
* @param fptr the function to add
|
||||
* @param type Which serial interrupt to attach the member function to (Seriall::RxIrq for receive, TxIrq for transmit buffer empty)
|
||||
*
|
||||
* @returns
|
||||
* The function object created for 'fptr'
|
||||
*/
|
||||
pFunctionPointer_t add_handler_front(void (*fptr)(void), IrqType type=RxIrq) {
|
||||
return add_handler_helper(fptr, type, true);
|
||||
}
|
||||
|
||||
/** Attach a member function to call whenever a serial interrupt is generated
|
||||
*
|
||||
* @param tptr pointer to the object to call the member function on
|
||||
* @param mptr pointer to the member function to be called
|
||||
* @param type Which serial interrupt to attach the member function to (Seriall::RxIrq for receive, TxIrq for transmit buffer empty)
|
||||
*
|
||||
* @param
|
||||
* The function object created for 'tptr' and 'mptr'
|
||||
*/
|
||||
template<typename T>
|
||||
pFunctionPointer_t attach(T* tptr, void (T::*mptr)(void), IrqType type=RxIrq) {
|
||||
if((mptr != NULL) && (tptr != NULL)) {
|
||||
_irq[type].clear();
|
||||
pFunctionPointer_t pf = _irq[type].add(tptr, mptr);
|
||||
serial_irq_set(&_serial, (SerialIrq)type, 1);
|
||||
return pf;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/** Add a function to be called when a serial interrupt is generated at the end of the call chain
|
||||
*
|
||||
* @param tptr pointer to the object to call the member function on
|
||||
* @param mptr pointer to the member function to be called
|
||||
* @param type Which serial interrupt to attach the member function to (Seriall::RxIrq for receive, TxIrq for transmit buffer empty)
|
||||
*
|
||||
* @returns
|
||||
* The function object created for 'fptr'
|
||||
*/
|
||||
template<typename T>
|
||||
pFunctionPointer_t add_handler(T* tptr, void (T::*mptr)(void), IrqType type=RxIrq) {
|
||||
return add_handler_helper(tptr, mptr, type);
|
||||
}
|
||||
|
||||
/** Add a function to be called when a serial interrupt is generated at the beginning of the call chain
|
||||
*
|
||||
* @param tptr pointer to the object to call the member function on
|
||||
* @param mptr pointer to the member function to be called
|
||||
* @param type Which serial interrupt to attach the member function to (Seriall::RxIrq for receive, TxIrq for transmit buffer empty)
|
||||
*
|
||||
* @returns
|
||||
* The function object created for 'fptr'
|
||||
*/
|
||||
template<typename T>
|
||||
pFunctionPointer_t add_handler_front(T* tptr, void (T::*mptr)(void), IrqType type=RxIrq) {
|
||||
return add_handler_helper(tptr, mptr, type, true);
|
||||
}
|
||||
|
||||
/** Remove a function from the list of functions to be called when a serial interrupt is generated
|
||||
*
|
||||
* @param pf the function object to remove
|
||||
* @param type Which serial interrupt to attach the member function to (Seriall::RxIrq for receive, TxIrq for transmit buffer empty)
|
||||
*
|
||||
* @returns
|
||||
* true if the function was found and removed, false otherwise
|
||||
*/
|
||||
bool remove_handler(pFunctionPointer_t pf, IrqType type=RxIrq);
|
||||
|
||||
/** Generate a break condition on the serial line
|
||||
*/
|
||||
void send_break();
|
||||
|
||||
static void _irq_handler(uint32_t id, SerialIrq irq_type);
|
||||
|
||||
protected:
|
||||
virtual int _getc();
|
||||
virtual int _putc(int c);
|
||||
pFunctionPointer_t add_handler_helper(void (*function)(void), IrqType type, bool front=false);
|
||||
|
||||
template<typename T>
|
||||
pFunctionPointer_t add_handler_helper(T* tptr, void (T::*mptr)(void), IrqType type, bool front=false) {
|
||||
if ((mptr != NULL) && (tptr != NULL)) {
|
||||
pFunctionPointer_t pf = front ? _irq[type].add_front(tptr, mptr) : _irq[type].add(tptr, mptr);
|
||||
serial_irq_set(&_serial, (SerialIrq)type, 1);
|
||||
return pf;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
serial_t _serial;
|
||||
CallChain _irq[2];
|
||||
int _baud;
|
||||
virtual int _putc(int c);
|
||||
};
|
||||
|
||||
} // namespace mbed
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2006-2013 ARM Limited
|
||||
*
|
||||
* 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 MBED_SERIALBASE_H
|
||||
#define MBED_SERIALBASE_H
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#if DEVICE_SERIAL
|
||||
|
||||
#include "Stream.h"
|
||||
#include "FunctionPointer.h"
|
||||
#include "serial_api.h"
|
||||
|
||||
namespace mbed {
|
||||
|
||||
/** A base class for serial port implementations
|
||||
* Can't be instantiated directly (use Serial or RawSerial)
|
||||
*/
|
||||
class SerialBase {
|
||||
|
||||
public:
|
||||
/** Set the baud rate of the serial port
|
||||
*
|
||||
* @param baudrate The baudrate of the serial port (default = 9600).
|
||||
*/
|
||||
void baud(int baudrate);
|
||||
|
||||
enum Parity {
|
||||
None = 0,
|
||||
Odd,
|
||||
Even,
|
||||
Forced1,
|
||||
Forced0
|
||||
};
|
||||
|
||||
enum IrqType {
|
||||
RxIrq = 0,
|
||||
TxIrq
|
||||
};
|
||||
|
||||
/** Set the transmission format used by the serial port
|
||||
*
|
||||
* @param bits The number of bits in a word (5-8; default = 8)
|
||||
* @param parity The parity used (SerialBase::None, SerialBase::Odd, SerialBase::Even, SerialBase::Forced1, SerialBase::Forced0; default = SerialBase::None)
|
||||
* @param stop The number of stop bits (1 or 2; default = 1)
|
||||
*/
|
||||
void format(int bits=8, Parity parity=SerialBase::None, int stop_bits=1);
|
||||
|
||||
/** Determine if there is a character available to read
|
||||
*
|
||||
* @returns
|
||||
* 1 if there is a character available to read,
|
||||
* 0 otherwise
|
||||
*/
|
||||
int readable();
|
||||
|
||||
/** Determine if there is space available to write a character
|
||||
*
|
||||
* @returns
|
||||
* 1 if there is space to write a character,
|
||||
* 0 otherwise
|
||||
*/
|
||||
int writeable();
|
||||
|
||||
/** Attach a function to call whenever a serial interrupt is generated
|
||||
*
|
||||
* @param fptr A pointer to a void function, or 0 to set as none
|
||||
* @param type Which serial interrupt to attach the member function to (Seriall::RxIrq for receive, TxIrq for transmit buffer empty)
|
||||
*/
|
||||
void attach(void (*fptr)(void), IrqType type=RxIrq);
|
||||
|
||||
/** Attach a member function to call whenever a serial interrupt is generated
|
||||
*
|
||||
* @param tptr pointer to the object to call the member function on
|
||||
* @param mptr pointer to the member function to be called
|
||||
* @param type Which serial interrupt to attach the member function to (Seriall::RxIrq for receive, TxIrq for transmit buffer empty)
|
||||
*/
|
||||
template<typename T>
|
||||
void attach(T* tptr, void (T::*mptr)(void), IrqType type=RxIrq) {
|
||||
if((mptr != NULL) && (tptr != NULL)) {
|
||||
_irq[type].attach(tptr, mptr);
|
||||
serial_irq_set(&_serial, (SerialIrq)type, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/** Generate a break condition on the serial line
|
||||
*/
|
||||
void send_break();
|
||||
|
||||
static void _irq_handler(uint32_t id, SerialIrq irq_type);
|
||||
|
||||
protected:
|
||||
SerialBase(PinName tx, PinName rx);
|
||||
|
||||
int _base_getc();
|
||||
int _base_putc(int c);
|
||||
|
||||
serial_t _serial;
|
||||
FunctionPointer _irq[2];
|
||||
int _baud;
|
||||
};
|
||||
|
||||
} // namespace mbed
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
#include "TimerEvent.h"
|
||||
#include "FunctionPointer.h"
|
||||
#include "CallChain.h"
|
||||
|
||||
namespace mbed {
|
||||
|
||||
|
@ -63,34 +62,9 @@ public:
|
|||
*
|
||||
* @param fptr pointer to the function to be called
|
||||
* @param t the time between calls in seconds
|
||||
*
|
||||
* @returns
|
||||
* The function object created for 'fptr'
|
||||
*/
|
||||
pFunctionPointer_t attach(void (*fptr)(void), float t) {
|
||||
return attach_us(fptr, t * 1000000.0f);
|
||||
}
|
||||
|
||||
/** Add a function to be called by the Ticker at the end of the call chain
|
||||
*
|
||||
* @param fptr the function to add
|
||||
*
|
||||
* @returns
|
||||
* The function object created for 'fptr'
|
||||
*/
|
||||
pFunctionPointer_t add_function(void (*fptr)(void)) {
|
||||
return add_function_helper(fptr);
|
||||
}
|
||||
|
||||
/** Add a function to be called by the Ticker at the beginning of the call chain
|
||||
*
|
||||
* @param fptr the function to add
|
||||
*
|
||||
* @returns
|
||||
* The function object created for 'fptr'
|
||||
*/
|
||||
pFunctionPointer_t add_function_front(void (*fptr)(void)) {
|
||||
return add_function_helper(fptr, true);
|
||||
void attach(void (*fptr)(void), float t) {
|
||||
attach_us(fptr, t * 1000000.0f);
|
||||
}
|
||||
|
||||
/** Attach a member function to be called by the Ticker, specifiying the interval in seconds
|
||||
|
@ -98,54 +72,20 @@ public:
|
|||
* @param tptr pointer to the object to call the member function on
|
||||
* @param mptr pointer to the member function to be called
|
||||
* @param t the time between calls in seconds
|
||||
*
|
||||
* @returns
|
||||
* The function object created for 'tptr' and 'mptr'
|
||||
*/
|
||||
template<typename T>
|
||||
pFunctionPointer_t attach(T* tptr, void (T::*mptr)(void), float t) {
|
||||
return attach_us(tptr, mptr, t * 1000000.0f);
|
||||
}
|
||||
|
||||
/** Add a function to be called by the Ticker at the end of the call chain
|
||||
*
|
||||
* @param tptr pointer to the object to call the member function on
|
||||
* @param mptr pointer to the member function to be called
|
||||
*
|
||||
* @returns
|
||||
* The function object created for 'tptr' and 'mptr'
|
||||
*/
|
||||
template<typename T>
|
||||
pFunctionPointer_t add_function(T* tptr, void (T::*mptr)(void)) {
|
||||
return add_function_helper(tptr, mptr);
|
||||
}
|
||||
|
||||
/** Add a function to be called by the Ticker at the beginning of the call chain
|
||||
*
|
||||
* @param tptr pointer to the object to call the member function on
|
||||
* @param mptr pointer to the member function to be called
|
||||
*
|
||||
* @returns
|
||||
* The function object created for 'tptr' and 'mptr'
|
||||
*/
|
||||
template<typename T>
|
||||
pFunctionPointer_t add_function_front(T* tptr, void (T::*mptr)(void)) {
|
||||
return add_function_helper(tptr, mptr, true);
|
||||
void attach(T* tptr, void (T::*mptr)(void), float t) {
|
||||
attach_us(tptr, mptr, t * 1000000.0f);
|
||||
}
|
||||
|
||||
/** Attach a function to be called by the Ticker, specifiying the interval in micro-seconds
|
||||
*
|
||||
* @param fptr pointer to the function to be called
|
||||
* @param t the time between calls in micro-seconds
|
||||
*
|
||||
* @returns
|
||||
* The function object created for 'fptr'
|
||||
*/
|
||||
pFunctionPointer_t attach_us(void (*fptr)(void), unsigned int t) {
|
||||
_chain.clear();
|
||||
pFunctionPointer_t pf = _chain.add(fptr);
|
||||
void attach_us(void (*fptr)(void), unsigned int t) {
|
||||
_function.attach(fptr);
|
||||
setup(t);
|
||||
return pf;
|
||||
}
|
||||
|
||||
/** Attach a member function to be called by the Ticker, specifiying the interval in micro-seconds
|
||||
|
@ -153,50 +93,23 @@ public:
|
|||
* @param tptr pointer to the object to call the member function on
|
||||
* @param mptr pointer to the member function to be called
|
||||
* @param t the time between calls in micro-seconds
|
||||
*
|
||||
* @returns
|
||||
* The function object created for 'tptr' and 'mptr'
|
||||
*/
|
||||
template<typename T>
|
||||
pFunctionPointer_t attach_us(T* tptr, void (T::*mptr)(void), unsigned int t) {
|
||||
_chain.clear();
|
||||
pFunctionPointer_t pf = _chain.add(tptr, mptr);
|
||||
void attach_us(T* tptr, void (T::*mptr)(void), unsigned int t) {
|
||||
_function.attach(tptr, mptr);
|
||||
setup(t);
|
||||
return pf;
|
||||
}
|
||||
|
||||
/** Detach the function
|
||||
*/
|
||||
void detach();
|
||||
|
||||
/** Remove a function from the Ticker's call chain
|
||||
*
|
||||
* @param pf the function object to remove
|
||||
*
|
||||
* @returns
|
||||
* true if the function was found and removed, false otherwise
|
||||
*/
|
||||
bool remove_function(pFunctionPointer_t pf) {
|
||||
bool res = _chain.remove(pf);
|
||||
if (res && _chain.size() == 0)
|
||||
detach();
|
||||
return res;
|
||||
}
|
||||
|
||||
protected:
|
||||
void setup(unsigned int t);
|
||||
pFunctionPointer_t add_function_helper(void (*fptr)(void), bool front=false);
|
||||
virtual void handler();
|
||||
|
||||
template<typename T>
|
||||
pFunctionPointer_t add_function_helper(T* tptr, void (T::*mptr)(void), bool front=false) {
|
||||
if (_chain.size() == 0)
|
||||
return NULL;
|
||||
return front ? _chain.add_front(tptr, mptr) : _chain.add(tptr, mptr);
|
||||
}
|
||||
|
||||
unsigned int _delay;
|
||||
CallChain _chain;
|
||||
FunctionPointer _function;
|
||||
};
|
||||
|
||||
} // namespace mbed
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include "I2CSlave.h"
|
||||
#include "Ethernet.h"
|
||||
#include "CAN.h"
|
||||
#include "RawSerial.h"
|
||||
|
||||
// mbed Internal components
|
||||
#include "Timer.h"
|
||||
|
|
|
@ -38,13 +38,11 @@ int CallChain::find(pFunctionPointer_t f) const {
|
|||
}
|
||||
|
||||
void CallChain::clear() {
|
||||
__disable_irq();
|
||||
for(int i = 0; i < _elements; i ++) {
|
||||
delete _chain[i];
|
||||
_chain[i] = NULL;
|
||||
}
|
||||
_elements = 0;
|
||||
__enable_irq();
|
||||
}
|
||||
|
||||
bool CallChain::remove(pFunctionPointer_t f) {
|
||||
|
@ -52,12 +50,10 @@ bool CallChain::remove(pFunctionPointer_t f) {
|
|||
|
||||
if ((i = find(f)) == -1)
|
||||
return false;
|
||||
__disable_irq();
|
||||
if (i != _elements - 1)
|
||||
memmove(_chain + i, _chain + i + 1, (_elements - i - 1) * sizeof(pFunctionPointer_t));
|
||||
delete f;
|
||||
_elements --;
|
||||
__enable_irq();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -69,13 +65,11 @@ void CallChain::call() {
|
|||
void CallChain::_check_size() {
|
||||
if (_elements < _size)
|
||||
return;
|
||||
__disable_irq();
|
||||
_size = (_size < 4) ? 4 : _size + 4;
|
||||
pFunctionPointer_t* new_chain = new pFunctionPointer_t[_size]();
|
||||
memcpy(new_chain, _chain, _elements * sizeof(pFunctionPointer_t));
|
||||
delete _chain;
|
||||
_chain = new_chain;
|
||||
__enable_irq();
|
||||
}
|
||||
|
||||
pFunctionPointer_t CallChain::common_add(pFunctionPointer_t pf) {
|
||||
|
@ -87,11 +81,9 @@ pFunctionPointer_t CallChain::common_add(pFunctionPointer_t pf) {
|
|||
|
||||
pFunctionPointer_t CallChain::common_add_front(pFunctionPointer_t pf) {
|
||||
_check_size();
|
||||
__disable_irq();
|
||||
memmove(_chain + 1, _chain, _elements * sizeof(pFunctionPointer_t));
|
||||
_chain[0] = pf;
|
||||
_elements ++;
|
||||
__enable_irq();
|
||||
return pf;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,58 +36,22 @@ void InterruptIn::mode(PinMode pull) {
|
|||
gpio_mode(&gpio, pull);
|
||||
}
|
||||
|
||||
pFunctionPointer_t InterruptIn::rise(void (*fptr)(void)) {
|
||||
pFunctionPointer_t pf = NULL;
|
||||
_rise.clear();
|
||||
void InterruptIn::rise(void (*fptr)(void)) {
|
||||
if (fptr) {
|
||||
pf = _rise.add(fptr);
|
||||
_rise.attach(fptr);
|
||||
gpio_irq_set(&gpio_irq, IRQ_RISE, 1);
|
||||
} else {
|
||||
gpio_irq_set(&gpio_irq, IRQ_RISE, 0);
|
||||
}
|
||||
return pf;
|
||||
}
|
||||
|
||||
pFunctionPointer_t InterruptIn::rise_add_common(void (*fptr)(void), bool front) {
|
||||
if (NULL == fptr)
|
||||
return NULL;
|
||||
pFunctionPointer_t pf = front ? _rise.add_front(fptr) : _rise.add(fptr);
|
||||
gpio_irq_set(&gpio_irq, IRQ_RISE, 1);
|
||||
return pf;
|
||||
}
|
||||
|
||||
bool InterruptIn::rise_remove(pFunctionPointer_t pf) {
|
||||
bool res = _rise.remove(pf);
|
||||
if (res && _rise.size() == 0)
|
||||
gpio_irq_set(&gpio_irq, IRQ_RISE, 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
pFunctionPointer_t InterruptIn::fall(void (*fptr)(void)) {
|
||||
pFunctionPointer_t pf = NULL;
|
||||
_fall.clear();
|
||||
void InterruptIn::fall(void (*fptr)(void)) {
|
||||
if (fptr) {
|
||||
pf = _fall.add(fptr);
|
||||
_fall.attach(fptr);
|
||||
gpio_irq_set(&gpio_irq, IRQ_FALL, 1);
|
||||
} else {
|
||||
gpio_irq_set(&gpio_irq, IRQ_FALL, 0);
|
||||
}
|
||||
return pf;
|
||||
}
|
||||
|
||||
pFunctionPointer_t InterruptIn::fall_add_common(void (*fptr)(void), bool front) {
|
||||
if (NULL == fptr)
|
||||
return NULL;
|
||||
pFunctionPointer_t pf = front ? _fall.add_front(fptr) : _fall.add(fptr);
|
||||
gpio_irq_set(&gpio_irq, IRQ_FALL, 1);
|
||||
return pf;
|
||||
}
|
||||
|
||||
bool InterruptIn::fall_remove(pFunctionPointer_t pf) {
|
||||
bool res = _fall.remove(pf);
|
||||
if (res && _fall.size() == 0)
|
||||
gpio_irq_set(&gpio_irq, IRQ_FALL, 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
void InterruptIn::_irq_handler(uint32_t id, gpio_irq_event event) {
|
||||
|
@ -99,6 +63,14 @@ void InterruptIn::_irq_handler(uint32_t id, gpio_irq_event event) {
|
|||
}
|
||||
}
|
||||
|
||||
void InterruptIn::enable_irq() {
|
||||
gpio_irq_enable(&gpio_irq);
|
||||
}
|
||||
|
||||
void InterruptIn::disable_irq() {
|
||||
gpio_irq_disable(&gpio_irq);
|
||||
}
|
||||
|
||||
#ifdef MBED_OPERATORS
|
||||
InterruptIn::operator int() {
|
||||
return read();
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2006-2013 ARM Limited
|
||||
*
|
||||
* 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 "RawSerial.h"
|
||||
#include "wait_api.h"
|
||||
|
||||
#if DEVICE_SERIAL
|
||||
|
||||
namespace mbed {
|
||||
|
||||
RawSerial::RawSerial(PinName tx, PinName rx) : SerialBase(tx, rx) {
|
||||
}
|
||||
|
||||
int RawSerial::getc() {
|
||||
return _base_getc();
|
||||
}
|
||||
|
||||
int RawSerial::putc(int c) {
|
||||
return _base_putc(c);
|
||||
}
|
||||
|
||||
} // namespace mbed
|
||||
|
||||
#endif
|
|
@ -20,83 +20,15 @@
|
|||
|
||||
namespace mbed {
|
||||
|
||||
Serial::Serial(PinName tx, PinName rx, const char *name) : Stream(name) {
|
||||
serial_init(&_serial, tx, rx);
|
||||
_baud = 9600;
|
||||
serial_irq_handler(&_serial, Serial::_irq_handler, (uint32_t)this);
|
||||
}
|
||||
|
||||
void Serial::baud(int baudrate) {
|
||||
serial_baud(&_serial, baudrate);
|
||||
_baud = baudrate;
|
||||
}
|
||||
|
||||
void Serial::format(int bits, Parity parity, int stop_bits) {
|
||||
serial_format(&_serial, bits, (SerialParity)parity, stop_bits);
|
||||
}
|
||||
|
||||
int Serial::readable() {
|
||||
return serial_readable(&_serial);
|
||||
}
|
||||
|
||||
|
||||
int Serial::writeable() {
|
||||
return serial_writable(&_serial);
|
||||
}
|
||||
|
||||
pFunctionPointer_t Serial::attach(void (*fptr)(void), IrqType type) {
|
||||
pFunctionPointer_t pf = NULL;
|
||||
_irq[type].clear();
|
||||
if (fptr) {
|
||||
pf = _irq[type].add(fptr);
|
||||
serial_irq_set(&_serial, (SerialIrq)type, 1);
|
||||
} else {
|
||||
serial_irq_set(&_serial, (SerialIrq)type, 0);
|
||||
}
|
||||
return pf;
|
||||
}
|
||||
|
||||
pFunctionPointer_t Serial::add_handler_helper(void (*fptr)(void), IrqType type, bool front) {
|
||||
if (NULL == fptr)
|
||||
return NULL;
|
||||
pFunctionPointer_t pf = front ? _irq[type].add_front(fptr) : _irq[type].add(fptr);
|
||||
serial_irq_set(&_serial, (SerialIrq)type, 1);
|
||||
return pf;
|
||||
}
|
||||
|
||||
bool Serial::remove_handler(pFunctionPointer_t pf, IrqType type) {
|
||||
bool res = _irq[type].remove(pf);
|
||||
if (res && _irq[type].size() == 0)
|
||||
serial_irq_set(&_serial, (SerialIrq)type, 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
void Serial::_irq_handler(uint32_t id, SerialIrq irq_type) {
|
||||
Serial *handler = (Serial*)id;
|
||||
handler->_irq[irq_type].call();
|
||||
Serial::Serial(PinName tx, PinName rx, const char *name) : SerialBase(tx, rx), Stream(name) {
|
||||
}
|
||||
|
||||
int Serial::_getc() {
|
||||
return serial_getc(&_serial);
|
||||
return _base_getc();
|
||||
}
|
||||
|
||||
int Serial::_putc(int c) {
|
||||
serial_putc(&_serial, c);
|
||||
return c;
|
||||
}
|
||||
|
||||
void Serial::send_break() {
|
||||
// Wait for 1.5 frames before clearing the break condition
|
||||
// This will have different effects on our platforms, but should
|
||||
// ensure that we keep the break active for at least one frame.
|
||||
// We consider a full frame (1 start bit + 8 data bits bits +
|
||||
// 1 parity bit + 2 stop bits = 12 bits) for computation.
|
||||
// One bit time (in us) = 1000000/_baud
|
||||
// Twelve bits: 12000000/baud delay
|
||||
// 1.5 frames: 18000000/baud delay
|
||||
serial_break_set(&_serial);
|
||||
wait_us(18000000/_baud);
|
||||
serial_break_clear(&_serial);
|
||||
return _base_putc(c);
|
||||
}
|
||||
|
||||
} // namespace mbed
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
/* mbed Microcontroller Library
|
||||
* Copyright (c) 2006-2013 ARM Limited
|
||||
*
|
||||
* 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 "SerialBase.h"
|
||||
#include "wait_api.h"
|
||||
|
||||
#if DEVICE_SERIAL
|
||||
|
||||
namespace mbed {
|
||||
|
||||
SerialBase::SerialBase(PinName tx, PinName rx) {
|
||||
serial_init(&_serial, tx, rx);
|
||||
_baud = 9600;
|
||||
serial_irq_handler(&_serial, SerialBase::_irq_handler, (uint32_t)this);
|
||||
}
|
||||
|
||||
void SerialBase::baud(int baudrate) {
|
||||
serial_baud(&_serial, baudrate);
|
||||
_baud = baudrate;
|
||||
}
|
||||
|
||||
void SerialBase::format(int bits, Parity parity, int stop_bits) {
|
||||
serial_format(&_serial, bits, (SerialParity)parity, stop_bits);
|
||||
}
|
||||
|
||||
int SerialBase::readable() {
|
||||
return serial_readable(&_serial);
|
||||
}
|
||||
|
||||
|
||||
int SerialBase::writeable() {
|
||||
return serial_writable(&_serial);
|
||||
}
|
||||
|
||||
void SerialBase::attach(void (*fptr)(void), IrqType type) {
|
||||
if (fptr) {
|
||||
_irq[type].attach(fptr);
|
||||
serial_irq_set(&_serial, (SerialIrq)type, 1);
|
||||
} else {
|
||||
serial_irq_set(&_serial, (SerialIrq)type, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void SerialBase::_irq_handler(uint32_t id, SerialIrq irq_type) {
|
||||
SerialBase *handler = (SerialBase*)id;
|
||||
handler->_irq[irq_type].call();
|
||||
}
|
||||
|
||||
int SerialBase::_base_getc() {
|
||||
return serial_getc(&_serial);
|
||||
}
|
||||
|
||||
int SerialBase::_base_putc(int c) {
|
||||
serial_putc(&_serial, c);
|
||||
return c;
|
||||
}
|
||||
|
||||
void SerialBase::send_break() {
|
||||
// Wait for 1.5 frames before clearing the break condition
|
||||
// This will have different effects on our platforms, but should
|
||||
// ensure that we keep the break active for at least one frame.
|
||||
// We consider a full frame (1 start bit + 8 data bits bits +
|
||||
// 1 parity bit + 2 stop bits = 12 bits) for computation.
|
||||
// One bit time (in us) = 1000000/_baud
|
||||
// Twelve bits: 12000000/baud delay
|
||||
// 1.5 frames: 18000000/baud delay
|
||||
serial_break_set(&_serial);
|
||||
wait_us(18000000/_baud);
|
||||
serial_break_clear(&_serial);
|
||||
}
|
||||
|
||||
} // namespace mbed
|
||||
|
||||
#endif
|
|
@ -22,7 +22,7 @@ namespace mbed {
|
|||
|
||||
void Ticker::detach() {
|
||||
remove();
|
||||
_chain.clear();
|
||||
_function.attach(0);
|
||||
}
|
||||
|
||||
void Ticker::setup(unsigned int t) {
|
||||
|
@ -33,13 +33,7 @@ void Ticker::setup(unsigned int t) {
|
|||
|
||||
void Ticker::handler() {
|
||||
insert(event.timestamp + _delay);
|
||||
_chain.call();
|
||||
}
|
||||
|
||||
pFunctionPointer_t Ticker::add_function_helper(void (*fptr)(void), bool front) {
|
||||
if (_chain.size() == 0)
|
||||
return NULL;
|
||||
return front ? _chain.add_front(fptr) : _chain.add(fptr);
|
||||
_function.call();
|
||||
}
|
||||
|
||||
} // namespace mbed
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
namespace mbed {
|
||||
|
||||
void Timeout::handler() {
|
||||
_chain.call();
|
||||
_function.call();
|
||||
}
|
||||
|
||||
} // namespace mbed
|
||||
|
|
|
@ -37,6 +37,8 @@ typedef void (*gpio_irq_handler)(uint32_t id, gpio_irq_event event);
|
|||
int gpio_irq_init(gpio_irq_t *obj, PinName pin, gpio_irq_handler handler, uint32_t id);
|
||||
void gpio_irq_free(gpio_irq_t *obj);
|
||||
void gpio_irq_set (gpio_irq_t *obj, gpio_irq_event event, uint32_t enable);
|
||||
void gpio_irq_enable(gpio_irq_t *obj);
|
||||
void gpio_irq_disable(gpio_irq_t *obj);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -154,3 +154,19 @@ void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable) {
|
|||
// Interrupt configuration and clear interrupt
|
||||
port->PCR[obj->pin] = (port->PCR[obj->pin] & ~PORT_PCR_IRQC_MASK) | irq_settings | PORT_PCR_ISF_MASK;
|
||||
}
|
||||
|
||||
void gpio_irq_enable(gpio_irq_t *obj) {
|
||||
if (obj->port == PortA) {
|
||||
NVIC_EnableIRQ(PORTA_IRQn);
|
||||
} else if (obj->port == PortB) {
|
||||
NVIC_EnableIRQ(PORTB_IRQn);
|
||||
}
|
||||
}
|
||||
|
||||
void gpio_irq_disable(gpio_irq_t *obj) {
|
||||
if (obj->port == PortA) {
|
||||
NVIC_DisableIRQ(PORTA_IRQn);
|
||||
} else if (obj->port == PortB) {
|
||||
NVIC_DisableIRQ(PORTB_IRQn);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -143,3 +143,19 @@ void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable) {
|
|||
// Interrupt configuration and clear interrupt
|
||||
port->PCR[obj->pin] = (port->PCR[obj->pin] & ~PORT_PCR_IRQC_MASK) | irq_settings | PORT_PCR_ISF_MASK;
|
||||
}
|
||||
|
||||
void gpio_irq_enable(gpio_irq_t *obj) {
|
||||
if (obj->port == PortA) {
|
||||
NVIC_EnableIRQ(PORTA_IRQn);
|
||||
} else if (obj->port == PortD) {
|
||||
NVIC_EnableIRQ(PORTD_IRQn);
|
||||
}
|
||||
}
|
||||
|
||||
void gpio_irq_disable(gpio_irq_t *obj) {
|
||||
if (obj->port == PortA) {
|
||||
NVIC_DisableIRQ(PORTA_IRQn);
|
||||
} else if (obj->port == PortD) {
|
||||
NVIC_DisableIRQ(PORTD_IRQn);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -143,3 +143,19 @@ void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable) {
|
|||
// Interrupt configuration and clear interrupt
|
||||
port->PCR[obj->pin] = (port->PCR[obj->pin] & ~PORT_PCR_IRQC_MASK) | irq_settings | PORT_PCR_ISF_MASK;
|
||||
}
|
||||
|
||||
void gpio_irq_enable(gpio_irq_t *obj) {
|
||||
if (obj->port == PortA) {
|
||||
NVIC_EnableIRQ(PORTA_IRQn);
|
||||
} else if (obj->port == PortD) {
|
||||
NVIC_EnableIRQ(PORTD_IRQn);
|
||||
}
|
||||
}
|
||||
|
||||
void gpio_irq_disable(gpio_irq_t *obj) {
|
||||
if (obj->port == PortA) {
|
||||
NVIC_DisableIRQ(PORTA_IRQn);
|
||||
} else if (obj->port == PortD) {
|
||||
NVIC_DisableIRQ(PORTD_IRQn);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -131,3 +131,11 @@ void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gpio_irq_enable(gpio_irq_t *obj) {
|
||||
NVIC_EnableIRQ((IRQn_Type)(PININT_IRQ + obj->ch));
|
||||
}
|
||||
|
||||
void gpio_irq_disable(gpio_irq_t *obj) {
|
||||
NVIC_DisableIRQ((IRQn_Type)(PININT_IRQ + obj->ch));
|
||||
}
|
||||
|
|
|
@ -174,3 +174,43 @@ void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable) {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
void gpio_irq_enable(gpio_irq_t *obj) {
|
||||
uint32_t port_num = ((obj->pin & 0xF000) >> PORT_SHIFT);
|
||||
switch (port_num) {
|
||||
case 0:
|
||||
NVIC_EnableIRQ(EINT0_IRQn);
|
||||
break;
|
||||
case 1:
|
||||
NVIC_EnableIRQ(EINT1_IRQn);
|
||||
break;
|
||||
case 2:
|
||||
NVIC_EnableIRQ(EINT2_IRQn);
|
||||
break;
|
||||
case 3:
|
||||
NVIC_EnableIRQ(EINT3_IRQn);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void gpio_irq_disable(gpio_irq_t *obj) {
|
||||
uint32_t port_num = ((obj->pin & 0xF000) >> PORT_SHIFT);
|
||||
switch (port_num) {
|
||||
case 0:
|
||||
NVIC_DisableIRQ(EINT0_IRQn);
|
||||
break;
|
||||
case 1:
|
||||
NVIC_DisableIRQ(EINT1_IRQn);
|
||||
break;
|
||||
case 2:
|
||||
NVIC_DisableIRQ(EINT2_IRQn);
|
||||
break;
|
||||
case 3:
|
||||
NVIC_DisableIRQ(EINT3_IRQn);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -131,3 +131,12 @@ void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gpio_irq_enable(gpio_irq_t *obj) {
|
||||
NVIC_EnableIRQ((IRQn_Type)(PININT_IRQ + obj->ch));
|
||||
}
|
||||
|
||||
void gpio_irq_disable(gpio_irq_t *obj) {
|
||||
NVIC_DisableIRQ((IRQn_Type)(PININT_IRQ + obj->ch));
|
||||
}
|
||||
|
||||
|
|
|
@ -150,3 +150,12 @@ void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gpio_irq_enable(gpio_irq_t *obj) {
|
||||
NVIC_EnableIRQ(EINT3_IRQn);
|
||||
}
|
||||
|
||||
void gpio_irq_disable(gpio_irq_t *obj) {
|
||||
NVIC_DisableIRQ(EINT3_IRQn);
|
||||
}
|
||||
|
||||
|
|
|
@ -143,3 +143,12 @@ void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gpio_irq_enable(gpio_irq_t *obj) {
|
||||
NVIC_EnableIRQ(EINT3_IRQn);
|
||||
}
|
||||
|
||||
void gpio_irq_disable(gpio_irq_t *obj) {
|
||||
NVIC_DisableIRQ(EINT3_IRQn);
|
||||
}
|
||||
|
||||
|
|
|
@ -164,3 +164,11 @@ void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gpio_irq_enable(gpio_irq_t *obj) {
|
||||
NVIC_EnableIRQ(GPIO_IRQn);
|
||||
}
|
||||
|
||||
void gpio_irq_disable(gpio_irq_t *obj) {
|
||||
NVIC_DisableIRQ(GPIO_IRQn);
|
||||
}
|
||||
|
|
|
@ -134,3 +134,19 @@ void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gpio_irq_enable(gpio_irq_t *obj) {
|
||||
#if !defined(CORE_M0)
|
||||
NVIC_EnableIRQ((IRQn_Type)(PIN_INT0_IRQn + obj->ch));
|
||||
#else
|
||||
NVIC_EnableIRQ((IRQn_Type)(PIN_INT4_IRQn + obj->ch));
|
||||
#endif
|
||||
}
|
||||
|
||||
void gpio_irq_disable(gpio_irq_t *obj) {
|
||||
#if !defined(CORE_M0)
|
||||
NVIC_DisableIRQ((IRQn_Type)(PIN_INT0_IRQn + obj->ch));
|
||||
#else
|
||||
NVIC_DisableIRQ((IRQn_Type)(PIN_INT4_IRQn + obj->ch));
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
|
||||
#define DEVICE_DEBUG_AWARENESS 0
|
||||
|
||||
#define DEVICE_STDIO_MESSAGES 1
|
||||
#define DEVICE_STDIO_MESSAGES 0
|
||||
|
||||
#define DEVICE_ERROR_RED 1
|
||||
|
||||
|
|
|
@ -125,3 +125,11 @@ void gpio_irq_set(gpio_irq_t *obj, gpio_irq_event event, uint32_t enable) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gpio_irq_enable(gpio_irq_t *obj) {
|
||||
NVIC_EnableIRQ((IRQn_Type)(PININT_IRQ + obj->ch));
|
||||
}
|
||||
|
||||
void gpio_irq_disable(gpio_irq_t *obj) {
|
||||
NVIC_DisableIRQ((IRQn_Type)(PININT_IRQ + obj->ch));
|
||||
}
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
/* IUSBHostSerial.h */
|
||||
/* Copyright (c) 2010-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 IUSBHOSTSERIAL_H_
|
||||
#define IUSBHOSTSERIAL_H_
|
||||
|
||||
/**
|
||||
* Generic interface to abstract 3G dongles' impl
|
||||
*/
|
||||
|
||||
#include "IUSBHostSerialListener.h"
|
||||
|
||||
class IUSBHostSerial {
|
||||
public:
|
||||
|
||||
enum IrqType {
|
||||
RxIrq,
|
||||
TxIrq
|
||||
};
|
||||
|
||||
/*
|
||||
* Get a char from the dongle's serial interface
|
||||
*/
|
||||
virtual int getc() = 0;
|
||||
|
||||
/*
|
||||
* Put a char to the dongle's serial interface
|
||||
*/
|
||||
virtual int putc(int c) = 0;
|
||||
|
||||
/*
|
||||
* Read a packet from the dongle's serial interface, to be called after multiple getc() calls
|
||||
*/
|
||||
virtual int readPacket() = 0;
|
||||
|
||||
/*
|
||||
* Write a packet to the dongle's serial interface, to be called after multiple putc() calls
|
||||
*/
|
||||
virtual int writePacket() = 0;
|
||||
|
||||
/**
|
||||
* Check the number of bytes available.
|
||||
*
|
||||
* @returns the number of bytes available
|
||||
*/
|
||||
virtual int readable() = 0;
|
||||
|
||||
/**
|
||||
* Check the free space in output.
|
||||
*
|
||||
* @returns the number of bytes available
|
||||
*/
|
||||
virtual int writeable() = 0;
|
||||
|
||||
/**
|
||||
* Attach a handler to call when a packet is received / when a packet has been transmitted.
|
||||
*
|
||||
* @param pListener instance of the listener deriving from the IUSBHostSerialListener
|
||||
*/
|
||||
virtual void attach(IUSBHostSerialListener* pListener) = 0;
|
||||
|
||||
/**
|
||||
* Enable or disable readable/writeable callbacks
|
||||
*/
|
||||
virtual void setupIrq(bool en, IrqType irq = RxIrq) = 0;
|
||||
|
||||
};
|
||||
|
||||
#endif /* IUSBHOSTSERIAL_H_ */
|
|
@ -1,32 +0,0 @@
|
|||
/* IUSBHostSerialListener.h */
|
||||
/* Copyright (c) 2010-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 IUSBHOSTSERIALLISTENER_H_
|
||||
#define IUSBHOSTSERIALLISTENER_H_
|
||||
|
||||
class IUSBHostSerialListener
|
||||
{
|
||||
public:
|
||||
virtual void readable() = 0; //Called when new data is available
|
||||
virtual void writeable() = 0; //Called when new space is available
|
||||
};
|
||||
|
||||
|
||||
#endif /* IUSBHOSTSERIALLISTENER_H_ */
|
|
@ -1,230 +0,0 @@
|
|||
/* Copyright (c) 2010-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
|
||||
#ifndef __MODULE__
|
||||
#define __MODULE__ "WANDongle.cpp"
|
||||
#endif
|
||||
|
||||
#include "core/dbg.h"
|
||||
#include <cstdint>
|
||||
#include "rtos.h"
|
||||
|
||||
#include "WANDongle.h"
|
||||
#include "WANDongleInitializer.h"
|
||||
|
||||
WANDongle::WANDongle() : m_pInitializer(NULL), m_serialCount(0)
|
||||
{
|
||||
host = USBHost::getHostInst();
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
bool WANDongle::connected() {
|
||||
return dev_connected;
|
||||
}
|
||||
|
||||
bool WANDongle::tryConnect()
|
||||
{
|
||||
//FIXME should run on USB thread
|
||||
|
||||
DBG("Trying to connect device");
|
||||
|
||||
if (dev_connected) {
|
||||
return true;
|
||||
}
|
||||
|
||||
m_pInitializer = NULL;
|
||||
|
||||
host->lock();
|
||||
|
||||
for (int i = 0; i < MAX_DEVICE_NB; i++)
|
||||
{
|
||||
if ((dev = host->getDevice(i)) != NULL)
|
||||
{
|
||||
m_pInitializer = NULL; //Will be set in setVidPid callback
|
||||
|
||||
DBG("Found one device reset it");
|
||||
int ret = host->resetDevice(dev);
|
||||
if(ret)
|
||||
{
|
||||
host->unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
DBG("Enumerate");
|
||||
ret = host->enumerate(dev, this);
|
||||
if(ret)
|
||||
{
|
||||
host->unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
DBG("Device has VID:%04x PID:%04x", dev->getVid(), dev->getPid());
|
||||
|
||||
if(m_pInitializer) //If an initializer has been found
|
||||
{
|
||||
DBG("m_pInitializer=%p", m_pInitializer);
|
||||
DBG("m_pInitializer->getSerialVid()=%04x", m_pInitializer->getSerialVid());
|
||||
DBG("m_pInitializer->getSerialPid()=%04x", m_pInitializer->getSerialPid());
|
||||
if ((dev->getVid() == m_pInitializer->getSerialVid()) && (dev->getPid() == m_pInitializer->getSerialPid()))
|
||||
{
|
||||
DBG("The dongle is in virtual serial mode");
|
||||
host->registerDriver(dev, 0, this, &WANDongle::init);
|
||||
m_serialCount = m_pInitializer->getSerialPortCount();
|
||||
if( m_serialCount > WANDONGLE_MAX_SERIAL_PORTS )
|
||||
{
|
||||
m_serialCount = WANDONGLE_MAX_SERIAL_PORTS;
|
||||
}
|
||||
for(int j = 0; j < m_serialCount; j++)
|
||||
{
|
||||
DBG("Connecting serial port #%d", j+1);
|
||||
DBG("Ep %p", m_pInitializer->getEp(dev, j, false));
|
||||
DBG("Ep %p", m_pInitializer->getEp(dev, j, true));
|
||||
m_serial[j].connect( dev, m_pInitializer->getEp(dev, j, false), m_pInitializer->getEp(dev, j, true) );
|
||||
}
|
||||
|
||||
DBG("Device connected");
|
||||
|
||||
dev_connected = true;
|
||||
host->unlock();
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
else if ((dev->getVid() == m_pInitializer->getMSDVid()) && (dev->getPid() == m_pInitializer->getMSDPid()))
|
||||
{
|
||||
DBG("Vodafone K3370 dongle detected in MSD mode");
|
||||
//Try to switch
|
||||
if( m_pInitializer->switchMode(dev) )
|
||||
{
|
||||
DBG("Switched OK");
|
||||
host->unlock();
|
||||
return false; //Will be connected on a next iteration
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR("Could not switch mode");
|
||||
host->unlock();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} //if()
|
||||
} //if()
|
||||
} //for()
|
||||
host->unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WANDongle::disconnect()
|
||||
{
|
||||
dev_connected = false;
|
||||
for(int i = 0; i < WANDONGLE_MAX_SERIAL_PORTS; i++)
|
||||
{
|
||||
m_serial[i].disconnect();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
WAN_DONGLE_TYPE WANDongle::getDongleType()
|
||||
{
|
||||
if( m_pInitializer != NULL )
|
||||
{
|
||||
return m_pInitializer->getType();
|
||||
}
|
||||
else
|
||||
{
|
||||
return WAN_DONGLE_TYPE_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
IUSBHostSerial& WANDongle::getSerial(int index)
|
||||
{
|
||||
return m_serial[index];
|
||||
}
|
||||
|
||||
int WANDongle::getSerialCount()
|
||||
{
|
||||
return m_serialCount;
|
||||
}
|
||||
|
||||
//Private methods
|
||||
void WANDongle::init()
|
||||
{
|
||||
m_pInitializer = NULL;
|
||||
dev_connected = false;
|
||||
for(int i = 0; i < WANDONGLE_MAX_SERIAL_PORTS; i++)
|
||||
{
|
||||
m_serial[i].init(host);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*virtual*/ void WANDongle::setVidPid(uint16_t vid, uint16_t pid)
|
||||
{
|
||||
//Load right initializer
|
||||
WANDongleInitializer** initializer = WANDongleInitializer::getInitializers(host);
|
||||
|
||||
while(*initializer)
|
||||
{
|
||||
DBG("*initializer=%p", *initializer);
|
||||
DBG("(*initializer)->getSerialVid()=%04x", (*initializer)->getSerialVid());
|
||||
DBG("(*initializer)->getSerialPid()=%04x", (*initializer)->getSerialPid());
|
||||
if ((dev->getVid() == (*initializer)->getSerialVid()) && (dev->getPid() == (*initializer)->getSerialPid()))
|
||||
{
|
||||
DBG("The dongle is in virtual serial mode");
|
||||
m_pInitializer = *initializer;
|
||||
break;
|
||||
}
|
||||
else if ((dev->getVid() == (*initializer)->getMSDVid()) && (dev->getPid() == (*initializer)->getMSDPid()))
|
||||
{
|
||||
DBG("Vodafone K3370 dongle detected in MSD mode");
|
||||
m_pInitializer = *initializer;
|
||||
break;
|
||||
}
|
||||
initializer++;
|
||||
} //while()
|
||||
if(m_pInitializer)
|
||||
{
|
||||
m_pInitializer->setVidPid(vid, pid);
|
||||
}
|
||||
}
|
||||
|
||||
/*virtual*/ bool WANDongle::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(m_pInitializer)
|
||||
{
|
||||
return m_pInitializer->parseInterface(intf_nb, intf_class, intf_subclass, intf_protocol);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*virtual*/ bool WANDongle::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
|
||||
{
|
||||
if(m_pInitializer)
|
||||
{
|
||||
return m_pInitializer->useEndpoint(intf_nb, type, dir);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,265 +0,0 @@
|
|||
/* Copyright (c) 2010-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
|
||||
#ifndef __MODULE__
|
||||
#define __MODULE__ "WANDongleInitializer.cpp"
|
||||
#endif
|
||||
|
||||
#include "core/dbg.h"
|
||||
|
||||
#include <cstdint>
|
||||
using std::uint16_t;
|
||||
|
||||
#include "WANDongleInitializer.h"
|
||||
|
||||
WANDongleInitializer::WANDongleInitializer(USBHost* pHost) : m_pHost(pHost)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
WANDongleInitializer** WANDongleInitializer::getInitializers(USBHost* pHost)
|
||||
{
|
||||
static VodafoneK3770Initializer vodafoneK3770(pHost);
|
||||
static VodafoneK3772ZInitializer vodafoneK3772Z(pHost);
|
||||
const static WANDongleInitializer* list[] = { &vodafoneK3770, &vodafoneK3772Z, NULL };
|
||||
return (WANDongleInitializer**)list;
|
||||
}
|
||||
|
||||
//Huawei K3770 (Vodafone)
|
||||
// Switching from mass storage device string is: "55 53 42 43 12 34 56 78 00 00 00 00 00 00 00 11 06 20 00 00 01 00 00 00 00 00 00 00 00 00 00"
|
||||
static uint8_t vodafone_k3770_switch_packet[] = {
|
||||
0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78, 0, 0, 0, 0, 0, 0, 0, 0x11, 0x06, 0x20, 0, 0, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
VodafoneK3770Initializer::VodafoneK3770Initializer(USBHost* pHost) : WANDongleInitializer(pHost)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
uint16_t VodafoneK3770Initializer::getMSDVid() { return 0x12D1; }
|
||||
uint16_t VodafoneK3770Initializer::getMSDPid() { return 0x14D1; }
|
||||
|
||||
uint16_t VodafoneK3770Initializer::getSerialVid() { return 0x12D1; }
|
||||
uint16_t VodafoneK3770Initializer::getSerialPid() { return 0x14C9; }
|
||||
|
||||
bool VodafoneK3770Initializer::switchMode(USBDeviceConnected* pDev)
|
||||
{
|
||||
for (int i = 0; i < pDev->getNbInterface(); i++)
|
||||
{
|
||||
if (pDev->getInterface(i)->intf_class == MSD_CLASS)
|
||||
{
|
||||
USBEndpoint* pEp = pDev->getEndpoint(i, BULK_ENDPOINT, OUT);
|
||||
if ( pEp != NULL )
|
||||
{
|
||||
DBG("MSD descriptor found on device %p, intf %d, will now try to switch into serial mode", (void *)pDev, i);
|
||||
m_pHost->bulkWrite(pDev, pEp, vodafone_k3770_switch_packet, 31);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
USBEndpoint* VodafoneK3770Initializer::getEp(USBDeviceConnected* pDev, int serialPortNumber, bool tx)
|
||||
{
|
||||
return pDev->getEndpoint(serialPortNumber, BULK_ENDPOINT, tx?OUT:IN, 0);
|
||||
}
|
||||
|
||||
int VodafoneK3770Initializer::getSerialPortCount()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*virtual*/ void VodafoneK3770Initializer::setVidPid(uint16_t vid, uint16_t pid)
|
||||
{
|
||||
if( (vid == getSerialVid() ) && ( pid == getSerialPid() ) )
|
||||
{
|
||||
m_hasSwitched = true;
|
||||
m_currentSerialIntf = 0;
|
||||
m_endpointsToFetch = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_hasSwitched = false;
|
||||
m_endpointsToFetch = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*virtual*/ bool VodafoneK3770Initializer::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( m_hasSwitched )
|
||||
{
|
||||
if( intf_class == 0xFF )
|
||||
{
|
||||
if( (m_currentSerialIntf == 0) || (m_currentSerialIntf == 4) )
|
||||
{
|
||||
m_currentSerialIntf++;
|
||||
return true;
|
||||
}
|
||||
m_currentSerialIntf++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( (intf_nb == 0) && (intf_class == MSD_CLASS) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*virtual*/ bool VodafoneK3770Initializer::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
|
||||
{
|
||||
if( m_hasSwitched )
|
||||
{
|
||||
if( (type == BULK_ENDPOINT) && m_endpointsToFetch )
|
||||
{
|
||||
m_endpointsToFetch--;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( (type == BULK_ENDPOINT) && (dir == OUT) && m_endpointsToFetch )
|
||||
{
|
||||
m_endpointsToFetch--;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*virtual*/ WAN_DONGLE_TYPE VodafoneK3770Initializer::getType()
|
||||
{
|
||||
return WAN_DONGLE_TYPE_VODAFONEK3770;
|
||||
}
|
||||
|
||||
// NVIDIA (ICERA) /ZTE K3772-Z (Vodafone)
|
||||
// Switching from mass storage device string is: "55 53 42 43 12 34 56 78 00 00 00 00 00 00 06 1b 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00"
|
||||
static uint8_t vodafone_k3772_z_switch_packet[] = {
|
||||
0x55, 0x53, 0x42, 0x43, 0x12, 0x34, 0x56, 0x78, 0, 0, 0, 0, 0, 0, 0x06, 0x1b, 0, 0, 0, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
VodafoneK3772ZInitializer::VodafoneK3772ZInitializer(USBHost* pHost) : WANDongleInitializer(pHost)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
uint16_t VodafoneK3772ZInitializer::getMSDVid() { return 0x19D2; }
|
||||
uint16_t VodafoneK3772ZInitializer::getMSDPid() { return 0x1179; }
|
||||
|
||||
uint16_t VodafoneK3772ZInitializer::getSerialVid() { return 0x19D2; }
|
||||
uint16_t VodafoneK3772ZInitializer::getSerialPid() { return 0x1181; }
|
||||
|
||||
bool VodafoneK3772ZInitializer::switchMode(USBDeviceConnected* pDev)
|
||||
{
|
||||
for (int i = 0; i < pDev->getNbInterface(); i++)
|
||||
{
|
||||
if (pDev->getInterface(i)->intf_class == MSD_CLASS)
|
||||
{
|
||||
USBEndpoint* pEp = pDev->getEndpoint(i, BULK_ENDPOINT, OUT);
|
||||
if ( pEp != NULL )
|
||||
{
|
||||
DBG("MSD descriptor found on device %p, intf %d, will now try to switch into serial mode", (void *)pDev, i);
|
||||
m_pHost->bulkWrite(pDev, pEp, vodafone_k3772_z_switch_packet, 31);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
USBEndpoint* VodafoneK3772ZInitializer::getEp(USBDeviceConnected* pDev, int serialPortNumber, bool tx)
|
||||
{
|
||||
return pDev->getEndpoint((serialPortNumber==1)?0:1, BULK_ENDPOINT, tx?OUT:IN, 0);
|
||||
}
|
||||
|
||||
int VodafoneK3772ZInitializer::getSerialPortCount()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*virtual*/ void VodafoneK3772ZInitializer::setVidPid(uint16_t vid, uint16_t pid)
|
||||
{
|
||||
if( (vid == getSerialVid() ) && ( pid == getSerialPid() ) )
|
||||
{
|
||||
m_hasSwitched = true;
|
||||
m_currentSerialIntf = 0;
|
||||
m_endpointsToFetch = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_hasSwitched = false;
|
||||
m_endpointsToFetch = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*virtual*/ bool VodafoneK3772ZInitializer::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( m_hasSwitched )
|
||||
{
|
||||
DBG("Interface #%d; Class:%02x; SubClass:%02x; Protocol:%02x", intf_nb, intf_class, intf_subclass, intf_protocol);
|
||||
if( intf_class == 0x0A )
|
||||
{
|
||||
if( (m_currentSerialIntf == 0) || (m_currentSerialIntf == 1) )
|
||||
{
|
||||
m_currentSerialIntf++;
|
||||
return true;
|
||||
}
|
||||
m_currentSerialIntf++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( (intf_nb == 0) && (intf_class == MSD_CLASS) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*virtual*/ bool VodafoneK3772ZInitializer::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
|
||||
{
|
||||
if( m_hasSwitched )
|
||||
{
|
||||
DBG("USBEndpoint on Inteface #%d; Type:%d; Direction:%d", intf_nb, type, dir);
|
||||
if( (type == BULK_ENDPOINT) && m_endpointsToFetch )
|
||||
{
|
||||
m_endpointsToFetch--;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( (type == BULK_ENDPOINT) && (dir == OUT) && m_endpointsToFetch )
|
||||
{
|
||||
m_endpointsToFetch--;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*virtual*/ WAN_DONGLE_TYPE VodafoneK3772ZInitializer::getType()
|
||||
{
|
||||
return WAN_DONGLE_TYPE_VODAFONEK3772Z;
|
||||
}
|
|
@ -1,130 +0,0 @@
|
|||
/* Copyright (c) 2010-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 WANDONGLEINITIALIZER_H
|
||||
#define WANDONGLEINITIALIZER_H
|
||||
|
||||
#include <cstdint>
|
||||
using std::uint16_t;
|
||||
using std::uint32_t;
|
||||
|
||||
#include "USBHost.h"
|
||||
#include "IUSBEnumerator.h"
|
||||
|
||||
enum WAN_DONGLE_TYPE
|
||||
{
|
||||
WAN_DONGLE_TYPE_UNKNOWN = -1,
|
||||
WAN_DONGLE_TYPE_VODAFONEK3770 = 0,
|
||||
WAN_DONGLE_TYPE_VODAFONEK3772Z = 1,
|
||||
};
|
||||
|
||||
class WANDongleInitializer : public IUSBEnumerator
|
||||
{
|
||||
protected:
|
||||
WANDongleInitializer(USBHost* pHost);
|
||||
USBHost* m_pHost;
|
||||
|
||||
public:
|
||||
virtual uint16_t getMSDVid() = 0;
|
||||
virtual uint16_t getMSDPid() = 0;
|
||||
|
||||
virtual uint16_t getSerialVid() = 0;
|
||||
virtual uint16_t getSerialPid() = 0;
|
||||
|
||||
virtual bool switchMode(USBDeviceConnected* pDev) = 0;
|
||||
|
||||
virtual USBEndpoint* getEp(USBDeviceConnected* pDev, int serialPortNumber, bool tx) = 0;
|
||||
|
||||
virtual int getSerialPortCount() = 0;
|
||||
|
||||
virtual void setVidPid(uint16_t vid, uint16_t pid) = 0;
|
||||
|
||||
virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) = 0; //Must return true if the interface should be parsed
|
||||
|
||||
virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) = 0; //Must return true if the endpoint will be used
|
||||
|
||||
virtual WAN_DONGLE_TYPE getType() = 0;
|
||||
|
||||
static WANDongleInitializer** getInitializers(USBHost* pHost);
|
||||
};
|
||||
|
||||
class VodafoneK3770Initializer : public WANDongleInitializer
|
||||
{
|
||||
public:
|
||||
VodafoneK3770Initializer(USBHost* pHost);
|
||||
|
||||
virtual uint16_t getMSDVid();
|
||||
virtual uint16_t getMSDPid();
|
||||
|
||||
virtual uint16_t getSerialVid();
|
||||
virtual uint16_t getSerialPid();
|
||||
|
||||
virtual bool switchMode(USBDeviceConnected* pDev);
|
||||
|
||||
virtual USBEndpoint* getEp(USBDeviceConnected* pDev, int serialPortNumber, bool tx);
|
||||
|
||||
virtual int getSerialPortCount();
|
||||
|
||||
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 WAN_DONGLE_TYPE getType();
|
||||
|
||||
private:
|
||||
|
||||
bool m_hasSwitched;
|
||||
int m_currentSerialIntf;
|
||||
int m_endpointsToFetch;
|
||||
};
|
||||
|
||||
class VodafoneK3772ZInitializer : public WANDongleInitializer
|
||||
{
|
||||
public:
|
||||
VodafoneK3772ZInitializer(USBHost* pHost);
|
||||
|
||||
virtual uint16_t getMSDVid();
|
||||
virtual uint16_t getMSDPid();
|
||||
|
||||
virtual uint16_t getSerialVid();
|
||||
virtual uint16_t getSerialPid();
|
||||
|
||||
virtual bool switchMode(USBDeviceConnected* pDev);
|
||||
|
||||
virtual USBEndpoint* getEp(USBDeviceConnected* pDev, int serialPortNumber, bool tx);
|
||||
|
||||
virtual int getSerialPortCount();
|
||||
|
||||
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 WAN_DONGLE_TYPE getType();
|
||||
|
||||
private:
|
||||
|
||||
bool m_hasSwitched;
|
||||
int m_currentSerialIntf;
|
||||
int m_endpointsToFetch;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,340 +0,0 @@
|
|||
/* Copyright (c) 2010-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
|
||||
#ifndef __MODULE__
|
||||
#define __MODULE__ "WANDongleSerialPort.cpp"
|
||||
#endif
|
||||
|
||||
#include "core/dbg.h"
|
||||
#include <cstdint>
|
||||
#include "rtos.h"
|
||||
|
||||
#include "WANDongleSerialPort.h"
|
||||
|
||||
WANDongleSerialPort::WANDongleSerialPort() : cb_tx_en(false), cb_rx_en(false), listener(NULL)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void WANDongleSerialPort::init(USBHost* pHost)
|
||||
{
|
||||
host = pHost;
|
||||
}
|
||||
|
||||
void WANDongleSerialPort::reset()
|
||||
{
|
||||
tx_mtx.lock();
|
||||
rx_mtx.lock();
|
||||
|
||||
bulk_in = NULL;
|
||||
bulk_out = NULL;
|
||||
|
||||
buf_out_len = 0;
|
||||
max_out_size = 0;
|
||||
lock_tx = false;
|
||||
cb_tx_pending = false;
|
||||
|
||||
buf_in_len = 0;
|
||||
buf_in_read_pos = 0;
|
||||
lock_rx = false;
|
||||
cb_rx_pending = false;
|
||||
|
||||
tx_mtx.unlock();
|
||||
rx_mtx.unlock();
|
||||
}
|
||||
|
||||
int WANDongleSerialPort::readPacket()
|
||||
{
|
||||
DBG("Read packet on %p", this);
|
||||
rx_mtx.lock();
|
||||
if(lock_rx)
|
||||
{
|
||||
ERR("Fail");
|
||||
rx_mtx.unlock();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( bulk_in == NULL )
|
||||
{
|
||||
WARN("Port is disconnected");
|
||||
rx_mtx.unlock();
|
||||
return -1;
|
||||
}
|
||||
|
||||
lock_rx = true; //Receiving
|
||||
rx_mtx.unlock();
|
||||
// DBG("readPacket");
|
||||
//lock_rx.lock();
|
||||
host->lock();
|
||||
USB_TYPE res = host->bulkRead(dev, (USBEndpoint *)bulk_in, buf_in, ((USBEndpoint *)bulk_in)->getSize(), false); //Queue transfer
|
||||
if(res != USB_TYPE_PROCESSING)
|
||||
{
|
||||
host->unlock();
|
||||
//lock_rx.unlock();
|
||||
ERR("host->bulkRead() returned %d", res);
|
||||
Thread::wait(100);
|
||||
return -1;
|
||||
}
|
||||
host->unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WANDongleSerialPort::writePacket()
|
||||
{
|
||||
tx_mtx.lock();
|
||||
if(lock_tx)
|
||||
{
|
||||
ERR("Fail");
|
||||
tx_mtx.unlock();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if( bulk_out == NULL )
|
||||
{
|
||||
WARN("Port is disconnected");
|
||||
tx_mtx.unlock();
|
||||
return -1;
|
||||
}
|
||||
|
||||
lock_tx = true; //Transmitting
|
||||
tx_mtx.unlock();
|
||||
// DBG("writePacket");
|
||||
|
||||
//lock_tx.lock();
|
||||
host->lock();
|
||||
USB_TYPE res = host->bulkWrite(dev, (USBEndpoint *)bulk_out, buf_out, buf_out_len, false); //Queue transfer
|
||||
if(res != USB_TYPE_PROCESSING)
|
||||
{
|
||||
host->unlock();
|
||||
//lock_tx.unlock();
|
||||
ERR("host->bulkWrite() returned %d", res);
|
||||
Thread::wait(100);
|
||||
return -1;
|
||||
}
|
||||
host->unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WANDongleSerialPort::putc(int c)
|
||||
{
|
||||
tx_mtx.lock();
|
||||
if(!lock_tx)
|
||||
{
|
||||
if(buf_out_len < max_out_size)
|
||||
{
|
||||
buf_out[buf_out_len] = (uint8_t)c;
|
||||
buf_out_len++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR("CAN'T WRITE!");
|
||||
}
|
||||
tx_mtx.unlock();
|
||||
return c;
|
||||
}
|
||||
|
||||
int WANDongleSerialPort::getc()
|
||||
{
|
||||
rx_mtx.lock();
|
||||
int c = 0;
|
||||
if(!lock_rx)
|
||||
{
|
||||
if(buf_in_read_pos < buf_in_len)
|
||||
{
|
||||
c = (int)buf_in[buf_in_read_pos];
|
||||
buf_in_read_pos++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR("CAN'T READ!");
|
||||
}
|
||||
rx_mtx.unlock();
|
||||
return c;
|
||||
}
|
||||
|
||||
int WANDongleSerialPort::readable()
|
||||
{
|
||||
rx_mtx.lock();
|
||||
if (lock_rx)
|
||||
{
|
||||
rx_mtx.unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* if( !lock_rx.trylock() )
|
||||
{
|
||||
return 0;
|
||||
}*/
|
||||
int res = buf_in_len - buf_in_read_pos;
|
||||
//lock_rx.unlock();
|
||||
rx_mtx.unlock();
|
||||
return res;
|
||||
}
|
||||
|
||||
int WANDongleSerialPort::writeable()
|
||||
{
|
||||
tx_mtx.lock();
|
||||
if (lock_tx)
|
||||
{
|
||||
tx_mtx.unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*if( !lock_tx.trylock() )
|
||||
{
|
||||
return 0;
|
||||
}*/
|
||||
int res = max_out_size - buf_out_len;
|
||||
tx_mtx.unlock();
|
||||
//lock_tx.unlock();
|
||||
return res;
|
||||
}
|
||||
|
||||
void WANDongleSerialPort::attach(IUSBHostSerialListener* pListener)
|
||||
{
|
||||
if(pListener == NULL)
|
||||
{
|
||||
setupIrq(false, RxIrq);
|
||||
setupIrq(false, TxIrq);
|
||||
}
|
||||
listener = pListener;
|
||||
if(pListener != NULL)
|
||||
{
|
||||
setupIrq(true, RxIrq);
|
||||
setupIrq(true, TxIrq);
|
||||
}
|
||||
}
|
||||
|
||||
void WANDongleSerialPort::setupIrq(bool en, IrqType irq /*= RxIrq*/)
|
||||
{
|
||||
switch(irq)
|
||||
{
|
||||
case RxIrq:
|
||||
rx_mtx.lock();
|
||||
cb_rx_en = en;
|
||||
if(en && cb_rx_pending)
|
||||
{
|
||||
cb_rx_pending = false;
|
||||
rx_mtx.unlock();
|
||||
listener->readable(); //Process the interrupt that was raised
|
||||
}
|
||||
else
|
||||
{
|
||||
rx_mtx.unlock();
|
||||
}
|
||||
break;
|
||||
case TxIrq:
|
||||
tx_mtx.lock();
|
||||
cb_tx_en = en;
|
||||
if(en && cb_tx_pending)
|
||||
{
|
||||
cb_tx_pending = false;
|
||||
tx_mtx.unlock();
|
||||
listener->writeable(); //Process the interrupt that was raised
|
||||
}
|
||||
else
|
||||
{
|
||||
tx_mtx.unlock();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void WANDongleSerialPort::connect( USBDeviceConnected* pDev, USBEndpoint* pInEp, USBEndpoint* pOutEp )
|
||||
{
|
||||
dev = pDev;
|
||||
bulk_in = pInEp;
|
||||
bulk_out = pOutEp;
|
||||
max_out_size = bulk_out->getSize();
|
||||
if( max_out_size > WANDONGLE_MAX_OUTEP_SIZE )
|
||||
{
|
||||
max_out_size = WANDONGLE_MAX_OUTEP_SIZE;
|
||||
}
|
||||
bulk_in->attach(this, &WANDongleSerialPort::rxHandler);
|
||||
bulk_out->attach(this, &WANDongleSerialPort::txHandler);
|
||||
readPacket(); //Start receiving data
|
||||
}
|
||||
|
||||
void WANDongleSerialPort::disconnect( )
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
//Private methods
|
||||
|
||||
|
||||
void WANDongleSerialPort::rxHandler()
|
||||
{
|
||||
if (((USBEndpoint *) bulk_in)->getState() == USB_TYPE_IDLE) //Success
|
||||
{
|
||||
buf_in_read_pos = 0;
|
||||
buf_in_len = ((USBEndpoint *) bulk_in)->getLengthTransferred(); //Update length
|
||||
//lock_rx.unlock();
|
||||
rx_mtx.lock();
|
||||
lock_rx = false; //Transmission complete
|
||||
if(cb_rx_en)
|
||||
{
|
||||
rx_mtx.unlock();
|
||||
listener->readable(); //Call handler from the IRQ context
|
||||
//readPacket() should be called by the handler subsequently once the buffer has been emptied
|
||||
}
|
||||
else
|
||||
{
|
||||
cb_rx_pending = true; //Queue the callback
|
||||
rx_mtx.unlock();
|
||||
}
|
||||
|
||||
}
|
||||
else //Error, try reading again
|
||||
{
|
||||
//lock_rx.unlock();
|
||||
DBG("Trying again");
|
||||
readPacket();
|
||||
}
|
||||
}
|
||||
|
||||
void WANDongleSerialPort::txHandler()
|
||||
{
|
||||
if (((USBEndpoint *) bulk_out)->getState() == USB_TYPE_IDLE) //Success
|
||||
{
|
||||
tx_mtx.lock();
|
||||
buf_out_len = 0; //Reset length
|
||||
lock_tx = false; //Transmission complete
|
||||
//lock_tx.unlock();
|
||||
if(cb_tx_en)
|
||||
{
|
||||
tx_mtx.unlock();
|
||||
listener->writeable(); //Call handler from the IRQ context
|
||||
//writePacket() should be called by the handler subsequently once the buffer has been filled
|
||||
}
|
||||
else
|
||||
{
|
||||
cb_tx_pending = true; //Queue the callback
|
||||
tx_mtx.unlock();
|
||||
}
|
||||
}
|
||||
else //Error, try reading again
|
||||
{
|
||||
//lock_tx.unlock();
|
||||
writePacket();
|
||||
}
|
||||
}
|
|
@ -1,126 +0,0 @@
|
|||
/* Copyright (c) 2010-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 WANDONGLESERIALPORT_H
|
||||
#define WANDONGLESERIALPORT_H
|
||||
|
||||
#include "USBHost.h"
|
||||
#include "IUSBHostSerial.h"
|
||||
|
||||
#include "rtos.h"
|
||||
|
||||
|
||||
#define WANDONGLE_MAX_OUTEP_SIZE 64
|
||||
#define WANDONGLE_MAX_INEP_SIZE 64
|
||||
|
||||
/** A class to use a WAN (3G/LTE) access dongle
|
||||
*
|
||||
*/
|
||||
class WANDongleSerialPort : public IUSBHostSerial {
|
||||
public:
|
||||
/*
|
||||
* Constructor
|
||||
*
|
||||
*/
|
||||
WANDongleSerialPort();
|
||||
|
||||
void init( USBHost* pHost );
|
||||
|
||||
void connect( USBDeviceConnected* pDev, USBEndpoint* pInEp, USBEndpoint* pOutEp );
|
||||
|
||||
void disconnect( );
|
||||
|
||||
/*
|
||||
* Get a char from the dongle's serial interface
|
||||
*/
|
||||
virtual int getc();
|
||||
|
||||
/*
|
||||
* Put a char to the dongle's serial interface
|
||||
*/
|
||||
virtual int putc(int c);
|
||||
|
||||
/*
|
||||
* Read a packet from the dongle's serial interface, to be called after multiple getc() calls
|
||||
*/
|
||||
virtual int readPacket();
|
||||
|
||||
/*
|
||||
* Write a packet to the dongle's serial interface, to be called after multiple putc() calls
|
||||
*/
|
||||
virtual int writePacket();
|
||||
|
||||
/**
|
||||
* Check the number of bytes available.
|
||||
*
|
||||
* @returns the number of bytes available
|
||||
*/
|
||||
virtual int readable();
|
||||
|
||||
/**
|
||||
* Check the free space in output.
|
||||
*
|
||||
* @returns the number of bytes available
|
||||
*/
|
||||
virtual int writeable();
|
||||
|
||||
/**
|
||||
* Attach a handler to call when a packet is received / when a packet has been transmitted.
|
||||
*
|
||||
* @param pListener instance of the listener deriving from the IUSBHostSerialListener
|
||||
*/
|
||||
virtual void attach(IUSBHostSerialListener* pListener);
|
||||
|
||||
/**
|
||||
* Enable or disable readable/writeable callbacks
|
||||
*/
|
||||
virtual void setupIrq(bool en, IrqType irq = RxIrq);
|
||||
|
||||
|
||||
protected:
|
||||
USBEndpoint * bulk_in;
|
||||
USBEndpoint * bulk_out;
|
||||
USBHost * host;
|
||||
USBDeviceConnected * dev;
|
||||
|
||||
uint8_t buf_out[WANDONGLE_MAX_OUTEP_SIZE];
|
||||
volatile uint32_t buf_out_len;
|
||||
uint32_t max_out_size;
|
||||
volatile bool lock_tx;
|
||||
volatile bool cb_tx_en;
|
||||
volatile bool cb_tx_pending;
|
||||
Mutex tx_mtx;
|
||||
|
||||
uint8_t buf_in[WANDONGLE_MAX_INEP_SIZE];
|
||||
volatile uint32_t buf_in_len;
|
||||
volatile uint32_t buf_in_read_pos;
|
||||
volatile bool lock_rx;
|
||||
volatile bool cb_rx_en;
|
||||
volatile bool cb_rx_pending;
|
||||
Mutex rx_mtx;
|
||||
|
||||
IUSBHostSerialListener* listener;
|
||||
|
||||
void reset();
|
||||
|
||||
void rxHandler();
|
||||
void txHandler();
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,122 +0,0 @@
|
|||
/* Copyright (c) 2010-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.
|
||||
*/
|
||||
|
||||
#include "USBDeviceConnected.h"
|
||||
|
||||
USBDeviceConnected::USBDeviceConnected() {
|
||||
init();
|
||||
}
|
||||
|
||||
void USBDeviceConnected::init() {
|
||||
hub = 0;
|
||||
port = 0;
|
||||
vid = 0;
|
||||
pid = 0;
|
||||
nb_interf = 0;
|
||||
enumerated = false;
|
||||
activeAddr = false;
|
||||
sizeControlEndpoint = 8;
|
||||
device_class = 0;
|
||||
device_subclass = 0;
|
||||
proto = 0;
|
||||
speed = false;
|
||||
for (int i = 0; i < MAX_INTF; i++) {
|
||||
memset((void *)&intf[i], 0, sizeof(INTERFACE));
|
||||
intf[i].in_use = false;
|
||||
for (int j = 0; j < MAX_ENDPOINT_PER_INTERFACE; j++) {
|
||||
intf[i].ep[j] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
INTERFACE * USBDeviceConnected::getInterface(uint8_t index) {
|
||||
if (index >= MAX_INTF) {
|
||||
return NULL;
|
||||
}
|
||||
return &intf[index];
|
||||
}
|
||||
|
||||
bool USBDeviceConnected::addInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) {
|
||||
if ((intf_nb >= MAX_INTF) || (intf[intf_nb].in_use)) {
|
||||
return false;
|
||||
}
|
||||
intf[intf_nb].in_use = true;
|
||||
intf[intf_nb].intf_class = intf_class;
|
||||
intf[intf_nb].intf_subclass = intf_subclass;
|
||||
intf[intf_nb].intf_protocol = intf_protocol;
|
||||
intf[intf_nb].nb_endpoint = 0;
|
||||
nb_interf++;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool USBDeviceConnected::addEndpoint(uint8_t intf_nb, USBEndpoint * ept) {
|
||||
if ((intf_nb >= MAX_INTF) || (intf[intf_nb].in_use == false) || (intf[intf_nb].nb_endpoint >= MAX_ENDPOINT_PER_INTERFACE)) {
|
||||
return false;
|
||||
}
|
||||
intf[intf_nb].nb_endpoint++;
|
||||
|
||||
for (int i = 0; i < MAX_ENDPOINT_PER_INTERFACE; i++) {
|
||||
if (intf[intf_nb].ep[i] == NULL) {
|
||||
intf[intf_nb].ep[i] = ept;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void USBDeviceConnected::init(uint8_t hub, uint8_t port, bool lowSpeed) {
|
||||
init();
|
||||
this->hub = hub;
|
||||
this->port = port;
|
||||
this->speed = lowSpeed;
|
||||
}
|
||||
|
||||
void USBDeviceConnected::disconnect() {
|
||||
for(int i = 0; i < nb_interf; i++) {
|
||||
intf[i].detach.call();
|
||||
}
|
||||
init();
|
||||
}
|
||||
|
||||
|
||||
|
||||
USBEndpoint * USBDeviceConnected::getEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint8_t index) {
|
||||
if (intf_nb >= MAX_INTF) {
|
||||
return NULL;
|
||||
}
|
||||
for (int i = 0; i < MAX_ENDPOINT_PER_INTERFACE; i++) {
|
||||
if ((intf[intf_nb].ep[i]->getType() == type) && (intf[intf_nb].ep[i]->getDir() == dir)) {
|
||||
if(index)
|
||||
{
|
||||
index--;
|
||||
}
|
||||
else
|
||||
{
|
||||
return intf[intf_nb].ep[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
USBEndpoint * USBDeviceConnected::getEndpoint(uint8_t intf_nb, uint8_t index) {
|
||||
if ((intf_nb >= MAX_INTF) || (index >= MAX_ENDPOINT_PER_INTERFACE)) {
|
||||
return NULL;
|
||||
}
|
||||
return intf[intf_nb].ep[index];
|
||||
}
|
|
@ -1,205 +0,0 @@
|
|||
/* Copyright (c) 2010-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 USBDEVICECONNECTED_H
|
||||
#define USBDEVICECONNECTED_H
|
||||
|
||||
#include "stdint.h"
|
||||
#include "USBEndpoint.h"
|
||||
|
||||
#define MAX_ENDPOINT_PER_INTERFACE 2
|
||||
#define MAX_INTF 2
|
||||
|
||||
typedef struct {
|
||||
bool in_use;
|
||||
uint8_t nb_endpoint;
|
||||
uint8_t intf_class;
|
||||
uint8_t intf_subclass;
|
||||
uint8_t intf_protocol;
|
||||
USBEndpoint * ep[MAX_ENDPOINT_PER_INTERFACE];
|
||||
FunctionPointer detach;
|
||||
}INTERFACE;
|
||||
|
||||
|
||||
class USBDeviceConnected {
|
||||
public:
|
||||
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
USBDeviceConnected();
|
||||
|
||||
/*
|
||||
* Attach an USBEndpoint to this device
|
||||
*
|
||||
* @param ep pointeur on the USBEndpoint which will be attached
|
||||
* @returns true if successful, false otherwise
|
||||
*/
|
||||
bool addEndpoint(uint8_t intf_nb, USBEndpoint * ep);
|
||||
|
||||
/*
|
||||
* Retrieve an USBEndpoint by its TYPE and DIRECTION
|
||||
*
|
||||
* @param intf_nb the interface on which to lookup the USBEndpoint
|
||||
* @param type type of the USBEndpoint looked for
|
||||
* @param direction of the USBEndpoint looked for
|
||||
* @param index the index of the USBEndpoint whitin the interface
|
||||
* @returns pointer on the USBEndpoint if found, NULL otherwise
|
||||
*/
|
||||
USBEndpoint * getEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint8_t index = 0);
|
||||
|
||||
/*
|
||||
* Retrieve an USBEndpoint by its index
|
||||
*
|
||||
* @param index index of the USBEndpoint
|
||||
* @returns pointer on the USBEndpoint if found, NULL otherwise
|
||||
*/
|
||||
USBEndpoint * getEndpoint(uint8_t intf_nb, uint8_t index);
|
||||
|
||||
bool addInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol);
|
||||
|
||||
uint8_t getNbInterface() {return nb_interf;};
|
||||
|
||||
INTERFACE * getInterface(uint8_t index);
|
||||
|
||||
/**
|
||||
* Attach a member function to call when a the device has been disconnected
|
||||
*
|
||||
* @param tptr pointer to the object to call the member function on
|
||||
* @param mptr pointer to the member function to be called
|
||||
*/
|
||||
template<typename T>
|
||||
void onDisconnect(uint8_t intf_nb, T* tptr, void (T::*mptr)(void)) {
|
||||
if ((mptr != NULL) && (tptr != NULL)) {
|
||||
intf[intf_nb].detach.attach(tptr, mptr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach a callback called when the device has been disconnected
|
||||
*
|
||||
* @param fptr function pointer
|
||||
*/
|
||||
void onDisconnect(uint8_t intf_nb, void (*fn)(void)) {
|
||||
if (fn != NULL) {
|
||||
intf[intf_nb].detach.attach(fn);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Disconnect the device by calling a callback function registered by a driver
|
||||
*/
|
||||
void disconnect();
|
||||
|
||||
/*
|
||||
* Setters
|
||||
*/
|
||||
void init(uint8_t hub, uint8_t port, bool lowSpeed);
|
||||
void setAddress(uint8_t addr) {
|
||||
this->addr = addr;
|
||||
};
|
||||
void setVid(uint16_t vid) {
|
||||
this->vid = vid;
|
||||
};
|
||||
void setPid(uint16_t pid) {
|
||||
this->pid = pid;
|
||||
};
|
||||
void setClass(uint8_t device_class) {
|
||||
this->device_class = device_class;
|
||||
};
|
||||
void setSubClass(uint8_t device_subclass) {
|
||||
this->device_subclass = device_subclass;
|
||||
};
|
||||
void setProtocol(uint8_t pr) {
|
||||
proto = pr;
|
||||
};
|
||||
void setSizeControlEndpoint(uint32_t size) {
|
||||
sizeControlEndpoint = size;
|
||||
};
|
||||
void activeAddress() {
|
||||
activeAddr = true;
|
||||
};
|
||||
void setEnumerated() {
|
||||
enumerated = true;
|
||||
};
|
||||
|
||||
/*
|
||||
* Getters
|
||||
*/
|
||||
uint8_t getPort() {
|
||||
return port;
|
||||
};
|
||||
uint8_t getHub() {
|
||||
return hub;
|
||||
};
|
||||
uint8_t getAddress() {
|
||||
return addr;
|
||||
};
|
||||
uint16_t getVid() {
|
||||
return vid;
|
||||
};
|
||||
uint16_t getPid() {
|
||||
return pid;
|
||||
};
|
||||
uint8_t getClass() {
|
||||
return device_class;
|
||||
};
|
||||
uint8_t getSubClass() {
|
||||
return device_subclass;
|
||||
};
|
||||
uint8_t getProtocol() {
|
||||
return proto;
|
||||
};
|
||||
bool getSpeed() {
|
||||
return speed;
|
||||
};
|
||||
uint32_t getSizeControlEndpoint() {
|
||||
return sizeControlEndpoint;
|
||||
};
|
||||
bool isActiveAddress() {
|
||||
return activeAddr;
|
||||
};
|
||||
bool isEnumerated() {
|
||||
return enumerated;
|
||||
};
|
||||
|
||||
|
||||
private:
|
||||
INTERFACE intf[MAX_INTF];
|
||||
//USBEndpoint * ep[MAX_ENDPOINT_PER_DEVICE];
|
||||
uint32_t sizeControlEndpoint;
|
||||
uint8_t hub;
|
||||
uint8_t port;
|
||||
uint16_t vid;
|
||||
uint16_t pid;
|
||||
uint8_t addr;
|
||||
uint8_t device_class;
|
||||
uint8_t device_subclass;
|
||||
uint8_t proto;
|
||||
bool speed;
|
||||
bool activeAddr;
|
||||
bool enumerated;
|
||||
|
||||
uint8_t nb_interf;
|
||||
|
||||
|
||||
void init();
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,233 +0,0 @@
|
|||
/* Copyright (c) 2010-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__ "USBEndpoint.cpp"
|
||||
#endif
|
||||
|
||||
#include "core/dbg.h"
|
||||
#include <cstdint>
|
||||
|
||||
#include "USBEndpoint.h"
|
||||
|
||||
|
||||
void USBEndpoint::init(HCED * hced, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint32_t size, uint8_t ep_number, HCTD* td_list[2]) {
|
||||
this->hced = hced;
|
||||
this->type = type;
|
||||
this->dir = /*(type == CONTROL_ENDPOINT) ? OUT :*/ dir;
|
||||
setup = (type == CONTROL_ENDPOINT) ? true : false;
|
||||
|
||||
//TDs have been allocated by the host
|
||||
memcpy((HCTD**)this->td_list, td_list, sizeof(HCTD*)*2); //TODO: Maybe should add a param for td_list size... at least a define
|
||||
memcpy(td_list[0], 0, sizeof(HCTD));
|
||||
memcpy(td_list[1], 0, sizeof(HCTD));
|
||||
|
||||
this->hced->control = 0;
|
||||
//Empty queue
|
||||
this->hced->tailTD = (uint32_t)td_list[0];
|
||||
this->hced->headTD = (uint32_t)td_list[0];
|
||||
this->hced->nextED = 0;
|
||||
|
||||
this->hced->control = ((ep_number & 0x7F) << 7) // Endpoint address
|
||||
| (type != CONTROL_ENDPOINT ? ( dir << 11) : 0 ) // direction : Out = 1, 2 = In
|
||||
| ((size & 0x3ff) << 16); // MaxPkt Size
|
||||
|
||||
//carry = false;
|
||||
transfer_len = 0;
|
||||
transferred = 0;
|
||||
buf_start = 0;
|
||||
nextEp = NULL;
|
||||
|
||||
td_current = td_list[0];
|
||||
td_next = td_list[1];
|
||||
|
||||
state = USB_TYPE_IDLE;
|
||||
}
|
||||
|
||||
void USBEndpoint::setSize(uint32_t size) {
|
||||
hced->control &= ~(0x3ff << 16);
|
||||
hced->control |= (size << 16);
|
||||
}
|
||||
|
||||
|
||||
uint32_t USBEndpoint::getSize() {
|
||||
return (hced->control >> 16) & 0x3ff;
|
||||
}
|
||||
|
||||
void USBEndpoint::setDeviceAddress(uint8_t addr) {
|
||||
hced->control &= ~(0x7f);
|
||||
hced->control |= (addr & 0x7F);
|
||||
}
|
||||
|
||||
uint8_t USBEndpoint::getDeviceAddress() {
|
||||
return hced->control & 0x7f;
|
||||
}
|
||||
|
||||
void USBEndpoint::setSpeed(uint8_t speed) {
|
||||
if(speed) {
|
||||
DBG("SET LOW SPEED");
|
||||
}
|
||||
hced->control &= ~(1 << 13);
|
||||
hced->control |= (speed << 13);
|
||||
}
|
||||
|
||||
|
||||
void USBEndpoint::setNextToken(uint32_t token) { //Only for control Eps
|
||||
switch (token) {
|
||||
case TD_SETUP:
|
||||
dir = OUT;
|
||||
setup = true;
|
||||
break;
|
||||
case TD_IN:
|
||||
dir = IN;
|
||||
setup = false;
|
||||
break;
|
||||
case TD_OUT:
|
||||
dir = OUT;
|
||||
setup = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
volatile HCTD* USBEndpoint::getNextTD()
|
||||
{
|
||||
return td_current/*(HCTD*) hced->tailTD*/; //It's the tailing one
|
||||
}
|
||||
|
||||
void USBEndpoint::queueTransfer() {
|
||||
//Try with OHCI impl
|
||||
//Caller of getNextTD() has now populated the td
|
||||
//So insert it into queue
|
||||
|
||||
//Find an OTHER free td
|
||||
//TODO: if we had more than 2 tds, this would have to be changed
|
||||
/*HCTD* toSendTD = (HCTD*) hced->tailTD;*/
|
||||
//HCTD* freeTD;
|
||||
/*
|
||||
if( hced->tailTD == td_list[0] )
|
||||
{
|
||||
freeTD = td_list[1];
|
||||
}
|
||||
else *//*if( hced->tailTD == (uint32_t) td_list[1] )*/
|
||||
/*{
|
||||
freeTD = td_list[0];
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
freeTD->control = 0;
|
||||
freeTD->currBufPtr = 0;
|
||||
freeTD->bufEnd = 0;
|
||||
freeTD->nextTD = 0;
|
||||
|
||||
td_current = toSendTD;
|
||||
*/
|
||||
transfer_len = td_current->bufEnd - td_current->currBufPtr + 1;
|
||||
transferred = transfer_len;
|
||||
buf_start = td_current->currBufPtr;
|
||||
|
||||
//No add this free TD at this end of the queue
|
||||
state = USB_TYPE_PROCESSING;
|
||||
td_current->nextTD = (volatile uint32_t)td_next;
|
||||
hced->tailTD = (volatile uint32_t)td_next;
|
||||
|
||||
#if 0
|
||||
// if TD list empty -> we put the head of the list
|
||||
if (!hced->headTD) {
|
||||
state = USB_TYPE_IDLE;
|
||||
hced->headTD = (uint32_t)(td);
|
||||
hced->tailTD = (uint32_t)(td);
|
||||
tailTD = (HCTD *) (hced->headTD);
|
||||
//DBG("queue null transfer: endpoint: %p, %08X\r\n", this, (uint32_t)(td));
|
||||
} else {
|
||||
state = USB_TYPE_PROCESSING;
|
||||
td->nextTD = (uint32_t)headTD & ~(0x0f);
|
||||
hced->headTD = (uint32_t)(td) | ((carry) ? 0x2 : 0);
|
||||
}
|
||||
headTD = (HCTD *) ((hced->headTD) & ~(0x3));
|
||||
transfer_len = td->bufEnd - td->currBufPtr + 1;
|
||||
transferred = transfer_len;
|
||||
buf_start = td->currBufPtr;
|
||||
#endif
|
||||
//printf("queue real transfer: endpoint: %p \t headTD: %p \t head: %08X \t tail: %08X \t td: %08X \t nexttd: %08X\r\n", this, hced->headTD, hced->headTD, ((HCTD *)((hced->headTD) & ~(0x0f)))->nextTD, toSendTD, toSendTD->nextTD);
|
||||
}
|
||||
|
||||
volatile HCTD * USBEndpoint::getProcessedTD()
|
||||
{
|
||||
return td_current;
|
||||
}
|
||||
|
||||
void USBEndpoint::setLengthTransferred(int len) {
|
||||
transferred = len;
|
||||
}
|
||||
|
||||
uint32_t USBEndpoint::getBufStart() {
|
||||
return buf_start;
|
||||
}
|
||||
|
||||
void USBEndpoint::unqueueTransfer(volatile HCTD * td) {
|
||||
//printf("unqueue transfer: %p on endpoint: %p\r\n", (void *)td, this);
|
||||
//headTD = tailTD; //FIXME FIXME
|
||||
// hced->headTD = hced->headTD | (td-> & 0x02);
|
||||
if(td != td_current)
|
||||
{
|
||||
ERR("MISMATCH");
|
||||
ERR("this=%p, td_current = %p, td_next=%p, td=%p", this, td_current, td_next, td);
|
||||
error("");
|
||||
}
|
||||
td->control=0;
|
||||
td->currBufPtr=0;
|
||||
td->bufEnd=0;
|
||||
td->nextTD=0;
|
||||
hced->headTD = hced->tailTD | (hced->headTD & 0x2); //Carry bit
|
||||
td_current = td_next;
|
||||
td_next = td;
|
||||
DBG("current:%p, next:%p", td_current, td_next);
|
||||
}
|
||||
|
||||
ENDPOINT_TYPE USBEndpoint::getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
|
||||
USBEndpoint * USBEndpoint::nextEndpoint() {
|
||||
return (USBEndpoint*)nextEp;
|
||||
}
|
||||
|
||||
|
||||
void USBEndpoint::queueEndpoint(USBEndpoint * ed) {
|
||||
nextEp = ed;
|
||||
hced->nextED = (ed == NULL) ? 0 : (uint32_t)ed->getHCED();
|
||||
}
|
||||
|
||||
volatile HCED * USBEndpoint::getHCED() {
|
||||
return hced;
|
||||
}
|
||||
|
||||
|
||||
volatile HCTD * USBEndpoint::getHeadTD() {
|
||||
//return headTD;
|
||||
return (volatile HCTD*) (hced->headTD & ~0xF);
|
||||
}
|
||||
|
||||
volatile HCTD ** USBEndpoint::getTDList()
|
||||
{
|
||||
return td_list;
|
||||
}
|
|
@ -1,189 +0,0 @@
|
|||
/* Copyright (c) 2010-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 USBENDPOINT_H
|
||||
#define USBENDPOINT_H
|
||||
|
||||
#include "stdint.h"
|
||||
#include "FunctionPointer.h"
|
||||
#include "USBHostTypes.h"
|
||||
|
||||
|
||||
enum ENDPOINT_TYPE {
|
||||
CONTROL_ENDPOINT = 0,
|
||||
ISOCHRONOUS_ENDPOINT,
|
||||
BULK_ENDPOINT,
|
||||
INTERRUPT_ENDPOINT
|
||||
};
|
||||
|
||||
enum ENDPOINT_DIRECTION {
|
||||
OUT = 1,
|
||||
IN
|
||||
};
|
||||
|
||||
class USBEndpoint {
|
||||
public:
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
USBEndpoint() {state = USB_TYPE_FREE; nextEp = NULL;};
|
||||
|
||||
/*
|
||||
* Initialize an endpoint
|
||||
*
|
||||
* @param hced hced associated to the endpoint
|
||||
* @param type endpoint type
|
||||
* @param dir endpoint direction
|
||||
* @param size endpoint size
|
||||
* @param ep_number endpoint number
|
||||
*/
|
||||
void init(HCED * hced, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint32_t size, uint8_t ep_number, HCTD* td_list[2]);
|
||||
|
||||
/*
|
||||
* Set next token. Warining: only useful for the control endpoint
|
||||
*
|
||||
* @param token IN, OUT or SETUP token
|
||||
*/
|
||||
void setNextToken(uint32_t token);
|
||||
|
||||
/*
|
||||
* Queue an endpoint
|
||||
*
|
||||
* endpoint endpoint which will be queued in the linked list
|
||||
*/
|
||||
void queueEndpoint(USBEndpoint * endpoint);
|
||||
|
||||
/*
|
||||
* Get a td to be queued
|
||||
*
|
||||
* @returns td hctd which will be queued
|
||||
*/
|
||||
volatile HCTD* getNextTD();
|
||||
|
||||
/*
|
||||
* Queue a transfer on the endpoint
|
||||
*
|
||||
*/
|
||||
void queueTransfer();
|
||||
|
||||
/*
|
||||
* Get the currently processed td
|
||||
*
|
||||
* @returns td hctd that was queued
|
||||
*/
|
||||
volatile HCTD * getProcessedTD();
|
||||
|
||||
/*
|
||||
* Unqueue a transfer from the endpoint
|
||||
*
|
||||
* @param td hctd which will be unqueued
|
||||
*/
|
||||
void unqueueTransfer(volatile HCTD * td);
|
||||
|
||||
/*
|
||||
* Return the next endpoint in the linked list
|
||||
*
|
||||
* @returns next endpoint
|
||||
*/
|
||||
USBEndpoint * nextEndpoint();
|
||||
|
||||
/**
|
||||
* Attach a member function to call when a transfer is finished
|
||||
*
|
||||
* @param tptr pointer to the object to call the member function on
|
||||
* @param mptr pointer to the member function to be called
|
||||
*/
|
||||
template<typename T>
|
||||
void attach(T* tptr, void (T::*mptr)(void)) {
|
||||
if((mptr != NULL) && (tptr != NULL)) {
|
||||
rx.attach(tptr, mptr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attach a callback called when a transfer is finished
|
||||
*
|
||||
* @param fptr function pointer
|
||||
*/
|
||||
void attach(void (*fn)(void)) {
|
||||
if(fn != NULL) {
|
||||
rx.attach(fn);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Call the handler associted to the end of a transfer
|
||||
*/
|
||||
void call() {
|
||||
rx.call();
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Setters
|
||||
*/
|
||||
void setState(USB_TYPE st) {state = st;}
|
||||
void setDeviceAddress(uint8_t addr);
|
||||
void setLengthTransferred(int len);
|
||||
void setSpeed(uint8_t speed);
|
||||
void setSize(uint32_t size);
|
||||
void setDir(ENDPOINT_DIRECTION d) {dir = d;}
|
||||
|
||||
/*
|
||||
* Getters
|
||||
*/
|
||||
USB_TYPE getState() {return state;}
|
||||
ENDPOINT_TYPE getType();
|
||||
uint8_t getDeviceAddress();
|
||||
int getLengthTransferred() {return transferred;}
|
||||
uint32_t getBufStart();
|
||||
uint32_t getSize();
|
||||
volatile HCTD * getHeadTD();
|
||||
volatile HCTD** getTDList();
|
||||
volatile HCED * getHCED();
|
||||
ENDPOINT_DIRECTION getDir() {return dir;}
|
||||
bool isSetup() {return setup;}
|
||||
|
||||
|
||||
private:
|
||||
ENDPOINT_TYPE type;
|
||||
volatile USB_TYPE state;
|
||||
ENDPOINT_DIRECTION dir;
|
||||
bool setup;
|
||||
|
||||
int transfer_len;
|
||||
int transferred;
|
||||
uint32_t buf_start;
|
||||
|
||||
FunctionPointer rx;
|
||||
|
||||
USBEndpoint* nextEp;
|
||||
|
||||
// USBEndpoint descriptor
|
||||
volatile HCED * hced;
|
||||
|
||||
volatile HCTD * td_list[2];
|
||||
volatile HCTD * td_current;
|
||||
volatile HCTD * td_next;
|
||||
/*bool carry;*/
|
||||
|
||||
int count;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,404 +0,0 @@
|
|||
/* Copyright (c) 2010-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 //WARN: ENABLING DEBUGGING HERE WILL PRINTF IN IRQS!! UNEXPECTED BEHAVIOUR MAY RESULT...
|
||||
#ifndef __MODULE__
|
||||
#define __MODULE__ "USBHALHost.cpp"
|
||||
#endif
|
||||
|
||||
#include "core/dbg.h"
|
||||
#include <cstdint>
|
||||
|
||||
#include "mbed.h"
|
||||
#include "USBHALHost.h"
|
||||
|
||||
// bits of the USB/OTG clock control register
|
||||
#define HOST_CLK_EN (1<<0)
|
||||
#define DEV_CLK_EN (1<<1)
|
||||
#define PORTSEL_CLK_EN (1<<3)
|
||||
#define AHB_CLK_EN (1<<4)
|
||||
|
||||
// bits of the USB/OTG clock status register
|
||||
#define HOST_CLK_ON (1<<0)
|
||||
#define DEV_CLK_ON (1<<1)
|
||||
#define PORTSEL_CLK_ON (1<<3)
|
||||
#define AHB_CLK_ON (1<<4)
|
||||
|
||||
// we need host clock, OTG/portsel clock and AHB clock
|
||||
#define CLOCK_MASK (HOST_CLK_EN | PORTSEL_CLK_EN | AHB_CLK_EN)
|
||||
|
||||
|
||||
|
||||
#define HCCA_SIZE 0x100
|
||||
#define ED_SIZE 0x10
|
||||
#define TD_SIZE 0x10
|
||||
|
||||
#define TOTAL_SIZE (HCCA_SIZE + (MAX_ENDPOINT*ED_SIZE) + (MAX_TD*TD_SIZE))
|
||||
|
||||
static volatile uint8_t usb_buf[TOTAL_SIZE] __attribute((section("AHBSRAM1"),aligned(256))); //256 bytes aligned!
|
||||
|
||||
USBHALHost * USBHALHost::instHost;
|
||||
|
||||
USBHALHost::USBHALHost() : thread(USBHALHost::staticCb, (void*)this, osPriorityNormal, 4*128) {
|
||||
instHost = this;
|
||||
memInit();
|
||||
memset((void*)usb_hcca, 0, HCCA_SIZE);
|
||||
for (int i = 0; i < MAX_ENDPOINT; i++) {
|
||||
edBufAlloc[i] = false;
|
||||
}
|
||||
for (int i = 0; i < MAX_TD; i++) {
|
||||
tdBufAlloc[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void USBHALHost::init() {
|
||||
thread.signal_set(USBHALHOST_SIG_INIT);
|
||||
}
|
||||
|
||||
|
||||
uint32_t USBHALHost::controlHeadED() {
|
||||
return LPC_USB->HcControlHeadED;
|
||||
}
|
||||
|
||||
uint32_t USBHALHost::bulkHeadED() {
|
||||
return LPC_USB->HcBulkHeadED;
|
||||
}
|
||||
|
||||
uint32_t USBHALHost::interruptHeadED() {
|
||||
return usb_hcca->IntTable[0];
|
||||
}
|
||||
|
||||
void USBHALHost::updateBulkHeadED(uint32_t addr) {
|
||||
LPC_USB->HcBulkHeadED = addr;
|
||||
}
|
||||
|
||||
|
||||
void USBHALHost::updateControlHeadED(uint32_t addr) {
|
||||
LPC_USB->HcControlHeadED = addr;
|
||||
}
|
||||
|
||||
void USBHALHost::updateInterruptHeadED(uint32_t addr) {
|
||||
usb_hcca->IntTable[0] = addr;
|
||||
}
|
||||
|
||||
|
||||
void USBHALHost::enableControlList() {
|
||||
LPC_USB->HcCommandStatus = OR_CMD_STATUS_CLF;
|
||||
LPC_USB->HcControl |= OR_CONTROL_CLE; //Enable control list
|
||||
}
|
||||
|
||||
void USBHALHost::enableBulkList() {
|
||||
LPC_USB->HcCommandStatus = OR_CMD_STATUS_BLF;
|
||||
LPC_USB->HcControl |= OR_CONTROL_BLE; //Enable bulk list
|
||||
}
|
||||
|
||||
void USBHALHost::enableInterruptList() {
|
||||
LPC_USB->HcControl |= OR_CONTROL_PLE;
|
||||
}
|
||||
|
||||
bool USBHALHost::disableControlList() {
|
||||
if(LPC_USB->HcControl & OR_CONTROL_CLE)
|
||||
{
|
||||
LPC_USB->HcControl &= ~OR_CONTROL_CLE; //Disable control list
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool USBHALHost::disableBulkList() {
|
||||
if(LPC_USB->HcControl & OR_CONTROL_BLE)
|
||||
{
|
||||
LPC_USB->HcControl &= ~OR_CONTROL_BLE; //Disable bulk list
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool USBHALHost::disableInterruptList() {
|
||||
if(LPC_USB->HcControl & OR_CONTROL_PLE)
|
||||
{
|
||||
LPC_USB->HcControl &= ~OR_CONTROL_PLE; //Disable interrupt list
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//Lock processing
|
||||
void USBHALHost::lock()
|
||||
{
|
||||
mtx.lock();
|
||||
}
|
||||
|
||||
void USBHALHost::unlock()
|
||||
{
|
||||
mtx.unlock();
|
||||
}
|
||||
|
||||
void USBHALHost::memInit() {
|
||||
usb_hcca = (volatile HCCA *)usb_buf;
|
||||
usb_edBuf = usb_buf + HCCA_SIZE;
|
||||
usb_tdBuf = usb_buf + HCCA_SIZE + (MAX_ENDPOINT*ED_SIZE);
|
||||
}
|
||||
|
||||
volatile uint8_t * USBHALHost::getED() {
|
||||
for (int i = 0; i < MAX_ENDPOINT; i++) {
|
||||
if ( !edBufAlloc[i] ) {
|
||||
edBufAlloc[i] = true;
|
||||
return (volatile uint8_t *)(usb_edBuf + i*ED_SIZE);
|
||||
}
|
||||
}
|
||||
perror("Could not allocate ED\r\n");
|
||||
return NULL; //Could not alloc ED
|
||||
}
|
||||
|
||||
volatile uint8_t * USBHALHost::getTD() {
|
||||
int i;
|
||||
for (i = 0; i < MAX_TD; i++) {
|
||||
if ( !tdBufAlloc[i] ) {
|
||||
tdBufAlloc[i] = true;
|
||||
return (volatile uint8_t *)(usb_tdBuf + i*TD_SIZE);
|
||||
}
|
||||
}
|
||||
perror("Could not allocate TD\r\n");
|
||||
return NULL; //Could not alloc TD
|
||||
}
|
||||
|
||||
|
||||
void USBHALHost::freeED(volatile uint8_t * ed) {
|
||||
int i;
|
||||
i = (ed - usb_edBuf) / ED_SIZE;
|
||||
edBufAlloc[i] = false;
|
||||
}
|
||||
|
||||
void USBHALHost::freeTD(volatile uint8_t * td) {
|
||||
int i;
|
||||
i = (td - usb_tdBuf) / TD_SIZE;
|
||||
tdBufAlloc[i] = false;
|
||||
}
|
||||
|
||||
|
||||
void USBHALHost::resetPort(int hub, int port) {
|
||||
DBG("Resetting hub %d, port %d\n", hub, port);
|
||||
if (hub == 0) { //Root hub
|
||||
// USB 2.0 spec says at least 50ms delay before port reset
|
||||
Thread::wait(200);
|
||||
LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRS; // Initiate port reset
|
||||
while (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRS);
|
||||
LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC; // ...and clear port reset signal
|
||||
// Wait for 100 MS after port reset
|
||||
Thread::wait(200);
|
||||
} else {
|
||||
//TODO: Hubs
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void USBHALHost::_usbisr(void) {
|
||||
if (instHost) {
|
||||
instHost->UsbIrqhandler();
|
||||
}
|
||||
}
|
||||
|
||||
void USBHALHost::UsbIrqhandler() {
|
||||
if( LPC_USB->HcInterruptStatus & LPC_USB->HcInterruptEnable ) //Is there something to actually process?
|
||||
{
|
||||
NVIC_DisableIRQ(USB_IRQn);
|
||||
NVIC_ClearPendingIRQ(USB_IRQn);
|
||||
thread.signal_set(USBHALHOST_SIG_IRQ); //Signal processing thread
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void USBHALHost::process()
|
||||
{
|
||||
DBG("USB Process started");
|
||||
|
||||
lock();
|
||||
Thread::signal_wait(USBHALHOST_SIG_INIT);
|
||||
|
||||
NVIC_DisableIRQ(USB_IRQn); // Disable the USB interrupt source
|
||||
|
||||
LPC_SC->PCONP &= ~(1UL<<31); //Cut power
|
||||
Thread::wait(200);
|
||||
|
||||
// turn on power for USB
|
||||
LPC_SC->PCONP |= (1UL<<31);
|
||||
|
||||
// Enable USB host clock, port selection and AHB clock
|
||||
LPC_USB->USBClkCtrl |= CLOCK_MASK;
|
||||
|
||||
// Wait for clocks to become available
|
||||
while ((LPC_USB->USBClkSt & CLOCK_MASK) != CLOCK_MASK);
|
||||
|
||||
// it seems the bits[0:1] mean the following
|
||||
// 0: U1=device, U2=host
|
||||
// 1: U1=host, U2=host
|
||||
// 2: reserved
|
||||
// 3: U1=host, U2=device
|
||||
// NB: this register is only available if OTG clock (aka "port select") is enabled!!
|
||||
// since we don't care about port 2, set just bit 0 to 1 (U1=host)
|
||||
LPC_USB->OTGStCtrl |= 1;
|
||||
|
||||
// now that we've configured the ports, we can turn off the portsel clock
|
||||
LPC_USB->USBClkCtrl &= ~PORTSEL_CLK_EN;
|
||||
|
||||
// configure USB D+/D- pins
|
||||
// P0[29] = USB_D+, 01
|
||||
// P0[30] = USB_D-, 01
|
||||
LPC_PINCON->PINSEL1 &= ~((3<<26) | (3<<28));
|
||||
LPC_PINCON->PINSEL1 |= ((1<<26)|(1<<28)); // 0x14000000
|
||||
|
||||
LPC_USB->HcControl = 0; // HARDWARE RESET
|
||||
LPC_USB->HcControlHeadED = 0; // Initialize Control list head to Zero
|
||||
LPC_USB->HcBulkHeadED = 0; // Initialize Bulk list head to Zero
|
||||
|
||||
//wait_ms(100); // Wait 50 ms before apply reset
|
||||
Thread::wait(100);
|
||||
|
||||
// SOFTWARE RESET
|
||||
LPC_USB->HcCommandStatus = OR_CMD_STATUS_HCR;
|
||||
LPC_USB->HcFmInterval = DEFAULT_FMINTERVAL; // Write Fm Interval and Largest Data Packet Counter
|
||||
LPC_USB->HcPeriodicStart = FI * 90 / 100;
|
||||
|
||||
// Put HC in operational state
|
||||
LPC_USB->HcControl = (LPC_USB->HcControl & (~OR_CONTROL_HCFS)) | OR_CONTROL_HC_OPER;
|
||||
LPC_USB->HcRhStatus = OR_RH_STATUS_LPSC; // Set Global Power
|
||||
|
||||
LPC_USB->HcHCCA = (uint32_t)(usb_hcca);
|
||||
LPC_USB->HcInterruptStatus |= LPC_USB->HcInterruptStatus; // Clear Interrrupt Status
|
||||
|
||||
LPC_USB->HcInterruptEnable = OR_INTR_ENABLE_MIE | OR_INTR_ENABLE_WDH | OR_INTR_ENABLE_RHSC;
|
||||
|
||||
//DG: Do not set prio
|
||||
//NVIC_SetPriority(USB_IRQn, 0); // highest priority
|
||||
// Enable the USB Interrupt
|
||||
NVIC_SetVector(USB_IRQn, (uint32_t)(_usbisr));
|
||||
LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC;
|
||||
LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC;
|
||||
|
||||
NVIC_EnableIRQ(USB_IRQn);
|
||||
|
||||
|
||||
// Check for any connected devices
|
||||
if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CCS) { //Root device connected
|
||||
//Device connected
|
||||
Thread::wait(500);
|
||||
DBG("Device connected (%08x)\n\r", LPC_USB->HcRhPortStatus1);
|
||||
deviceConnected(0, 1, LPC_USB->HcRhPortStatus1 & OR_RH_PORT_LSDA); //Hub 0 (root hub), Port 1 (count starts at 1), Low or High speed
|
||||
}
|
||||
|
||||
unlock();
|
||||
|
||||
|
||||
for(;;)
|
||||
{
|
||||
Thread::signal_wait(USBHALHOST_SIG_IRQ); //Wait for IRQ to process
|
||||
|
||||
lock();
|
||||
DBG("Locked");
|
||||
|
||||
WARN("isr %08x [EN %08x]", LPC_USB->HcInterruptStatus, LPC_USB->HcInterruptEnable);
|
||||
|
||||
//Now process IRQ
|
||||
uint32_t int_status = LPC_USB->HcInterruptStatus & LPC_USB->HcInterruptEnable;
|
||||
|
||||
if (int_status & OR_INTR_STATUS_RHSC)
|
||||
{ // Root hub status change interrupt
|
||||
WARN("Port status %08x", LPC_USB->HcRhPortStatus1);
|
||||
if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CSC)
|
||||
{
|
||||
if (LPC_USB->HcRhStatus & OR_RH_STATUS_DRWE)
|
||||
{
|
||||
|
||||
// When DRWE is on, Connect Status Change
|
||||
// means a remote wakeup event.
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// When DRWE is off, Connect Status Change
|
||||
// is NOT a remote wakeup event
|
||||
|
||||
if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_CCS)
|
||||
{ //Root device connected
|
||||
//Device connected
|
||||
WARN("Device connected!!");
|
||||
// Thread::wait(500);
|
||||
deviceConnected(0, 1, LPC_USB->HcRhPortStatus1 & OR_RH_PORT_LSDA); //Hub 0 (root hub), Port 1 (count starts at 1), Low or High speed
|
||||
}
|
||||
else
|
||||
{ //Root device disconnected
|
||||
//Device disconnected
|
||||
WARN("Device disconnected!!");
|
||||
Thread::wait(500);
|
||||
if (!(int_status & OR_INTR_STATUS_WDH))
|
||||
{
|
||||
usb_hcca->DoneHead = 0;
|
||||
}
|
||||
deviceDisconnected(0, 1, usb_hcca->DoneHead & 0xFFFFFFFE);
|
||||
if (int_status & OR_INTR_STATUS_WDH)
|
||||
{
|
||||
usb_hcca->DoneHead = 0;
|
||||
LPC_USB->HcInterruptStatus = OR_INTR_STATUS_WDH;
|
||||
}
|
||||
|
||||
}
|
||||
//TODO: HUBS
|
||||
}
|
||||
LPC_USB->HcRhPortStatus1 = OR_RH_PORT_CSC;
|
||||
}
|
||||
if (LPC_USB->HcRhPortStatus1 & OR_RH_PORT_PRSC)
|
||||
{
|
||||
LPC_USB->HcRhPortStatus1 = OR_RH_PORT_PRSC;
|
||||
//int_status &= ~OR_RH_PORT_PRSC;
|
||||
}
|
||||
LPC_USB->HcInterruptStatus = OR_INTR_STATUS_RHSC;
|
||||
}
|
||||
|
||||
if (int_status & OR_INTR_STATUS_WDH)
|
||||
{ // Writeback Done Head interrupt
|
||||
transferCompleted(usb_hcca->DoneHead & 0xFFFFFFFE);
|
||||
LPC_USB->HcInterruptStatus = OR_INTR_STATUS_WDH;
|
||||
}
|
||||
|
||||
//IRQ Processed
|
||||
|
||||
DBG("Unlocked");
|
||||
|
||||
NVIC_EnableIRQ(USB_IRQn);
|
||||
|
||||
unlock();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*static*/ void USBHALHost::staticCb(void const* p)
|
||||
{
|
||||
((USBHALHost*)p)->process();
|
||||
}
|
|
@ -1,206 +0,0 @@
|
|||
/* Copyright (c) 2010-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 USBHALHOST_H
|
||||
#define USBHALHOST_H
|
||||
|
||||
#include "rtos.h"
|
||||
|
||||
#include "USBHostTypes.h"
|
||||
|
||||
#define MAX_ENDPOINT 5
|
||||
#define MAX_TD (MAX_ENDPOINT*2)
|
||||
|
||||
#define USBHALHOST_SIG_INIT 0x01
|
||||
#define USBHALHOST_SIG_IRQ 0x02
|
||||
|
||||
class USBHALHost {
|
||||
public:
|
||||
|
||||
/*
|
||||
* Constructor
|
||||
* init variables and memory where will be stored HCCA, ED and TD
|
||||
*/
|
||||
USBHALHost();
|
||||
|
||||
/*
|
||||
* Initialize host controller. Enable USB interrupts. This part is not in the constructor because,
|
||||
* this function calls a virtual method if a device is already connected
|
||||
*/
|
||||
void init();
|
||||
|
||||
/*
|
||||
* reset a port of a specific hub
|
||||
* TODO: support hub
|
||||
*/
|
||||
void resetPort(int hub, int port);
|
||||
|
||||
/*
|
||||
* return the value contained in the control HEAD ED register
|
||||
*
|
||||
* @returns address of the control Head ED
|
||||
*/
|
||||
uint32_t controlHeadED();
|
||||
|
||||
/*
|
||||
* return the value contained in the bulk HEAD ED register
|
||||
*
|
||||
* @returns address of the bulk head ED
|
||||
*/
|
||||
uint32_t bulkHeadED();
|
||||
|
||||
/*
|
||||
* return the value of the head interrupt ED contained in the HCCA
|
||||
*
|
||||
* @returns address of the head interrupt ED contained in the HCCA
|
||||
*/
|
||||
uint32_t interruptHeadED();
|
||||
|
||||
|
||||
/*
|
||||
* Update the head ED for control transfers
|
||||
*/
|
||||
void updateControlHeadED(uint32_t addr);
|
||||
|
||||
/*
|
||||
* Update the head ED for bulk transfers
|
||||
*/
|
||||
void updateBulkHeadED(uint32_t addr);
|
||||
|
||||
/*
|
||||
* Update the head ED for interrupt transfers
|
||||
*/
|
||||
void updateInterruptHeadED(uint32_t addr);
|
||||
|
||||
/*
|
||||
* Enable control list ED
|
||||
*/
|
||||
void enableControlList();
|
||||
|
||||
/*
|
||||
* Enable bulk list ED
|
||||
*/
|
||||
void enableBulkList();
|
||||
|
||||
/*
|
||||
* Enable Interrupt list ED
|
||||
*/
|
||||
void enableInterruptList();
|
||||
|
||||
/*
|
||||
* Disable control list ED
|
||||
*/
|
||||
bool disableControlList();
|
||||
|
||||
/*
|
||||
* Disable bulk list ED
|
||||
*/
|
||||
bool disableBulkList();
|
||||
|
||||
/*
|
||||
* Disable Interrupt list ED
|
||||
*/
|
||||
bool disableInterruptList();
|
||||
|
||||
//Lock processing
|
||||
void lock();
|
||||
|
||||
void unlock();
|
||||
|
||||
|
||||
protected:
|
||||
/*
|
||||
* Virtual method called when a device has been connected
|
||||
*
|
||||
* @param hub hub number of the device
|
||||
* @param port port number of the device
|
||||
* @param lowSpeed 1 if low speed, 0 otherwise
|
||||
*/
|
||||
virtual void deviceConnected(int hub, int port, bool lowSpeed) {};
|
||||
|
||||
/*
|
||||
* Virtuel method called when a device has been disconnected
|
||||
*
|
||||
* @param hub hub number of the device
|
||||
* @param port port number of the device
|
||||
* @param addr list of the TDs which have been completed to dequeue freed TDs
|
||||
*/
|
||||
virtual void deviceDisconnected(int hub, int port, volatile uint32_t addr) {};
|
||||
|
||||
/*
|
||||
* Virtual method called when a transfer has been completed
|
||||
*
|
||||
* @param addr list of the TDs which have been completed
|
||||
*/
|
||||
virtual void transferCompleted(volatile uint32_t addr){};
|
||||
|
||||
/*
|
||||
* Find a memory section for a new ED
|
||||
*
|
||||
* @returns the address of this section
|
||||
*/
|
||||
volatile uint8_t * getED();
|
||||
|
||||
/*
|
||||
* Find a memory section for a new TD
|
||||
*
|
||||
* @returns the address of this section
|
||||
*/
|
||||
volatile uint8_t * getTD();
|
||||
|
||||
/*
|
||||
* Release a previous memory section reserved for an ED
|
||||
*
|
||||
* @param ed address of the ED
|
||||
*/
|
||||
void freeED(volatile uint8_t * ed);
|
||||
|
||||
/*
|
||||
* Release a previous memory section reserved for an TD
|
||||
*
|
||||
* @param ed address of the TD
|
||||
*/
|
||||
void freeTD(volatile uint8_t * td);
|
||||
|
||||
|
||||
private:
|
||||
static void _usbisr(void);
|
||||
void UsbIrqhandler();
|
||||
|
||||
void memInit();
|
||||
|
||||
void process();
|
||||
|
||||
static void staticCb(void const* p);
|
||||
|
||||
HCCA volatile * usb_hcca; //256 bytes aligned!
|
||||
uint8_t volatile * usb_edBuf; //4 bytes aligned!
|
||||
uint8_t volatile * usb_tdBuf; //4 bytes aligned!
|
||||
|
||||
static USBHALHost * instHost;
|
||||
|
||||
bool volatile edBufAlloc[MAX_ENDPOINT];
|
||||
bool volatile tdBufAlloc[MAX_TD];
|
||||
|
||||
//RTOS impl
|
||||
Thread thread;
|
||||
Mutex mtx;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,960 +0,0 @@
|
|||
/* Copyright (c) 2010-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 //WARN: ENABLING DEBUGGING HERE WILL PRINTF IN IRQS!! UNEXPECTED BEHAVIOUR MAY RESULT...
|
||||
#ifndef __MODULE__
|
||||
#define __MODULE__ "USBHost.cpp"
|
||||
#endif
|
||||
|
||||
#include "core/dbg.h"
|
||||
#include <cstdint>
|
||||
|
||||
#include "USBHost.h"
|
||||
#include "rtos.h"
|
||||
|
||||
|
||||
#define NB_MAX_INTF 2
|
||||
|
||||
USBHost * USBHost::instHost = NULL;
|
||||
|
||||
USBHost::USBHost()
|
||||
#if 0 //try not to use this
|
||||
: m_usbQueue(), m_usbThread(3, this, &USBHost::usbProcess)
|
||||
#endif
|
||||
{
|
||||
headControlEndpoint = NULL;
|
||||
headBulkEndpoint = NULL;
|
||||
headInterruptEndpoint = NULL;
|
||||
tailControlEndpoint = NULL;
|
||||
tailBulkEndpoint = NULL;
|
||||
tailInterruptEndpoint = NULL;
|
||||
|
||||
nb_devices = 0;
|
||||
lenReportDescr = 0;
|
||||
|
||||
controlEndpointAllocated = false;
|
||||
|
||||
for (int i = 0; i < MAX_DEVICE_NB; i++) {
|
||||
deviceInUse[i] = false;
|
||||
devices[i].setAddress(i + 1);
|
||||
deviceReset[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void USBHost::transferCompleted(volatile uint32_t addr) {
|
||||
#if 0 //try not to use this
|
||||
Interrupt::enter();
|
||||
m_usbQueue.post(addr);
|
||||
Interrupt::leave();
|
||||
#else
|
||||
|
||||
if(addr == NULL) //Nothing to process?
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
volatile HCTD* tdList = NULL;
|
||||
|
||||
//First we must reverse the list order and dequeue each TD
|
||||
do
|
||||
{
|
||||
volatile HCTD* td = (volatile HCTD*)addr;
|
||||
|
||||
if(td->control & 0xF0000000 != 0)
|
||||
{
|
||||
WARN("Condition code %02x", td->control >> 28);
|
||||
}
|
||||
|
||||
addr = td->nextTD; //Dequeue from physical list
|
||||
td->nextTD = (uint32_t)tdList; //Enqueue into reversed list
|
||||
tdList = td;
|
||||
} while(addr);
|
||||
|
||||
//Now we can process the list
|
||||
USBEndpoint * volatile iter = NULL;
|
||||
|
||||
while(tdList != NULL)
|
||||
{
|
||||
bool found = false;
|
||||
volatile HCTD* td = tdList;
|
||||
tdList = (volatile HCTD*)td->nextTD; //Dequeue element now as it could be modified below
|
||||
for (int i = 0; i < 3; i++) {
|
||||
if (found) {
|
||||
break;
|
||||
}
|
||||
iter = (i == 0) ? headControlEndpoint : ( (i == 1) ? headBulkEndpoint : headInterruptEndpoint);
|
||||
while (iter != NULL) {
|
||||
if (iter->getProcessedTD() == td) {
|
||||
DBG("td=%p FOUND ed: %08X", td, (void *)iter->getHCED());
|
||||
if (((HCTD *)td)->control >> 28) {
|
||||
DBG("TD Error: %d", td->control >> 28);
|
||||
iter->setState(USB_TYPE_TDFAIL);
|
||||
} else if ((uint32_t)iter->getHCED() & 0x1) {
|
||||
DBG("HALTED");
|
||||
iter->setState(USB_TYPE_HALTED);
|
||||
} else if (!td->currBufPtr) {
|
||||
DBG("!%p", iter);
|
||||
iter->setState(USB_TYPE_IDLE);
|
||||
found=true;
|
||||
} else {
|
||||
DBG("!%p", iter);
|
||||
iter->setState(USB_TYPE_IDLE);
|
||||
iter->setLengthTransferred(td->currBufPtr - iter->getBufStart());
|
||||
found=true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
iter = iter->nextEndpoint();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (found) {
|
||||
iter->unqueueTransfer(td);
|
||||
|
||||
if (iter->getType() != CONTROL_ENDPOINT) {
|
||||
iter->call();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
WARN("TD not found!!!");
|
||||
freeTD((uint8_t *)td); //Device must have been disconnected meanwhile
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
USBHost * USBHost::getHostInst() {
|
||||
if (instHost == NULL) {
|
||||
instHost = new USBHost();
|
||||
instHost->init();
|
||||
}
|
||||
return instHost;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Call in ISR when a device has been connected
|
||||
*/
|
||||
void USBHost::deviceConnected(int hub, int port, bool lowSpeed) {
|
||||
|
||||
for (int i = 0; i < MAX_DEVICE_NB; i++) {
|
||||
if (!deviceInUse[i]) {
|
||||
deviceInUse[i] = true;
|
||||
WARN("will call init on device %p: speed: %d", (void *)&devices[i], lowSpeed);
|
||||
devices[i].init(hub, port, lowSpeed);
|
||||
deviceReset[i] = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!controlEndpointAllocated) {
|
||||
control = newEndpoint(CONTROL_ENDPOINT, OUT, 0x08, 0x00);
|
||||
addEndpoint(NULL, 0, (USBEndpoint*)control);
|
||||
controlEndpointAllocated = true;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Call in ISR when a device has been disconnected
|
||||
*/
|
||||
void USBHost::deviceDisconnected(int hub, int port, volatile uint32_t addr) {
|
||||
|
||||
bool controlListState = disableControlList();
|
||||
bool bulkListState = disableBulkList();
|
||||
bool interruptListState = disableInterruptList();
|
||||
|
||||
transferCompleted(addr); //Finish processing any pending completed TD
|
||||
|
||||
for (int i = 0; i < MAX_DEVICE_NB; i++) {
|
||||
if ((devices[i].getHub() == hub) && (devices[i].getPort() == port)) {
|
||||
WARN("device disconnected: %p", (void *)&devices[i]);
|
||||
deviceInUse[i] = false;
|
||||
deviceReset[i] = false;
|
||||
freeDevice((USBDeviceConnected*)&devices[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
nb_devices--;
|
||||
|
||||
if (controlListState) enableControlList();
|
||||
if (bulkListState) enableBulkList();
|
||||
if (interruptListState) enableInterruptList();
|
||||
}
|
||||
|
||||
void USBHost::freeDevice(USBDeviceConnected * dev) {
|
||||
USBEndpoint * ep = NULL;
|
||||
// HCTD * td = NULL;
|
||||
HCED * ed = NULL;
|
||||
|
||||
for (int j = 0; j < dev->getNbInterface(); j++) {
|
||||
DBG("FREE INTF %d, %p, nb_endpot: %d", j, (void *)dev->getInterface(j), dev->getInterface(j)->nb_endpoint);
|
||||
for (int i = 0; i < dev->getInterface(j)->nb_endpoint; i++) {
|
||||
if ((ep = dev->getEndpoint(j, i)) != NULL) {
|
||||
DBG("Freeing USBEndpoint");
|
||||
ed = (HCED *)ep->getHCED();
|
||||
ed->control |= (1 << 13); //sKip bit
|
||||
DBG("Dequeueing USBEndpoint");
|
||||
unqueueEndpoint(ep);
|
||||
|
||||
DBG("Freeing first transfer descriptor");
|
||||
freeTD((volatile uint8_t*)ep->getTDList()[0]);
|
||||
DBG("Freeing second transfer descriptor");
|
||||
freeTD((volatile uint8_t*)ep->getTDList()[1]);
|
||||
|
||||
DBG("Freeing USBEndpoint descriptor");
|
||||
freeED((uint8_t *)ep->getHCED());
|
||||
}
|
||||
//printBulk();
|
||||
//printInt();
|
||||
}
|
||||
}
|
||||
DBG("Disconnecting device");
|
||||
dev->disconnect();
|
||||
DBG("Device disconnected");
|
||||
}
|
||||
|
||||
|
||||
void USBHost::unqueueEndpoint(USBEndpoint * ep) {
|
||||
USBEndpoint * prec = NULL;
|
||||
USBEndpoint * current = NULL;
|
||||
bool found = false;
|
||||
|
||||
DBG("want to unqueue ep: %p", (void *)ep->getHCED());
|
||||
|
||||
for (int i = 0; i < 2; i++) {
|
||||
if (found) {
|
||||
DBG("USBEndpoint unqueued: %p", (void *)ep->getHCED());
|
||||
break;
|
||||
}
|
||||
current = (i == 0) ? (USBEndpoint*)headBulkEndpoint : (USBEndpoint*)headInterruptEndpoint;
|
||||
prec = current;
|
||||
while (current != NULL) {
|
||||
if (current == ep) {
|
||||
if (current->nextEndpoint() != NULL) {
|
||||
prec->queueEndpoint(current->nextEndpoint());
|
||||
if (current == headBulkEndpoint) {
|
||||
updateBulkHeadED((uint32_t)current->nextEndpoint()->getHCED());
|
||||
headBulkEndpoint = current->nextEndpoint();
|
||||
}
|
||||
if (current == headInterruptEndpoint) {
|
||||
updateInterruptHeadED((uint32_t)current->nextEndpoint()->getHCED());
|
||||
headInterruptEndpoint = current->nextEndpoint();
|
||||
}
|
||||
} else {
|
||||
prec->queueEndpoint(NULL);
|
||||
if (current == headBulkEndpoint) {
|
||||
updateBulkHeadED(0);
|
||||
headBulkEndpoint = current->nextEndpoint();
|
||||
}
|
||||
if (current == headInterruptEndpoint) {
|
||||
updateInterruptHeadED(0);
|
||||
headInterruptEndpoint = current->nextEndpoint();
|
||||
}
|
||||
}
|
||||
found = true;
|
||||
current->setState(USB_TYPE_FREE);
|
||||
break;
|
||||
}
|
||||
prec = current;
|
||||
current = current->nextEndpoint();
|
||||
}
|
||||
}
|
||||
//printBulk();
|
||||
//printInt();
|
||||
}
|
||||
|
||||
|
||||
USBDeviceConnected * USBHost::getDevice(uint8_t index) {
|
||||
if ((index >= MAX_DEVICE_NB) || (!deviceInUse[index])) {
|
||||
return NULL;
|
||||
}
|
||||
return (USBDeviceConnected*)&devices[index];
|
||||
}
|
||||
|
||||
|
||||
|
||||
// create an USBEndpoint descriptor. the USBEndpoint is not linked
|
||||
USBEndpoint * USBHost::newEndpoint(ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint32_t size, uint8_t addr) {
|
||||
int i = 0;
|
||||
HCED * ed = (HCED *)getED();
|
||||
HCTD* td_list[2] = { (HCTD*)getTD(), (HCTD*)getTD() };
|
||||
|
||||
memset((void *)td_list[0], 0x00, sizeof(HCTD));
|
||||
memset((void *)td_list[1], 0x00, sizeof(HCTD));
|
||||
|
||||
// search a free USBEndpoint
|
||||
for (i = 0; i < MAX_ENDPOINT; i++) {
|
||||
if (endpoints[i].getState() == USB_TYPE_FREE) {
|
||||
DBG("Trying to create ep");
|
||||
endpoints[i].init(ed, type, dir, size, addr, td_list);
|
||||
//endpoints[i].queueTransfer(nullTd);
|
||||
DBG("USBEndpoint created (%p): type: %d, dir: %d, size: %d, addr: %d", &endpoints[i], type, dir, size, addr);
|
||||
return &endpoints[i];
|
||||
}
|
||||
}
|
||||
DBG("could not allocate more endpoints!!!!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
USB_TYPE USBHost::resetDevice(USBDeviceConnected * dev) {
|
||||
int index = findDevice(dev);
|
||||
if ((index != -1) && (!deviceReset[index])) {
|
||||
resetPort(dev->getHub(), dev->getPort());
|
||||
deviceReset[index] = true;
|
||||
return USB_TYPE_OK;
|
||||
}
|
||||
return USB_TYPE_NOTFOUND;
|
||||
}
|
||||
|
||||
// link the USBEndpoint to the linked list and attach an USBEndpoint to a device
|
||||
bool USBHost::addEndpoint(USBDeviceConnected * dev, uint8_t intf_nb, USBEndpoint * ep) {
|
||||
|
||||
if (ep == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DBG("New ep %p", ep);
|
||||
|
||||
HCED * prevEd;
|
||||
|
||||
// set device address in the USBEndpoint descriptor
|
||||
if (dev == NULL) {
|
||||
ep->setDeviceAddress(0);
|
||||
} else {
|
||||
ep->setDeviceAddress(dev->getAddress());
|
||||
}
|
||||
|
||||
if (dev != NULL && dev->getSpeed()) {
|
||||
DBG("add USBEndpoint: set speed");
|
||||
ep->setSpeed(dev->getSpeed());
|
||||
}
|
||||
|
||||
// queue the new USBEndpoint on the ED list
|
||||
switch (ep->getType()) {
|
||||
|
||||
case CONTROL_ENDPOINT:
|
||||
prevEd = ( HCED*) controlHeadED();
|
||||
if (!prevEd) {
|
||||
updateControlHeadED((uint32_t) ep->getHCED());
|
||||
DBG("First control USBEndpoint: %08X", (uint32_t) ep->getHCED());
|
||||
headControlEndpoint = ep;
|
||||
tailControlEndpoint = ep;
|
||||
return true;
|
||||
}
|
||||
tailControlEndpoint->queueEndpoint(ep);
|
||||
tailControlEndpoint = ep;
|
||||
return true;
|
||||
|
||||
case BULK_ENDPOINT:
|
||||
prevEd = ( HCED*) bulkHeadED();
|
||||
if (!prevEd) {
|
||||
updateBulkHeadED((uint32_t) ep->getHCED());
|
||||
//DBG("First bulk USBEndpoint: %08X\r\n", (uint32_t) ep->getHCED());
|
||||
headBulkEndpoint = ep;
|
||||
tailBulkEndpoint = ep;
|
||||
break;
|
||||
}
|
||||
tailBulkEndpoint->queueEndpoint(ep);
|
||||
tailBulkEndpoint = ep;
|
||||
break;
|
||||
|
||||
case INTERRUPT_ENDPOINT:
|
||||
prevEd = ( HCED*) interruptHeadED();
|
||||
if (!prevEd) {
|
||||
updateInterruptHeadED((uint32_t) ep->getHCED());
|
||||
//DBG("First interrupt USBEndpoint: %08X\r\n", (uint32_t) ep->getHCED());
|
||||
headInterruptEndpoint = ep;
|
||||
tailInterruptEndpoint = ep;
|
||||
break;
|
||||
}
|
||||
tailInterruptEndpoint->queueEndpoint(ep);
|
||||
tailInterruptEndpoint = ep;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
dev->addEndpoint(intf_nb, ep);
|
||||
//printBulk();
|
||||
//printInt();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int USBHost::findDevice(USBDeviceConnected * dev) {
|
||||
for (int i = 0; i < MAX_DEVICE_NB; i++) {
|
||||
if (dev == &devices[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void USBHost::printBulk() {
|
||||
HCED * hced = (HCED *)bulkHeadED();
|
||||
HCTD * hctd = NULL;
|
||||
printf("---------State of Bulk:--------\r\n");
|
||||
while (hced != NULL) {
|
||||
printf("hced: %p\r\n", hced);
|
||||
hctd = (HCTD *)((uint32_t)(hced->headTD) & ~(0x0f));
|
||||
while (((uint32_t)hctd & ~(0x0f)) != ((hced->tailTD) & ~(0x0f))) {
|
||||
printf("\thctd: %p\r\n", hctd);
|
||||
hctd = (HCTD *)((uint32_t)(hctd->nextTD) & ~(0x0f));
|
||||
}
|
||||
printf("\thctd: %p\r\n", hctd);
|
||||
hced = (HCED *)((uint32_t)(hced->nextED) & ~(0x0f));
|
||||
}
|
||||
printf("--------------------\r\n");
|
||||
}
|
||||
|
||||
void USBHost::printInt() {
|
||||
HCED * hced = (HCED *)interruptHeadED();
|
||||
HCTD * hctd = NULL;
|
||||
printf("---------State of Int:--------\r\n");
|
||||
while (hced != NULL) {
|
||||
printf("hced: %p\r\n", hced);
|
||||
hctd = (HCTD *)((uint32_t)(hced->headTD) & ~(0x0f));
|
||||
while (((uint32_t)hctd & ~(0x0f)) != ((hced->tailTD) & ~(0x0f))) {
|
||||
printf("\thctd: %p\r\n", hctd);
|
||||
hctd = (HCTD *)((uint32_t)(hctd->nextTD) & ~(0x0f));
|
||||
}
|
||||
printf("\thctd: %p\r\n", hctd);
|
||||
hced = (HCED *)((uint32_t)(hced->nextED) & ~(0x0f));
|
||||
}
|
||||
printf("--------------------\r\n");
|
||||
}
|
||||
|
||||
|
||||
// add a transfer on the TD linked list
|
||||
USB_TYPE USBHost::addTransfer(USBEndpoint * ed, uint8_t * buf, uint32_t len) {
|
||||
|
||||
// allocate a TD which will be freed in TDcompletion
|
||||
volatile HCTD * td = ed->getNextTD();
|
||||
if (td == NULL) {
|
||||
return USB_TYPE_ERROR;
|
||||
}
|
||||
|
||||
DBG("Next td = %p",td);
|
||||
|
||||
uint32_t token = (ed->isSetup() ? TD_SETUP : ( (ed->getDir() == IN) ? TD_IN : TD_OUT ));
|
||||
|
||||
uint32_t td_toggle;
|
||||
|
||||
if (ed->getType() == CONTROL_ENDPOINT) {
|
||||
if (ed->isSetup()) {
|
||||
td_toggle = TD_TOGGLE_0;
|
||||
} else {
|
||||
td_toggle = TD_TOGGLE_1;
|
||||
}
|
||||
} else {
|
||||
td_toggle = 0;
|
||||
}
|
||||
|
||||
DBG("Buf=%d, len=%d", buf, len);
|
||||
td->control = (TD_ROUNDING | token | TD_DELAY_INT(0) | td_toggle | TD_CC);
|
||||
td->currBufPtr = (uint32_t) buf;
|
||||
td->bufEnd = (uint32_t)(buf + (len - 1));
|
||||
|
||||
DBG("Now do queue transfer on ep %p", ed);
|
||||
|
||||
ed->queueTransfer();
|
||||
|
||||
DBG("Enable list if needed");
|
||||
|
||||
switch (ed->getType()) {
|
||||
case CONTROL_ENDPOINT:
|
||||
enableControlList();
|
||||
break;
|
||||
case BULK_ENDPOINT:
|
||||
enableBulkList();
|
||||
break;
|
||||
case INTERRUPT_ENDPOINT:
|
||||
//printInt();
|
||||
enableInterruptList();
|
||||
break;
|
||||
}
|
||||
|
||||
DBG("Wait for HC to process TD");
|
||||
|
||||
|
||||
return USB_TYPE_PROCESSING;
|
||||
}
|
||||
|
||||
|
||||
|
||||
USB_TYPE USBHost::getDeviceDescriptor(USBDeviceConnected * dev, uint8_t * buf) {
|
||||
return controlRead( dev,
|
||||
USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE,
|
||||
GET_DESCRIPTOR,
|
||||
(DEVICE_DESCRIPTOR << 8) | (0),
|
||||
0,
|
||||
buf,
|
||||
DEVICE_DESCRIPTOR_LENGTH);
|
||||
}
|
||||
|
||||
USB_TYPE USBHost::getConfigurationDescriptor(USBDeviceConnected * dev, uint8_t * buf, uint16_t * len_conf_descr) {
|
||||
USB_TYPE res;
|
||||
uint16_t total_conf_descr_length = 0;
|
||||
|
||||
// fourth step: get the beginning of the configuration descriptor to have the total length of the conf descr
|
||||
res = controlRead( dev,
|
||||
USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE,
|
||||
GET_DESCRIPTOR,
|
||||
(CONFIGURATION_DESCRIPTOR << 8) | (0),
|
||||
0,
|
||||
buf,
|
||||
CONFIGURATION_DESCRIPTOR_LENGTH);
|
||||
|
||||
if (res != USB_TYPE_OK) {
|
||||
ERR("GET CONF 1 DESCR FAILED");
|
||||
return res;
|
||||
}
|
||||
total_conf_descr_length = buf[2] | (buf[3] << 8);
|
||||
if (len_conf_descr != NULL) {
|
||||
*len_conf_descr = total_conf_descr_length;
|
||||
}
|
||||
DBG("TOTAL_LENGTH: %d \t NUM_INTERF: %d", total_conf_descr_length, buf[4]);
|
||||
|
||||
return controlRead( dev,
|
||||
USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE,
|
||||
GET_DESCRIPTOR,
|
||||
(CONFIGURATION_DESCRIPTOR << 8) | (0),
|
||||
0,
|
||||
buf,
|
||||
total_conf_descr_length);
|
||||
|
||||
}
|
||||
|
||||
USB_TYPE USBHost::setConfiguration(USBDeviceConnected * dev, uint8_t conf) {
|
||||
return controlWrite( dev,
|
||||
USB_HOST_TO_DEVICE | USB_RECIPIENT_DEVICE,
|
||||
SET_CONFIGURATION,
|
||||
conf,
|
||||
0,
|
||||
NULL,
|
||||
0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// enumerate a device with the control USBEndpoint
|
||||
USB_TYPE USBHost::enumerate(USBDeviceConnected * dev, IUSBEnumerator* pEnumerator) {
|
||||
uint8_t data[384];
|
||||
uint16_t total_conf_descr_length = 0;
|
||||
USB_TYPE res;
|
||||
|
||||
DBG("data = %p", data);
|
||||
|
||||
if (dev->isEnumerated()) {
|
||||
return USB_TYPE_OK;
|
||||
}
|
||||
|
||||
// first step: get the size of USBEndpoint 0
|
||||
DBG("Get size of EP 0");
|
||||
res = controlRead( dev,
|
||||
USB_DEVICE_TO_HOST | USB_RECIPIENT_DEVICE,
|
||||
GET_DESCRIPTOR,
|
||||
(DEVICE_DESCRIPTOR << 8) | (0),
|
||||
0,
|
||||
data,
|
||||
8);
|
||||
|
||||
if (res != USB_TYPE_OK) {
|
||||
ERR("Control read failed!!");
|
||||
return res;
|
||||
}
|
||||
dev->setSizeControlEndpoint(data[7]);
|
||||
DBG("size control USBEndpoint: %d", dev->getSizeControlEndpoint());
|
||||
|
||||
DBG("Now set addr");
|
||||
// second step: set an address to the device
|
||||
res = controlWrite( dev,
|
||||
USB_HOST_TO_DEVICE | USB_RECIPIENT_DEVICE,
|
||||
SET_ADDRESS,
|
||||
dev->getAddress(),
|
||||
0,
|
||||
NULL,
|
||||
0);
|
||||
|
||||
if (res != USB_TYPE_OK) {
|
||||
DBG("SET ADDR FAILED");
|
||||
freeDevice(dev);
|
||||
return res;
|
||||
}
|
||||
dev->activeAddress();
|
||||
|
||||
|
||||
// third step: get the whole device descriptor to see vid, pid
|
||||
res = getDeviceDescriptor(dev, data);
|
||||
|
||||
if (res != USB_TYPE_OK) {
|
||||
DBG("GET DEV DESCR FAILED");
|
||||
return res;
|
||||
}
|
||||
dev->setClass(data[4]);
|
||||
dev->setSubClass(data[5]);
|
||||
dev->setProtocol(data[6]);
|
||||
dev->setVid(data[8] | (data[9] << 8));
|
||||
dev->setPid(data[10] | (data[11] << 8));
|
||||
DBG("CLASS: %02X \t VID: %04X \t PID: %04X", data[4], data[8] | (data[9] << 8), data[10] | (data[11] << 8));
|
||||
|
||||
pEnumerator->setVidPid( data[8] | (data[9] << 8), data[10] | (data[11] << 8) );
|
||||
|
||||
res = getConfigurationDescriptor(dev, data, &total_conf_descr_length);
|
||||
if (res != USB_TYPE_OK) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Parse the configuration descriptor
|
||||
parseConfDescr(dev, data, total_conf_descr_length, pEnumerator);
|
||||
|
||||
|
||||
// sixth step: set configuration (only 1 supported)
|
||||
res = setConfiguration(dev, 1);
|
||||
|
||||
if (res != USB_TYPE_OK) {
|
||||
DBG("SET CONF FAILED");
|
||||
freeDevice(dev);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Now the device is enumerated!
|
||||
dev->setEnumerated();
|
||||
DBG("device enumerated!!!!");
|
||||
|
||||
// Some devices may require this delay
|
||||
Thread::wait(100);
|
||||
|
||||
return USB_TYPE_OK;
|
||||
}
|
||||
|
||||
// this method fills the USBDeviceConnected object: class,.... . It also add endpoints found in the descriptor.
|
||||
void USBHost::parseConfDescr(USBDeviceConnected * dev, uint8_t * conf_descr, uint32_t len, IUSBEnumerator* pEnumerator) {
|
||||
uint32_t index = 0;
|
||||
uint32_t len_desc = 0;
|
||||
uint8_t id = 0;
|
||||
int nb_endpoints_used = 0;
|
||||
USBEndpoint * ep = NULL;
|
||||
uint8_t intf_nb = 0;
|
||||
bool parsing_intf = false;
|
||||
|
||||
while (index < len) {
|
||||
len_desc = conf_descr[index];
|
||||
id = conf_descr[index+1];
|
||||
switch (id) {
|
||||
case CONFIGURATION_DESCRIPTOR:
|
||||
break;
|
||||
case INTERFACE_DESCRIPTOR:
|
||||
if(pEnumerator->parseInterface(intf_nb, conf_descr[index + 5], conf_descr[index + 6], conf_descr[index + 7]))
|
||||
{
|
||||
if (intf_nb++ <= NB_MAX_INTF) {
|
||||
dev->addInterface(intf_nb - 1, conf_descr[index + 5], conf_descr[index + 6], conf_descr[index + 7]);
|
||||
nb_endpoints_used = 0;
|
||||
DBG("ADD INTF %d on device %p: class: %d, subclass: %d, proto: %d", intf_nb - 1, (void *)dev, conf_descr[index + 5],conf_descr[index + 6],conf_descr[index + 7]);
|
||||
} else {
|
||||
DBG("Drop intf...");
|
||||
}
|
||||
parsing_intf = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
parsing_intf = false;
|
||||
}
|
||||
break;
|
||||
case ENDPOINT_DESCRIPTOR:
|
||||
DBG("Ep DESC");
|
||||
if (parsing_intf && (intf_nb <= NB_MAX_INTF) ) {
|
||||
if (nb_endpoints_used < MAX_ENDPOINT_PER_INTERFACE) {
|
||||
if( pEnumerator->useEndpoint(intf_nb - 1, (ENDPOINT_TYPE)(conf_descr[index + 3] & 0x03), (ENDPOINT_DIRECTION)((conf_descr[index + 2] >> 7) + 1)) )
|
||||
{
|
||||
// if the USBEndpoint is isochronous -> skip it (TODO: fix this)
|
||||
if ((conf_descr[index + 3] & 0x03) != ISOCHRONOUS_ENDPOINT) {
|
||||
ep = newEndpoint((ENDPOINT_TYPE)(conf_descr[index+3] & 0x03),
|
||||
(ENDPOINT_DIRECTION)((conf_descr[index + 2] >> 7) + 1),
|
||||
conf_descr[index + 4] | (conf_descr[index + 5] << 8),
|
||||
conf_descr[index + 2] & 0x0f);
|
||||
DBG("ADD USBEndpoint %p, on interf %d on device %p", (void *)ep, intf_nb - 1, (void *)dev);
|
||||
if (ep != NULL && dev != NULL) {
|
||||
addEndpoint(dev, intf_nb - 1, ep);
|
||||
} else {
|
||||
DBG("EP NULL");
|
||||
}
|
||||
nb_endpoints_used++;
|
||||
} else {
|
||||
DBG("ISO USBEndpoint NOT SUPPORTED");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//DBG("USBEndpoint DESCR");
|
||||
break;
|
||||
case HID_DESCRIPTOR:
|
||||
lenReportDescr = conf_descr[index + 7] | (conf_descr[index + 8] << 8);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
index += len_desc;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
USB_TYPE USBHost::bulkRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) {
|
||||
USB_TYPE res;
|
||||
|
||||
if (dev == NULL || ep == NULL) {
|
||||
return USB_TYPE_ERROR;
|
||||
}
|
||||
|
||||
if ((ep->getDir() != IN) || (ep->getType() != BULK_ENDPOINT)) {
|
||||
DBG("wrong dir or bad USBEndpoint type");
|
||||
return USB_TYPE_ERROR;
|
||||
}
|
||||
if (dev->getAddress() != ep->getDeviceAddress()) {
|
||||
DBG("USBEndpoint addr and device addr don't match");
|
||||
return USB_TYPE_ERROR;
|
||||
}
|
||||
addTransfer(ep, buf, len);
|
||||
if (blocking) {
|
||||
unlock();
|
||||
while ((res = control->getState()) == USB_TYPE_PROCESSING);
|
||||
lock();
|
||||
if (res != USB_TYPE_IDLE) {
|
||||
return res;
|
||||
}
|
||||
return USB_TYPE_OK;
|
||||
}
|
||||
return USB_TYPE_PROCESSING;
|
||||
}
|
||||
|
||||
USB_TYPE USBHost::bulkWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) {
|
||||
USB_TYPE res;
|
||||
|
||||
if (dev == NULL || ep == NULL) {
|
||||
return USB_TYPE_ERROR;
|
||||
}
|
||||
|
||||
if ((ep->getDir() != OUT) || (ep->getType() != BULK_ENDPOINT)) {
|
||||
DBG("wrong dir or bad USBEndpoint type");
|
||||
return USB_TYPE_ERROR;
|
||||
}
|
||||
if (dev->getAddress() != ep->getDeviceAddress()) {
|
||||
DBG("USBEndpoint addr and device addr don't match");
|
||||
return USB_TYPE_ERROR;
|
||||
}
|
||||
addTransfer(ep, buf, len);
|
||||
if (blocking) {
|
||||
unlock();
|
||||
while ((res = control->getState()) == USB_TYPE_PROCESSING)
|
||||
{
|
||||
DBG("!!!!!!!!!!!!!wait bulkwrite");
|
||||
Thread::wait(100);
|
||||
}
|
||||
lock();
|
||||
DBG("!!!!!!!!!!!!! bulkwrite finished");
|
||||
if (res != USB_TYPE_IDLE) {
|
||||
return res;
|
||||
}
|
||||
return USB_TYPE_OK;
|
||||
}
|
||||
return USB_TYPE_PROCESSING;
|
||||
}
|
||||
|
||||
USB_TYPE USBHost::interruptWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) {
|
||||
USB_TYPE res;
|
||||
|
||||
if (dev == NULL || ep == NULL) {
|
||||
return USB_TYPE_ERROR;
|
||||
}
|
||||
|
||||
if (ep->getState() != USB_TYPE_IDLE) {
|
||||
return ep->getState();
|
||||
}
|
||||
|
||||
if ((ep->getDir() != OUT) || (ep->getType() != INTERRUPT_ENDPOINT)) {
|
||||
ERR("wrong dir or bad USBEndpoint type: %d, %d", ep->getDir(), ep->getType());
|
||||
return USB_TYPE_ERROR;
|
||||
}
|
||||
if (dev->getAddress() != ep->getDeviceAddress()) {
|
||||
ERR("USBEndpoint addr and device addr don't match");
|
||||
return USB_TYPE_ERROR;
|
||||
}
|
||||
addTransfer(ep, buf, len);
|
||||
if (blocking) {
|
||||
while ((res = ep->getState()) == USB_TYPE_PROCESSING);
|
||||
if (res != USB_TYPE_IDLE) {
|
||||
return res;
|
||||
}
|
||||
return USB_TYPE_OK;
|
||||
}
|
||||
return USB_TYPE_PROCESSING;
|
||||
}
|
||||
|
||||
USB_TYPE USBHost::interruptRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking) {
|
||||
USB_TYPE res;
|
||||
|
||||
if (dev == NULL || ep == NULL) {
|
||||
return USB_TYPE_ERROR;
|
||||
}
|
||||
|
||||
if (ep->getState() != USB_TYPE_IDLE) {
|
||||
return ep->getState();
|
||||
}
|
||||
|
||||
if ((ep->getDir() != IN) || (ep->getType() != INTERRUPT_ENDPOINT)) {
|
||||
ERR("wrong dir or bad USBEndpoint type");
|
||||
return USB_TYPE_ERROR;
|
||||
}
|
||||
|
||||
if (dev->getAddress() != ep->getDeviceAddress()) {
|
||||
ERR("USBEndpoint addr and device addr don't match");
|
||||
return USB_TYPE_ERROR;
|
||||
}
|
||||
addTransfer(ep, buf, len);
|
||||
if (blocking) {
|
||||
while ((res = ep->getState()) == USB_TYPE_PROCESSING);
|
||||
if (res != USB_TYPE_IDLE) {
|
||||
return res;
|
||||
}
|
||||
return USB_TYPE_OK;
|
||||
}
|
||||
return USB_TYPE_PROCESSING;
|
||||
}
|
||||
|
||||
|
||||
USB_TYPE USBHost::controlRead(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) {
|
||||
int length_transfer = len;
|
||||
//DBG("want to transfer: %d bytes\r\n", length_transfer);
|
||||
USB_TYPE res;
|
||||
control->setSpeed(dev->getSpeed());
|
||||
control->setSize(dev->getSizeControlEndpoint());
|
||||
if (dev->isActiveAddress()) {
|
||||
control->setDeviceAddress(dev->getAddress());
|
||||
} else {
|
||||
control->setDeviceAddress(0);
|
||||
}
|
||||
fillControlBuf(requestType, request, value, index, len);
|
||||
/* DBG("will call transfer: ");
|
||||
for (int i = 0; i < 8; i++) {
|
||||
DBG("%02X ", setupPacket[i]);
|
||||
}*/
|
||||
control->setNextToken(TD_SETUP);
|
||||
addTransfer(control, (uint8_t*)setupPacket, 8);
|
||||
DBG("Now wait for TD to be processed");
|
||||
unlock();
|
||||
DBG("Unlocked");
|
||||
while ((res = control->getState()) == USB_TYPE_PROCESSING);
|
||||
lock();
|
||||
DBG("TD processed with result %d", res);
|
||||
if (res != USB_TYPE_IDLE) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (length_transfer) {
|
||||
DBG("In data to be transfered...");
|
||||
control->setNextToken(TD_IN);
|
||||
addTransfer(control, (uint8_t *)buf, length_transfer);
|
||||
unlock();
|
||||
while ((res = control->getState()) == USB_TYPE_PROCESSING);
|
||||
lock();
|
||||
if (res != USB_TYPE_IDLE) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
DBG("Transfer NULL packet (OUT)");
|
||||
control->setNextToken(TD_OUT);
|
||||
addTransfer(control, NULL, 0);
|
||||
unlock();
|
||||
while ((res = control->getState()) == USB_TYPE_PROCESSING);
|
||||
lock();
|
||||
if (res != USB_TYPE_IDLE) {
|
||||
return res;
|
||||
}
|
||||
return USB_TYPE_OK;
|
||||
}
|
||||
|
||||
|
||||
USB_TYPE USBHost::controlWrite(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) {
|
||||
control->setSpeed(dev->getSpeed());
|
||||
|
||||
int length_transfer = len;
|
||||
USB_TYPE res;
|
||||
|
||||
control->setSize(dev->getSizeControlEndpoint());
|
||||
if (dev->isActiveAddress()) {
|
||||
control->setDeviceAddress(dev->getAddress());
|
||||
} else {
|
||||
control->setDeviceAddress(0);
|
||||
}
|
||||
fillControlBuf(requestType, request, value, index, len);
|
||||
/*DBG("will call transfer: ");
|
||||
for (int i = 0; i < 8; i++) {
|
||||
printf("%01X ", setupPacket[i]);
|
||||
}
|
||||
printf("\r\n");*/
|
||||
control->setNextToken(TD_SETUP);
|
||||
addTransfer(control, (uint8_t*)setupPacket, 8);
|
||||
unlock();
|
||||
while ((res = control->getState()) == USB_TYPE_PROCESSING);
|
||||
lock();
|
||||
if (res != USB_TYPE_IDLE) {
|
||||
return res;
|
||||
}
|
||||
|
||||
if (length_transfer) {
|
||||
control->setNextToken(TD_OUT);
|
||||
addTransfer(control, (uint8_t *)buf, length_transfer);
|
||||
unlock();
|
||||
while ((res = control->getState()) == USB_TYPE_PROCESSING);
|
||||
lock();
|
||||
if (res != USB_TYPE_IDLE) {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
control->setNextToken(TD_IN);
|
||||
addTransfer(control, NULL, 0);
|
||||
unlock();
|
||||
while ((res = control->getState()) == USB_TYPE_PROCESSING);
|
||||
lock();
|
||||
if (res != USB_TYPE_IDLE) {
|
||||
return res;
|
||||
}
|
||||
return USB_TYPE_OK;
|
||||
}
|
||||
|
||||
|
||||
void USBHost::fillControlBuf(uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, int len) {
|
||||
#ifdef __BIG_ENDIAN
|
||||
#error "Must implement BE to LE conv here"
|
||||
#endif
|
||||
setupPacket[0] = requestType;
|
||||
setupPacket[1] = request;
|
||||
//We are in LE so it's fine
|
||||
*((uint32_t*)&setupPacket[2]) = value;
|
||||
*((uint32_t*)&setupPacket[4]) = index;
|
||||
*((uint32_t*)&setupPacket[6]) = (uint32_t) len;
|
||||
}
|
||||
|
|
@ -1,304 +0,0 @@
|
|||
/* Copyright (c) 2010-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 USBHOST_H
|
||||
#define USBHOST_H
|
||||
|
||||
#include "USBHALHost.h"
|
||||
#include "USBDeviceConnected.h"
|
||||
#include "USBEndpoint.h"
|
||||
#include "IUSBEnumerator.h"
|
||||
|
||||
#define MAX_DEVICE_NB 1
|
||||
|
||||
// singleton class
|
||||
class USBHost : public USBHALHost {
|
||||
public:
|
||||
/*
|
||||
* Static method to create or retrieve the single USBHost instance
|
||||
*/
|
||||
static USBHost * getHostInst();
|
||||
|
||||
USB_TYPE getDeviceDescriptor(USBDeviceConnected * dev, uint8_t * buf) ;
|
||||
USB_TYPE getConfigurationDescriptor(USBDeviceConnected * dev, uint8_t * buf, uint16_t * len_conf_descr = NULL) ;
|
||||
USB_TYPE setConfiguration(USBDeviceConnected * dev, uint8_t conf) ;
|
||||
USB_TYPE getStringDescriptor(USBDeviceConnected * dev, uint8_t index, uint8_t * buf) ;
|
||||
USB_TYPE getReportDescriptor(USBDeviceConnected * dev, uint8_t * buf, uint8_t len) ;
|
||||
|
||||
/*
|
||||
* Control read: setup stage, data stage and status stage
|
||||
*
|
||||
* @param dev the control read will be done for this device
|
||||
* @param requestType request type
|
||||
* @param request request
|
||||
* @param value value
|
||||
* @param index index
|
||||
* @param buf pointer on a buffer where will be store the data received
|
||||
* @param len length of the transfer
|
||||
*
|
||||
* @returns status of the control read
|
||||
*/
|
||||
USB_TYPE controlRead(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) ;
|
||||
|
||||
/*
|
||||
* Control write: setup stage, data stage and status stage
|
||||
*
|
||||
* @param dev the control write will be done for this device
|
||||
* @param requestType request type
|
||||
* @param request request
|
||||
* @param value value
|
||||
* @param index index
|
||||
* @param buf pointer on a buffer which will be written
|
||||
* @param len length of the transfer
|
||||
*
|
||||
* @returns status of the control write
|
||||
*/
|
||||
USB_TYPE controlWrite(USBDeviceConnected * dev, uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, uint8_t * buf, uint32_t len) ;
|
||||
|
||||
|
||||
/*
|
||||
* Bulk read
|
||||
*
|
||||
* @param dev the bulk transfer will be done for this device
|
||||
* @param ep USBEndpoint which will be used to read a packet
|
||||
* @param buf pointer on a buffer where will be store the data received
|
||||
* @param len length of the transfer
|
||||
* @param blocking if true, the read is blocking (wait for completion)
|
||||
*
|
||||
* @returns status of the bulk read
|
||||
*/
|
||||
USB_TYPE bulkRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true) ;
|
||||
|
||||
/*
|
||||
* Bulk write
|
||||
*
|
||||
* @param dev the bulk transfer will be done for this device
|
||||
* @param ep USBEndpoint which will be used to write a packet
|
||||
* @param buf pointer on a buffer which will be written
|
||||
* @param len length of the transfer
|
||||
* @param blocking if true, the write is blocking (wait for completion)
|
||||
*
|
||||
* @returns status of the bulk write
|
||||
*/
|
||||
USB_TYPE bulkWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true) ;
|
||||
|
||||
/*
|
||||
* Interrupt read
|
||||
*
|
||||
* @param dev the bulk transfer will be done for this device
|
||||
* @param ep USBEndpoint which will be used to write a packet
|
||||
* @param buf pointer on a buffer which will be written
|
||||
* @param len length of the transfer
|
||||
* @param blocking if true, the read is blocking (wait for completion)
|
||||
*
|
||||
* @returns status of the interrupt read
|
||||
*/
|
||||
USB_TYPE interruptRead(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true) ;
|
||||
|
||||
/*
|
||||
* Interrupt write
|
||||
*
|
||||
* @param dev the bulk transfer will be done for this device
|
||||
* @param ep USBEndpoint which will be used to write a packet
|
||||
* @param buf pointer on a buffer which will be written
|
||||
* @param len length of the transfer
|
||||
* @param blocking if true, the write is blocking (wait for completion)
|
||||
*
|
||||
* @returns status of the interrupt write
|
||||
*/
|
||||
USB_TYPE interruptWrite(USBDeviceConnected * dev, USBEndpoint * ep, uint8_t * buf, uint32_t len, bool blocking = true) ;
|
||||
|
||||
/*
|
||||
* Enumerate a device. This method is responsible for:
|
||||
* - set the address of the device
|
||||
* - fill a USBDeviceConnected object:
|
||||
* - add interfaces, endpoints, ...
|
||||
* - set a configuration
|
||||
*
|
||||
* @param dev device which will be enumerated
|
||||
*
|
||||
* @returns status of the enumeration
|
||||
*/
|
||||
USB_TYPE enumerate(USBDeviceConnected * dev, IUSBEnumerator* pEnumerator) ;
|
||||
|
||||
/*
|
||||
* Get a device
|
||||
*
|
||||
* @param index index of the device which will be returned
|
||||
*
|
||||
* @returns pointer on the "index" device
|
||||
*/
|
||||
USBDeviceConnected * getDevice(uint8_t index) ;
|
||||
|
||||
/*
|
||||
* reset port and hub of a specific device
|
||||
*
|
||||
* @param pointer on the device hich will be reseted
|
||||
*/
|
||||
USB_TYPE resetDevice(USBDeviceConnected * dev) ;
|
||||
|
||||
/*
|
||||
* If there is a HID device connected, the host stores the length of the report descriptor.
|
||||
* This avoid to the driver to re-ask the configuration descriptor to request the report descriptor
|
||||
*
|
||||
* @returns length of the report descriptor
|
||||
*/
|
||||
uint16_t getLengthReportDescr() {
|
||||
return lenReportDescr;
|
||||
};
|
||||
|
||||
/**
|
||||
* register a driver into the host associated with a callback function called when the device is disconnected
|
||||
*
|
||||
* @param dev device
|
||||
* @param tptr pointer to the object to call the member function on
|
||||
* @param mptr pointer to the member function to be called
|
||||
*/
|
||||
template<typename T>
|
||||
void registerDriver(USBDeviceConnected * dev, uint8_t intf, T* tptr, void (T::*mptr)(void)) {
|
||||
int index = findDevice(dev);
|
||||
if ((index != -1) && (mptr != NULL) && (tptr != NULL)) {
|
||||
dev->onDisconnect(intf, tptr, mptr);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* register a driver into the host associated with a callback function called when the device is disconnected
|
||||
*
|
||||
* @param dev device
|
||||
* @param fn callback called when the specified device has been disconnected
|
||||
*/
|
||||
void registerDriver(USBDeviceConnected * dev, uint8_t intf, void (*fn)(void)) {
|
||||
int index = findDevice(dev);
|
||||
if ((index != -1) && (fn != NULL)) {
|
||||
dev->onDisconnect(intf, fn);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
/*
|
||||
* Virtual method called when a device has been connected
|
||||
*
|
||||
* @param hub hub number of the device
|
||||
* @param port port number of the device
|
||||
* @param lowSpeed 1 if low speed, 0 otherwise
|
||||
*/
|
||||
virtual void deviceConnected(int hub, int port, bool lowSpeed) ;
|
||||
|
||||
/*
|
||||
* Virtuel method called when a device has been disconnected
|
||||
*
|
||||
* @param hub hub number of the device
|
||||
* @param port port number of the device
|
||||
* @param addr list of the TDs which have been completed to dequeue freed TDs
|
||||
*/
|
||||
virtual void deviceDisconnected(int hub, int port, volatile uint32_t addr) ;
|
||||
|
||||
/*
|
||||
* Virtual method called when a transfer has been completed
|
||||
*
|
||||
* @param addr list of the TDs which have been completed
|
||||
*/
|
||||
virtual void transferCompleted(volatile uint32_t addr) ;
|
||||
|
||||
|
||||
private:
|
||||
// singleton class -> constructor is private
|
||||
USBHost();
|
||||
|
||||
static USBHost * instHost;
|
||||
|
||||
uint8_t nb_devices;
|
||||
uint16_t lenReportDescr;
|
||||
|
||||
void fillControlBuf(uint8_t requestType, uint8_t request, uint32_t value, uint32_t index, int len) ;
|
||||
void parseConfDescr(USBDeviceConnected * dev, uint8_t * conf_descr, uint32_t len, IUSBEnumerator* pEnumerator) ;
|
||||
void freeDevice(USBDeviceConnected * dev) ;
|
||||
int findDevice(USBDeviceConnected * dev) ;
|
||||
|
||||
|
||||
// endpoints
|
||||
void unqueueEndpoint(USBEndpoint * ep) ;
|
||||
USBEndpoint endpoints[MAX_ENDPOINT];
|
||||
USBEndpoint* volatile control;
|
||||
|
||||
USBEndpoint* volatile headControlEndpoint;
|
||||
USBEndpoint* volatile headBulkEndpoint;
|
||||
USBEndpoint* volatile headInterruptEndpoint;
|
||||
|
||||
USBEndpoint* volatile tailControlEndpoint;
|
||||
USBEndpoint* volatile tailBulkEndpoint;
|
||||
USBEndpoint* volatile tailInterruptEndpoint;
|
||||
|
||||
bool controlEndpointAllocated;
|
||||
|
||||
|
||||
// devices connected
|
||||
USBDeviceConnected devices[MAX_DEVICE_NB];
|
||||
volatile bool deviceInUse[MAX_DEVICE_NB];
|
||||
volatile bool deviceReset[MAX_DEVICE_NB];
|
||||
|
||||
/*
|
||||
* Add a transfer on the TD linked list associated to an ED
|
||||
*
|
||||
* @param ed the transfer is associated to this ed
|
||||
* @param buf pointer on a buffer where will be read/write data to send or receive
|
||||
* @param len transfer length
|
||||
*
|
||||
* @return status of the transfer
|
||||
*/
|
||||
USB_TYPE addTransfer(USBEndpoint * ed, uint8_t * buf, uint32_t len) ;
|
||||
|
||||
/*
|
||||
* Link the USBEndpoint to the linked list and attach an USBEndpoint this USBEndpoint to a device
|
||||
*
|
||||
* @param dev pointer on a USBDeviceConnected object
|
||||
* @param ep pointer on the USBEndpoint which will be added
|
||||
*
|
||||
* return true if successful
|
||||
*/
|
||||
bool addEndpoint(USBDeviceConnected * dev, uint8_t intf_nb, USBEndpoint * ep) ;
|
||||
|
||||
/*
|
||||
* Create an USBEndpoint descriptor. Warning: the USBEndpoint is not linked.
|
||||
*
|
||||
* @param type USBEndpoint type (CONTROL_ENDPOINT, BULK_ENDPOINT, INTERRUPT_ENDPOINT)
|
||||
* @param dir USBEndpoint direction (no meaning for CONTROL_ENDPOINT)
|
||||
* @param size USBEndpoint max packet size
|
||||
* @param addr USBEndpoint address
|
||||
*
|
||||
* @returns pointer on the USBEndpoint created
|
||||
*/
|
||||
USBEndpoint * newEndpoint(ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir, uint32_t size, uint8_t addr) ;
|
||||
|
||||
|
||||
// to store a setup packet
|
||||
uint8_t setupPacket[8];
|
||||
|
||||
|
||||
/////////////////////////
|
||||
/// FOR DEBUG
|
||||
/////////////////////////
|
||||
void printBulk();
|
||||
void printInt();
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -1,191 +0,0 @@
|
|||
/* Copyright (c) 2010-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 USB_INC_H
|
||||
#define USB_INC_H
|
||||
|
||||
#include "mbed.h"
|
||||
|
||||
enum USB_TYPE {
|
||||
USB_TYPE_DISCONNECTED = -10,
|
||||
USB_TYPE_NOTFOUND = -9,
|
||||
USB_TYPE_BADCONFIG = -8,
|
||||
USB_TYPE_FREE = -7,
|
||||
USB_TYPE_IDLE = -6,
|
||||
USB_TYPE_PROCESSING = -5,
|
||||
USB_TYPE_HALTED = -4, //Transfer on an ep is stalled
|
||||
USB_TYPE_BUSY = -3,
|
||||
USB_TYPE_TDFAIL = -2,
|
||||
USB_TYPE_ERROR = -1,
|
||||
USB_TYPE_OK = 0
|
||||
};
|
||||
|
||||
#define AUDIO_CLASS 0x01
|
||||
#define CDC_CLASS 0x02
|
||||
#define MSD_CLASS 0x08
|
||||
#define HID_CLASS 0x03
|
||||
|
||||
|
||||
// From NXP's USBHostLite stack's usbhost_lpc17xx.h
|
||||
// Only the types names have been changed to avoid unecessary typedefs
|
||||
|
||||
|
||||
/*
|
||||
**************************************************************************************************************
|
||||
* NXP USB Host Stack
|
||||
*
|
||||
* (c) Copyright 2008, NXP SemiConductors
|
||||
* (c) Copyright 2008, OnChip Technologies LLC
|
||||
* All Rights Reserved
|
||||
*
|
||||
* www.nxp.com
|
||||
* www.onchiptech.com
|
||||
*
|
||||
* File : usbhost_lpc17xx.h
|
||||
* Programmer(s) : Ravikanth.P
|
||||
* Version :
|
||||
*
|
||||
**************************************************************************************************************
|
||||
*/
|
||||
|
||||
|
||||
// ------------------ HcControl Register ---------------------
|
||||
#define OR_CONTROL_PLE 0x00000004
|
||||
#define OR_CONTROL_CLE 0x00000010
|
||||
#define OR_CONTROL_BLE 0x00000020
|
||||
#define OR_CONTROL_HCFS 0x000000C0
|
||||
#define OR_CONTROL_HC_OPER 0x00000080
|
||||
// ----------------- HcCommandStatus Register -----------------
|
||||
#define OR_CMD_STATUS_HCR 0x00000001
|
||||
#define OR_CMD_STATUS_CLF 0x00000002
|
||||
#define OR_CMD_STATUS_BLF 0x00000004
|
||||
// --------------- HcInterruptStatus Register -----------------
|
||||
#define OR_INTR_STATUS_WDH 0x00000002
|
||||
#define OR_INTR_STATUS_RHSC 0x00000040
|
||||
#define OR_INTR_STATUS_UE 0x00000010
|
||||
// --------------- HcInterruptEnable Register -----------------
|
||||
#define OR_INTR_ENABLE_WDH 0x00000002
|
||||
#define OR_INTR_ENABLE_RHSC 0x00000040
|
||||
#define OR_INTR_ENABLE_MIE 0x80000000
|
||||
// ---------------- HcRhDescriptorA Register ------------------
|
||||
#define OR_RH_STATUS_LPSC 0x00010000
|
||||
#define OR_RH_STATUS_DRWE 0x00008000
|
||||
// -------------- HcRhPortStatus[1:NDP] Register --------------
|
||||
#define OR_RH_PORT_CCS 0x00000001
|
||||
#define OR_RH_PORT_PRS 0x00000010
|
||||
#define OR_RH_PORT_CSC 0x00010000
|
||||
#define OR_RH_PORT_PRSC 0x00100000
|
||||
#define OR_RH_PORT_LSDA 0x00000200
|
||||
|
||||
|
||||
//
|
||||
//**************************************************************************************************************
|
||||
//* FRAME INTERVAL
|
||||
//**************************************************************************************************************
|
||||
//
|
||||
|
||||
#define FI 0x2EDF // 12000 bits per frame (-1)
|
||||
#define DEFAULT_FMINTERVAL ((((6 * (FI - 210)) / 7) << 16) | FI)
|
||||
|
||||
//
|
||||
//**************************************************************************************************************
|
||||
//* ENDPOINT DESCRIPTOR CONTROL FIELDS
|
||||
//**************************************************************************************************************
|
||||
//
|
||||
|
||||
#define ED_SKIP (uint32_t) (0x00001000) // Skip this ep in queue
|
||||
|
||||
//
|
||||
//**************************************************************************************************************
|
||||
//* TRANSFER DESCRIPTOR CONTROL FIELDS
|
||||
//**************************************************************************************************************
|
||||
//
|
||||
|
||||
#define TD_ROUNDING (uint32_t) (0x00040000) // Buffer Rounding
|
||||
#define TD_SETUP (uint32_t)(0) // Direction of Setup Packet
|
||||
#define TD_IN (uint32_t)(0x00100000) // Direction In
|
||||
#define TD_OUT (uint32_t)(0x00080000) // Direction Out
|
||||
#define TD_DELAY_INT(x) (uint32_t)((x) << 21) // Delay Interrupt
|
||||
#define TD_TOGGLE_0 (uint32_t)(0x02000000) // Toggle 0
|
||||
#define TD_TOGGLE_1 (uint32_t)(0x03000000) // Toggle 1
|
||||
#define TD_CC (uint32_t)(0xF0000000) // Completion Code
|
||||
|
||||
//
|
||||
//**************************************************************************************************************
|
||||
//* USB STANDARD REQUEST DEFINITIONS
|
||||
//**************************************************************************************************************
|
||||
//
|
||||
|
||||
#define DEVICE_DESCRIPTOR (1)
|
||||
#define CONFIGURATION_DESCRIPTOR (2)
|
||||
#define INTERFACE_DESCRIPTOR (4)
|
||||
#define ENDPOINT_DESCRIPTOR (5)
|
||||
#define HID_DESCRIPTOR (33)
|
||||
|
||||
// ----------- Control RequestType Fields -----------
|
||||
#define USB_DEVICE_TO_HOST 0x80
|
||||
#define USB_HOST_TO_DEVICE 0x00
|
||||
#define USB_REQUEST_TYPE_CLASS 0x20
|
||||
#define USB_RECIPIENT_DEVICE 0x00
|
||||
#define USB_RECIPIENT_INTERFACE 0x01
|
||||
|
||||
// -------------- USB Standard Requests --------------
|
||||
#define SET_ADDRESS 5
|
||||
#define GET_DESCRIPTOR 6
|
||||
#define SET_CONFIGURATION 9
|
||||
#define SET_INTERFACE 11
|
||||
|
||||
// -------------- USB Descriptor Length --------------
|
||||
#define DEVICE_DESCRIPTOR_LENGTH 0x12
|
||||
#define CONFIGURATION_DESCRIPTOR_LENGTH 0x09
|
||||
|
||||
|
||||
//
|
||||
//**************************************************************************************************************
|
||||
//* TYPE DEFINITIONS
|
||||
//**************************************************************************************************************
|
||||
//
|
||||
|
||||
// ----------- HostController EndPoint Descriptor -------------
|
||||
typedef struct hcEd {
|
||||
volatile uint32_t control; // Endpoint descriptor control
|
||||
volatile uint32_t tailTD; // Physical address of tail in Transfer descriptor list
|
||||
volatile uint32_t headTD; // Physcial address of head in Transfer descriptor list
|
||||
volatile uint32_t nextED; // Physical address of next Endpoint descriptor
|
||||
} HCED;
|
||||
|
||||
// ------------ HostController Transfer Descriptor ------------
|
||||
typedef struct hcTd {
|
||||
volatile uint32_t control; // Transfer descriptor control
|
||||
volatile uint32_t currBufPtr; // Physical address of current buffer pointer
|
||||
volatile uint32_t nextTD; // Physical pointer to next Transfer Descriptor
|
||||
volatile uint32_t bufEnd; // Physical address of end of buffer
|
||||
} HCTD;
|
||||
|
||||
// ----------- Host Controller Communication Area ------------
|
||||
typedef struct hcca {
|
||||
volatile uint32_t IntTable[32]; // Interrupt Table
|
||||
volatile uint32_t FrameNumber; // Frame Number
|
||||
volatile uint32_t DoneHead; // Done Head
|
||||
volatile uint8_t Reserved[116]; // Reserved for future use
|
||||
volatile uint8_t Unknown[4]; // Unused
|
||||
} HCCA;
|
||||
|
||||
|
||||
|
||||
#endif
|
|
@ -1,253 +0,0 @@
|
|||
/* 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"
|
||||
|
||||
IOSerialStream::IOSerialStream(mbed::Serial& 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::Serial::RxIrq);
|
||||
m_serial.attach(this, &IOSerialStream::writeable, mbed::Serial::TxIrq);
|
||||
}
|
||||
|
||||
/*virtual*/ IOSerialStream::~IOSerialStream()
|
||||
{
|
||||
m_serial.attach(NULL, mbed::Serial::RxIrq);
|
||||
m_serial.attach(NULL, mbed::Serial::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)
|
||||
{
|
||||
((LPC_UART_TypeDef *)(UART_3))->IER |= 1 << 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
((LPC_UART_TypeDef *)(UART_3))->IER &= ~(1 << 0);
|
||||
}
|
||||
}
|
||||
|
||||
void IOSerialStream::readable() //Callback from m_serial when new data is available
|
||||
{
|
||||
do
|
||||
{
|
||||
m_inBuf.queue(((LPC_UART_TypeDef *)UART_3)->RBR); //FIXME mbed libraries this is an awful kludge
|
||||
} 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);
|
||||
((LPC_UART_TypeDef *)UART_3)->THR = c; //FIXME awful kludge
|
||||
}
|
||||
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)
|
||||
{
|
||||
((LPC_UART_TypeDef *)(UART_3))->IER |= 1 << 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
((LPC_UART_TypeDef *)(UART_3))->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);
|
||||
((LPC_UART_TypeDef *)UART_3)->THR = c; //FIXME awful kludge
|
||||
}
|
||||
}
|
||||
m_spaceSphre.release(); //Force exiting the waiting state
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
/* 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 "Serial.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
|
||||
*/
|
||||
#define CIRCBUF_SIZE 255
|
||||
class IOSerialStream : public IOStream
|
||||
{
|
||||
public:
|
||||
IOSerialStream(mbed::Serial& 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::Serial& 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_ */
|
|
@ -1,236 +0,0 @@
|
|||
/* USBSerialStream.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
|
||||
#ifndef __MODULE__
|
||||
#define __MODULE__ "USBSerialStream.cpp"
|
||||
#endif
|
||||
|
||||
#include "core/fwk.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "USBSerialStream.h"
|
||||
|
||||
|
||||
USBSerialStream::USBSerialStream(IUSBHostSerial& serial) : m_serial(serial), m_serialTxFifoEmpty(true),
|
||||
m_availableSphre(1), m_spaceSphre(1), m_inBuf()
|
||||
{
|
||||
m_availableSphre.wait();
|
||||
m_spaceSphre.wait();
|
||||
//Attach interrupts
|
||||
m_serial.attach(this);
|
||||
}
|
||||
|
||||
/*virtual*/ USBSerialStream::~USBSerialStream()
|
||||
{
|
||||
m_serial.attach(NULL);
|
||||
}
|
||||
|
||||
//0 for non-blocking (returns immediately), -1 for infinite blocking
|
||||
/*virtual*/ int USBSerialStream::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 a = available(); //Prevent macro issues
|
||||
int readLen = MIN( a, 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 USBSerialStream::available()
|
||||
{
|
||||
setupReadableISR(false); //m_inBuf.available() is not reentrant
|
||||
size_t len = m_inBuf.available();
|
||||
setupReadableISR(true);
|
||||
return len;
|
||||
}
|
||||
|
||||
/*virtual*/ int USBSerialStream::waitAvailable(uint32_t timeout/*=osWaitForever*/) //Wait for data to be available
|
||||
{
|
||||
int ret;
|
||||
if(available()) //Is data already available?
|
||||
{
|
||||
while( m_availableSphre.wait(0) > 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(!m_inBuf.available()) //Even if abort has been called, return that data is available
|
||||
{
|
||||
DBG("Aborted");
|
||||
return NET_INTERRUPTED;
|
||||
}
|
||||
DBG("Finished waiting");
|
||||
while( m_availableSphre.wait(0) > 0 ); //Clear the queue as data is available
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*virtual*/ int USBSerialStream::abortRead() //Abort current reading (or waiting) operation
|
||||
{
|
||||
if( /*!available()*/true ) //If there is data pending, no need to abort
|
||||
{
|
||||
m_availableSphre.release(); //Force exiting the waiting state
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG("Serial is readable"); ;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
void USBSerialStream::setupReadableISR(bool en)
|
||||
{
|
||||
m_serial.setupIrq(en, IUSBHostSerial::RxIrq);
|
||||
}
|
||||
|
||||
void USBSerialStream::readable() //Callback from m_serial when new data is available
|
||||
{
|
||||
while(m_serial.readable())
|
||||
{
|
||||
m_inBuf.queue(m_serial.getc());
|
||||
}
|
||||
m_serial.readPacket(); //Start read of next packet
|
||||
m_availableSphre.release(); //Force exiting the waiting state
|
||||
}
|
||||
|
||||
//0 for non-blocking (returns immediately), -1 for infinite blocking
|
||||
/*virtual*/ int USBSerialStream::write(uint8_t* buf, size_t length, uint32_t timeout/*=-1*/)
|
||||
{
|
||||
DBG("Trying to write %d chars", length);
|
||||
do
|
||||
{
|
||||
int ret = waitSpace(timeout);
|
||||
if(ret)
|
||||
{
|
||||
WARN("Error %d while waiting for space", ret);
|
||||
return ret;
|
||||
}
|
||||
int s = space(); //Prevent macro issues
|
||||
int writeLen = MIN( s, length );
|
||||
DBG("Writing %d chars", writeLen);
|
||||
setupWriteableISR(false);
|
||||
while(writeLen)
|
||||
{
|
||||
m_outBuf.queue(*buf);
|
||||
buf++;
|
||||
length--;
|
||||
writeLen--;
|
||||
}
|
||||
//If m_serial tx fifo is empty we need to start the packet write
|
||||
if( m_outBuf.available() && m_serialTxFifoEmpty )
|
||||
{
|
||||
writeable();
|
||||
}
|
||||
setupWriteableISR(true);
|
||||
} while(length);
|
||||
|
||||
DBG("Write successful");
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*virtual*/ size_t USBSerialStream::space()
|
||||
{
|
||||
setupWriteableISR(false); //m_outBuf.available() is not reentrant
|
||||
size_t len = CIRCBUF_SIZE - m_outBuf.available();
|
||||
setupWriteableISR(true);
|
||||
return len;
|
||||
}
|
||||
|
||||
/*virtual*/ int USBSerialStream::waitSpace(uint32_t timeout/*=-1*/) //Wait for space to be available
|
||||
{
|
||||
int ret;
|
||||
if(space()) //Is still space already left?
|
||||
{
|
||||
while( m_spaceSphre.wait(0) > 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;
|
||||
}
|
||||
while( m_spaceSphre.wait(0) > 0); //Clear the queue as space is available
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*virtual*/ int USBSerialStream::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 USBSerialStream::setupWriteableISR(bool en)
|
||||
{
|
||||
m_serial.setupIrq(en, IUSBHostSerial::TxIrq);
|
||||
}
|
||||
|
||||
void USBSerialStream::writeable() //Callback from m_serial when new space is available
|
||||
{
|
||||
if(m_outBuf.isEmpty())
|
||||
{
|
||||
m_serialTxFifoEmpty = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_serialTxFifoEmpty = false;
|
||||
while(m_serial.writeable() && !m_outBuf.isEmpty())
|
||||
{
|
||||
uint8_t c;
|
||||
m_outBuf.dequeue(&c);
|
||||
m_serial.putc((char)c);
|
||||
}
|
||||
m_serial.writePacket(); //Start packet write
|
||||
}
|
||||
if(!m_outBuf.isFull())
|
||||
{
|
||||
m_spaceSphre.release(); //Force exiting the waiting state
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
/* USBSerialStream.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 USBSERIALSTREAM_H_
|
||||
#define USBSERIALSTREAM_H_
|
||||
|
||||
|
||||
#include "core/fwk.h"
|
||||
|
||||
#include "USB3GModule/IUSBHostSerial.h"
|
||||
#include "USB3GModule/IUSBHostSerialListener.h"
|
||||
|
||||
#include "rtos.h"
|
||||
#include "core/MtxCircBuffer.h"
|
||||
|
||||
/* 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
|
||||
*/
|
||||
#define CIRCBUF_SIZE 127
|
||||
class USBSerialStream : public IOStream, IUSBHostSerialListener
|
||||
{
|
||||
public:
|
||||
USBSerialStream(IUSBHostSerial& serial);
|
||||
/*virtual*/ ~USBSerialStream();
|
||||
|
||||
//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:
|
||||
IUSBHostSerial& m_serial;
|
||||
volatile bool m_serialTxFifoEmpty;
|
||||
|
||||
void setupReadableISR(bool en);
|
||||
virtual void readable(); //Callback from m_serial when new data is available
|
||||
|
||||
Semaphore m_availableSphre; //Used for signalling
|
||||
|
||||
void setupWriteableISR(bool en);
|
||||
virtual 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 /* USBSERIALSTREAM_H_ */
|
|
@ -1,34 +0,0 @@
|
|||
/* 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 BSD_SOCKET_H_
|
||||
#define BSD_SOCKET_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "socket/sys/socket.h" //Must conform to <http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_socket.h.html>
|
||||
#include "socket/netinet/in.h" //Must conform to <http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netinet_in.h.html>
|
||||
#include "socket/netdb.h" //Must conform to <http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/netdb.h.html>
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* BSD_SOCKET_H_ */
|
|
@ -1,47 +0,0 @@
|
|||
/* netdb.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 NETDB_H_
|
||||
#define NETDB_H_
|
||||
|
||||
#include "lwip/netdb.h"
|
||||
|
||||
//DNS
|
||||
|
||||
inline struct hostent *gethostbyname(const char *name)
|
||||
{
|
||||
return lwip_gethostbyname(name);
|
||||
}
|
||||
|
||||
inline int gethostbyname_r(const char *name, struct hostent *ret, char *buf, size_t buflen, struct hostent **result, int *h_errnop)
|
||||
{
|
||||
return lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop);
|
||||
}
|
||||
|
||||
inline void freeaddrinfo(struct addrinfo *ai)
|
||||
{
|
||||
return lwip_freeaddrinfo(ai);
|
||||
}
|
||||
|
||||
inline int getaddrinfo(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res)
|
||||
{
|
||||
return lwip_getaddrinfo(nodename, servname, hints, res);
|
||||
}
|
||||
|
||||
#endif /* NETDB_H_ */
|
|
@ -1,25 +0,0 @@
|
|||
/* in.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 IN_H_
|
||||
#define IN_H_
|
||||
|
||||
#include "lwip/inet.h"
|
||||
|
||||
#endif /* IN_H_ */
|
|
@ -1,126 +0,0 @@
|
|||
/* socket.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 SYS_SOCKET_H_
|
||||
#define SYS_SOCKET_H_
|
||||
|
||||
#include "lwip/sockets.h"
|
||||
|
||||
//Sockets
|
||||
|
||||
inline int accept(int s, struct sockaddr *addr, socklen_t *addrlen)
|
||||
{
|
||||
return lwip_accept(s, addr, addrlen);
|
||||
}
|
||||
|
||||
inline int bind(int s, const struct sockaddr *name, socklen_t namelen)
|
||||
{
|
||||
return lwip_bind(s, name, namelen);
|
||||
}
|
||||
|
||||
inline int shutdown(int s, int how)
|
||||
{
|
||||
return lwip_shutdown(s, how);
|
||||
}
|
||||
|
||||
inline int getsockname (int s, struct sockaddr *name, socklen_t *namelen)
|
||||
{
|
||||
return lwip_getsockname(s, name, namelen);
|
||||
}
|
||||
|
||||
inline int getpeername (int s, struct sockaddr *name, socklen_t *namelen)
|
||||
{
|
||||
return lwip_getpeername(s, name, namelen);
|
||||
}
|
||||
|
||||
inline int getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen)
|
||||
{
|
||||
return lwip_getsockopt(s, level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
inline int setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen)
|
||||
{
|
||||
return lwip_setsockopt(s, level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
inline int connect(int s, const struct sockaddr *name, socklen_t namelen)
|
||||
{
|
||||
return lwip_connect(s, name, namelen);
|
||||
}
|
||||
|
||||
inline int listen(int s, int backlog)
|
||||
{
|
||||
return lwip_listen(s, backlog);
|
||||
}
|
||||
|
||||
inline int recv(int s, void *mem, size_t len, int flags)
|
||||
{
|
||||
return lwip_recv(s, mem, len, flags);
|
||||
}
|
||||
|
||||
inline int recvfrom(int s, void *mem, size_t len, int flags,
|
||||
struct sockaddr *from, socklen_t *fromlen)
|
||||
{
|
||||
return lwip_recvfrom(s, mem, len, flags, from, fromlen);
|
||||
}
|
||||
|
||||
inline int send(int s, const void *dataptr, size_t size, int flags)
|
||||
{
|
||||
return lwip_send(s, dataptr, size, flags);
|
||||
}
|
||||
|
||||
inline int sendto(int s, const void *dataptr, size_t size, int flags,
|
||||
const struct sockaddr *to, socklen_t tolen)
|
||||
{
|
||||
return lwip_sendto(s, dataptr, size, flags, to, tolen);
|
||||
}
|
||||
|
||||
inline int socket(int domain, int type, int protocol)
|
||||
{
|
||||
return lwip_socket(domain, type, protocol);
|
||||
}
|
||||
|
||||
inline int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
|
||||
struct timeval *timeout)
|
||||
{
|
||||
return lwip_select(maxfdp1, readset, writeset, exceptset, timeout);
|
||||
}
|
||||
|
||||
inline int ioctlsocket(int s, long cmd, void *argp)
|
||||
{
|
||||
return lwip_ioctl(s, cmd, argp);
|
||||
}
|
||||
|
||||
inline int read(int s, void *mem, size_t len)
|
||||
{
|
||||
return lwip_read(s, mem, len);
|
||||
}
|
||||
|
||||
inline int write(int s, const void *dataptr, size_t size)
|
||||
{
|
||||
return lwip_write(s, dataptr, size);
|
||||
}
|
||||
|
||||
inline int close(int s)
|
||||
{
|
||||
return lwip_close(s);
|
||||
}
|
||||
|
||||
#endif /* SYS_SOCKET_H_ */
|
|
@ -0,0 +1,78 @@
|
|||
/* CellularModem.h */
|
||||
/* Copyright (C) 2013 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 CELLULARMODEM_H_
|
||||
#define CELLULARMODEM_H_
|
||||
|
||||
#include "core/fwk.h"
|
||||
#include "at/ATCommandsInterface.h"
|
||||
|
||||
class CellularModem
|
||||
{
|
||||
public:
|
||||
//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) = 0;
|
||||
|
||||
/** Close the internet connection
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int disconnect() = 0;
|
||||
|
||||
|
||||
/** 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) = 0;
|
||||
|
||||
|
||||
/** 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) = 0;
|
||||
|
||||
/** 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) = 0;
|
||||
|
||||
/** Get the ATCommandsInterface instance
|
||||
@return Pointer to the ATCommandsInterface instance
|
||||
*/
|
||||
virtual ATCommandsInterface* getATCommandsInterface() = 0;
|
||||
|
||||
/** Switch power on or off
|
||||
In order to use this function, a pin name must have been entered in the constructor
|
||||
@param enable true to switch the dongle on, false to switch it off
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int power(bool enable) = 0;
|
||||
};
|
||||
|
||||
|
||||
#endif /* CELLULARMODEM_H_ */
|
|
@ -20,8 +20,6 @@
|
|||
#ifndef IOSTREAM_H_
|
||||
#define IOSTREAM_H_
|
||||
|
||||
#include "fwk.h"
|
||||
|
||||
#include "rtos.h"
|
||||
|
||||
class IStream
|
|
@ -20,8 +20,6 @@
|
|||
#ifndef MTXCIRCBUFFER_H
|
||||
#define MTXCIRCBUFFER_H
|
||||
|
||||
#include "fwk.h"
|
||||
|
||||
#include "rtos.h"
|
||||
|
||||
//Mutex protected circualr buffer
|
|
@ -32,9 +32,10 @@ using std::sscanf;
|
|||
|
||||
#define MSISDN "*99#"
|
||||
|
||||
#define CONNECT_CMD "ATD " MSISDN "\x0D"
|
||||
#define EXPECTED_RESP CONNECT_CMD "\x0D" "\x0A" "CONNECT" "\x0D" "\x0A"
|
||||
#define EXPECTED_RESP_DATARATE CONNECT_CMD "\x0D" "\x0A" "CONNECT %d" "\x0D" "\x0A"
|
||||
#define CONNECT_CMD_PREFIX "ATD "
|
||||
#define CONNECT_CMD_SUFFIX "\x0D"
|
||||
#define EXPECTED_RESP_SUFFIX "\x0D" "\x0A" "CONNECT" "\x0D" "\x0A"
|
||||
#define EXPECTED_RESP_DATARATE_SUFFIX "\x0D" "\x0A" "CONNECT %d" "\x0D" "\x0A"
|
||||
#define EXPECTED_RESP_MIN_LEN 20
|
||||
#define OK_RESP "\x0D" "\x0A" "OK" "\x0D" "\x0A"
|
||||
#define ESCAPE_SEQ "+++"
|
||||
|
@ -49,14 +50,22 @@ extern "C" {
|
|||
#include "netif/ppp/ppp.h"
|
||||
}
|
||||
|
||||
PPPIPInterface::PPPIPInterface(IOStream* pStream) : LwIPInterface(), m_linkStatusSphre(1), m_pppErrCode(0), m_pStream(pStream), m_streamAvail(true), m_pppd(-1)
|
||||
PPPIPInterface::PPPIPInterface(IOStream* pStream, const char* msisdn) : 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();
|
||||
}
|
||||
|
||||
/*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
|
||||
|
@ -86,15 +95,15 @@ int PPPIPInterface::setup(const char* user, const char* pw)
|
|||
|
||||
cleanupLink();
|
||||
|
||||
DBG("Sending %s", CONNECT_CMD);
|
||||
DBG("Sending %s", m_connectCmd);
|
||||
|
||||
ret = m_pStream->write((uint8_t*)CONNECT_CMD, strlen(CONNECT_CMD), osWaitForever);
|
||||
ret = m_pStream->write((uint8_t*)m_connectCmd, strlen(m_connectCmd), osWaitForever);
|
||||
if( ret != OK )
|
||||
{
|
||||
return NET_UNKNOWN;
|
||||
}
|
||||
|
||||
DBG("Expect %s", EXPECTED_RESP);
|
||||
DBG("Expect %s", m_expectedResp);
|
||||
|
||||
len = 0;
|
||||
size_t readLen;
|
||||
|
@ -119,7 +128,7 @@ int PPPIPInterface::setup(const char* user, const char* pw)
|
|||
DBG("Got %s[len %d]", buf, len);
|
||||
|
||||
int datarate = 0;
|
||||
if( (sscanf( buf, EXPECTED_RESP_DATARATE, &datarate ) != 1) && (strcmp(EXPECTED_RESP, buf) != 0) )
|
||||
if( (sscanf(buf, m_expectedRespDatarate, &datarate ) != 1) && (strcmp(m_expectedResp, buf) != 0) )
|
||||
{
|
||||
//Discard buffer
|
||||
do //Clear buf
|
|
@ -31,13 +31,16 @@ class Semaphore;
|
|||
}
|
||||
using namespace rtos;
|
||||
|
||||
#define DEFAULT_MSISDN_GSM "*99#"
|
||||
#define DEFAULT_MSISDN_CDMA "#777"
|
||||
|
||||
/** Interface using PPP to connect to an IP-based network
|
||||
*
|
||||
*/
|
||||
class PPPIPInterface : public LwIPInterface
|
||||
{
|
||||
public:
|
||||
PPPIPInterface(IOStream* pStream);
|
||||
PPPIPInterface(IOStream* pStream, const char* msisdn);
|
||||
virtual ~PPPIPInterface();
|
||||
|
||||
int init(); //Init PPP-specific stuff, create the right bindings, etc
|
||||
|
@ -60,6 +63,10 @@ private:
|
|||
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 void sio_read_abort(sio_fd_t fd);
|
||||
|
||||
char* m_connectCmd;
|
||||
char* m_expectedResp;
|
||||
char* m_expectedRespDatarate;
|
||||
};
|
||||
|
||||
#endif /* PPPIPINTERFACE_H_ */
|
|
@ -23,3 +23,4 @@
|
|||
#define LWIP_TRANSPORT_PPP 1
|
||||
|
||||
#endif /* LWIPOPTS_CONF_H_ */
|
||||
|
|
@ -0,0 +1,348 @@
|
|||
/* CDMASMSInterface.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
|
||||
#ifndef __MODULE__
|
||||
#define __MODULE__ "CDMASMSInterface.cpp"
|
||||
#endif
|
||||
|
||||
#include "core/fwk.h"
|
||||
|
||||
#include "CDMASMSInterface.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#define DEFAULT_TIMEOUT 10000
|
||||
|
||||
CDMASMSInterface::CDMASMSInterface(ATCommandsInterface* pIf) : m_pIf(pIf), m_msg(NULL), m_maxMsgLength(0), m_msisdn(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
int CDMASMSInterface::init()
|
||||
{
|
||||
m_state = SMS_IDLE;
|
||||
|
||||
DBG("Get number of messages in the different inboxes");
|
||||
int ret = updateInbox();
|
||||
if(ret)
|
||||
{
|
||||
return NET_PROTOCOL;
|
||||
}
|
||||
|
||||
DBG("Initialization done");
|
||||
return OK;
|
||||
}
|
||||
|
||||
int CDMASMSInterface::send(const char* number, const char* message)
|
||||
{
|
||||
if( strlen(number) > 16 )
|
||||
{
|
||||
return NET_INVALID; //Number too long
|
||||
}
|
||||
|
||||
int ret;
|
||||
|
||||
//Prepare infos
|
||||
m_state = SMS_SEND_CMD_SENT;
|
||||
|
||||
bool intlNumber=(number[0]=='+'); //If the number starts with the + sign, replace it with 011 instead (int'l dialing code in the US)
|
||||
|
||||
DBG("Send SM");
|
||||
//Send command
|
||||
char cmd[32+strlen(message)];
|
||||
std::sprintf(cmd, "AT!SSMS=0,%s%s,,\"%s\"",intlNumber?"011":"", intlNumber?(number+1):number, message); //Send with normal priority
|
||||
ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT);
|
||||
|
||||
if(ret != OK)
|
||||
{
|
||||
WARN("ret %d", ret);
|
||||
m_state = SMS_IDLE;
|
||||
return NET_PROTOCOL;
|
||||
}
|
||||
|
||||
DBG("Check status");
|
||||
m_txState = SMS_PENDING;
|
||||
|
||||
int tries = 10;
|
||||
while(tries--)
|
||||
{
|
||||
m_state = SMS_GET_TX_STATUS_CMD_SENT;
|
||||
ret = m_pIf->execute("AT!SSMS?", this, NULL, DEFAULT_TIMEOUT);
|
||||
if(ret)
|
||||
{
|
||||
m_state = SMS_IDLE;
|
||||
return ret;
|
||||
}
|
||||
m_state = SMS_IDLE;
|
||||
if(m_txState == SMS_PENDING) //Wait more
|
||||
{
|
||||
Thread::wait(1000);
|
||||
continue;
|
||||
}
|
||||
else if(m_txState == SMS_FAILED)
|
||||
{
|
||||
ERR("The modem could not send the SM");
|
||||
return NET_CONN; //Probably a conenction issue, the user can retry
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!tries)
|
||||
{
|
||||
ERR("The is still trying to send the SM");
|
||||
return NET_TIMEOUT;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
int CDMASMSInterface::get(char* number, char* message, size_t maxLength)
|
||||
{
|
||||
if( maxLength < 1 )
|
||||
{
|
||||
return NET_INVALID; //Buffer too short
|
||||
}
|
||||
|
||||
int ret;
|
||||
|
||||
DBG("Get next message");
|
||||
if( (m_msgInListsCount[0] + m_msgInListsCount[1] + m_msgInListsCount[2]) == 0)
|
||||
{
|
||||
DBG("Message list count is 0 and needs updating. Running updateInbox.");
|
||||
ret = updateInbox();
|
||||
if (ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if( (m_msgInListsCount[0] + m_msgInListsCount[1] + m_msgInListsCount[2]) == 0)
|
||||
{
|
||||
DBG("Message list count is 0");
|
||||
return NET_EMPTY; //No message to read
|
||||
}
|
||||
|
||||
//Determine which index to use : 3 (read), then 1 (urgent), then 2 (regular)
|
||||
int index;
|
||||
if(m_msgInListsCount[2])
|
||||
{
|
||||
index = 3;
|
||||
}
|
||||
else if(m_msgInListsCount[0])
|
||||
{
|
||||
index = 1;
|
||||
}
|
||||
else //if(m_msgInListsCount[1])
|
||||
{
|
||||
index = 2;
|
||||
}
|
||||
|
||||
//Prepare infos
|
||||
m_state = SMS_GET_CMD_SENT;
|
||||
m_msisdn = (char*) number;
|
||||
m_msg = (char*) message;
|
||||
m_maxMsgLength = maxLength;
|
||||
m_headersToRead = 3;
|
||||
|
||||
m_msisdn[0] = '\0';
|
||||
|
||||
DBG("Get SMS");
|
||||
//Read command
|
||||
char cmd[32];
|
||||
std::sprintf(cmd, "AT!GSMS?%d,1", index); //1 is the oldest message
|
||||
ret = m_pIf->execute(cmd, this, NULL, DEFAULT_TIMEOUT);
|
||||
if( ret != OK )
|
||||
{
|
||||
WARN("AT!GSMS returned %d", ret);
|
||||
m_state = SMS_IDLE;
|
||||
return NET_PROTOCOL;
|
||||
}
|
||||
|
||||
//If message is not read, it will be put at the end of the read list
|
||||
int item;
|
||||
if( index != 3 )
|
||||
{
|
||||
//Decrement count in relevant list
|
||||
m_msgInListsCount[index-1]--;
|
||||
//Increment count in read list
|
||||
m_msgInListsCount[3-1]++;
|
||||
item = m_msgInListsCount[3-1];
|
||||
//Normally item should be equal to 1 as we'd have read any older messages first
|
||||
if( item != 1 )
|
||||
{
|
||||
WARN("Still some older messages pending in the read inbox");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//The item is still the oldest one
|
||||
item = 1;
|
||||
}
|
||||
|
||||
DBG("Deleting message");
|
||||
//Delete message from inbox
|
||||
std::sprintf(cmd, "AT!DSMS=3"/*,%d", item*/); //FIXME why doesn't that work when specifying the index??
|
||||
ret = m_pIf->executeSimple(cmd, NULL, DEFAULT_TIMEOUT);
|
||||
if(ret != OK)
|
||||
{
|
||||
ERR("Could not delete message");
|
||||
}
|
||||
else
|
||||
{
|
||||
//Now we can decrease the number of read messages
|
||||
m_msgInListsCount[3-1]--;
|
||||
}
|
||||
|
||||
if (m_state != SMS_CMD_PROCESSED)
|
||||
{
|
||||
WARN("Message could not be retrieved properly");
|
||||
m_state = SMS_IDLE;
|
||||
return NET_EMPTY;
|
||||
}
|
||||
|
||||
m_state = SMS_IDLE;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
int CDMASMSInterface::getCount(size_t* pCount)
|
||||
{
|
||||
int ret = updateInbox();
|
||||
if(ret)
|
||||
{
|
||||
return NET_PROTOCOL;
|
||||
}
|
||||
|
||||
*pCount = m_msgInListsCount[0] + m_msgInListsCount[1] + m_msgInListsCount[2]; //Urgent messages + regular messages + read messages
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
/*virtual*/ int CDMASMSInterface::onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
|
||||
{
|
||||
if(m_state == SMS_SEND_CMD_SENT)
|
||||
{
|
||||
DBG("SMS Send: %s", line);
|
||||
}
|
||||
else if(m_state == SMS_GET_TX_STATUS_CMD_SENT)
|
||||
{
|
||||
if(!strcmp(line, "sent"))
|
||||
{
|
||||
m_txState = SMS_SENT;
|
||||
m_state = SMS_CMD_PROCESSED;
|
||||
}
|
||||
else if(!strcmp(line, "failed"))
|
||||
{
|
||||
m_txState = SMS_FAILED;
|
||||
m_state = SMS_CMD_PROCESSED;
|
||||
}
|
||||
else if(!strcmp(line, "none"))
|
||||
{
|
||||
m_txState = SMS_NONE;
|
||||
m_state = SMS_CMD_PROCESSED;
|
||||
}
|
||||
else if(!strcmp(line, "pending"))
|
||||
{
|
||||
m_txState = SMS_PENDING;
|
||||
m_state = SMS_CMD_PROCESSED;
|
||||
}
|
||||
}
|
||||
else if(m_state == SMS_GET_CMD_SENT)
|
||||
{
|
||||
DBG("Header: %s", line);
|
||||
|
||||
if(m_msisdn[0]=='\0')
|
||||
{
|
||||
sscanf(line, "From: %16s", m_msisdn);
|
||||
}
|
||||
|
||||
m_headersToRead--;
|
||||
|
||||
if(m_headersToRead==0) //End of headers
|
||||
{
|
||||
if(m_msisdn[0]!='\0') //Checks that the incoming number has been retrieved
|
||||
{
|
||||
m_state = SMS_GET_HDR_RECEIVED;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_state = SMS_IDLE; //Error, signal it
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(m_state == SMS_GET_HDR_RECEIVED)
|
||||
{
|
||||
DBG("Message: %s", line);
|
||||
size_t cpyLen = MIN( std::strlen(line), m_maxMsgLength - 1 );
|
||||
std::memcpy( m_msg, line, cpyLen );
|
||||
m_msg[cpyLen] = '\0';
|
||||
m_state = SMS_CMD_PROCESSED;
|
||||
}
|
||||
else if(m_state == SMS_GET_COUNT_CMD_SENT)
|
||||
{
|
||||
DBG("Inbox: %s", line);
|
||||
int index;
|
||||
size_t count;
|
||||
if((strlen(line) > 16) && sscanf(line + 16, "{Index = %d}: %d", &index, &count) == 2)
|
||||
{
|
||||
if((index > 0) && (index <=4))
|
||||
{
|
||||
m_msgInListsCount[index-1] = count;
|
||||
}
|
||||
if(index == 4)
|
||||
{
|
||||
m_state = SMS_CMD_PROCESSED;
|
||||
}
|
||||
}
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*virtual*/ int CDMASMSInterface::onNewEntryPrompt(ATCommandsInterface* pInst)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
int CDMASMSInterface::updateInbox()
|
||||
{
|
||||
//Get number of unread/read messages
|
||||
|
||||
DBG("Updating inbox");
|
||||
m_msgInListsCount[0] = m_msgInListsCount[1] = m_msgInListsCount[2] = m_msgInListsCount[3] = 0; //Reset counts
|
||||
|
||||
//Get counts
|
||||
m_state = SMS_GET_COUNT_CMD_SENT;
|
||||
int ret = m_pIf->execute("AT!CNTSMS", this, NULL, DEFAULT_TIMEOUT);
|
||||
if( ret != OK )
|
||||
{
|
||||
WARN("AT!CNTSMS returned %d", ret);
|
||||
m_msgInListsCount[0] = m_msgInListsCount[1] = m_msgInListsCount[2] = m_msgInListsCount[3] = 0; //Invalidate counts
|
||||
m_state = SMS_IDLE;
|
||||
return NET_PROTOCOL;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
/* SMSInterface.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 CDMASMSINTERFACE_H_
|
||||
#define CDMASMSINTERFACE_H_
|
||||
|
||||
#include "SMSInterface.h"
|
||||
|
||||
#define MAX_SM 8
|
||||
|
||||
/** Component to use the Short Messages Service (SMS)
|
||||
*
|
||||
*/
|
||||
class CDMASMSInterface : public ISMSInterface, protected IATCommandsProcessor
|
||||
{
|
||||
public:
|
||||
/** Create SMSInterface instance
|
||||
@param pIf Pointer to the ATCommandsInterface instance to use
|
||||
*/
|
||||
CDMASMSInterface(ATCommandsInterface* pIf);
|
||||
|
||||
/** Initialize interface
|
||||
Configure SMS commands & register for SMS-related unsolicited result codes
|
||||
*/
|
||||
virtual int init();
|
||||
|
||||
/** 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 send(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 space 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 get(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 getCount(size_t* pCount);
|
||||
|
||||
protected:
|
||||
//IATCommandsProcessor
|
||||
virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line);
|
||||
virtual int onNewEntryPrompt(ATCommandsInterface* pInst);
|
||||
|
||||
int updateInbox(); //Update messages count in the different inboxes
|
||||
|
||||
private:
|
||||
ATCommandsInterface* m_pIf;
|
||||
|
||||
//Current message
|
||||
char* m_msg;
|
||||
size_t m_maxMsgLength;
|
||||
char* m_msisdn;
|
||||
|
||||
//Messages list
|
||||
size_t m_msgInListsCount[4]; //4 lists
|
||||
|
||||
size_t m_headersToRead;
|
||||
|
||||
enum { SMS_NONE, SMS_SENT, SMS_PENDING, SMS_FAILED } m_txState;
|
||||
enum { SMS_IDLE, SMS_SEND_CMD_SENT, SMS_GET_TX_STATUS_CMD_SENT, SMS_GET_CMD_SENT, SMS_GET_HDR_RECEIVED, SMS_GET_COUNT_CMD_SENT, SMS_CMD_PROCESSED } m_state;
|
||||
};
|
||||
|
||||
#endif /* CDMASMSINTERFACE_H_ */
|
|
@ -1,4 +1,4 @@
|
|||
/* SMSInterface.cpp */
|
||||
/* GSMSMSInterface.cpp */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
|
@ -19,24 +19,24 @@
|
|||
|
||||
#define __DEBUG__ 2
|
||||
#ifndef __MODULE__
|
||||
#define __MODULE__ "SMSInterface.cpp"
|
||||
#define __MODULE__ "GSMSMSInterface.cpp"
|
||||
#endif
|
||||
|
||||
#include "core/fwk.h"
|
||||
|
||||
#include "SMSInterface.h"
|
||||
#include "GSMSMSInterface.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#define DEFAULT_TIMEOUT 10000
|
||||
|
||||
SMSInterface::SMSInterface(ATCommandsInterface* pIf) : m_pIf(pIf), m_msg(NULL), m_maxMsgLength(0), m_msisdn(NULL)
|
||||
GSMSMSInterface::GSMSMSInterface(ATCommandsInterface* pIf) : m_pIf(pIf), m_msg(NULL), m_maxMsgLength(0), m_msisdn(NULL)
|
||||
{
|
||||
m_pIf->registerEventsHandler(this); //Add us to the unsolicited result codes handlers
|
||||
}
|
||||
|
||||
int SMSInterface::init()
|
||||
int GSMSMSInterface::init()
|
||||
{
|
||||
m_msgRefListCount = 0;
|
||||
m_needsUpdate = true;
|
||||
|
@ -75,7 +75,7 @@ int SMSInterface::init()
|
|||
return OK;
|
||||
}
|
||||
|
||||
int SMSInterface::send(const char* number, const char* message)
|
||||
int GSMSMSInterface::send(const char* number, const char* message)
|
||||
{
|
||||
if( strlen(number) > 16 )
|
||||
{
|
||||
|
@ -107,7 +107,7 @@ int SMSInterface::send(const char* number, const char* message)
|
|||
}
|
||||
|
||||
|
||||
int SMSInterface::get(char* number, char* message, size_t maxLength)
|
||||
int GSMSMSInterface::get(char* number, char* message, size_t maxLength)
|
||||
{
|
||||
if( maxLength < 1 )
|
||||
{
|
||||
|
@ -197,7 +197,7 @@ int SMSInterface::get(char* number, char* message, size_t maxLength)
|
|||
}
|
||||
|
||||
|
||||
int SMSInterface::getCount(size_t* pCount)
|
||||
int GSMSMSInterface::getCount(size_t* pCount)
|
||||
{
|
||||
int ret;
|
||||
|
||||
|
@ -219,7 +219,7 @@ int SMSInterface::getCount(size_t* pCount)
|
|||
}
|
||||
|
||||
|
||||
/*virtual*/ int SMSInterface::onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
|
||||
/*virtual*/ int GSMSMSInterface::onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
|
||||
{
|
||||
if(m_state == SMS_SEND_CMD_SENT)
|
||||
{
|
||||
|
@ -269,7 +269,7 @@ int SMSInterface::getCount(size_t* pCount)
|
|||
return OK;
|
||||
}
|
||||
|
||||
/*virtual*/ int SMSInterface::onNewEntryPrompt(ATCommandsInterface* pInst)
|
||||
/*virtual*/ int GSMSMSInterface::onNewEntryPrompt(ATCommandsInterface* pInst)
|
||||
{
|
||||
if(m_state == SMS_SEND_CMD_SENT)
|
||||
{
|
||||
|
@ -316,7 +316,7 @@ int SMSInterface::getCount(size_t* pCount)
|
|||
return OK;
|
||||
}
|
||||
|
||||
/*virtual*/ bool SMSInterface::isATCodeHandled(const char* atCode) //Is this AT code handled
|
||||
/*virtual*/ bool GSMSMSInterface::isATCodeHandled(const char* atCode) //Is this AT code handled
|
||||
{
|
||||
DBG("AT code is %s", atCode);
|
||||
if( strcmp("+CMTI", atCode) == 0 )
|
||||
|
@ -328,27 +328,27 @@ int SMSInterface::getCount(size_t* pCount)
|
|||
return false;
|
||||
}
|
||||
|
||||
/*virtual*/ void SMSInterface::onDispatchStart()
|
||||
/*virtual*/ void GSMSMSInterface::onDispatchStart()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*virtual*/ void SMSInterface::onDispatchStop()
|
||||
/*virtual*/ void GSMSMSInterface::onDispatchStop()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/*virtual*/ char* SMSInterface::getEventsEnableCommand()
|
||||
/*virtual*/ char* GSMSMSInterface::getEventsEnableCommand()
|
||||
{
|
||||
return "AT+CNMI=2,1,0,0,0";
|
||||
}
|
||||
|
||||
/*virtual*/ char* SMSInterface::getEventsDisableCommand()
|
||||
/*virtual*/ char* GSMSMSInterface::getEventsDisableCommand()
|
||||
{
|
||||
return "AT+CNMI=0,0,0,0,0"; //Indications will be buffered within the modem and flushed back when the former command is executed
|
||||
}
|
||||
|
||||
/*virtual*/ void SMSInterface::onEvent(const char* atCode, const char* evt)
|
||||
/*virtual*/ void GSMSMSInterface::onEvent(const char* atCode, const char* evt)
|
||||
{
|
||||
if( strcmp("+CMTI", atCode) != 0 )
|
||||
{
|
||||
|
@ -359,7 +359,8 @@ int SMSInterface::getCount(size_t* pCount)
|
|||
|
||||
//Get index
|
||||
int msgRef;
|
||||
if( std::sscanf(evt, "\"SM\",%d", &msgRef) == 1 )
|
||||
if(( std::sscanf(evt, "\"SM\",%d", &msgRef) == 1 ) ||
|
||||
( std::sscanf(evt, "\"ME\",%d", &msgRef) == 1 ))
|
||||
{
|
||||
DBG("Adding message to list (ref %d)", msgRef);
|
||||
if(m_inboxMtx.trylock())
|
||||
|
@ -380,7 +381,7 @@ int SMSInterface::getCount(size_t* pCount)
|
|||
}
|
||||
}
|
||||
|
||||
int SMSInterface::updateInbox()
|
||||
int GSMSMSInterface::updateInbox()
|
||||
{
|
||||
//Get memory indexes of unread messages
|
||||
|
|
@ -17,39 +17,33 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef SMSINTERFACE_H_
|
||||
#define SMSINTERFACE_H_
|
||||
#ifndef GSMSMSINTERFACE_H_
|
||||
#define GSMSMSINTERFACE_H_
|
||||
|
||||
#include "core/fwk.h"
|
||||
|
||||
#include "rtos.h"
|
||||
|
||||
#include "at/ATCommandsInterface.h"
|
||||
|
||||
#define MAX_SM 8
|
||||
#include "SMSInterface.h"
|
||||
|
||||
/** Component to use the Short Messages Service (SMS)
|
||||
*
|
||||
*/
|
||||
class SMSInterface : protected IATCommandsProcessor, IATEventsHandler
|
||||
class GSMSMSInterface : public ISMSInterface, protected IATCommandsProcessor, IATEventsHandler
|
||||
{
|
||||
public:
|
||||
/** Create SMSInterface instance
|
||||
@param pIf Pointer to the ATCommandsInterface instance to use
|
||||
*/
|
||||
SMSInterface(ATCommandsInterface* pIf);
|
||||
GSMSMSInterface(ATCommandsInterface* pIf);
|
||||
|
||||
/** Initialize interface
|
||||
Configure SMS commands & register for SMS-related unsolicited result codes
|
||||
*/
|
||||
int init();
|
||||
virtual int init();
|
||||
|
||||
/** Send a SM
|
||||
@param number The receiver's phone number
|
||||
@param message The message to send
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
int send(const char* number, const char* message);
|
||||
virtual int send(const char* number, const char* message);
|
||||
|
||||
|
||||
/** Receive a SM
|
||||
|
@ -58,14 +52,14 @@ public:
|
|||
@param maxLength Maximum message length that can be stored in buffer (including null-terminating character)
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
int get(char* number, char* message, size_t maxLength);
|
||||
virtual int get(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
|
||||
*/
|
||||
int getCount(size_t* pCount);
|
||||
virtual int getCount(size_t* pCount);
|
||||
|
||||
protected:
|
||||
//IATCommandsProcessor
|
||||
|
@ -100,4 +94,4 @@ private:
|
|||
enum { SMS_IDLE, SMS_SEND_CMD_SENT, SMS_GET_CMD_SENT, SMS_GET_HDR_RECEIVED, SMS_GET_COUNT_CMD_SENT, SMS_GET_COUNT_HDR_RECEIVED, SMS_CMD_PROCESSED } m_state;
|
||||
};
|
||||
|
||||
#endif /* SMSINTERFACE_H_ */
|
||||
#endif /* GSMSMSINTERFACE_H_ */
|
|
@ -0,0 +1,67 @@
|
|||
/* SMSInterface.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 ISMSINTERFACE_H_
|
||||
#define ISMSINTERFACE_H_
|
||||
|
||||
#include "core/fwk.h"
|
||||
|
||||
#include "rtos.h"
|
||||
|
||||
#include "at/ATCommandsInterface.h"
|
||||
|
||||
#define MAX_SM 8
|
||||
|
||||
/** Component to use the Short Messages Service (SMS)
|
||||
*
|
||||
*/
|
||||
class ISMSInterface
|
||||
{
|
||||
public:
|
||||
/** Initialize interface
|
||||
Configure SMS commands & register for SMS-related unsolicited result codes
|
||||
*/
|
||||
virtual int init() = 0;
|
||||
|
||||
|
||||
/** 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 send(const char* number, const char* message) = 0;
|
||||
|
||||
|
||||
/** 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 space 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 get(char* number, char* message, size_t maxLength) = 0;
|
||||
|
||||
|
||||
/** 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 getCount(size_t* pCount) = 0;
|
||||
};
|
||||
|
||||
#endif /* ISMSINTERFACE_H_ */
|
|
@ -0,0 +1,114 @@
|
|||
/* Copyright (c) 2010-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__ 4
|
||||
#ifndef __MODULE__
|
||||
#define __MODULE__ "UbloxCDMAModemInitializer.cpp"
|
||||
#endif
|
||||
|
||||
#include "core/dbg.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "UbloxCDMAModemInitializer.h"
|
||||
|
||||
UbloxCDMAModemInitializer::UbloxCDMAModemInitializer(USBHost* pHost) : WANDongleInitializer(pHost)
|
||||
{
|
||||
}
|
||||
|
||||
uint16_t UbloxCDMAModemInitializer::getMSDVid()
|
||||
{
|
||||
return 0x05C6;
|
||||
}
|
||||
uint16_t UbloxCDMAModemInitializer::getMSDPid()
|
||||
{
|
||||
return 0x0000; //No MSD mode (presumably)
|
||||
}
|
||||
|
||||
uint16_t UbloxCDMAModemInitializer::getSerialVid()
|
||||
{
|
||||
return 0x05C6;
|
||||
}
|
||||
uint16_t UbloxCDMAModemInitializer::getSerialPid()
|
||||
{
|
||||
return 0x9004;
|
||||
}
|
||||
|
||||
bool UbloxCDMAModemInitializer::switchMode(USBDeviceConnected* pDev)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int UbloxCDMAModemInitializer::getSerialPortCount()
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
|
||||
/*virtual*/ void UbloxCDMAModemInitializer::setVidPid(uint16_t vid, uint16_t pid)
|
||||
{
|
||||
m_currentSerialIntf = 0;
|
||||
m_currentEndpoint = 0;
|
||||
}
|
||||
|
||||
/*virtual*/ bool UbloxCDMAModemInitializer::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
|
||||
{
|
||||
DBG("Interface #%d; Class:%02x; SubClass:%02x; Protocol:%02x", intf_nb, intf_class, intf_subclass, intf_protocol);
|
||||
|
||||
if( intf_class == 0xFF ) {
|
||||
if( m_currentSerialIntf == 0 || m_currentSerialIntf == 1) {
|
||||
m_serialIntfMap[m_currentSerialIntf++] = intf_nb;
|
||||
return true;
|
||||
}
|
||||
m_currentSerialIntf++;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*virtual*/ bool UbloxCDMAModemInitializer::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
|
||||
{
|
||||
DBG("USBEndpoint on Interface #%d; Type:%d; Direction:%d Current %d", intf_nb, type, dir, m_currentEndpoint);
|
||||
if(type == BULK_ENDPOINT) {
|
||||
if( intf_nb == 1 || intf_nb == 0) {
|
||||
m_currentEndpoint++;
|
||||
return true;
|
||||
} else {
|
||||
m_currentEndpoint++;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if(type == INTERRUPT_ENDPOINT) {
|
||||
if( intf_nb == 1) {
|
||||
m_currentEndpoint++;
|
||||
return true;
|
||||
} else {
|
||||
m_currentEndpoint++;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*virtual*/ int UbloxCDMAModemInitializer::getType()
|
||||
{
|
||||
return WAN_DONGLE_TYPE_UBLOXC200;
|
||||
}
|
||||
|
|
@ -16,62 +16,34 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef WANDONGLE_H
|
||||
#define WANDONGLE_H
|
||||
#ifndef UBLOXCDMAMODEMINITIALIZER_H
|
||||
#define UBLOXCDMAMODEMINITIALIZER_H
|
||||
|
||||
#include "USBHost.h"
|
||||
#include "IUSBHostSerial.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#include "rtos.h"
|
||||
|
||||
#include "WANDongleSerialPort.h"
|
||||
#include "WANDongleInitializer.h"
|
||||
#include "USBHost.h"
|
||||
#include "IUSBEnumerator.h"
|
||||
|
||||
#define WANDONGLE_MAX_OUTEP_SIZE 64
|
||||
#define WANDONGLE_MAX_INEP_SIZE 64
|
||||
enum
|
||||
{
|
||||
WAN_DONGLE_TYPE_UBLOXC200
|
||||
};
|
||||
|
||||
#define WANDONGLE_MAX_SERIAL_PORTS 2
|
||||
|
||||
/** A class to use a WAN (3G/LTE) access dongle
|
||||
*
|
||||
*/
|
||||
class WANDongle : public IUSBEnumerator {
|
||||
class UbloxCDMAModemInitializer : public WANDongleInitializer
|
||||
{
|
||||
public:
|
||||
/*
|
||||
* Constructor
|
||||
*
|
||||
* @param rootdir mount name
|
||||
*/
|
||||
WANDongle();
|
||||
|
||||
/*
|
||||
* Check if a serial port device is connected
|
||||
*
|
||||
* @return true if a serial device is connected
|
||||
*/
|
||||
bool connected();
|
||||
UbloxCDMAModemInitializer(USBHost* pHost);
|
||||
|
||||
/*
|
||||
* Try to connect device
|
||||
*
|
||||
* * @return true if connection was successful
|
||||
*/
|
||||
bool tryConnect();
|
||||
virtual uint16_t getMSDVid();
|
||||
virtual uint16_t getMSDPid();
|
||||
|
||||
/*
|
||||
* Disconnect device
|
||||
*
|
||||
* * @return true if disconnection was successful
|
||||
*/
|
||||
bool disconnect();
|
||||
|
||||
WAN_DONGLE_TYPE getDongleType();
|
||||
virtual uint16_t getSerialVid();
|
||||
virtual uint16_t getSerialPid();
|
||||
|
||||
IUSBHostSerial& getSerial(int index);
|
||||
int getSerialCount();
|
||||
virtual bool switchMode(USBDeviceConnected* pDev);
|
||||
|
||||
//From IUSBEnumerator
|
||||
virtual int getSerialPortCount();
|
||||
|
||||
virtual void setVidPid(uint16_t vid, uint16_t pid);
|
||||
|
||||
|
@ -79,17 +51,13 @@ public:
|
|||
|
||||
virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir); //Must return true if the endpoint will be used
|
||||
|
||||
protected:
|
||||
USBHost * host;
|
||||
USBDeviceConnected * dev;
|
||||
bool dev_connected;
|
||||
virtual int getType();
|
||||
|
||||
WANDongleInitializer* m_pInitializer;
|
||||
private:
|
||||
|
||||
void init();
|
||||
|
||||
WANDongleSerialPort m_serial[WANDONGLE_MAX_SERIAL_PORTS];
|
||||
int m_serialCount;
|
||||
int m_currentSerialIntf;
|
||||
int m_currentEndpoint;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
/* Copyright (c) 2010-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.
|
||||
*/
|
||||
|
||||
#include "UbloxGSMModemInitializer.h"
|
||||
#include "core/dbg.h"
|
||||
|
||||
#define __DEBUG__ 0
|
||||
#ifndef __MODULE__
|
||||
#define __MODULE__ "UbloxGSMModemInitializer.cpp"
|
||||
#endif
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
// mamm, u-blox Modem
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
UbloxGSMModemInitializer::UbloxGSMModemInitializer(USBHost* pHost) : WANDongleInitializer(pHost)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
uint16_t UbloxGSMModemInitializer::getMSDVid() { return 0x1546; }
|
||||
uint16_t UbloxGSMModemInitializer::getMSDPid() { return 0x0000; }
|
||||
|
||||
uint16_t UbloxGSMModemInitializer::getSerialVid() { return 0x1546; }
|
||||
uint16_t UbloxGSMModemInitializer::getSerialPid() { return 0x1102; }
|
||||
|
||||
bool UbloxGSMModemInitializer::switchMode(USBDeviceConnected* pDev)
|
||||
{
|
||||
for (int i = 0; i < pDev->getNbIntf(); i++)
|
||||
{
|
||||
if (pDev->getInterface(i)->intf_class == MSD_CLASS)
|
||||
{
|
||||
USBEndpoint* pEp = pDev->getEndpoint(i, BULK_ENDPOINT, OUT);
|
||||
if ( pEp != NULL )
|
||||
{
|
||||
ERR("MSD descriptor found on device %p, intf %d", (void *)pDev, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#define UBX_SERIALCOUNT 7
|
||||
|
||||
int UbloxGSMModemInitializer::getSerialPortCount()
|
||||
{
|
||||
return UBX_SERIALCOUNT;
|
||||
}
|
||||
|
||||
/*virtual*/ void UbloxGSMModemInitializer::setVidPid(uint16_t vid, uint16_t pid)
|
||||
{
|
||||
if( (vid == getSerialVid() ) && ( pid == getSerialPid() ) )
|
||||
{
|
||||
m_hasSwitched = true;
|
||||
m_currentSerialIntf = 0;
|
||||
m_endpointsToFetch = UBX_SERIALCOUNT*2;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_hasSwitched = false;
|
||||
m_endpointsToFetch = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*virtual*/ bool UbloxGSMModemInitializer::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( m_hasSwitched )
|
||||
{
|
||||
DBG("Interface #%d; Class:%02x; SubClass:%02x; Protocol:%02x", intf_nb, intf_class, intf_subclass, intf_protocol);
|
||||
if( intf_class == 0x0A )
|
||||
{
|
||||
if( (m_currentSerialIntf == 0) || (m_currentSerialIntf == 1) )
|
||||
{
|
||||
m_serialIntfMap[m_currentSerialIntf++] = intf_nb;
|
||||
return true;
|
||||
}
|
||||
m_currentSerialIntf++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( (intf_nb == 0) && (intf_class == MSD_CLASS) )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*virtual*/ bool UbloxGSMModemInitializer::useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) //Must return true if the endpoint will be used
|
||||
{
|
||||
if( m_hasSwitched )
|
||||
{
|
||||
DBG("USBEndpoint on Interface #%d; Type:%d; Direction:%d", intf_nb, type, dir);
|
||||
if( (type == BULK_ENDPOINT) && m_endpointsToFetch )
|
||||
{
|
||||
m_endpointsToFetch--;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( (type == BULK_ENDPOINT) && (dir == OUT) && m_endpointsToFetch )
|
||||
{
|
||||
m_endpointsToFetch--;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*virtual*/ int UbloxGSMModemInitializer::getType()
|
||||
{
|
||||
return WAN_DONGLE_TYPE_UBX;
|
||||
}
|
||||
|
|
@ -16,26 +16,48 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef IUSBENUMERATOR_H_
|
||||
#define IUSBENUMERATOR_H_
|
||||
#ifndef UBLOXGSMMODEMINITIALIZER_H
|
||||
#define UBLOXGSNMODEMINITIALIZER_H
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
#include "USBEndpoint.h"
|
||||
|
||||
/*
|
||||
Generic interface to implement for "smart" USB enumeration
|
||||
*/
|
||||
|
||||
class IUSBEnumerator {
|
||||
public:
|
||||
|
||||
virtual void setVidPid(uint16_t vid, uint16_t pid) = 0;
|
||||
|
||||
virtual bool parseInterface(uint8_t intf_nb, uint8_t intf_class, uint8_t intf_subclass, uint8_t intf_protocol) = 0; //Must return true if the interface should be parsed
|
||||
|
||||
virtual bool useEndpoint(uint8_t intf_nb, ENDPOINT_TYPE type, ENDPOINT_DIRECTION dir) = 0; //Must return true if the endpoint will be used
|
||||
#include "WANDongleInitializer.h"
|
||||
|
||||
enum
|
||||
{
|
||||
WAN_DONGLE_TYPE_UBX
|
||||
};
|
||||
|
||||
#endif /*IUSBENUMERATOR_H_*/
|
||||
//-----------------------------------------------------------------------
|
||||
// mamm, u-blox Modem
|
||||
//-----------------------------------------------------------------------
|
||||
|
||||
class UbloxGSMModemInitializer : public WANDongleInitializer
|
||||
{
|
||||
public:
|
||||
UbloxGSMModemInitializer(USBHost* pHost);
|
||||
|
||||
virtual uint16_t getMSDVid();
|
||||
virtual uint16_t getMSDPid();
|
||||
|
||||
virtual uint16_t getSerialVid();
|
||||
virtual uint16_t getSerialPid();
|
||||
|
||||
virtual bool switchMode(USBDeviceConnected* pDev);
|
||||
|
||||
virtual int getSerialPortCount();
|
||||
|
||||
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 getType();
|
||||
|
||||
private:
|
||||
|
||||
bool m_hasSwitched;
|
||||
int m_currentSerialIntf;
|
||||
int m_endpointsToFetch;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,398 @@
|
|||
/* UbloxUSBCDMAModem.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__ 4
|
||||
#ifndef __MODULE__
|
||||
#define __MODULE__ "UbloxUSBCDMAModem.cpp"
|
||||
#endif
|
||||
|
||||
#include "core/fwk.h"
|
||||
|
||||
#include "UbloxUSBCDMAModem.h"
|
||||
#include "UbloxCDMAModemInitializer.h"
|
||||
#include "USBHost.h"
|
||||
|
||||
#define USE_ONE_PORT 1
|
||||
|
||||
UbloxUSBCDMAModem::UbloxUSBCDMAModem(PinName powerGatingPin /*= NC*/, bool powerGatingOnWhenPinHigh /* = true*/, int serial /* 0 */) : m_dongle(),
|
||||
m_stream(m_dongle.getSerial(serial)),
|
||||
m_at(&m_stream),
|
||||
m_sms(&m_at), m_ppp(&m_stream, DEFAULT_MSISDN_CDMA),
|
||||
m_dongleConnected(false), m_ipInit(false), m_smsInit(false), m_atOpen(false),
|
||||
m_powerGatingPin(powerGatingPin), m_powerGatingOnWhenPinHigh(powerGatingOnWhenPinHigh)
|
||||
{
|
||||
USBHost* host = USBHost::getHostInst();
|
||||
m_dongle.addInitializer(new UbloxCDMAModemInitializer(host));
|
||||
if( m_powerGatingPin != NC )
|
||||
{
|
||||
power(false); //Dongle will have to be powered on manually
|
||||
}
|
||||
}
|
||||
|
||||
class CSSProcessor : public IATCommandsProcessor
|
||||
{
|
||||
public:
|
||||
CSSProcessor() : status(STATUS_REGISTERING)
|
||||
{
|
||||
|
||||
}
|
||||
enum REGISTERING_STATUS { STATUS_REGISTERING, STATUS_OK };
|
||||
REGISTERING_STATUS getStatus()
|
||||
{
|
||||
return status;
|
||||
}
|
||||
private:
|
||||
virtual int onNewATResponseLine(ATCommandsInterface* pInst, const char* line)
|
||||
{
|
||||
char b;
|
||||
char bc[3] = "";
|
||||
int sid = 99999;
|
||||
|
||||
//if( sscanf(line, "%*d, %c", &r) == 1 )
|
||||
if(sscanf(line, "%*s %c,%2s,%d", &b,bc,&sid)==3)
|
||||
{
|
||||
if(strcmp("Z", bc) == 0)
|
||||
status = STATUS_REGISTERING;
|
||||
else
|
||||
status = STATUS_OK;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
virtual int onNewEntryPrompt(ATCommandsInterface* pInst)
|
||||
{
|
||||
return OK;
|
||||
}
|
||||
volatile REGISTERING_STATUS status;
|
||||
};
|
||||
|
||||
int UbloxUSBCDMAModem::connect(const char* apn, const char* user, const char* password)
|
||||
{
|
||||
if( !m_ipInit )
|
||||
{
|
||||
m_ipInit = true;
|
||||
m_ppp.init();
|
||||
}
|
||||
m_ppp.setup(user, password);
|
||||
|
||||
int ret = init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if USE_ONE_PORT
|
||||
m_smsInit = false; //SMS status reset
|
||||
//m_ussdInit = false; //USSD status reset
|
||||
//m_linkMonitorInit = false; //Link monitor status reset
|
||||
#endif
|
||||
|
||||
ATCommandsInterface::ATResult result;
|
||||
|
||||
if(apn != NULL)
|
||||
{
|
||||
char cmd[48];
|
||||
sprintf(cmd, "AT+CGDCONT=1,\"IP\",\"%s\"", apn);
|
||||
ret = m_at.executeSimple(cmd, &result);
|
||||
DBG("Result of command: Err code=%d", ret);
|
||||
DBG("ATResult: AT return=%d (code %d)", result.result, result.code);
|
||||
DBG("APN set to %s", apn);
|
||||
}
|
||||
|
||||
|
||||
//Connect
|
||||
DBG("Connecting");
|
||||
#if USE_ONE_PORT
|
||||
m_at.close(); // Closing AT parser
|
||||
m_atOpen = false; //Will need to be reinitialized afterwards
|
||||
#endif
|
||||
|
||||
DBG("Connecting PPP");
|
||||
|
||||
ret = m_ppp.connect();
|
||||
DBG("Result of connect: Err code=%d", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int UbloxUSBCDMAModem::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 USE_ONE_PORT
|
||||
ATCommandsInterface::ATResult result;
|
||||
DBG("Starting AT thread");
|
||||
ret = m_at.open();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
DBG("Trying to hangup");
|
||||
|
||||
#if 0 //Does not appear to work
|
||||
int tries = 10;
|
||||
do
|
||||
{
|
||||
ret = m_at.executeSimple("+++", &result, 1000);
|
||||
DBG("Result of command: Err code=%d\n", ret);
|
||||
DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
|
||||
} while(tries-- && ret);
|
||||
if(!ret)
|
||||
{
|
||||
ret = m_at.executeSimple("ATH", &result);
|
||||
DBG("Result of command: Err code=%d\n", ret);
|
||||
DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if USE_ONE_PORT
|
||||
//Reinit AT parser
|
||||
ret = m_at.init();
|
||||
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;
|
||||
}
|
||||
|
||||
#if 0
|
||||
m_at.close(); // Closing AT parser
|
||||
DBG("AT Parser closed");
|
||||
#endif
|
||||
#endif
|
||||
return OK;
|
||||
}
|
||||
|
||||
int UbloxUSBCDMAModem::sendSM(const char* number, const char* message)
|
||||
{
|
||||
int ret = init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(!m_smsInit)
|
||||
{
|
||||
ret = m_sms.init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
m_smsInit = true;
|
||||
}
|
||||
|
||||
ret = m_sms.send(number, message);
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int UbloxUSBCDMAModem::getSM(char* number, char* message, size_t maxLength)
|
||||
{
|
||||
int ret = init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(!m_smsInit)
|
||||
{
|
||||
ret = m_sms.init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
m_smsInit = true;
|
||||
}
|
||||
|
||||
ret = m_sms.get(number, message, maxLength);
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int UbloxUSBCDMAModem::getSMCount(size_t* pCount)
|
||||
{
|
||||
int ret = init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(!m_smsInit)
|
||||
{
|
||||
ret = m_sms.init();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
m_smsInit = true;
|
||||
}
|
||||
|
||||
ret = m_sms.getCount(pCount);
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
ATCommandsInterface* UbloxUSBCDMAModem::getATCommandsInterface()
|
||||
{
|
||||
return &m_at;
|
||||
}
|
||||
|
||||
int UbloxUSBCDMAModem::power(bool enable)
|
||||
{
|
||||
if( m_powerGatingPin == NC )
|
||||
{
|
||||
return NET_INVALID; //A pin name has not been provided in the constructor
|
||||
}
|
||||
|
||||
if(!enable) //Will force components to re-init
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
|
||||
DigitalOut powerGatingOut(m_powerGatingPin);
|
||||
powerGatingOut = m_powerGatingOnWhenPinHigh?enable:!enable;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
bool UbloxUSBCDMAModem::power()
|
||||
{
|
||||
if( m_powerGatingPin == NC )
|
||||
{
|
||||
return true; //Assume power is always on
|
||||
}
|
||||
|
||||
DigitalOut powerGatingOut(m_powerGatingPin);
|
||||
return m_powerGatingOnWhenPinHigh?powerGatingOut:!powerGatingOut;
|
||||
}
|
||||
|
||||
int UbloxUSBCDMAModem::init()
|
||||
{
|
||||
if( !m_dongleConnected )
|
||||
{
|
||||
if(!power())
|
||||
{
|
||||
//Obviously cannot initialize the dongle if it is disconnected...
|
||||
ERR("Power is off");
|
||||
return NET_INVALID;
|
||||
}
|
||||
m_dongleConnected = true;
|
||||
while( !m_dongle.connected() )
|
||||
{
|
||||
m_dongle.tryConnect();
|
||||
Thread::wait(100);
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
if(ret)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBLOXC200)
|
||||
{
|
||||
INFO("Using a UBLOX C200 Dongle");
|
||||
}
|
||||
else
|
||||
{
|
||||
WARN("Using an Unknown Dongle");
|
||||
}
|
||||
|
||||
ATCommandsInterface::ATResult result;
|
||||
|
||||
//Wait for network registration
|
||||
CSSProcessor cssProcessor;
|
||||
do
|
||||
{
|
||||
DBG("Waiting for network registration");
|
||||
ret = m_at.execute("AT+CSS?", &cssProcessor, &result);
|
||||
DBG("Result of command: Err code=%d\n", ret);
|
||||
DBG("ATResult: AT return=%d (code %d)\n", result.result, result.code);
|
||||
if(cssProcessor.getStatus() == CSSProcessor::STATUS_REGISTERING)
|
||||
{
|
||||
Thread::wait(3000);
|
||||
}
|
||||
} while(cssProcessor.getStatus() == CSSProcessor::STATUS_REGISTERING);
|
||||
|
||||
m_atOpen = true;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
int UbloxUSBCDMAModem::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_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;
|
||||
}
|
||||
|
||||
m_dongle.disconnect();
|
||||
m_dongleConnected = false;
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
/* UbloxUSBCDMAModem.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 UBLOXUSBCDMAMODEM_H_
|
||||
#define UBLOXUSBCDMAMODEM_H_
|
||||
|
||||
#include "core/fwk.h"
|
||||
|
||||
#include "WANDongle.h"
|
||||
#include "at/ATCommandsInterface.h"
|
||||
#include "USBSerialStream.h"
|
||||
#include "ip/PPPIPInterface.h"
|
||||
#include "sms/CDMASMSInterface.h"
|
||||
#include "CellularModem.h"
|
||||
|
||||
/** u-blox LISA-C200 modem
|
||||
*/
|
||||
class UbloxUSBCDMAModem: public CellularModem
|
||||
{
|
||||
public:
|
||||
/** Create Sprint USB Modem (Sierra Wireless 598U) 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
|
||||
*/
|
||||
UbloxUSBCDMAModem(PinName powerGatingPin = NC, bool powerGatingOnWhenPinHigh = true, int serial = 0);
|
||||
|
||||
//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);
|
||||
|
||||
/** Get the ATCommandsInterface instance
|
||||
@return Pointer to the ATCommandsInterface instance
|
||||
*/
|
||||
virtual ATCommandsInterface* getATCommandsInterface();
|
||||
|
||||
/** Switch power on or off
|
||||
In order to use this function, a pin name must have been entered in the constructor
|
||||
@param enable true to switch the dongle on, false to switch it off
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
virtual int power(bool enable);
|
||||
|
||||
protected:
|
||||
bool power();
|
||||
|
||||
int init();
|
||||
int cleanup();
|
||||
|
||||
private:
|
||||
WANDongle m_dongle;
|
||||
|
||||
USBSerialStream m_stream;
|
||||
|
||||
ATCommandsInterface m_at;
|
||||
|
||||
CDMASMSInterface m_sms;
|
||||
|
||||
PPPIPInterface m_ppp;
|
||||
|
||||
bool m_dongleConnected;
|
||||
bool m_ipInit;
|
||||
bool m_smsInit;
|
||||
bool m_atOpen;
|
||||
|
||||
PinName m_powerGatingPin;
|
||||
bool m_powerGatingOnWhenPinHigh;
|
||||
};
|
||||
|
||||
|
||||
#endif /* UBLOXUSBCDMAMODEM_H_ */
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
/* VodafoneUSBModem.cpp */
|
||||
/* UbloxUSBGSMModem.cpp */
|
||||
/* Copyright (C) 2012 mbed.org, MIT License
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
|
||||
|
@ -19,31 +19,35 @@
|
|||
|
||||
#define __DEBUG__ 3
|
||||
#ifndef __MODULE__
|
||||
#define __MODULE__ "VodafoneUSBModem.cpp"
|
||||
#define __MODULE__ "UbloxUSBGSMModem.cpp"
|
||||
#endif
|
||||
|
||||
#include "core/fwk.h"
|
||||
|
||||
#include "VodafoneUSBModem.h"
|
||||
#include "UbloxUSBGSMModem.h"
|
||||
#include "UbloxGSMModemInitializer.h"
|
||||
#include "USBHost.h"
|
||||
|
||||
VodafoneUSBModem::VodafoneUSBModem(PinName powerGatingPin /*= NC*/, bool powerGatingOnWhenPinHigh /* = true*/) :
|
||||
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_at(&m_atStream), // Construct ATCommandsInterface with the AT serial channel
|
||||
m_sms(&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(&m_pppStream), // Construct PPPIPInterface with the PPP serial channel
|
||||
m_dongleConnected(false), // Dongle is initially not ready for anything
|
||||
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_powerGatingPin(powerGatingPin), // set power gating pin
|
||||
UbloxUSBGSMModem::UbloxUSBGSMModem(PinName powerGatingPin /*= NC*/, bool powerGatingOnWhenPinHigh /* = true*/) :
|
||||
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_at(&m_atStream), // Construct ATCommandsInterface with the AT serial channel
|
||||
m_sms(&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(&m_pppStream, DEFAULT_MSISDN_GSM), // Construct PPPIPInterface with the PPP serial channel
|
||||
m_dongleConnected(false), // Dongle is initially not ready for anything
|
||||
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_powerGatingPin(powerGatingPin), // set power gating pin
|
||||
m_powerGatingOnWhenPinHigh(powerGatingOnWhenPinHigh) // set state semantics for power gating pin
|
||||
{
|
||||
USBHost* host = USBHost::getHostInst();
|
||||
m_dongle.addInitializer(new UbloxGSMModemInitializer(host));
|
||||
if( m_powerGatingPin != NC )
|
||||
{
|
||||
power(false); //Dongle will have to be powered on manually
|
||||
|
@ -174,7 +178,7 @@ private:
|
|||
};
|
||||
#endif
|
||||
|
||||
int VodafoneUSBModem::connect(const char* apn, const char* user, const char* password)
|
||||
int UbloxUSBGSMModem::connect(const char* apn, const char* user, const char* password)
|
||||
{
|
||||
if( !m_ipInit )
|
||||
{
|
||||
|
@ -273,7 +277,7 @@ int VodafoneUSBModem::connect(const char* apn, const char* user, const char* pas
|
|||
}
|
||||
|
||||
|
||||
int VodafoneUSBModem::disconnect()
|
||||
int UbloxUSBGSMModem::disconnect()
|
||||
{
|
||||
DBG("Disconnecting from PPP");
|
||||
int ret = m_ppp.disconnect();
|
||||
|
@ -332,7 +336,7 @@ int VodafoneUSBModem::disconnect()
|
|||
return OK;
|
||||
}
|
||||
|
||||
int VodafoneUSBModem::sendSM(const char* number, const char* message)
|
||||
int UbloxUSBGSMModem::sendSM(const char* number, const char* message)
|
||||
{
|
||||
int ret = init();
|
||||
if(ret)
|
||||
|
@ -359,7 +363,7 @@ int VodafoneUSBModem::sendSM(const char* number, const char* message)
|
|||
return OK;
|
||||
}
|
||||
|
||||
int VodafoneUSBModem::getSM(char* number, char* message, size_t maxLength)
|
||||
int UbloxUSBGSMModem::getSM(char* number, char* message, size_t maxLength)
|
||||
{
|
||||
int ret = init();
|
||||
if(ret)
|
||||
|
@ -386,7 +390,7 @@ int VodafoneUSBModem::getSM(char* number, char* message, size_t maxLength)
|
|||
return OK;
|
||||
}
|
||||
|
||||
int VodafoneUSBModem::getSMCount(size_t* pCount)
|
||||
int UbloxUSBGSMModem::getSMCount(size_t* pCount)
|
||||
{
|
||||
int ret = init();
|
||||
if(ret)
|
||||
|
@ -413,7 +417,7 @@ int VodafoneUSBModem::getSMCount(size_t* pCount)
|
|||
return OK;
|
||||
}
|
||||
|
||||
int VodafoneUSBModem::sendUSSD(const char* command, char* result, size_t maxLength)
|
||||
int UbloxUSBGSMModem::sendUSSD(const char* command, char* result, size_t maxLength)
|
||||
{
|
||||
int ret = init();
|
||||
if(ret)
|
||||
|
@ -440,7 +444,7 @@ int VodafoneUSBModem::sendUSSD(const char* command, char* result, size_t maxLeng
|
|||
return OK;
|
||||
}
|
||||
|
||||
int VodafoneUSBModem::getLinkState(int* pRssi, LinkMonitor::REGISTRATION_STATE* pRegistrationState, LinkMonitor::BEARER* pBearer)
|
||||
int UbloxUSBGSMModem::getLinkState(int* pRssi, LinkMonitor::REGISTRATION_STATE* pRegistrationState, LinkMonitor::BEARER* pBearer)
|
||||
{
|
||||
int ret = init();
|
||||
if(ret)
|
||||
|
@ -468,12 +472,12 @@ int VodafoneUSBModem::getLinkState(int* pRssi, LinkMonitor::REGISTRATION_STATE*
|
|||
}
|
||||
|
||||
|
||||
ATCommandsInterface* VodafoneUSBModem::getATCommandsInterface()
|
||||
ATCommandsInterface* UbloxUSBGSMModem::getATCommandsInterface()
|
||||
{
|
||||
return &m_at;
|
||||
}
|
||||
|
||||
int VodafoneUSBModem::power(bool enable)
|
||||
int UbloxUSBGSMModem::power(bool enable)
|
||||
{
|
||||
if( m_powerGatingPin == NC )
|
||||
{
|
||||
|
@ -491,7 +495,7 @@ int VodafoneUSBModem::power(bool enable)
|
|||
return OK;
|
||||
}
|
||||
|
||||
bool VodafoneUSBModem::power()
|
||||
bool UbloxUSBGSMModem::power()
|
||||
{
|
||||
if( m_powerGatingPin == NC )
|
||||
{
|
||||
|
@ -502,7 +506,7 @@ bool VodafoneUSBModem::power()
|
|||
return m_powerGatingOnWhenPinHigh?powerGatingOut:!powerGatingOut;
|
||||
}
|
||||
|
||||
int VodafoneUSBModem::init()
|
||||
int UbloxUSBGSMModem::init()
|
||||
{
|
||||
if( !m_dongleConnected )
|
||||
{
|
||||
|
@ -539,38 +543,9 @@ int VodafoneUSBModem::init()
|
|||
return ret;
|
||||
}
|
||||
|
||||
if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_VODAFONEK3770)
|
||||
if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_UBX)
|
||||
{
|
||||
INFO("Using a Vodafone K3770 Dongle");
|
||||
#if USE_ONE_PORT
|
||||
DBG("Configuring unsolicited result codes support properly");
|
||||
//Configuring port to enable 3GPP-compliant unsollicited response codes but disable Huawei-specific unsollicited response codes
|
||||
ret = m_at.executeSimple("AT^CURC=0;^PORTSEL=1", NULL); //Huawei-specific, not 3GPP-compliant
|
||||
if(ret != OK)
|
||||
{
|
||||
return NET_PROTOCOL;
|
||||
}
|
||||
#else
|
||||
//Configuring port to disable Huawei-specific unsollicited response codes
|
||||
ret = m_at.executeSimple("AT^CURC=0", NULL); //Huawei-specific, not 3GPP-compliant
|
||||
if(ret != OK)
|
||||
{
|
||||
return NET_PROTOCOL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else if(m_dongle.getDongleType() == WAN_DONGLE_TYPE_VODAFONEK3772Z)
|
||||
{
|
||||
INFO("Using a Vodafone K3772-Z Dongle");
|
||||
//FIXME this returns %USBMODEM: [0] MODEM DRIVER<CR><LF><CR><LF><CR><LF>OK<CR><LF> which is not a compliant response
|
||||
/*
|
||||
//Configuring modem to directly boot into modem mode
|
||||
ret = m_at.executeSimple("AT%USBMODEM=0", NULL); //Icera-specific, not 3GPP-compliant
|
||||
if(ret != OK)
|
||||
{
|
||||
return NET_PROTOCOL;
|
||||
}
|
||||
*/
|
||||
INFO("Using a u-blox LISA-U");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -603,7 +578,7 @@ int VodafoneUSBModem::init()
|
|||
return OK;
|
||||
}
|
||||
|
||||
int VodafoneUSBModem::cleanup()
|
||||
int UbloxUSBGSMModem::cleanup()
|
||||
{
|
||||
if(m_ppp.isConnected())
|
||||
{
|
|
@ -17,8 +17,8 @@
|
|||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef VODAFONEUSBMODEM_H_
|
||||
#define VODAFONEUSBMODEM_H_
|
||||
#ifndef UBLOXUSBGSMMODEM_H_
|
||||
#define UBLOXUSBGSMMODEM_H_
|
||||
|
||||
#include "core/fwk.h"
|
||||
|
||||
|
@ -26,32 +26,33 @@
|
|||
#include "at/ATCommandsInterface.h"
|
||||
#include "serial/usb/USBSerialStream.h"
|
||||
#include "ip/PPPIPInterface.h"
|
||||
#include "sms/SMSInterface.h"
|
||||
#include "sms/GSMSMSInterface.h"
|
||||
#include "ussd/USSDInterface.h"
|
||||
#include "link/LinkMonitor.h"
|
||||
#include "CellularModem.h"
|
||||
|
||||
/** Vodafone USB Modem (K3770/K3772-Z) dongle
|
||||
/** u-blox WCDMA modem (LISA-U200)
|
||||
*/
|
||||
class VodafoneUSBModem
|
||||
class UbloxUSBGSMModem: public CellularModem
|
||||
{
|
||||
public:
|
||||
/** Create Vodafone USB Modem (K3770/K3772-Z) dongle API instance
|
||||
/** 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
|
||||
*/
|
||||
VodafoneUSBModem(PinName powerGatingPin = NC, bool powerGatingOnWhenPinHigh = true);
|
||||
UbloxUSBGSMModem(PinName powerGatingPin = NC, bool powerGatingOnWhenPinHigh = true);
|
||||
|
||||
//Internet-related functions
|
||||
|
||||
/** Open a 3G internet connection
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
int connect(const char* apn = NULL, const char* user = NULL, const char* password = NULL);
|
||||
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
|
||||
*/
|
||||
int disconnect();
|
||||
virtual int disconnect();
|
||||
|
||||
|
||||
/** Send a SM
|
||||
|
@ -59,7 +60,7 @@ public:
|
|||
@param message The message to send
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
int sendSM(const char* number, const char* message);
|
||||
virtual int sendSM(const char* number, const char* message);
|
||||
|
||||
|
||||
/** Receive a SM
|
||||
|
@ -68,13 +69,13 @@ public:
|
|||
@param maxLength Maximum message length that can be stored in buffer (including null-terminating character)
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
int getSM(char* number, char* message, size_t maxLength);
|
||||
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
|
||||
*/
|
||||
int getSMCount(size_t* pCount);
|
||||
virtual int getSMCount(size_t* pCount);
|
||||
|
||||
/** Send a USSD command & wait for its result
|
||||
@param command The command to send
|
||||
|
@ -95,14 +96,14 @@ public:
|
|||
/** Get the ATCommandsInterface instance
|
||||
@return Pointer to the ATCommandsInterface instance
|
||||
*/
|
||||
ATCommandsInterface* getATCommandsInterface();
|
||||
virtual ATCommandsInterface* getATCommandsInterface();
|
||||
|
||||
/** Switch power on or off
|
||||
In order to use this function, a pin name must have been entered in the constructor
|
||||
@param enable true to switch the dongle on, false to switch it off
|
||||
@return 0 on success, error code on failure
|
||||
*/
|
||||
int power(bool enable);
|
||||
virtual int power(bool enable);
|
||||
|
||||
protected:
|
||||
bool power(); //< Turn power to USB dongle ON.
|
||||
|
@ -133,7 +134,7 @@ private:
|
|||
|
||||
ATCommandsInterface m_at; //< Interface to AT commands processing
|
||||
|
||||
SMSInterface m_sms; //< Interface to SMS manager (send/receive etc)
|
||||
GSMSMSInterface m_sms; //< Interface to SMS manager (send/receive etc)
|
||||
USSDInterface m_ussd; //< Interface to USSD manager (send etc)
|
||||
LinkMonitor m_linkMonitor; //< Interface to link monitor (RSSI)
|
||||
|
||||
|
@ -151,4 +152,4 @@ private:
|
|||
};
|
||||
|
||||
|
||||
#endif /* VODAFONEUSBMODEM_H_ */
|
||||
#endif /* UBLOXMODEM_H_ */
|
|
@ -1,121 +0,0 @@
|
|||
#include "test_env.h"
|
||||
|
||||
DigitalOut myled(LED1);
|
||||
DigitalOut led2(LED2);
|
||||
DigitalOut led3(LED3);
|
||||
|
||||
volatile int checks = 0;
|
||||
volatile int total = 0;
|
||||
void in_handler() {
|
||||
checks++;
|
||||
led2 = !led2;
|
||||
}
|
||||
|
||||
#if defined(TARGET_KL25Z)
|
||||
#define PIN_OUT PTC6
|
||||
#define PIN_IN PTA5
|
||||
|
||||
#elif defined(TARGET_KL05Z)
|
||||
#define PIN_OUT PTB11
|
||||
#define PIN_IN PTB1
|
||||
|
||||
#elif defined(TARGET_LPC812)
|
||||
#define PIN_OUT D10
|
||||
#define PIN_IN D11
|
||||
|
||||
#elif defined(TARGET_LPC4088)
|
||||
#define PIN_IN (p11)
|
||||
#define PIN_OUT (p12)
|
||||
|
||||
#elif defined(TARGET_LPC1114)
|
||||
#define PIN_IN (dp1)
|
||||
#define PIN_OUT (dp2)
|
||||
|
||||
#else
|
||||
#define PIN_IN (p5)
|
||||
#define PIN_OUT (p25)
|
||||
|
||||
#endif
|
||||
|
||||
DigitalOut out(PIN_OUT);
|
||||
InterruptIn in(PIN_IN);
|
||||
|
||||
void flipper() {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
out = 1; myled = 1; wait(0.2);
|
||||
|
||||
out = 0; myled = 0; wait(0.2);
|
||||
}
|
||||
}
|
||||
|
||||
void flipper2() {
|
||||
led3 = !led3;
|
||||
}
|
||||
|
||||
void handler2() {
|
||||
total++;
|
||||
}
|
||||
|
||||
int object_cnt = 0;
|
||||
|
||||
class Incrementer {
|
||||
public:
|
||||
Incrementer() : _cnt(0) {}
|
||||
void inc() { _cnt++; }
|
||||
int get() const { return _cnt; }
|
||||
private:
|
||||
int _cnt;
|
||||
};
|
||||
|
||||
int main() {
|
||||
out = 0; myled = 0;
|
||||
|
||||
//Test falling edges first
|
||||
Incrementer i1;
|
||||
in.rise(NULL);
|
||||
in.fall(in_handler);
|
||||
in.fall_add(handler2);
|
||||
in.fall_add(flipper2);
|
||||
in.fall_add_front(&i1, &Incrementer::inc);
|
||||
flipper();
|
||||
|
||||
if(checks != 5 || i1.get() != 5) {
|
||||
printf("falling edges test failed\n");
|
||||
notify_completion(false);
|
||||
}
|
||||
|
||||
//Now test rising edges
|
||||
Incrementer i2;
|
||||
in.rise(in_handler);
|
||||
in.rise_add(handler2);
|
||||
in.rise_add(&i2, &Incrementer::inc);
|
||||
in.rise_add_front(flipper2);
|
||||
in.fall(NULL);
|
||||
flipper();
|
||||
|
||||
if (checks != 10 || i2.get() != 5) {
|
||||
printf("raising edges test failed\n");
|
||||
notify_completion(false);
|
||||
}
|
||||
|
||||
//Finally test both
|
||||
in.rise(in_handler);
|
||||
in.rise_add(handler2);
|
||||
pFunctionPointer_t rise_led = in.rise_add(flipper2);
|
||||
in.fall(in_handler);
|
||||
in.fall_add(handler2);
|
||||
pFunctionPointer_t fall_led = in.fall_add(flipper2);
|
||||
if (!in.rise_remove(rise_led) || !in.fall_remove(fall_led)) {
|
||||
printf("remove handler failed\n");
|
||||
notify_completion(false);
|
||||
}
|
||||
flipper();
|
||||
|
||||
if (checks != 20) {
|
||||
printf("Simultaneous rising and falling edges failed! check=%d\n", checks);
|
||||
notify_completion(false);
|
||||
}
|
||||
printf("Total: %d\n", total);
|
||||
notify_completion(true);
|
||||
return 0;
|
||||
}
|
|
@ -84,9 +84,7 @@ int main() {
|
|||
|
||||
// Test chaining inside Serial class
|
||||
flipper_1.attach(&flip_1, 1.0); // the address of the function to be attached (flip) and the interval (1 second)
|
||||
flipper_1.add_function_front(&s1, &Sender::send);
|
||||
flipper_2.attach(&flip_2, 2.0); // the address of the function to be attached (flip) and the interval (2 seconds)
|
||||
flipper_2.add_function(&s2, &Sender::send);
|
||||
|
||||
// Test global chaining (InterruptManager)
|
||||
printf("Handler initially: %08X\n", initial_handler = NVIC_GetVector(TIMER_IRQ));
|
|
@ -1,41 +0,0 @@
|
|||
#include "mbed.h"
|
||||
|
||||
DigitalOut led1(LED1);
|
||||
DigitalOut led2(LED2);
|
||||
|
||||
Serial computer(USBTX, USBRX);
|
||||
|
||||
// This function is called when a character goes into the TX buffer.
|
||||
void txCallback() {
|
||||
led1 = !led1;
|
||||
}
|
||||
|
||||
// This function is called when a character goes into the RX buffer.
|
||||
void rxCallback() {
|
||||
led2 = !led2;
|
||||
computer.putc(computer.getc());
|
||||
}
|
||||
|
||||
class Counter {
|
||||
public:
|
||||
Counter(const char* name): _name(name), _cnt(0) {}
|
||||
void inc() { _cnt++; }
|
||||
void show() const { printf("%s: %d\n", _name, _cnt); }
|
||||
int get() const { return _cnt; }
|
||||
~Counter() { show(); }
|
||||
private:
|
||||
const char *_name;
|
||||
volatile int _cnt;
|
||||
};
|
||||
|
||||
int main() {
|
||||
printf("start test\n");
|
||||
Counter rx("RX bytes"), tx("TX bytes");
|
||||
|
||||
computer.attach(&txCallback, Serial::TxIrq);
|
||||
computer.add_handler(&tx, &Counter::inc, Serial::TxIrq);
|
||||
computer.attach(&rxCallback, Serial::RxIrq);
|
||||
computer.add_handler_front(&rx, &Counter::inc, Serial::RxIrq);
|
||||
|
||||
while (rx.get() < 40);
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue