Merge branch 'master' of git://github.com/mbedmicro/mbed into bugfix-STM32-vectors

pull/93/head
Joe Turner 2013-10-25 13:11:25 +01:00
commit 6ae1e9e360
162 changed files with 2482 additions and 9635 deletions

8
.gitignore vendored
View File

@ -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

96
MANIFEST Normal file
View File

@ -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

2
MANIFEST.in Normal file
View File

@ -0,0 +1,2 @@
graft workspace_tools
include __init__.py LICENSE

View File

@ -30,6 +30,10 @@
#include "IUSBHostSerialListener.h"
// This is needed by some versions of GCC
#undef putc
#undef getc
class IUSBHostSerial {
public:

View File

@ -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];
}

View File

@ -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;

View File

@ -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();
}
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -48,6 +48,7 @@
#include "I2CSlave.h"
#include "Ethernet.h"
#include "CAN.h"
#include "RawSerial.h"
// mbed Internal components
#include "Timer.h"

View File

@ -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;
}

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -18,7 +18,7 @@
namespace mbed {
void Timeout::handler() {
_chain.call();
_function.call();
}
} // namespace mbed

View File

@ -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
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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);
}
}

View File

@ -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));
}

View File

@ -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;
}
}

View File

@ -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));
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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
}

View File

@ -48,7 +48,7 @@
#define DEVICE_DEBUG_AWARENESS 0
#define DEVICE_STDIO_MESSAGES 1
#define DEVICE_STDIO_MESSAGES 0
#define DEVICE_ERROR_RED 1

View File

@ -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));
}

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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

View File

@ -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();
}
}

View File

@ -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

View File

@ -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];
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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();
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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_ */

View File

@ -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
}
}

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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_ */

View File

@ -20,8 +20,6 @@
#ifndef IOSTREAM_H_
#define IOSTREAM_H_
#include "fwk.h"
#include "rtos.h"
class IStream

View File

@ -20,8 +20,6 @@
#ifndef MTXCIRCBUFFER_H
#define MTXCIRCBUFFER_H
#include "fwk.h"
#include "rtos.h"
//Mutex protected circualr buffer

View File

@ -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

View File

@ -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_ */

View File

@ -23,3 +23,4 @@
#define LWIP_TRANSPORT_PPP 1
#endif /* LWIPOPTS_CONF_H_ */

View File

@ -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;
}

View File

@ -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_ */

View File

@ -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

View File

@ -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_ */

View File

@ -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_ */

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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_ */

View File

@ -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())
{

View File

@ -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_ */

View File

@ -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;
}

View File

@ -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));

View File

@ -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