mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #1863 from c1728p9/thread_safe_cpp_api
Make core mbed API thread safepull/1775/head^2
commit
1947c48502
|
@ -25,6 +25,8 @@
|
|||
namespace mbed {
|
||||
|
||||
/** An analog input, used for reading the voltage on a pin
|
||||
*
|
||||
* @Note Synchronization level: Thread safe
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -53,7 +55,9 @@ public:
|
|||
* @param name (optional) A string to identify the object
|
||||
*/
|
||||
AnalogIn(PinName pin) {
|
||||
lock();
|
||||
analogin_init(&_adc, pin);
|
||||
unlock();
|
||||
}
|
||||
|
||||
/** Read the input voltage, represented as a float in the range [0.0, 1.0]
|
||||
|
@ -61,7 +65,10 @@ public:
|
|||
* @returns A floating-point value representing the current input voltage, measured as a percentage
|
||||
*/
|
||||
float read() {
|
||||
return analogin_read(&_adc);
|
||||
lock();
|
||||
float ret = analogin_read(&_adc);
|
||||
unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** Read the input voltage, represented as an unsigned short in the range [0x0, 0xFFFF]
|
||||
|
@ -70,7 +77,10 @@ public:
|
|||
* 16-bit unsigned short representing the current input voltage, normalised to a 16-bit value
|
||||
*/
|
||||
unsigned short read_u16() {
|
||||
return analogin_read_u16(&_adc);
|
||||
lock();
|
||||
unsigned short ret = analogin_read_u16(&_adc);
|
||||
unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef MBED_OPERATORS
|
||||
|
@ -88,12 +98,23 @@ public:
|
|||
* @endcode
|
||||
*/
|
||||
operator float() {
|
||||
// Underlying call is thread safe
|
||||
return read();
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
virtual void lock() {
|
||||
_mutex.lock();
|
||||
}
|
||||
|
||||
virtual void unlock() {
|
||||
_mutex.unlock();
|
||||
}
|
||||
|
||||
analogin_t _adc;
|
||||
static PlatformMutex _mutex;
|
||||
};
|
||||
|
||||
} // namespace mbed
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
namespace mbed {
|
||||
|
||||
/** An analog output, used for setting the voltage on a pin
|
||||
*
|
||||
* @Note Synchronization level: Thread safe
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -64,7 +66,9 @@ public:
|
|||
* Values outside this range will be saturated to 0.0f or 1.0f.
|
||||
*/
|
||||
void write(float value) {
|
||||
lock();
|
||||
analogout_write(&_dac, value);
|
||||
unlock();
|
||||
}
|
||||
|
||||
/** Set the output voltage, represented as an unsigned short in the range [0x0, 0xFFFF]
|
||||
|
@ -73,7 +77,9 @@ public:
|
|||
* normalised to a 16-bit value (0x0000 = 0v, 0xFFFF = 3.3v)
|
||||
*/
|
||||
void write_u16(unsigned short value) {
|
||||
lock();
|
||||
analogout_write_u16(&_dac, value);
|
||||
unlock();
|
||||
}
|
||||
|
||||
/** Return the current output voltage setting, measured as a percentage (float)
|
||||
|
@ -87,18 +93,23 @@ public:
|
|||
* This value may not match exactly the value set by a previous write().
|
||||
*/
|
||||
float read() {
|
||||
return analogout_read(&_dac);
|
||||
lock();
|
||||
float ret = analogout_read(&_dac);
|
||||
unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef MBED_OPERATORS
|
||||
/** An operator shorthand for write()
|
||||
*/
|
||||
AnalogOut& operator= (float percent) {
|
||||
// Underlying write call is thread safe
|
||||
write(percent);
|
||||
return *this;
|
||||
}
|
||||
|
||||
AnalogOut& operator= (AnalogOut& rhs) {
|
||||
// Underlying write call is thread safe
|
||||
write(rhs.read());
|
||||
return *this;
|
||||
}
|
||||
|
@ -106,12 +117,23 @@ public:
|
|||
/** An operator shorthand for read()
|
||||
*/
|
||||
operator float() {
|
||||
// Underlying read call is thread safe
|
||||
return read();
|
||||
}
|
||||
#endif
|
||||
|
||||
protected:
|
||||
|
||||
virtual void lock() {
|
||||
_mutex.lock();
|
||||
}
|
||||
|
||||
virtual void unlock() {
|
||||
_mutex.unlock();
|
||||
}
|
||||
|
||||
dac_t _dac;
|
||||
PlatformMutex _mutex;
|
||||
};
|
||||
|
||||
} // namespace mbed
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
namespace mbed {
|
||||
|
||||
/** A digital input bus, used for reading the state of a collection of pins
|
||||
*
|
||||
* @Note Synchronization level: Thread safe
|
||||
*/
|
||||
class BusIn {
|
||||
|
||||
|
@ -65,6 +67,7 @@ public:
|
|||
* Binary mask of connected pins
|
||||
*/
|
||||
int mask() {
|
||||
// No lock needed since _nc_mask is not modified outside the constructor
|
||||
return _nc_mask;
|
||||
}
|
||||
|
||||
|
@ -87,8 +90,12 @@ protected:
|
|||
*/
|
||||
int _nc_mask;
|
||||
|
||||
PlatformMutex _mutex;
|
||||
|
||||
/* disallow copy constructor and assignment operators */
|
||||
private:
|
||||
virtual void lock();
|
||||
virtual void unlock();
|
||||
BusIn(const BusIn&);
|
||||
BusIn & operator = (const BusIn&);
|
||||
};
|
||||
|
|
|
@ -21,6 +21,8 @@
|
|||
namespace mbed {
|
||||
|
||||
/** A digital input output bus, used for setting the state of a collection of pins
|
||||
*
|
||||
* @Note Synchronization level: Thread safe
|
||||
*/
|
||||
class BusInOut {
|
||||
|
||||
|
@ -79,6 +81,7 @@ public:
|
|||
* Binary mask of connected pins
|
||||
*/
|
||||
int mask() {
|
||||
// No lock needed since _nc_mask is not modified outside the constructor
|
||||
return _nc_mask;
|
||||
}
|
||||
|
||||
|
@ -98,6 +101,8 @@ public:
|
|||
#endif
|
||||
|
||||
protected:
|
||||
virtual void lock();
|
||||
virtual void unlock();
|
||||
DigitalInOut* _pin[16];
|
||||
|
||||
/** Mask of bus's NC pins
|
||||
|
@ -106,6 +111,8 @@ protected:
|
|||
*/
|
||||
int _nc_mask;
|
||||
|
||||
PlatformMutex _mutex;
|
||||
|
||||
/* disallow copy constructor and assignment operators */
|
||||
private:
|
||||
BusInOut(const BusInOut&);
|
||||
|
|
|
@ -30,6 +30,8 @@ public:
|
|||
*
|
||||
* @param p<n> DigitalOut pin to connect to bus bit <n> (p5-p30, NC)
|
||||
*
|
||||
* @Note Synchronization level: Thread safe
|
||||
*
|
||||
* @note
|
||||
* It is only required to specify as many pin variables as is required
|
||||
* for the bus; the rest will default to NC (not connected)
|
||||
|
@ -63,6 +65,7 @@ public:
|
|||
* Binary mask of connected pins
|
||||
*/
|
||||
int mask() {
|
||||
// No lock needed since _nc_mask is not modified outside the constructor
|
||||
return _nc_mask;
|
||||
}
|
||||
|
||||
|
@ -82,6 +85,8 @@ public:
|
|||
#endif
|
||||
|
||||
protected:
|
||||
virtual void lock();
|
||||
virtual void unlock();
|
||||
DigitalOut* _pin[16];
|
||||
|
||||
/** Mask of bus's NC pins
|
||||
|
@ -90,6 +95,8 @@ protected:
|
|||
*/
|
||||
int _nc_mask;
|
||||
|
||||
PlatformMutex _mutex;
|
||||
|
||||
/* disallow copy constructor and assignment operators */
|
||||
private:
|
||||
BusOut(const BusOut&);
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
namespace mbed {
|
||||
|
||||
/** CANMessage class
|
||||
*
|
||||
* @Note Synchronization level: Thread safe
|
||||
*/
|
||||
class CANMessage : public CAN_Message {
|
||||
|
||||
|
@ -220,6 +222,7 @@ public:
|
|||
*/
|
||||
template<typename T>
|
||||
void attach(T* obj, void (T::*method)(), IrqType type=RxIrq) {
|
||||
// Underlying call thread safe
|
||||
attach(Callback<void()>(obj, method), type);
|
||||
}
|
||||
|
||||
|
@ -232,14 +235,18 @@ public:
|
|||
*/
|
||||
template<typename T>
|
||||
void attach(T* obj, void (*method)(T*), IrqType type=RxIrq) {
|
||||
// Underlying call thread safe
|
||||
attach(Callback<void()>(obj, method), type);
|
||||
}
|
||||
|
||||
static void _irq_handler(uint32_t id, CanIrqType type);
|
||||
|
||||
protected:
|
||||
virtual void lock();
|
||||
virtual void unlock();
|
||||
can_t _can;
|
||||
Callback<void()> _irq[9];
|
||||
PlatformMutex _mutex;
|
||||
};
|
||||
|
||||
} // namespace mbed
|
||||
|
|
|
@ -71,6 +71,11 @@
|
|||
/* IRQ/Exception compatible thunk entry function */
|
||||
typedef void (*CThunkEntry)(void);
|
||||
|
||||
/**
|
||||
* Class for created a pointer with data bound to it
|
||||
*
|
||||
* @Note Synchronization level: Not protected
|
||||
*/
|
||||
template<class T>
|
||||
class CThunk
|
||||
{
|
||||
|
|
|
@ -25,6 +25,8 @@ namespace mbed {
|
|||
* sequence using CallChain::call(). Used mostly by the interrupt chaining code,
|
||||
* but can be used for other purposes.
|
||||
*
|
||||
* @Note Synchronization level: Not protected
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* #include "mbed.h"
|
||||
|
@ -58,6 +60,7 @@ namespace mbed {
|
|||
*/
|
||||
|
||||
typedef Callback<void()> *pFunctionPointer_t;
|
||||
class CallChainLink;
|
||||
|
||||
class CallChain {
|
||||
public:
|
||||
|
@ -160,17 +163,11 @@ public:
|
|||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
void _check_size();
|
||||
|
||||
pFunctionPointer_t* _chain;
|
||||
int _size;
|
||||
int _elements;
|
||||
|
||||
/* disallow copy constructor and assignment operators */
|
||||
private:
|
||||
CallChain(const CallChain&);
|
||||
CallChain & operator = (const CallChain&);
|
||||
CallChainLink *_chain;
|
||||
};
|
||||
|
||||
} // namespace mbed
|
||||
|
|
|
@ -23,6 +23,8 @@ namespace mbed {
|
|||
|
||||
|
||||
/** Callback class based on template specialization
|
||||
*
|
||||
* @Note Synchronization level: Not protected
|
||||
*/
|
||||
template <typename F>
|
||||
class Callback;
|
||||
|
|
|
@ -16,9 +16,13 @@
|
|||
#ifndef MBED_CIRCULARBUFFER_H
|
||||
#define MBED_CIRCULARBUFFER_H
|
||||
|
||||
#include "critical.h"
|
||||
|
||||
namespace mbed {
|
||||
|
||||
/** Templated Circular buffer class
|
||||
*
|
||||
* @Note Synchronization level: Interrupt safe
|
||||
*/
|
||||
template<typename T, uint32_t BufferSize, typename CounterType = uint32_t>
|
||||
class CircularBuffer {
|
||||
|
@ -35,6 +39,7 @@ public:
|
|||
* @param data Data to be pushed to the buffer
|
||||
*/
|
||||
void push(const T& data) {
|
||||
core_util_critical_section_enter();
|
||||
if (full()) {
|
||||
_tail++;
|
||||
_tail %= BufferSize;
|
||||
|
@ -44,6 +49,7 @@ public:
|
|||
if (_head == _tail) {
|
||||
_full = true;
|
||||
}
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
/** Pop the transaction from the buffer
|
||||
|
@ -52,13 +58,16 @@ public:
|
|||
* @return True if the buffer is not empty and data contains a transaction, false otherwise
|
||||
*/
|
||||
bool pop(T& data) {
|
||||
bool data_popped = false;
|
||||
core_util_critical_section_enter();
|
||||
if (!empty()) {
|
||||
data = _pool[_tail++];
|
||||
_tail %= BufferSize;
|
||||
_full = false;
|
||||
return true;
|
||||
data_popped = true;
|
||||
}
|
||||
return false;
|
||||
core_util_critical_section_exit();
|
||||
return data_popped;
|
||||
}
|
||||
|
||||
/** Check if the buffer is empty
|
||||
|
@ -66,7 +75,10 @@ public:
|
|||
* @return True if the buffer is empty, false if not
|
||||
*/
|
||||
bool empty() {
|
||||
return (_head == _tail) && !_full;
|
||||
core_util_critical_section_enter();
|
||||
bool is_empty = (_head == _tail) && !_full;
|
||||
core_util_critical_section_exit();
|
||||
return is_empty;
|
||||
}
|
||||
|
||||
/** Check if the buffer is full
|
||||
|
@ -74,16 +86,21 @@ public:
|
|||
* @return True if the buffer is full, false if not
|
||||
*/
|
||||
bool full() {
|
||||
return _full;
|
||||
core_util_critical_section_enter();
|
||||
bool full = _full;
|
||||
core_util_critical_section_exit();
|
||||
return full;
|
||||
}
|
||||
|
||||
/** Reset the buffer
|
||||
*
|
||||
*/
|
||||
void reset() {
|
||||
core_util_critical_section_enter();
|
||||
_head = 0;
|
||||
_tail = 0;
|
||||
_full = false;
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -19,10 +19,13 @@
|
|||
#include "platform.h"
|
||||
|
||||
#include "gpio_api.h"
|
||||
#include "critical.h"
|
||||
|
||||
namespace mbed {
|
||||
|
||||
/** A digital input, used for reading the state of a pin
|
||||
*
|
||||
* @Note Synchronization level: Interrupt safe
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -51,6 +54,7 @@ public:
|
|||
* @param pin DigitalIn pin to connect to
|
||||
*/
|
||||
DigitalIn(PinName pin) : gpio() {
|
||||
// No lock needed in the constructor
|
||||
gpio_init_in(&gpio, pin);
|
||||
}
|
||||
|
||||
|
@ -60,6 +64,7 @@ public:
|
|||
* @param mode the initial mode of the pin
|
||||
*/
|
||||
DigitalIn(PinName pin, PinMode mode) : gpio() {
|
||||
// No lock needed in the constructor
|
||||
gpio_init_in_ex(&gpio, pin, mode);
|
||||
}
|
||||
/** Read the input, represented as 0 or 1 (int)
|
||||
|
@ -69,6 +74,7 @@ public:
|
|||
* 0 for logical 0, 1 for logical 1
|
||||
*/
|
||||
int read() {
|
||||
// Thread safe / atomic HAL call
|
||||
return gpio_read(&gpio);
|
||||
}
|
||||
|
||||
|
@ -77,7 +83,9 @@ public:
|
|||
* @param mode PullUp, PullDown, PullNone, OpenDrain
|
||||
*/
|
||||
void mode(PinMode pull) {
|
||||
core_util_critical_section_enter();
|
||||
gpio_mode(&gpio, pull);
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
/** Return the output setting, represented as 0 or 1 (int)
|
||||
|
@ -87,6 +95,7 @@ public:
|
|||
* 0 if gpio object was initialized with NC
|
||||
*/
|
||||
int is_connected() {
|
||||
// Thread safe / atomic HAL call
|
||||
return gpio_is_connected(&gpio);
|
||||
}
|
||||
|
||||
|
@ -94,6 +103,7 @@ public:
|
|||
/** An operator shorthand for read()
|
||||
*/
|
||||
operator int() {
|
||||
// Underlying read is thread safe
|
||||
return read();
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -19,10 +19,13 @@
|
|||
#include "platform.h"
|
||||
|
||||
#include "gpio_api.h"
|
||||
#include "critical.h"
|
||||
|
||||
namespace mbed {
|
||||
|
||||
/** A digital input/output, used for setting or reading a bi-directional pin
|
||||
*
|
||||
* @Note Synchronization level: Interrupt safe
|
||||
*/
|
||||
class DigitalInOut {
|
||||
|
||||
|
@ -32,6 +35,7 @@ public:
|
|||
* @param pin DigitalInOut pin to connect to
|
||||
*/
|
||||
DigitalInOut(PinName pin) : gpio() {
|
||||
// No lock needed in the constructor
|
||||
gpio_init_in(&gpio, pin);
|
||||
}
|
||||
|
||||
|
@ -43,6 +47,7 @@ public:
|
|||
* @param value the initial value of the pin if is an output
|
||||
*/
|
||||
DigitalInOut(PinName pin, PinDirection direction, PinMode mode, int value) : gpio() {
|
||||
// No lock needed in the constructor
|
||||
gpio_init_inout(&gpio, pin, direction, mode, value);
|
||||
}
|
||||
|
||||
|
@ -52,6 +57,7 @@ public:
|
|||
* 0 for logical 0, 1 (or any other non-zero value) for logical 1
|
||||
*/
|
||||
void write(int value) {
|
||||
// Thread safe / atomic HAL call
|
||||
gpio_write(&gpio, value);
|
||||
}
|
||||
|
||||
|
@ -62,19 +68,24 @@ public:
|
|||
* or read the input if set as an input
|
||||
*/
|
||||
int read() {
|
||||
// Thread safe / atomic HAL call
|
||||
return gpio_read(&gpio);
|
||||
}
|
||||
|
||||
/** Set as an output
|
||||
*/
|
||||
void output() {
|
||||
core_util_critical_section_enter();
|
||||
gpio_dir(&gpio, PIN_OUTPUT);
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
/** Set as an input
|
||||
*/
|
||||
void input() {
|
||||
core_util_critical_section_enter();
|
||||
gpio_dir(&gpio, PIN_INPUT);
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
/** Set the input pin mode
|
||||
|
@ -82,7 +93,9 @@ public:
|
|||
* @param mode PullUp, PullDown, PullNone, OpenDrain
|
||||
*/
|
||||
void mode(PinMode pull) {
|
||||
core_util_critical_section_enter();
|
||||
gpio_mode(&gpio, pull);
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
/** Return the output setting, represented as 0 or 1 (int)
|
||||
|
@ -92,6 +105,7 @@ public:
|
|||
* 0 if gpio object was initialized with NC
|
||||
*/
|
||||
int is_connected() {
|
||||
// Thread safe / atomic HAL call
|
||||
return gpio_is_connected(&gpio);
|
||||
}
|
||||
|
||||
|
@ -99,18 +113,22 @@ public:
|
|||
/** A shorthand for write()
|
||||
*/
|
||||
DigitalInOut& operator= (int value) {
|
||||
// Underlying write is thread safe
|
||||
write(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
DigitalInOut& operator= (DigitalInOut& rhs) {
|
||||
core_util_critical_section_enter();
|
||||
write(rhs.read());
|
||||
core_util_critical_section_exit();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** A shorthand for read()
|
||||
*/
|
||||
operator int() {
|
||||
// Underlying call is thread safe
|
||||
return read();
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -18,10 +18,13 @@
|
|||
|
||||
#include "platform.h"
|
||||
#include "gpio_api.h"
|
||||
#include "critical.h"
|
||||
|
||||
namespace mbed {
|
||||
|
||||
/** A digital output, used for setting the state of a pin
|
||||
*
|
||||
* @Note Synchronization level: Interrupt safe
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -46,6 +49,7 @@ public:
|
|||
* @param pin DigitalOut pin to connect to
|
||||
*/
|
||||
DigitalOut(PinName pin) : gpio() {
|
||||
// No lock needed in the constructor
|
||||
gpio_init_out(&gpio, pin);
|
||||
}
|
||||
|
||||
|
@ -55,6 +59,7 @@ public:
|
|||
* @param value the initial pin value
|
||||
*/
|
||||
DigitalOut(PinName pin, int value) : gpio() {
|
||||
// No lock needed in the constructor
|
||||
gpio_init_out_ex(&gpio, pin, value);
|
||||
}
|
||||
|
||||
|
@ -64,6 +69,7 @@ public:
|
|||
* 0 for logical 0, 1 (or any other non-zero value) for logical 1
|
||||
*/
|
||||
void write(int value) {
|
||||
// Thread safe / atomic HAL call
|
||||
gpio_write(&gpio, value);
|
||||
}
|
||||
|
||||
|
@ -74,6 +80,7 @@ public:
|
|||
* 0 for logical 0, 1 for logical 1
|
||||
*/
|
||||
int read() {
|
||||
// Thread safe / atomic HAL call
|
||||
return gpio_read(&gpio);
|
||||
}
|
||||
|
||||
|
@ -84,6 +91,7 @@ public:
|
|||
* 0 if gpio object was initialized with NC
|
||||
*/
|
||||
int is_connected() {
|
||||
// Thread safe / atomic HAL call
|
||||
return gpio_is_connected(&gpio);
|
||||
}
|
||||
|
||||
|
@ -91,18 +99,22 @@ public:
|
|||
/** A shorthand for write()
|
||||
*/
|
||||
DigitalOut& operator= (int value) {
|
||||
// Underlying write is thread safe
|
||||
write(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
DigitalOut& operator= (DigitalOut& rhs) {
|
||||
core_util_critical_section_enter();
|
||||
write(rhs.read());
|
||||
core_util_critical_section_exit();
|
||||
return *this;
|
||||
}
|
||||
|
||||
/** A shorthand for read()
|
||||
*/
|
||||
operator int() {
|
||||
// Underlying call is thread safe
|
||||
return read();
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -44,6 +44,8 @@ namespace mbed {
|
|||
* The root directory is considered to contain all FileLike and
|
||||
* FileSystemLike objects, so the DIR* returned by opendir("/") will
|
||||
* reflect this.
|
||||
*
|
||||
* @Note Synchronization level: Set by subclass
|
||||
*/
|
||||
class DirHandle {
|
||||
|
||||
|
@ -85,6 +87,20 @@ public:
|
|||
virtual void seekdir(off_t location) { (void)location;}
|
||||
|
||||
virtual ~DirHandle() {}
|
||||
|
||||
protected:
|
||||
|
||||
/** Acquire exclusive access to this object.
|
||||
*/
|
||||
virtual void lock() {
|
||||
// Stub
|
||||
}
|
||||
|
||||
/** Release exclusive access to this object.
|
||||
*/
|
||||
virtual void unlock() {
|
||||
// Stub
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mbed
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
namespace mbed {
|
||||
|
||||
/** An ethernet interface, to use with the ethernet pins.
|
||||
*
|
||||
* @Note Synchronization level: Not protected
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
|
|
@ -62,15 +62,14 @@ public:
|
|||
|
||||
static FileBase *get(int n);
|
||||
|
||||
protected:
|
||||
static FileBase *_head;
|
||||
|
||||
FileBase *_next;
|
||||
const char *_name;
|
||||
PathType _path_type;
|
||||
|
||||
/* disallow copy constructor and assignment operators */
|
||||
private:
|
||||
static FileBase *_head;
|
||||
static PlatformMutex _mutex;
|
||||
|
||||
FileBase *_next;
|
||||
const char * const _name;
|
||||
const PathType _path_type;
|
||||
FileBase(const FileBase&);
|
||||
FileBase & operator = (const FileBase&);
|
||||
};
|
||||
|
|
|
@ -38,6 +38,8 @@ namespace mbed {
|
|||
*
|
||||
* No one ever directly tals to/instanciates a FileHandle - it gets
|
||||
* created by FileSystem, and wrapped up by stdio.
|
||||
*
|
||||
* @Note Synchronization level: Set by subclass
|
||||
*/
|
||||
class FileHandle {
|
||||
|
||||
|
@ -101,17 +103,36 @@ public:
|
|||
virtual int fsync() = 0;
|
||||
|
||||
virtual off_t flen() {
|
||||
lock();
|
||||
/* remember our current position */
|
||||
off_t pos = lseek(0, SEEK_CUR);
|
||||
if(pos == -1) return -1;
|
||||
if(pos == -1) {
|
||||
unlock();
|
||||
return -1;
|
||||
}
|
||||
/* seek to the end to get the file length */
|
||||
off_t res = lseek(0, SEEK_END);
|
||||
/* return to our old position */
|
||||
lseek(pos, SEEK_SET);
|
||||
unlock();
|
||||
return res;
|
||||
}
|
||||
|
||||
virtual ~FileHandle();
|
||||
|
||||
protected:
|
||||
|
||||
/** Acquire exclusive access to this object.
|
||||
*/
|
||||
virtual void lock() {
|
||||
// Stub
|
||||
}
|
||||
|
||||
/** Release exclusive access to this object.
|
||||
*/
|
||||
virtual void unlock() {
|
||||
// Stub
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace mbed
|
||||
|
|
|
@ -25,6 +25,8 @@ namespace mbed {
|
|||
* A file-like object is one that can be opened with fopen by
|
||||
* fopen("/name", mode). It is intersection of the classes Base and
|
||||
* FileHandle.
|
||||
*
|
||||
* @Note Synchronization level: Set by subclass
|
||||
*/
|
||||
class FileLike : public FileHandle, public FileBase {
|
||||
|
||||
|
@ -37,6 +39,7 @@ public:
|
|||
FileLike(const char *name);
|
||||
|
||||
virtual ~FileLike();
|
||||
|
||||
};
|
||||
|
||||
} // namespace mbed
|
||||
|
|
|
@ -29,6 +29,8 @@ namespace mbed {
|
|||
*
|
||||
* Implementations must define at least open (the default definitions
|
||||
* of the rest of the functions just return error values).
|
||||
*
|
||||
* @Note Synchronization level: Set by subclass
|
||||
*/
|
||||
class FileSystemLike : public FileBase {
|
||||
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
namespace mbed {
|
||||
|
||||
/** An I2C Master, used for communicating with I2C slave devices
|
||||
*
|
||||
* @Note Synchronization level: Thread safe
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -135,6 +137,14 @@ public:
|
|||
*/
|
||||
void stop(void);
|
||||
|
||||
/** Acquire exclusive access to this I2C bus
|
||||
*/
|
||||
virtual void lock(void);
|
||||
|
||||
/** Release exclusive access to this I2C bus
|
||||
*/
|
||||
virtual void unlock(void);
|
||||
|
||||
#if DEVICE_I2C_ASYNCH
|
||||
|
||||
/** Start non-blocking I2C transfer.
|
||||
|
@ -167,6 +177,7 @@ protected:
|
|||
i2c_t _i2c;
|
||||
static I2C *_owner;
|
||||
int _hz;
|
||||
static PlatformMutex _mutex;
|
||||
};
|
||||
|
||||
} // namespace mbed
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
namespace mbed {
|
||||
|
||||
/** An I2C Slave, used for communicating with an I2C Master device
|
||||
*
|
||||
* @Note Synchronization level: Not protected
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
|
|
@ -23,10 +23,13 @@
|
|||
#include "gpio_api.h"
|
||||
#include "gpio_irq_api.h"
|
||||
#include "Callback.h"
|
||||
#include "critical.h"
|
||||
|
||||
namespace mbed {
|
||||
|
||||
/** A digital interrupt input, used to call a function on a rising or falling edge
|
||||
*
|
||||
* @Note Synchronization level: Interrupt safe
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -81,7 +84,9 @@ public:
|
|||
*/
|
||||
template<typename T, typename M>
|
||||
void rise(T *obj, M method) {
|
||||
core_util_critical_section_enter();
|
||||
rise(Callback<void()>(obj, method));
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
/** Attach a function to call when a falling edge occurs on the input
|
||||
|
@ -97,7 +102,9 @@ public:
|
|||
*/
|
||||
template<typename T, typename M>
|
||||
void fall(T *obj, M method) {
|
||||
core_util_critical_section_enter();
|
||||
fall(Callback<void()>(obj, method));
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
/** Set the input pin mode
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef MBED_INTERRUPTMANAGER_H
|
||||
#define MBED_INTERRUPTMANAGER_H
|
||||
|
||||
#include "platform.h"
|
||||
|
||||
#include "cmsis.h"
|
||||
#include "CallChain.h"
|
||||
#include <string.h>
|
||||
|
@ -8,6 +10,8 @@
|
|||
namespace mbed {
|
||||
|
||||
/** Use this singleton if you need to chain interrupt handlers.
|
||||
*
|
||||
* @Note Synchronization level: Thread safe
|
||||
*
|
||||
* Example (for LPC1768):
|
||||
* @code
|
||||
|
@ -52,6 +56,7 @@ public:
|
|||
* The function object created for 'function'
|
||||
*/
|
||||
pFunctionPointer_t add_handler(void (*function)(void), IRQn_Type irq) {
|
||||
// Underlying call is thread safe
|
||||
return add_common(function, irq);
|
||||
}
|
||||
|
||||
|
@ -64,6 +69,7 @@ public:
|
|||
* The function object created for 'function'
|
||||
*/
|
||||
pFunctionPointer_t add_handler_front(void (*function)(void), IRQn_Type irq) {
|
||||
// Underlying call is thread safe
|
||||
return add_common(function, irq, true);
|
||||
}
|
||||
|
||||
|
@ -78,6 +84,7 @@ public:
|
|||
*/
|
||||
template<typename T>
|
||||
pFunctionPointer_t add_handler(T* tptr, void (T::*mptr)(void), IRQn_Type irq) {
|
||||
// Underlying call is thread safe
|
||||
return add_common(tptr, mptr, irq);
|
||||
}
|
||||
|
||||
|
@ -92,6 +99,7 @@ public:
|
|||
*/
|
||||
template<typename T>
|
||||
pFunctionPointer_t add_handler_front(T* tptr, void (T::*mptr)(void), IRQn_Type irq) {
|
||||
// Underlying call is thread safe
|
||||
return add_common(tptr, mptr, irq, true);
|
||||
}
|
||||
|
||||
|
@ -105,6 +113,10 @@ public:
|
|||
*/
|
||||
bool remove_handler(pFunctionPointer_t handler, IRQn_Type irq);
|
||||
|
||||
protected:
|
||||
virtual void lock();
|
||||
virtual void unlock();
|
||||
|
||||
private:
|
||||
InterruptManager();
|
||||
~InterruptManager();
|
||||
|
@ -117,12 +129,14 @@ private:
|
|||
|
||||
template<typename T>
|
||||
pFunctionPointer_t add_common(T *tptr, void (T::*mptr)(void), IRQn_Type irq, bool front=false) {
|
||||
_mutex.lock();
|
||||
int irq_pos = get_irq_index(irq);
|
||||
bool change = must_replace_vector(irq);
|
||||
|
||||
pFunctionPointer_t pf = front ? _chains[irq_pos]->add_front(tptr, mptr) : _chains[irq_pos]->add(tptr, mptr);
|
||||
if (change)
|
||||
NVIC_SetVector(irq, (uint32_t)&InterruptManager::static_irq_helper);
|
||||
_mutex.unlock();
|
||||
return pf;
|
||||
}
|
||||
|
||||
|
@ -135,6 +149,7 @@ private:
|
|||
|
||||
CallChain* _chains[NVIC_NUM_VECTORS];
|
||||
static InterruptManager* _instance;
|
||||
PlatformMutex _mutex;
|
||||
};
|
||||
|
||||
} // namespace mbed
|
||||
|
|
|
@ -46,8 +46,11 @@ public:
|
|||
virtual off_t flen();
|
||||
|
||||
protected:
|
||||
virtual void lock();
|
||||
virtual void unlock();
|
||||
FILEHANDLE _fh;
|
||||
int pos;
|
||||
PlatformMutex _mutex;
|
||||
};
|
||||
|
||||
/** A filesystem for accessing the local mbed Microcontroller USB disk drive
|
||||
|
@ -56,6 +59,8 @@ protected:
|
|||
* mbed Microcontroller. Once created, the standard C file access functions are used to open,
|
||||
* read and write files.
|
||||
*
|
||||
* @Note Synchronization level: Thread safe
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* #include "mbed.h"
|
||||
|
@ -85,6 +90,7 @@ protected:
|
|||
* not exit, you will need to hold down reset on the mbed Microcontroller to be able to see the drive again!
|
||||
*/
|
||||
class LocalFileSystem : public FileSystemLike {
|
||||
// No modifiable state
|
||||
|
||||
public:
|
||||
LocalFileSystem(const char* n) : FileSystemLike(n) {
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
namespace mbed {
|
||||
|
||||
/** Low Power Ticker
|
||||
*
|
||||
* @Note Synchronization level: Interrupt safe
|
||||
*/
|
||||
class LowPowerTicker : public Ticker {
|
||||
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
namespace mbed {
|
||||
|
||||
/** Low Power Timout
|
||||
*
|
||||
* @Note Synchronization level: Interrupt safe
|
||||
*/
|
||||
class LowPowerTimeout : public LowPowerTicker {
|
||||
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
namespace mbed {
|
||||
|
||||
/** Low power timer
|
||||
*
|
||||
* @Note Synchronization level: Interrupt safe
|
||||
*/
|
||||
class LowPowerTimer : public Timer {
|
||||
|
||||
|
|
|
@ -21,10 +21,13 @@
|
|||
#if DEVICE_PORTIN
|
||||
|
||||
#include "port_api.h"
|
||||
#include "critical.h"
|
||||
|
||||
namespace mbed {
|
||||
|
||||
/** A multiple pin digital input
|
||||
*
|
||||
* @Note Synchronization level: Interrupt safe
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -56,7 +59,9 @@ public:
|
|||
* @param mask A bitmask to identify which bits in the port should be included (0 - ignore)
|
||||
*/
|
||||
PortIn(PortName port, int mask = 0xFFFFFFFF) {
|
||||
core_util_critical_section_enter();
|
||||
port_init(&_port, port, mask, PIN_INPUT);
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
/** Read the value currently output on the port
|
||||
|
@ -73,7 +78,9 @@ public:
|
|||
* @param mode PullUp, PullDown, PullNone, OpenDrain
|
||||
*/
|
||||
void mode(PinMode mode) {
|
||||
core_util_critical_section_enter();
|
||||
port_mode(&_port, mode);
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
/** A shorthand for read()
|
||||
|
|
|
@ -21,10 +21,13 @@
|
|||
#if DEVICE_PORTINOUT
|
||||
|
||||
#include "port_api.h"
|
||||
#include "critical.h"
|
||||
|
||||
namespace mbed {
|
||||
|
||||
/** A multiple pin digital in/out used to set/read multiple bi-directional pins
|
||||
*
|
||||
* @Note Synchronization level: Interrupt safe
|
||||
*/
|
||||
class PortInOut {
|
||||
public:
|
||||
|
@ -35,7 +38,9 @@ public:
|
|||
* @param mask A bitmask to identify which bits in the port should be included (0 - ignore)
|
||||
*/
|
||||
PortInOut(PortName port, int mask = 0xFFFFFFFF) {
|
||||
core_util_critical_section_enter();
|
||||
port_init(&_port, port, mask, PIN_INPUT);
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
/** Write the value to the output port
|
||||
|
@ -58,13 +63,17 @@ public:
|
|||
/** Set as an output
|
||||
*/
|
||||
void output() {
|
||||
core_util_critical_section_enter();
|
||||
port_dir(&_port, PIN_OUTPUT);
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
/** Set as an input
|
||||
*/
|
||||
void input() {
|
||||
core_util_critical_section_enter();
|
||||
port_dir(&_port, PIN_INPUT);
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
/** Set the input pin mode
|
||||
|
@ -72,7 +81,9 @@ public:
|
|||
* @param mode PullUp, PullDown, PullNone, OpenDrain
|
||||
*/
|
||||
void mode(PinMode mode) {
|
||||
core_util_critical_section_enter();
|
||||
port_mode(&_port, mode);
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
/** A shorthand for write()
|
||||
|
|
|
@ -21,9 +21,12 @@
|
|||
#if DEVICE_PORTOUT
|
||||
|
||||
#include "port_api.h"
|
||||
#include "critical.h"
|
||||
|
||||
namespace mbed {
|
||||
/** A multiple pin digital out
|
||||
*
|
||||
* @Note Synchronization level: Interrupt safe
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
@ -55,7 +58,9 @@ public:
|
|||
* @param mask A bitmask to identify which bits in the port should be included (0 - ignore)
|
||||
*/
|
||||
PortOut(PortName port, int mask = 0xFFFFFFFF) {
|
||||
core_util_critical_section_enter();
|
||||
port_init(&_port, port, mask, PIN_OUTPUT);
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
/** Write the value to the output port
|
||||
|
|
|
@ -20,10 +20,13 @@
|
|||
|
||||
#if DEVICE_PWMOUT
|
||||
#include "pwmout_api.h"
|
||||
#include "critical.h"
|
||||
|
||||
namespace mbed {
|
||||
|
||||
/** A pulse-width modulation digital output
|
||||
*
|
||||
* @Note Synchronization level: Interrupt safe
|
||||
*
|
||||
* Example
|
||||
* @code
|
||||
|
@ -59,7 +62,9 @@ public:
|
|||
* @param pin PwmOut pin to connect to
|
||||
*/
|
||||
PwmOut(PinName pin) {
|
||||
core_util_critical_section_enter();
|
||||
pwmout_init(&_pwm, pin);
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
/** Set the ouput duty-cycle, specified as a percentage (float)
|
||||
|
@ -70,7 +75,9 @@ public:
|
|||
* Values outside this range will be saturated to 0.0f or 1.0f.
|
||||
*/
|
||||
void write(float value) {
|
||||
core_util_critical_section_enter();
|
||||
pwmout_write(&_pwm, value);
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
/** Return the current output duty-cycle setting, measured as a percentage (float)
|
||||
|
@ -84,7 +91,10 @@ public:
|
|||
* This value may not match exactly the value set by a previous <write>.
|
||||
*/
|
||||
float read() {
|
||||
return pwmout_read(&_pwm);
|
||||
core_util_critical_section_enter();
|
||||
float val = pwmout_read(&_pwm);
|
||||
core_util_critical_section_exit();
|
||||
return val;
|
||||
}
|
||||
|
||||
/** Set the PWM period, specified in seconds (float), keeping the duty cycle the same.
|
||||
|
@ -94,48 +104,62 @@ public:
|
|||
* will be set to zero.
|
||||
*/
|
||||
void period(float seconds) {
|
||||
core_util_critical_section_enter();
|
||||
pwmout_period(&_pwm, seconds);
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
/** Set the PWM period, specified in milli-seconds (int), keeping the duty cycle the same.
|
||||
*/
|
||||
void period_ms(int ms) {
|
||||
core_util_critical_section_enter();
|
||||
pwmout_period_ms(&_pwm, ms);
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
/** Set the PWM period, specified in micro-seconds (int), keeping the duty cycle the same.
|
||||
*/
|
||||
void period_us(int us) {
|
||||
core_util_critical_section_enter();
|
||||
pwmout_period_us(&_pwm, us);
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
/** Set the PWM pulsewidth, specified in seconds (float), keeping the period the same.
|
||||
*/
|
||||
void pulsewidth(float seconds) {
|
||||
core_util_critical_section_enter();
|
||||
pwmout_pulsewidth(&_pwm, seconds);
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
/** Set the PWM pulsewidth, specified in milli-seconds (int), keeping the period the same.
|
||||
*/
|
||||
void pulsewidth_ms(int ms) {
|
||||
core_util_critical_section_enter();
|
||||
pwmout_pulsewidth_ms(&_pwm, ms);
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
/** Set the PWM pulsewidth, specified in micro-seconds (int), keeping the period the same.
|
||||
*/
|
||||
void pulsewidth_us(int us) {
|
||||
core_util_critical_section_enter();
|
||||
pwmout_pulsewidth_us(&_pwm, us);
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
#ifdef MBED_OPERATORS
|
||||
/** A operator shorthand for write()
|
||||
*/
|
||||
PwmOut& operator= (float value) {
|
||||
// Underlying call is thread safe
|
||||
write(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
PwmOut& operator= (PwmOut& rhs) {
|
||||
// Underlying call is thread safe
|
||||
write(rhs.read());
|
||||
return *this;
|
||||
}
|
||||
|
@ -143,6 +167,7 @@ public:
|
|||
/** An operator shorthand for read()
|
||||
*/
|
||||
operator float() {
|
||||
// Underlying call is thread safe
|
||||
return read();
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -32,6 +32,8 @@ namespace mbed {
|
|||
* Can be used for Full Duplex communication, or Simplex by specifying
|
||||
* one pin as NC (Not Connected)
|
||||
*
|
||||
* @Note Synchronization level: Not protected
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* // Send a char to the PC
|
||||
|
@ -81,6 +83,16 @@ public:
|
|||
int puts(const char *str);
|
||||
|
||||
int printf(const char *format, ...);
|
||||
|
||||
protected:
|
||||
|
||||
/** Acquire exclusive access to this serial port
|
||||
*/
|
||||
virtual void lock(void);
|
||||
|
||||
/** Release exclusive access to this serial port
|
||||
*/
|
||||
virtual void unlock(void);
|
||||
};
|
||||
|
||||
} // namespace mbed
|
||||
|
|
|
@ -39,6 +39,8 @@ namespace mbed {
|
|||
* Most SPI devices will also require Chip Select and Reset signals. These
|
||||
* can be controlled using <DigitalOut> pins
|
||||
*
|
||||
* @Note Synchronization level: Thread safe
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* // Send a byte to a SPI slave, and record the response
|
||||
|
@ -56,10 +58,13 @@ namespace mbed {
|
|||
* // hardware ssel (where applicable)
|
||||
* //int response = device.write(0xFF);
|
||||
*
|
||||
* device.lock();
|
||||
* // software ssel
|
||||
* cs = 0;
|
||||
* int response = device.write(0xFF);
|
||||
* cs = 1;
|
||||
* device.unlock();
|
||||
*
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
|
@ -109,6 +114,14 @@ public:
|
|||
*/
|
||||
virtual int write(int value);
|
||||
|
||||
/** Acquire exclusive access to this SPI bus
|
||||
*/
|
||||
virtual void lock(void);
|
||||
|
||||
/** Release exclusive access to this SPI bus
|
||||
*/
|
||||
virtual void unlock(void);
|
||||
|
||||
#if DEVICE_SPI_ASYNCH
|
||||
|
||||
/** Start non-blocking SPI transfer using 8bit buffers.
|
||||
|
@ -233,6 +246,7 @@ protected:
|
|||
|
||||
void aquire(void);
|
||||
static SPI *_owner;
|
||||
PlatformMutex _mutex;
|
||||
int _bits;
|
||||
int _mode;
|
||||
int _hz;
|
||||
|
|
|
@ -28,6 +28,8 @@ namespace mbed {
|
|||
*
|
||||
* The default format is set to 8-bits, mode 0, and a clock frequency of 1MHz
|
||||
*
|
||||
* @Note Synchronization level: Not protected
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* // Reply to a SPI master as slave
|
||||
|
|
|
@ -31,6 +31,8 @@ namespace mbed {
|
|||
* Can be used for Full Duplex communication, or Simplex by specifying
|
||||
* one pin as NC (Not Connected)
|
||||
*
|
||||
* @Note Synchronization level: Thread safe
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* // Print "Hello World" to the PC
|
||||
|
@ -65,6 +67,10 @@ public:
|
|||
protected:
|
||||
virtual int _getc();
|
||||
virtual int _putc(int c);
|
||||
virtual void lock();
|
||||
virtual void unlock();
|
||||
|
||||
PlatformMutex _mutex;
|
||||
};
|
||||
|
||||
} // namespace mbed
|
||||
|
|
|
@ -33,6 +33,8 @@ namespace mbed {
|
|||
|
||||
/** A base class for serial port implementations
|
||||
* Can't be instantiated directly (use Serial or RawSerial)
|
||||
*
|
||||
* @Note Synchronization level: Set by subclass
|
||||
*/
|
||||
class SerialBase {
|
||||
|
||||
|
@ -120,6 +122,18 @@ public:
|
|||
*/
|
||||
void send_break();
|
||||
|
||||
protected:
|
||||
|
||||
/** Acquire exclusive access to this serial port
|
||||
*/
|
||||
virtual void lock(void);
|
||||
|
||||
/** Release exclusive access to this serial port
|
||||
*/
|
||||
virtual void unlock(void);
|
||||
|
||||
public:
|
||||
|
||||
#if DEVICE_SERIAL_FC
|
||||
/** Set the flow control type on the serial port
|
||||
*
|
||||
|
|
|
@ -26,6 +26,10 @@ extern void mbed_set_unbuffered_stream(FILE *_file);
|
|||
extern int mbed_getc(FILE *_file);
|
||||
extern char* mbed_gets(char *s, int size, FILE *_file);
|
||||
|
||||
/** File stream
|
||||
*
|
||||
* @Note Synchronization level: Set by subclass
|
||||
*/
|
||||
class Stream : public FileLike {
|
||||
|
||||
public:
|
||||
|
|
|
@ -25,6 +25,8 @@ namespace mbed {
|
|||
*
|
||||
* You can use as many seperate Ticker objects as you require.
|
||||
*
|
||||
* @Note Synchronization level: Interrupt safe
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* // Toggle the blinking led after 5 seconds
|
||||
|
|
|
@ -24,6 +24,8 @@ namespace mbed {
|
|||
*
|
||||
* You can use as many seperate Timeout objects as you require.
|
||||
*
|
||||
* @Note Synchronization level: Interrupt safe
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* // Blink until timeout.
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
namespace mbed {
|
||||
|
||||
/** A general purpose timer
|
||||
*
|
||||
* @Note Synchronization level: Interrupt safe
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
|
|
@ -22,7 +22,9 @@
|
|||
namespace mbed {
|
||||
|
||||
/** Base abstraction for timer interrupts
|
||||
*/
|
||||
*
|
||||
* @Note Synchronization level: Interrupt safe
|
||||
*/
|
||||
class TimerEvent {
|
||||
public:
|
||||
TimerEvent();
|
||||
|
|
|
@ -34,6 +34,8 @@ typedef struct {
|
|||
} transaction_t;
|
||||
|
||||
/** Transaction class defines a transaction.
|
||||
*
|
||||
* @Note Synchronization level: Not protected
|
||||
*/
|
||||
template<typename Class>
|
||||
class Transaction {
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
#ifndef MBED_INTERFACE_H
|
||||
#define MBED_INTERFACE_H
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include "device.h"
|
||||
|
||||
/* Mbed interface mac address
|
||||
|
@ -107,6 +109,20 @@ void mbed_mac_address(char *mac);
|
|||
*/
|
||||
void mbed_die(void);
|
||||
|
||||
/** Print out an error message. This is typically called when
|
||||
* hanlding a crash.
|
||||
*
|
||||
* @Note Synchronization level: Interrupt safe
|
||||
*/
|
||||
void mbed_error_printf(const char* format, ...);
|
||||
|
||||
/** Print out an error message. Similar to mbed_error_printf
|
||||
* but uses a va_list.
|
||||
*
|
||||
* @Note Synchronization level: Interrupt safe
|
||||
*/
|
||||
void mbed_error_vfprintf(const char * format, va_list arg);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -27,4 +27,31 @@
|
|||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#ifdef MBED_CONF_RTOS_PRESENT
|
||||
#include "Mutex.h"
|
||||
typedef rtos::Mutex PlatformMutex;
|
||||
#else
|
||||
/** A stub mutex for when an RTOS is not present
|
||||
*/
|
||||
class PlatformMutex {
|
||||
public:
|
||||
PlatformMutex() {
|
||||
// Stub
|
||||
|
||||
}
|
||||
~PlatformMutex() {
|
||||
// Stub
|
||||
}
|
||||
|
||||
void lock() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
void unlock() {
|
||||
// Do nothing
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
|
@ -58,6 +58,8 @@ extern "C" {
|
|||
*
|
||||
* @param t Number of seconds since January 1, 1970 (the UNIX timestamp)
|
||||
*
|
||||
* @Note Synchronization level: Thread safe
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
* #include "mbed.h"
|
||||
|
@ -71,7 +73,7 @@ void set_time(time_t t);
|
|||
|
||||
/** Attach an external RTC to be used for the C time functions
|
||||
*
|
||||
* Do not call this function from an interrupt while an RTC read/write operation may be occurring
|
||||
* @Note Synchronization level: Thread safe
|
||||
*
|
||||
* @param read_rtc pointer to function which returns current UNIX timestamp
|
||||
* @param write_rtc pointer to function which sets current UNIX timestamp, can be NULL
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
/* 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 "mbed.h"
|
||||
|
||||
#include "AnalogIn.h"
|
||||
|
||||
#if DEVICE_ANALOGIN
|
||||
|
||||
namespace mbed {
|
||||
|
||||
PlatformMutex AnalogIn::_mutex;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -21,6 +21,7 @@ namespace mbed {
|
|||
BusIn::BusIn(PinName p0, PinName p1, PinName p2, PinName p3, PinName p4, PinName p5, PinName p6, PinName p7, PinName p8, PinName p9, PinName p10, PinName p11, PinName p12, PinName p13, PinName p14, PinName p15) {
|
||||
PinName pins[16] = {p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15};
|
||||
|
||||
// No lock needed in the constructor
|
||||
_nc_mask = 0;
|
||||
for (int i=0; i<16; i++) {
|
||||
_pin[i] = (pins[i] != NC) ? new DigitalIn(pins[i]) : 0;
|
||||
|
@ -31,6 +32,7 @@ BusIn::BusIn(PinName p0, PinName p1, PinName p2, PinName p3, PinName p4, PinName
|
|||
}
|
||||
|
||||
BusIn::BusIn(PinName pins[16]) {
|
||||
// No lock needed in the constructor
|
||||
_nc_mask = 0;
|
||||
for (int i=0; i<16; i++) {
|
||||
_pin[i] = (pins[i] != NC) ? new DigitalIn(pins[i]) : 0;
|
||||
|
@ -41,6 +43,7 @@ BusIn::BusIn(PinName pins[16]) {
|
|||
}
|
||||
|
||||
BusIn::~BusIn() {
|
||||
// No lock needed in the destructor
|
||||
for (int i=0; i<16; i++) {
|
||||
if (_pin[i] != 0) {
|
||||
delete _pin[i];
|
||||
|
@ -50,28 +53,42 @@ BusIn::~BusIn() {
|
|||
|
||||
int BusIn::read() {
|
||||
int v = 0;
|
||||
lock();
|
||||
for (int i=0; i<16; i++) {
|
||||
if (_pin[i] != 0) {
|
||||
v |= _pin[i]->read() << i;
|
||||
}
|
||||
}
|
||||
unlock();
|
||||
return v;
|
||||
}
|
||||
|
||||
void BusIn::mode(PinMode pull) {
|
||||
lock();
|
||||
for (int i=0; i<16; i++) {
|
||||
if (_pin[i] != 0) {
|
||||
_pin[i]->mode(pull);
|
||||
}
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
||||
void BusIn::lock() {
|
||||
_mutex.lock();
|
||||
}
|
||||
|
||||
void BusIn::unlock() {
|
||||
_mutex.unlock();
|
||||
}
|
||||
|
||||
#ifdef MBED_OPERATORS
|
||||
BusIn::operator int() {
|
||||
// Underlying read is thread safe
|
||||
return read();
|
||||
}
|
||||
|
||||
DigitalIn& BusIn::operator[] (int index) {
|
||||
// No lock needed since _pin is not modified outside the constructor
|
||||
MBED_ASSERT(index >= 0 && index <= 16);
|
||||
MBED_ASSERT(_pin[index]);
|
||||
return *_pin[index];
|
||||
|
|
|
@ -21,6 +21,7 @@ namespace mbed {
|
|||
BusInOut::BusInOut(PinName p0, PinName p1, PinName p2, PinName p3, PinName p4, PinName p5, PinName p6, PinName p7, PinName p8, PinName p9, PinName p10, PinName p11, PinName p12, PinName p13, PinName p14, PinName p15) {
|
||||
PinName pins[16] = {p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15};
|
||||
|
||||
// No lock needed in the constructor
|
||||
_nc_mask = 0;
|
||||
for (int i=0; i<16; i++) {
|
||||
_pin[i] = (pins[i] != NC) ? new DigitalInOut(pins[i]) : 0;
|
||||
|
@ -31,6 +32,7 @@ BusInOut::BusInOut(PinName p0, PinName p1, PinName p2, PinName p3, PinName p4, P
|
|||
}
|
||||
|
||||
BusInOut::BusInOut(PinName pins[16]) {
|
||||
// No lock needed in the constructor
|
||||
_nc_mask = 0;
|
||||
for (int i=0; i<16; i++) {
|
||||
_pin[i] = (pins[i] != NC) ? new DigitalInOut(pins[i]) : 0;
|
||||
|
@ -41,6 +43,7 @@ BusInOut::BusInOut(PinName pins[16]) {
|
|||
}
|
||||
|
||||
BusInOut::~BusInOut() {
|
||||
// No lock needed in the destructor
|
||||
for (int i=0; i<16; i++) {
|
||||
if (_pin[i] != 0) {
|
||||
delete _pin[i];
|
||||
|
@ -49,67 +52,89 @@ BusInOut::~BusInOut() {
|
|||
}
|
||||
|
||||
void BusInOut::write(int value) {
|
||||
lock();
|
||||
for (int i=0; i<16; i++) {
|
||||
if (_pin[i] != 0) {
|
||||
_pin[i]->write((value >> i) & 1);
|
||||
}
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
||||
int BusInOut::read() {
|
||||
lock();
|
||||
int v = 0;
|
||||
for (int i=0; i<16; i++) {
|
||||
if (_pin[i] != 0) {
|
||||
v |= _pin[i]->read() << i;
|
||||
}
|
||||
}
|
||||
unlock();
|
||||
return v;
|
||||
}
|
||||
|
||||
void BusInOut::output() {
|
||||
lock();
|
||||
for (int i=0; i<16; i++) {
|
||||
if (_pin[i] != 0) {
|
||||
_pin[i]->output();
|
||||
}
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
||||
void BusInOut::input() {
|
||||
lock();
|
||||
for (int i=0; i<16; i++) {
|
||||
if (_pin[i] != 0) {
|
||||
_pin[i]->input();
|
||||
}
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
||||
void BusInOut::mode(PinMode pull) {
|
||||
lock();
|
||||
for (int i=0; i<16; i++) {
|
||||
if (_pin[i] != 0) {
|
||||
_pin[i]->mode(pull);
|
||||
}
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
||||
#ifdef MBED_OPERATORS
|
||||
BusInOut& BusInOut::operator= (int v) {
|
||||
// Underlying write is thread safe
|
||||
write(v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
BusInOut& BusInOut::operator= (BusInOut& rhs) {
|
||||
// Underlying read is thread safe
|
||||
write(rhs.read());
|
||||
return *this;
|
||||
}
|
||||
|
||||
DigitalInOut& BusInOut::operator[] (int index) {
|
||||
// No lock needed since _pin is not modified outside the constructor
|
||||
MBED_ASSERT(index >= 0 && index <= 16);
|
||||
MBED_ASSERT(_pin[index]);
|
||||
return *_pin[index];
|
||||
}
|
||||
|
||||
BusInOut::operator int() {
|
||||
// Underlying read is thread safe
|
||||
return read();
|
||||
}
|
||||
#endif
|
||||
|
||||
void BusInOut::lock() {
|
||||
_mutex.lock();
|
||||
}
|
||||
|
||||
void BusInOut::unlock() {
|
||||
_mutex.unlock();
|
||||
}
|
||||
|
||||
} // namespace mbed
|
||||
|
|
|
@ -21,6 +21,7 @@ namespace mbed {
|
|||
BusOut::BusOut(PinName p0, PinName p1, PinName p2, PinName p3, PinName p4, PinName p5, PinName p6, PinName p7, PinName p8, PinName p9, PinName p10, PinName p11, PinName p12, PinName p13, PinName p14, PinName p15) {
|
||||
PinName pins[16] = {p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15};
|
||||
|
||||
// No lock needed in the constructor
|
||||
_nc_mask = 0;
|
||||
for (int i=0; i<16; i++) {
|
||||
_pin[i] = (pins[i] != NC) ? new DigitalOut(pins[i]) : 0;
|
||||
|
@ -31,6 +32,7 @@ BusOut::BusOut(PinName p0, PinName p1, PinName p2, PinName p3, PinName p4, PinNa
|
|||
}
|
||||
|
||||
BusOut::BusOut(PinName pins[16]) {
|
||||
// No lock needed in the constructor
|
||||
_nc_mask = 0;
|
||||
for (int i=0; i<16; i++) {
|
||||
_pin[i] = (pins[i] != NC) ? new DigitalOut(pins[i]) : 0;
|
||||
|
@ -41,6 +43,7 @@ BusOut::BusOut(PinName pins[16]) {
|
|||
}
|
||||
|
||||
BusOut::~BusOut() {
|
||||
// No lock needed in the destructor
|
||||
for (int i=0; i<16; i++) {
|
||||
if (_pin[i] != 0) {
|
||||
delete _pin[i];
|
||||
|
@ -49,43 +52,59 @@ BusOut::~BusOut() {
|
|||
}
|
||||
|
||||
void BusOut::write(int value) {
|
||||
lock();
|
||||
for (int i=0; i<16; i++) {
|
||||
if (_pin[i] != 0) {
|
||||
_pin[i]->write((value >> i) & 1);
|
||||
}
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
||||
int BusOut::read() {
|
||||
lock();
|
||||
int v = 0;
|
||||
for (int i=0; i<16; i++) {
|
||||
if (_pin[i] != 0) {
|
||||
v |= _pin[i]->read() << i;
|
||||
}
|
||||
}
|
||||
unlock();
|
||||
return v;
|
||||
}
|
||||
|
||||
#ifdef MBED_OPERATORS
|
||||
BusOut& BusOut::operator= (int v) {
|
||||
// Underlying write is thread safe
|
||||
write(v);
|
||||
return *this;
|
||||
}
|
||||
|
||||
BusOut& BusOut::operator= (BusOut& rhs) {
|
||||
// Underlying write is thread safe
|
||||
write(rhs.read());
|
||||
return *this;
|
||||
}
|
||||
|
||||
DigitalOut& BusOut::operator[] (int index) {
|
||||
// No lock needed since _pin is not modified outside the constructor
|
||||
MBED_ASSERT(index >= 0 && index <= 16);
|
||||
MBED_ASSERT(_pin[index]);
|
||||
return *_pin[index];
|
||||
}
|
||||
|
||||
BusOut::operator int() {
|
||||
// Underlying read is thread safe
|
||||
return read();
|
||||
}
|
||||
#endif
|
||||
|
||||
void BusOut::lock() {
|
||||
_mutex.lock();
|
||||
}
|
||||
|
||||
void BusOut::unlock() {
|
||||
_mutex.unlock();
|
||||
}
|
||||
|
||||
} // namespace mbed
|
||||
|
|
|
@ -22,58 +22,87 @@
|
|||
namespace mbed {
|
||||
|
||||
CAN::CAN(PinName rd, PinName td) : _can(), _irq() {
|
||||
// No lock needed in constructor
|
||||
can_init(&_can, rd, td);
|
||||
can_irq_init(&_can, (&CAN::_irq_handler), (uint32_t)this);
|
||||
}
|
||||
|
||||
CAN::~CAN() {
|
||||
// No lock needed in destructor
|
||||
can_irq_free(&_can);
|
||||
can_free(&_can);
|
||||
}
|
||||
|
||||
int CAN::frequency(int f) {
|
||||
return can_frequency(&_can, f);
|
||||
lock();
|
||||
int ret = can_frequency(&_can, f);
|
||||
unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int CAN::write(CANMessage msg) {
|
||||
return can_write(&_can, msg, 0);
|
||||
lock();
|
||||
int ret = can_write(&_can, msg, 0);
|
||||
unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int CAN::read(CANMessage &msg, int handle) {
|
||||
return can_read(&_can, &msg, handle);
|
||||
lock();
|
||||
int ret = can_read(&_can, &msg, handle);
|
||||
unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CAN::reset() {
|
||||
lock();
|
||||
can_reset(&_can);
|
||||
unlock();
|
||||
}
|
||||
|
||||
unsigned char CAN::rderror() {
|
||||
return can_rderror(&_can);
|
||||
lock();
|
||||
int ret = can_rderror(&_can);
|
||||
unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
unsigned char CAN::tderror() {
|
||||
return can_tderror(&_can);
|
||||
lock();
|
||||
int ret = can_tderror(&_can);
|
||||
unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CAN::monitor(bool silent) {
|
||||
lock();
|
||||
can_monitor(&_can, (silent) ? 1 : 0);
|
||||
unlock();
|
||||
}
|
||||
|
||||
int CAN::mode(Mode mode) {
|
||||
return can_mode(&_can, (CanMode)mode);
|
||||
lock();
|
||||
int ret = can_mode(&_can, (CanMode)mode);
|
||||
unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int CAN::filter(unsigned int id, unsigned int mask, CANFormat format, int handle) {
|
||||
return can_filter(&_can, id, mask, format, handle);
|
||||
lock();
|
||||
int ret = can_filter(&_can, id, mask, format, handle);
|
||||
unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CAN::attach(Callback<void()> func, IrqType type) {
|
||||
lock();
|
||||
if (func) {
|
||||
_irq[(CanIrqType)type].attach(func);
|
||||
can_irq_set(&_can, (CanIrqType)type, 1);
|
||||
} else {
|
||||
can_irq_set(&_can, (CanIrqType)type, 0);
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
||||
void CAN::_irq_handler(uint32_t id, CanIrqType type) {
|
||||
|
@ -81,6 +110,14 @@ void CAN::_irq_handler(uint32_t id, CanIrqType type) {
|
|||
handler->_irq[type].call();
|
||||
}
|
||||
|
||||
void CAN::lock() {
|
||||
_mutex.lock();
|
||||
}
|
||||
|
||||
void CAN::unlock() {
|
||||
_mutex.unlock();
|
||||
}
|
||||
|
||||
} // namespace mbed
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,82 +1,116 @@
|
|||
#include "CallChain.h"
|
||||
#include "cmsis.h"
|
||||
#include "critical.h"
|
||||
|
||||
namespace mbed {
|
||||
|
||||
CallChain::CallChain(int size) : _chain(), _size(size), _elements(0) {
|
||||
_chain = new pFunctionPointer_t[size]();
|
||||
class CallChainLink {
|
||||
public:
|
||||
CallChainLink(): cb(), next(NULL) {
|
||||
// No work to do
|
||||
}
|
||||
|
||||
CallChainLink(Callback<void()> &callback): cb(callback), next(NULL) {
|
||||
// No work to do
|
||||
}
|
||||
Callback<void()> cb;
|
||||
CallChainLink * next;
|
||||
};
|
||||
|
||||
CallChain::CallChain(int size) : _chain(NULL) {
|
||||
// No work to do
|
||||
}
|
||||
|
||||
CallChain::~CallChain() {
|
||||
clear();
|
||||
delete _chain;
|
||||
}
|
||||
|
||||
pFunctionPointer_t CallChain::add(Callback<void()> func) {
|
||||
_check_size();
|
||||
_chain[_elements] = new Callback<void()>(func);
|
||||
_elements ++;
|
||||
return _chain[_elements];
|
||||
CallChainLink *new_link = new CallChainLink(func);
|
||||
if (NULL == _chain) {
|
||||
_chain = new_link;
|
||||
return &new_link->cb;
|
||||
}
|
||||
|
||||
CallChainLink *link = _chain;
|
||||
while (true) {
|
||||
if (NULL == link->next) {
|
||||
link->next = new_link;
|
||||
return &new_link->cb;
|
||||
}
|
||||
link = link->next;
|
||||
}
|
||||
}
|
||||
|
||||
pFunctionPointer_t CallChain::add_front(Callback<void()> func) {
|
||||
_check_size();
|
||||
memmove(_chain + 1, _chain, _elements * sizeof(pFunctionPointer_t));
|
||||
_chain[0] = new Callback<void()>(func);
|
||||
_elements ++;
|
||||
return _chain[0];
|
||||
CallChainLink *link = new CallChainLink(func);
|
||||
link->next = _chain;
|
||||
_chain = link->next;
|
||||
return &link->cb;
|
||||
}
|
||||
|
||||
int CallChain::size() const {
|
||||
return _elements;
|
||||
CallChainLink *link = _chain;
|
||||
int elements = 0;
|
||||
while (link != NULL) {
|
||||
elements++;
|
||||
link = link->next;
|
||||
}
|
||||
return elements;
|
||||
}
|
||||
|
||||
pFunctionPointer_t CallChain::get(int i) const {
|
||||
if (i < 0 || i >= _elements)
|
||||
return NULL;
|
||||
return _chain[i];
|
||||
pFunctionPointer_t CallChain::get(int idx) const {
|
||||
CallChainLink *link = _chain;
|
||||
for (int i = 0; i < idx; i++) {
|
||||
if (NULL == link) {
|
||||
break;
|
||||
}
|
||||
link = link->next;
|
||||
}
|
||||
return &link->cb;
|
||||
}
|
||||
|
||||
int CallChain::find(pFunctionPointer_t f) const {
|
||||
for (int i = 0; i < _elements; i++)
|
||||
if (f == _chain[i])
|
||||
CallChainLink *link = _chain;
|
||||
int i = 0;
|
||||
while (link != NULL) {
|
||||
if (f == &link->cb) {
|
||||
return i;
|
||||
}
|
||||
i++;
|
||||
link = link->next;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void CallChain::clear() {
|
||||
for(int i = 0; i < _elements; i ++) {
|
||||
delete _chain[i];
|
||||
_chain[i] = NULL;
|
||||
CallChainLink *link = _chain;
|
||||
_chain = NULL;
|
||||
while (link != NULL) {
|
||||
CallChainLink *temp = link->next;
|
||||
delete link;
|
||||
link = temp;
|
||||
}
|
||||
_elements = 0;
|
||||
}
|
||||
|
||||
bool CallChain::remove(pFunctionPointer_t f) {
|
||||
int i;
|
||||
|
||||
if ((i = find(f)) == -1)
|
||||
return false;
|
||||
if (i != _elements - 1)
|
||||
memmove(_chain + i, _chain + i + 1, (_elements - i - 1) * sizeof(pFunctionPointer_t));
|
||||
delete f;
|
||||
_elements --;
|
||||
return true;
|
||||
CallChainLink *link = _chain;
|
||||
while (link != NULL) {
|
||||
if (f == &link->cb) {
|
||||
delete link;
|
||||
return true;
|
||||
}
|
||||
link = link->next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CallChain::call() {
|
||||
for(int i = 0; i < _elements; i++)
|
||||
_chain[i]->call();
|
||||
}
|
||||
|
||||
void CallChain::_check_size() {
|
||||
if (_elements < _size)
|
||||
return;
|
||||
_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;
|
||||
CallChainLink *link = _chain;
|
||||
while (link != NULL) {
|
||||
link->cb.call();
|
||||
link = link->next;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace mbed
|
||||
|
|
|
@ -18,10 +18,12 @@
|
|||
namespace mbed {
|
||||
|
||||
FileBase *FileBase::_head = NULL;
|
||||
PlatformMutex FileBase::_mutex;
|
||||
|
||||
FileBase::FileBase(const char *name, PathType t) : _next(NULL),
|
||||
_name(name),
|
||||
_path_type(t) {
|
||||
_mutex.lock();
|
||||
if (name != NULL) {
|
||||
// put this object at head of the list
|
||||
_next = _head;
|
||||
|
@ -29,9 +31,11 @@ FileBase::FileBase(const char *name, PathType t) : _next(NULL),
|
|||
} else {
|
||||
_next = NULL;
|
||||
}
|
||||
_mutex.unlock();
|
||||
}
|
||||
|
||||
FileBase::~FileBase() {
|
||||
_mutex.lock();
|
||||
if (_name != NULL) {
|
||||
// remove this object from the list
|
||||
if (_head == this) { // first in the list, so just drop me
|
||||
|
@ -44,37 +48,48 @@ FileBase::~FileBase() {
|
|||
p->_next = _next;
|
||||
}
|
||||
}
|
||||
_mutex.unlock();
|
||||
}
|
||||
|
||||
FileBase *FileBase::lookup(const char *name, unsigned int len) {
|
||||
_mutex.lock();
|
||||
FileBase *p = _head;
|
||||
while (p != NULL) {
|
||||
/* Check that p->_name matches name and is the correct length */
|
||||
if (p->_name != NULL && std::strncmp(p->_name, name, len) == 0 && std::strlen(p->_name) == len) {
|
||||
_mutex.unlock();
|
||||
return p;
|
||||
}
|
||||
p = p->_next;
|
||||
}
|
||||
_mutex.unlock();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
FileBase *FileBase::get(int n) {
|
||||
_mutex.lock();
|
||||
FileBase *p = _head;
|
||||
int m = 0;
|
||||
while (p != NULL) {
|
||||
if (m == n) return p;
|
||||
if (m == n) {
|
||||
_mutex.unlock();
|
||||
return p;
|
||||
}
|
||||
|
||||
m++;
|
||||
p = p->_next;
|
||||
}
|
||||
_mutex.unlock();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char* FileBase::getName(void) {
|
||||
// Constant read so no lock needed
|
||||
return _name;
|
||||
}
|
||||
|
||||
PathType FileBase::getPathType(void) {
|
||||
// Constant read so no lock needed
|
||||
return _path_type;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,32 +33,56 @@ public:
|
|||
}
|
||||
|
||||
virtual int closedir() {
|
||||
// No lock can be used in destructor
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual struct dirent *readdir() {
|
||||
lock();
|
||||
FileBase *ptr = FileBase::get(n);
|
||||
if (ptr == NULL) return NULL;
|
||||
if (ptr == NULL) {
|
||||
unlock();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Increment n, so next readdir gets the next item */
|
||||
n++;
|
||||
|
||||
/* Setup cur entry and return a pointer to it */
|
||||
std::strncpy(cur_entry.d_name, ptr->getName(), NAME_MAX);
|
||||
unlock();
|
||||
return &cur_entry;
|
||||
}
|
||||
|
||||
virtual off_t telldir() {
|
||||
return n;
|
||||
lock();
|
||||
off_t offset = n;
|
||||
unlock();
|
||||
return offset;
|
||||
}
|
||||
|
||||
virtual void seekdir(off_t offset) {
|
||||
lock();
|
||||
n = offset;
|
||||
unlock();
|
||||
}
|
||||
|
||||
virtual void rewinddir() {
|
||||
lock();
|
||||
n = 0;
|
||||
unlock();
|
||||
}
|
||||
|
||||
protected:
|
||||
PlatformMutex _mutex;
|
||||
|
||||
virtual void lock() {
|
||||
_mutex.lock();
|
||||
}
|
||||
|
||||
virtual void unlock() {
|
||||
_mutex.unlock();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -20,12 +20,15 @@
|
|||
namespace mbed {
|
||||
|
||||
I2C *I2C::_owner = NULL;
|
||||
PlatformMutex I2C::_mutex;
|
||||
|
||||
I2C::I2C(PinName sda, PinName scl) :
|
||||
#if DEVICE_I2C_ASYNCH
|
||||
_irq(this), _usage(DMA_USAGE_NEVER),
|
||||
#endif
|
||||
_i2c(), _hz(100000) {
|
||||
// No lock needed in the constructor
|
||||
|
||||
// The init function also set the frequency to 100000
|
||||
i2c_init(&_i2c, sda, scl);
|
||||
|
||||
|
@ -34,6 +37,7 @@ I2C::I2C(PinName sda, PinName scl) :
|
|||
}
|
||||
|
||||
void I2C::frequency(int hz) {
|
||||
lock();
|
||||
_hz = hz;
|
||||
|
||||
// We want to update the frequency even if we are already the bus owners
|
||||
|
@ -41,60 +45,88 @@ void I2C::frequency(int hz) {
|
|||
|
||||
// Updating the frequency of the bus we become the owners of it
|
||||
_owner = this;
|
||||
unlock();
|
||||
}
|
||||
|
||||
void I2C::aquire() {
|
||||
lock();
|
||||
if (_owner != this) {
|
||||
i2c_frequency(&_i2c, _hz);
|
||||
_owner = this;
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
||||
// write - Master Transmitter Mode
|
||||
int I2C::write(int address, const char* data, int length, bool repeated) {
|
||||
lock();
|
||||
aquire();
|
||||
|
||||
int stop = (repeated) ? 0 : 1;
|
||||
int written = i2c_write(&_i2c, address, data, length, stop);
|
||||
|
||||
unlock();
|
||||
return length != written;
|
||||
}
|
||||
|
||||
int I2C::write(int data) {
|
||||
return i2c_byte_write(&_i2c, data);
|
||||
lock();
|
||||
int ret = i2c_byte_write(&_i2c, data);
|
||||
unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
// read - Master Reciever Mode
|
||||
int I2C::read(int address, char* data, int length, bool repeated) {
|
||||
lock();
|
||||
aquire();
|
||||
|
||||
int stop = (repeated) ? 0 : 1;
|
||||
int read = i2c_read(&_i2c, address, data, length, stop);
|
||||
|
||||
unlock();
|
||||
return length != read;
|
||||
}
|
||||
|
||||
int I2C::read(int ack) {
|
||||
lock();
|
||||
int ret;
|
||||
if (ack) {
|
||||
return i2c_byte_read(&_i2c, 0);
|
||||
ret = i2c_byte_read(&_i2c, 0);
|
||||
} else {
|
||||
return i2c_byte_read(&_i2c, 1);
|
||||
ret = i2c_byte_read(&_i2c, 1);
|
||||
}
|
||||
unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void I2C::start(void) {
|
||||
lock();
|
||||
i2c_start(&_i2c);
|
||||
unlock();
|
||||
}
|
||||
|
||||
void I2C::stop(void) {
|
||||
lock();
|
||||
i2c_stop(&_i2c);
|
||||
unlock();
|
||||
}
|
||||
|
||||
void I2C::lock() {
|
||||
_mutex.lock();
|
||||
}
|
||||
|
||||
void I2C::unlock() {
|
||||
_mutex.unlock();
|
||||
}
|
||||
|
||||
#if DEVICE_I2C_ASYNCH
|
||||
|
||||
int I2C::transfer(int address, const char *tx_buffer, int tx_length, char *rx_buffer, int rx_length, const event_callback_t& callback, int event, bool repeated)
|
||||
{
|
||||
lock();
|
||||
if (i2c_active(&_i2c)) {
|
||||
unlock();
|
||||
return -1; // transaction ongoing
|
||||
}
|
||||
aquire();
|
||||
|
@ -103,12 +135,15 @@ int I2C::transfer(int address, const char *tx_buffer, int tx_length, char *rx_bu
|
|||
int stop = (repeated) ? 0 : 1;
|
||||
_irq.callback(&I2C::irq_handler_asynch);
|
||||
i2c_transfer_asynch(&_i2c, (void *)tx_buffer, tx_length, (void *)rx_buffer, rx_length, address, stop, _irq.entry(), event, _usage);
|
||||
unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void I2C::abort_transfer(void)
|
||||
{
|
||||
lock();
|
||||
i2c_abort_asynch(&_i2c);
|
||||
unlock();
|
||||
}
|
||||
|
||||
void I2C::irq_handler_asynch(void)
|
||||
|
|
|
@ -23,23 +23,29 @@ InterruptIn::InterruptIn(PinName pin) : gpio(),
|
|||
gpio_irq(),
|
||||
_rise(),
|
||||
_fall() {
|
||||
// No lock needed in the constructor
|
||||
gpio_irq_init(&gpio_irq, pin, (&InterruptIn::_irq_handler), (uint32_t)this);
|
||||
gpio_init_in(&gpio, pin);
|
||||
}
|
||||
|
||||
InterruptIn::~InterruptIn() {
|
||||
// No lock needed in the destructor
|
||||
gpio_irq_free(&gpio_irq);
|
||||
}
|
||||
|
||||
int InterruptIn::read() {
|
||||
// Read only
|
||||
return gpio_read(&gpio);
|
||||
}
|
||||
|
||||
void InterruptIn::mode(PinMode pull) {
|
||||
core_util_critical_section_enter();
|
||||
gpio_mode(&gpio, pull);
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
void InterruptIn::rise(Callback<void()> func) {
|
||||
core_util_critical_section_enter();
|
||||
if (func) {
|
||||
_rise.attach(func);
|
||||
gpio_irq_set(&gpio_irq, IRQ_RISE, 1);
|
||||
|
@ -47,9 +53,11 @@ void InterruptIn::rise(Callback<void()> func) {
|
|||
_rise.attach(NULL);
|
||||
gpio_irq_set(&gpio_irq, IRQ_RISE, 0);
|
||||
}
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
void InterruptIn::fall(Callback<void()> func) {
|
||||
core_util_critical_section_enter();
|
||||
if (func) {
|
||||
_fall.attach(func);
|
||||
gpio_irq_set(&gpio_irq, IRQ_FALL, 1);
|
||||
|
@ -57,6 +65,7 @@ void InterruptIn::fall(Callback<void()> func) {
|
|||
_fall.attach(NULL);
|
||||
gpio_irq_set(&gpio_irq, IRQ_FALL, 0);
|
||||
}
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
void InterruptIn::_irq_handler(uint32_t id, gpio_irq_event event) {
|
||||
|
@ -69,15 +78,20 @@ void InterruptIn::_irq_handler(uint32_t id, gpio_irq_event event) {
|
|||
}
|
||||
|
||||
void InterruptIn::enable_irq() {
|
||||
core_util_critical_section_enter();
|
||||
gpio_irq_enable(&gpio_irq);
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
void InterruptIn::disable_irq() {
|
||||
core_util_critical_section_enter();
|
||||
gpio_irq_disable(&gpio_irq);
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
#ifdef MBED_OPERATORS
|
||||
InterruptIn::operator int() {
|
||||
// Underlying call is atomic
|
||||
return read();
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#if defined(NVIC_NUM_VECTORS)
|
||||
|
||||
#include "InterruptManager.h"
|
||||
#include "critical.h"
|
||||
#include <string.h>
|
||||
|
||||
#define CHAIN_INITIAL_SIZE 4
|
||||
|
@ -13,12 +14,28 @@ typedef void (*pvoidf)(void);
|
|||
InterruptManager* InterruptManager::_instance = (InterruptManager*)NULL;
|
||||
|
||||
InterruptManager* InterruptManager::get() {
|
||||
if (NULL == _instance)
|
||||
_instance = new InterruptManager();
|
||||
|
||||
if (NULL == _instance) {
|
||||
InterruptManager* temp = new InterruptManager();
|
||||
|
||||
// Atomically set _instance
|
||||
core_util_critical_section_enter();
|
||||
if (NULL == _instance) {
|
||||
_instance = temp;
|
||||
}
|
||||
core_util_critical_section_exit();
|
||||
|
||||
// Another thread got there first so delete ours
|
||||
if (temp != _instance) {
|
||||
delete temp;
|
||||
}
|
||||
|
||||
}
|
||||
return _instance;
|
||||
}
|
||||
|
||||
InterruptManager::InterruptManager() {
|
||||
// No mutex needed in constructor
|
||||
memset(_chains, 0, NVIC_NUM_VECTORS * sizeof(CallChain*));
|
||||
}
|
||||
|
||||
|
@ -39,34 +56,44 @@ InterruptManager::~InterruptManager() {
|
|||
}
|
||||
|
||||
bool InterruptManager::must_replace_vector(IRQn_Type irq) {
|
||||
int irq_pos = get_irq_index(irq);
|
||||
lock();
|
||||
|
||||
int ret = false;
|
||||
int irq_pos = get_irq_index(irq);
|
||||
if (NULL == _chains[irq_pos]) {
|
||||
_chains[irq_pos] = new CallChain(CHAIN_INITIAL_SIZE);
|
||||
_chains[irq_pos]->add((pvoidf)NVIC_GetVector(irq));
|
||||
return true;
|
||||
ret = true;
|
||||
}
|
||||
return false;
|
||||
unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
pFunctionPointer_t InterruptManager::add_common(void (*function)(void), IRQn_Type irq, bool front) {
|
||||
lock();
|
||||
int irq_pos = get_irq_index(irq);
|
||||
bool change = must_replace_vector(irq);
|
||||
|
||||
pFunctionPointer_t pf = front ? _chains[irq_pos]->add_front(function) : _chains[irq_pos]->add(function);
|
||||
if (change)
|
||||
NVIC_SetVector(irq, (uint32_t)&InterruptManager::static_irq_helper);
|
||||
unlock();
|
||||
return pf;
|
||||
}
|
||||
|
||||
bool InterruptManager::remove_handler(pFunctionPointer_t handler, IRQn_Type irq) {
|
||||
int irq_pos = get_irq_index(irq);
|
||||
bool ret = false;
|
||||
|
||||
if (NULL == _chains[irq_pos])
|
||||
return false;
|
||||
if (!_chains[irq_pos]->remove(handler))
|
||||
return false;
|
||||
return true;
|
||||
lock();
|
||||
if (_chains[irq_pos] != NULL) {
|
||||
if (_chains[irq_pos]->remove(handler)) {
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void InterruptManager::irq_helper() {
|
||||
|
@ -74,6 +101,7 @@ void InterruptManager::irq_helper() {
|
|||
}
|
||||
|
||||
int InterruptManager::get_irq_index(IRQn_Type irq) {
|
||||
// Pure function - no lock needed
|
||||
return (int)irq + NVIC_USER_IRQ_OFFSET;
|
||||
}
|
||||
|
||||
|
@ -81,6 +109,14 @@ void InterruptManager::static_irq_helper() {
|
|||
InterruptManager::get()->irq_helper();
|
||||
}
|
||||
|
||||
void InterruptManager::lock() {
|
||||
_mutex.lock();
|
||||
}
|
||||
|
||||
void InterruptManager::unlock() {
|
||||
_mutex.unlock();
|
||||
}
|
||||
|
||||
} // namespace mbed
|
||||
|
||||
#endif
|
||||
|
|
|
@ -108,6 +108,7 @@ FILEHANDLE local_file_open(const char* name, int flags) {
|
|||
}
|
||||
|
||||
LocalFileHandle::LocalFileHandle(FILEHANDLE fh) : _fh(fh), pos(0) {
|
||||
// No lock needed in constructor
|
||||
}
|
||||
|
||||
int LocalFileHandle::close() {
|
||||
|
@ -117,24 +118,32 @@ int LocalFileHandle::close() {
|
|||
}
|
||||
|
||||
ssize_t LocalFileHandle::write(const void *buffer, size_t length) {
|
||||
lock();
|
||||
ssize_t n = semihost_write(_fh, (const unsigned char*)buffer, length, 0); // number of characters not written
|
||||
n = length - n; // number of characters written
|
||||
pos += n;
|
||||
unlock();
|
||||
return n;
|
||||
}
|
||||
|
||||
ssize_t LocalFileHandle::read(void *buffer, size_t length) {
|
||||
lock();
|
||||
ssize_t n = semihost_read(_fh, (unsigned char*)buffer, length, 0); // number of characters not read
|
||||
n = length - n; // number of characters read
|
||||
pos += n;
|
||||
unlock();
|
||||
return n;
|
||||
}
|
||||
|
||||
int LocalFileHandle::isatty() {
|
||||
return semihost_istty(_fh);
|
||||
lock();
|
||||
int ret = semihost_istty(_fh);
|
||||
unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
off_t LocalFileHandle::lseek(off_t position, int whence) {
|
||||
lock();
|
||||
if (whence == SEEK_CUR) {
|
||||
position += pos;
|
||||
} else if (whence == SEEK_END) {
|
||||
|
@ -144,15 +153,30 @@ off_t LocalFileHandle::lseek(off_t position, int whence) {
|
|||
/* Always seems to return -1, so just ignore for now. */
|
||||
semihost_seek(_fh, position);
|
||||
pos = position;
|
||||
unlock();
|
||||
return position;
|
||||
}
|
||||
|
||||
int LocalFileHandle::fsync() {
|
||||
return semihost_ensure(_fh);
|
||||
lock();
|
||||
int ret = semihost_ensure(_fh);
|
||||
unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
off_t LocalFileHandle::flen() {
|
||||
return semihost_flen(_fh);
|
||||
lock();
|
||||
off_t off = semihost_flen(_fh);
|
||||
unlock();
|
||||
return off;
|
||||
}
|
||||
|
||||
void LocalFileHandle::lock() {
|
||||
_mutex.lock();
|
||||
}
|
||||
|
||||
void LocalFileHandle::unlock() {
|
||||
_mutex.unlock();
|
||||
}
|
||||
|
||||
class LocalDirHandle : public DirHandle {
|
||||
|
@ -165,32 +189,56 @@ public:
|
|||
}
|
||||
|
||||
virtual int closedir() {
|
||||
// No lock can be used in destructor
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual struct dirent *readdir() {
|
||||
lock();
|
||||
if (xffind("*", &info)!=0) {
|
||||
unlock();
|
||||
return NULL;
|
||||
}
|
||||
memcpy(cur_entry.d_name, info.name, sizeof(info.name));
|
||||
unlock();
|
||||
return &cur_entry;
|
||||
}
|
||||
|
||||
virtual void rewinddir() {
|
||||
lock();
|
||||
info.fileID = 0;
|
||||
unlock();
|
||||
}
|
||||
|
||||
virtual off_t telldir() {
|
||||
return info.fileID;
|
||||
lock();
|
||||
int fileId = info.fileID;
|
||||
unlock();
|
||||
return fileId;
|
||||
}
|
||||
|
||||
virtual void seekdir(off_t offset) {
|
||||
lock();
|
||||
info.fileID = offset;
|
||||
unlock();
|
||||
}
|
||||
|
||||
protected:
|
||||
PlatformMutex _mutex;
|
||||
|
||||
virtual void lock() {
|
||||
_mutex.lock();
|
||||
}
|
||||
|
||||
virtual void unlock() {
|
||||
_mutex.unlock();
|
||||
}
|
||||
};
|
||||
|
||||
FileHandle *LocalFileSystem::open(const char* name, int flags) {
|
||||
// No global state modified so function is thread safe
|
||||
|
||||
/* reject filenames with / in them */
|
||||
for (const char *tmp = name; *tmp; tmp++) {
|
||||
if (*tmp == '/') {
|
||||
|
@ -211,10 +259,14 @@ FileHandle *LocalFileSystem::open(const char* name, int flags) {
|
|||
}
|
||||
|
||||
int LocalFileSystem::remove(const char *filename) {
|
||||
// No global state modified so function is thread safe
|
||||
|
||||
return semihost_remove(filename);
|
||||
}
|
||||
|
||||
DirHandle *LocalFileSystem::opendir(const char *name) {
|
||||
// No global state modified so function is thread safe
|
||||
|
||||
return new LocalDirHandle();
|
||||
}
|
||||
|
||||
|
|
|
@ -24,19 +24,28 @@
|
|||
namespace mbed {
|
||||
|
||||
RawSerial::RawSerial(PinName tx, PinName rx) : SerialBase(tx, rx) {
|
||||
// No lock needed in the constructor
|
||||
}
|
||||
|
||||
int RawSerial::getc() {
|
||||
return _base_getc();
|
||||
lock();
|
||||
int ret = _base_getc();
|
||||
unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int RawSerial::putc(int c) {
|
||||
return _base_putc(c);
|
||||
lock();
|
||||
int ret = _base_putc(c);
|
||||
unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int RawSerial::puts(const char *str) {
|
||||
lock();
|
||||
while (*str)
|
||||
putc(*str ++);
|
||||
unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -45,6 +54,7 @@ int RawSerial::puts(const char *str) {
|
|||
// We only call malloc() for the sprintf() buffer if the buffer
|
||||
// length is above a certain threshold, otherwise we use just the stack.
|
||||
int RawSerial::printf(const char *format, ...) {
|
||||
lock();
|
||||
std::va_list arg;
|
||||
va_start(arg, format);
|
||||
// ARMCC microlib does not properly handle a size of 0.
|
||||
|
@ -62,9 +72,22 @@ int RawSerial::printf(const char *format, ...) {
|
|||
delete[] temp;
|
||||
}
|
||||
va_end(arg);
|
||||
unlock();
|
||||
return len;
|
||||
}
|
||||
|
||||
/** Acquire exclusive access to this serial port
|
||||
*/
|
||||
void RawSerial::lock() {
|
||||
// No lock used - external synchronization required
|
||||
}
|
||||
|
||||
/** Release exclusive access to this serial port
|
||||
*/
|
||||
void RawSerial::unlock() {
|
||||
// No lock used - external synchronization required
|
||||
}
|
||||
|
||||
} // namespace mbed
|
||||
|
||||
#endif
|
||||
|
|
|
@ -33,38 +33,57 @@ SPI::SPI(PinName mosi, PinName miso, PinName sclk, PinName ssel) :
|
|||
_bits(8),
|
||||
_mode(0),
|
||||
_hz(1000000) {
|
||||
// No lock needed in the constructor
|
||||
|
||||
spi_init(&_spi, mosi, miso, sclk, ssel);
|
||||
spi_format(&_spi, _bits, _mode, 0);
|
||||
spi_frequency(&_spi, _hz);
|
||||
}
|
||||
|
||||
void SPI::format(int bits, int mode) {
|
||||
lock();
|
||||
_bits = bits;
|
||||
_mode = mode;
|
||||
SPI::_owner = NULL; // Not that elegant, but works. rmeyer
|
||||
aquire();
|
||||
unlock();
|
||||
}
|
||||
|
||||
void SPI::frequency(int hz) {
|
||||
lock();
|
||||
_hz = hz;
|
||||
SPI::_owner = NULL; // Not that elegant, but works. rmeyer
|
||||
aquire();
|
||||
unlock();
|
||||
}
|
||||
|
||||
SPI* SPI::_owner = NULL;
|
||||
|
||||
// ignore the fact there are multiple physical spis, and always update if it wasnt us last
|
||||
void SPI::aquire() {
|
||||
lock();
|
||||
if (_owner != this) {
|
||||
spi_format(&_spi, _bits, _mode, 0);
|
||||
spi_frequency(&_spi, _hz);
|
||||
_owner = this;
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
||||
int SPI::write(int value) {
|
||||
lock();
|
||||
aquire();
|
||||
return spi_master_write(&_spi, value);
|
||||
int ret = spi_master_write(&_spi, value);
|
||||
unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SPI::lock() {
|
||||
_mutex.lock();
|
||||
}
|
||||
|
||||
void SPI::unlock() {
|
||||
_mutex.unlock();
|
||||
}
|
||||
|
||||
#if DEVICE_SPI_ASYNCH
|
||||
|
|
|
@ -24,13 +24,23 @@ Serial::Serial(PinName tx, PinName rx, const char *name) : SerialBase(tx, rx), S
|
|||
}
|
||||
|
||||
int Serial::_getc() {
|
||||
// Mutex is already held
|
||||
return _base_getc();
|
||||
}
|
||||
|
||||
int Serial::_putc(int c) {
|
||||
// Mutex is already held
|
||||
return _base_putc(c);
|
||||
}
|
||||
|
||||
void Serial::lock() {
|
||||
_mutex.lock();
|
||||
}
|
||||
|
||||
void Serial::unlock() {
|
||||
_mutex.unlock();
|
||||
}
|
||||
|
||||
} // namespace mbed
|
||||
|
||||
#endif
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
*/
|
||||
#include "SerialBase.h"
|
||||
#include "wait_api.h"
|
||||
#include "critical.h"
|
||||
|
||||
#if DEVICE_SERIAL
|
||||
|
||||
|
@ -26,35 +27,52 @@ SerialBase::SerialBase(PinName tx, PinName rx) :
|
|||
_rx_usage(DMA_USAGE_NEVER),
|
||||
#endif
|
||||
_serial(), _baud(9600) {
|
||||
// No lock needed in the constructor
|
||||
|
||||
serial_init(&_serial, tx, rx);
|
||||
serial_irq_handler(&_serial, SerialBase::_irq_handler, (uint32_t)this);
|
||||
}
|
||||
|
||||
void SerialBase::baud(int baudrate) {
|
||||
lock();
|
||||
serial_baud(&_serial, baudrate);
|
||||
_baud = baudrate;
|
||||
unlock();
|
||||
}
|
||||
|
||||
void SerialBase::format(int bits, Parity parity, int stop_bits) {
|
||||
lock();
|
||||
serial_format(&_serial, bits, (SerialParity)parity, stop_bits);
|
||||
unlock();
|
||||
}
|
||||
|
||||
int SerialBase::readable() {
|
||||
return serial_readable(&_serial);
|
||||
lock();
|
||||
int ret = serial_readable(&_serial);
|
||||
unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int SerialBase::writeable() {
|
||||
return serial_writable(&_serial);
|
||||
lock();
|
||||
int ret = serial_writable(&_serial);
|
||||
unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SerialBase::attach(Callback<void()> func, IrqType type) {
|
||||
lock();
|
||||
// Disable interrupts when attaching interrupt handler
|
||||
core_util_critical_section_enter();
|
||||
if (func) {
|
||||
_irq[type].attach(func);
|
||||
serial_irq_set(&_serial, (SerialIrq)type, 1);
|
||||
} else {
|
||||
serial_irq_set(&_serial, (SerialIrq)type, 0);
|
||||
}
|
||||
core_util_critical_section_exit();
|
||||
unlock();
|
||||
}
|
||||
|
||||
void SerialBase::_irq_handler(uint32_t id, SerialIrq irq_type) {
|
||||
|
@ -63,15 +81,18 @@ void SerialBase::_irq_handler(uint32_t id, SerialIrq irq_type) {
|
|||
}
|
||||
|
||||
int SerialBase::_base_getc() {
|
||||
// Mutex is already held
|
||||
return serial_getc(&_serial);
|
||||
}
|
||||
|
||||
int SerialBase::_base_putc(int c) {
|
||||
// Mutex is already held
|
||||
serial_putc(&_serial, c);
|
||||
return c;
|
||||
}
|
||||
|
||||
void SerialBase::send_break() {
|
||||
lock();
|
||||
// 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.
|
||||
|
@ -83,10 +104,20 @@ void SerialBase::send_break() {
|
|||
serial_break_set(&_serial);
|
||||
wait_us(18000000/_baud);
|
||||
serial_break_clear(&_serial);
|
||||
unlock();
|
||||
}
|
||||
|
||||
void SerialBase::lock() {
|
||||
// Stub
|
||||
}
|
||||
|
||||
void SerialBase:: unlock() {
|
||||
// Stub
|
||||
}
|
||||
|
||||
#if DEVICE_SERIAL_FC
|
||||
void SerialBase::set_flow_control(Flow type, PinName flow1, PinName flow2) {
|
||||
lock();
|
||||
FlowControl flow_type = (FlowControl)type;
|
||||
switch(type) {
|
||||
case RTS:
|
||||
|
@ -105,6 +136,7 @@ void SerialBase::set_flow_control(Flow type, PinName flow1, PinName flow2) {
|
|||
default:
|
||||
break;
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
namespace mbed {
|
||||
|
||||
Stream::Stream(const char *name) : FileLike(name), _file(NULL) {
|
||||
// No lock needed in constructor
|
||||
/* open ourselves */
|
||||
char buf[12]; /* :0x12345678 + null byte */
|
||||
std::sprintf(buf, ":%p", this);
|
||||
|
@ -26,24 +27,37 @@ Stream::Stream(const char *name) : FileLike(name), _file(NULL) {
|
|||
}
|
||||
|
||||
Stream::~Stream() {
|
||||
// No lock can be used in destructor
|
||||
fclose(_file);
|
||||
}
|
||||
|
||||
int Stream::putc(int c) {
|
||||
lock();
|
||||
fflush(_file);
|
||||
return std::fputc(c, _file);
|
||||
int ret = std::fputc(c, _file);
|
||||
unlock();
|
||||
return ret;
|
||||
}
|
||||
int Stream::puts(const char *s) {
|
||||
lock();
|
||||
fflush(_file);
|
||||
return std::fputs(s, _file);
|
||||
int ret = std::fputs(s, _file);
|
||||
unlock();
|
||||
return ret;
|
||||
}
|
||||
int Stream::getc() {
|
||||
lock();
|
||||
fflush(_file);
|
||||
return mbed_getc(_file);
|
||||
int ret = mbed_getc(_file);
|
||||
unlock();
|
||||
return ret;
|
||||
}
|
||||
char* Stream::gets(char *s, int size) {
|
||||
lock();
|
||||
fflush(_file);
|
||||
return mbed_gets(s,size,_file);
|
||||
char *ret = mbed_gets(s,size,_file);
|
||||
unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int Stream::close() {
|
||||
|
@ -53,22 +67,30 @@ int Stream::close() {
|
|||
ssize_t Stream::write(const void* buffer, size_t length) {
|
||||
const char* ptr = (const char*)buffer;
|
||||
const char* end = ptr + length;
|
||||
|
||||
lock();
|
||||
while (ptr != end) {
|
||||
if (_putc(*ptr++) == EOF) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
unlock();
|
||||
|
||||
return ptr - (const char*)buffer;
|
||||
}
|
||||
|
||||
ssize_t Stream::read(void* buffer, size_t length) {
|
||||
char* ptr = (char*)buffer;
|
||||
char* end = ptr + length;
|
||||
|
||||
lock();
|
||||
while (ptr != end) {
|
||||
int c = _getc();
|
||||
if (c==EOF) break;
|
||||
*ptr++ = c;
|
||||
}
|
||||
unlock();
|
||||
|
||||
return ptr - (const char*)buffer;
|
||||
}
|
||||
|
||||
|
@ -89,32 +111,40 @@ off_t Stream::flen() {
|
|||
}
|
||||
|
||||
int Stream::printf(const char* format, ...) {
|
||||
lock();
|
||||
std::va_list arg;
|
||||
va_start(arg, format);
|
||||
fflush(_file);
|
||||
int r = vfprintf(_file, format, arg);
|
||||
va_end(arg);
|
||||
unlock();
|
||||
return r;
|
||||
}
|
||||
|
||||
int Stream::scanf(const char* format, ...) {
|
||||
lock();
|
||||
std::va_list arg;
|
||||
va_start(arg, format);
|
||||
fflush(_file);
|
||||
int r = vfscanf(_file, format, arg);
|
||||
va_end(arg);
|
||||
unlock();
|
||||
return r;
|
||||
}
|
||||
|
||||
int Stream::vprintf(const char* format, std::va_list args) {
|
||||
lock();
|
||||
fflush(_file);
|
||||
int r = vfprintf(_file, format, args);
|
||||
unlock();
|
||||
return r;
|
||||
}
|
||||
|
||||
int Stream::vscanf(const char* format, std::va_list args) {
|
||||
lock();
|
||||
fflush(_file);
|
||||
int r = vfscanf(_file, format, args);
|
||||
unlock();
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,18 +18,23 @@
|
|||
#include "TimerEvent.h"
|
||||
#include "FunctionPointer.h"
|
||||
#include "ticker_api.h"
|
||||
#include "critical.h"
|
||||
|
||||
namespace mbed {
|
||||
|
||||
void Ticker::detach() {
|
||||
core_util_critical_section_enter();
|
||||
remove();
|
||||
_function.attach(0);
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
void Ticker::setup(timestamp_t t) {
|
||||
core_util_critical_section_enter();
|
||||
remove();
|
||||
_delay = t;
|
||||
insert(_delay + ticker_read(_ticker_data));
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
void Ticker::handler() {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "Timer.h"
|
||||
#include "ticker_api.h"
|
||||
#include "us_ticker_api.h"
|
||||
#include "critical.h"
|
||||
|
||||
namespace mbed {
|
||||
|
||||
|
@ -28,19 +29,26 @@ Timer::Timer(const ticker_data_t *data) : _running(), _start(), _time(), _ticker
|
|||
}
|
||||
|
||||
void Timer::start() {
|
||||
core_util_critical_section_enter();
|
||||
if (!_running) {
|
||||
_start = ticker_read(_ticker_data);
|
||||
_running = 1;
|
||||
}
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
void Timer::stop() {
|
||||
core_util_critical_section_enter();
|
||||
_time += slicetime();
|
||||
_running = 0;
|
||||
_running = 0;
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
int Timer::read_us() {
|
||||
return _time + slicetime();
|
||||
core_util_critical_section_enter();
|
||||
int time = _time + slicetime();
|
||||
core_util_critical_section_exit();
|
||||
return time;
|
||||
}
|
||||
|
||||
float Timer::read() {
|
||||
|
@ -52,16 +60,20 @@ int Timer::read_ms() {
|
|||
}
|
||||
|
||||
int Timer::slicetime() {
|
||||
core_util_critical_section_enter();
|
||||
int ret = 0;
|
||||
if (_running) {
|
||||
return ticker_read(_ticker_data) - _start;
|
||||
} else {
|
||||
return 0;
|
||||
ret = ticker_read(_ticker_data) - _start;
|
||||
}
|
||||
core_util_critical_section_exit();
|
||||
return ret;
|
||||
}
|
||||
|
||||
void Timer::reset() {
|
||||
core_util_critical_section_enter();
|
||||
_start = ticker_read(_ticker_data);
|
||||
_time = 0;
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
#ifdef MBED_OPERATORS
|
||||
|
|
|
@ -16,17 +16,12 @@
|
|||
#include "mbed_assert.h"
|
||||
#include "device.h"
|
||||
|
||||
#if DEVICE_STDIO_MESSAGES
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "mbed_interface.h"
|
||||
#include "critical.h"
|
||||
|
||||
void mbed_assert_internal(const char *expr, const char *file, int line)
|
||||
{
|
||||
#if DEVICE_STDIO_MESSAGES
|
||||
fprintf(stderr, "mbed assertation failed: %s, file: %s, line %d \n", expr, file, line);
|
||||
#endif
|
||||
core_util_critical_section_enter();
|
||||
mbed_error_printf("mbed assertation failed: %s, file: %s, line %d \n", expr, file, line);
|
||||
mbed_die();
|
||||
}
|
||||
|
|
|
@ -13,11 +13,18 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "gpio_api.h"
|
||||
#include "wait_api.h"
|
||||
#include "toolchain.h"
|
||||
#include "mbed_interface.h"
|
||||
#include "critical.h"
|
||||
#include "serial_api.h"
|
||||
|
||||
#if DEVICE_SERIAL
|
||||
extern int stdio_uart_inited;
|
||||
extern serial_t stdio_uart;
|
||||
#endif
|
||||
|
||||
WEAK void mbed_die(void) {
|
||||
#if !defined (NRF51_H) && !defined(TARGET_EFM32)
|
||||
|
@ -58,3 +65,27 @@ WEAK void mbed_die(void) {
|
|||
wait_ms(150);
|
||||
}
|
||||
}
|
||||
|
||||
void mbed_error_printf(const char* format, ...) {
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
mbed_error_vfprintf(format, arg);
|
||||
va_end(arg);
|
||||
}
|
||||
|
||||
void mbed_error_vfprintf(const char * format, va_list arg) {
|
||||
#if DEVICE_SERIAL
|
||||
core_util_critical_section_enter();
|
||||
char buffer[128];
|
||||
int size = vsprintf(buffer, format, arg);
|
||||
if (size > 0) {
|
||||
if (!stdio_uart_inited) {
|
||||
serial_init(&stdio_uart, STDIO_UART_TX, STDIO_UART_RX);
|
||||
}
|
||||
for (int i = 0; i < size; i++) {
|
||||
serial_putc(&stdio_uart, buffer[i]);
|
||||
}
|
||||
}
|
||||
core_util_critical_section_exit();
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -23,11 +23,9 @@
|
|||
#endif
|
||||
|
||||
WEAK void error(const char* format, ...) {
|
||||
#if DEVICE_STDIO_MESSAGES
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
vfprintf(stderr, format, arg);
|
||||
mbed_error_vfprintf(format, arg);
|
||||
va_end(arg);
|
||||
#endif
|
||||
exit(1);
|
||||
}
|
||||
|
|
|
@ -50,6 +50,8 @@
|
|||
# define PREFIX(x) x
|
||||
#endif
|
||||
|
||||
#define FILE_HANDLE_RESERVED 0xFFFFFFFF
|
||||
|
||||
using namespace mbed;
|
||||
|
||||
#if defined(__MICROLIB) && (__ARMCC_VERSION>5030000)
|
||||
|
@ -70,14 +72,17 @@ extern const char __stderr_name[] = "/stderr";
|
|||
* (or rather index+3, as filehandles 0-2 are stdin/out/err).
|
||||
*/
|
||||
static FileHandle *filehandles[OPEN_MAX];
|
||||
static PlatformMutex filehandle_mutex;
|
||||
|
||||
FileHandle::~FileHandle() {
|
||||
filehandle_mutex.lock();
|
||||
/* Remove all open filehandles for this */
|
||||
for (unsigned int fh_i = 0; fh_i < sizeof(filehandles)/sizeof(*filehandles); fh_i++) {
|
||||
if (filehandles[fh_i] == this) {
|
||||
filehandles[fh_i] = NULL;
|
||||
}
|
||||
}
|
||||
filehandle_mutex.unlock();
|
||||
}
|
||||
|
||||
#if DEVICE_SERIAL
|
||||
|
@ -150,13 +155,17 @@ extern "C" FILEHANDLE PREFIX(_open)(const char* name, int openmode) {
|
|||
#endif
|
||||
|
||||
// find the first empty slot in filehandles
|
||||
filehandle_mutex.lock();
|
||||
unsigned int fh_i;
|
||||
for (fh_i = 0; fh_i < sizeof(filehandles)/sizeof(*filehandles); fh_i++) {
|
||||
if (filehandles[fh_i] == NULL) break;
|
||||
}
|
||||
if (fh_i >= sizeof(filehandles)/sizeof(*filehandles)) {
|
||||
filehandle_mutex.unlock();
|
||||
return -1;
|
||||
}
|
||||
filehandles[fh_i] = (FileHandle*)FILE_HANDLE_RESERVED;
|
||||
filehandle_mutex.unlock();
|
||||
|
||||
FileHandle *res;
|
||||
|
||||
|
@ -170,19 +179,29 @@ extern "C" FILEHANDLE PREFIX(_open)(const char* name, int openmode) {
|
|||
} else {
|
||||
FilePath path(name);
|
||||
|
||||
if (!path.exists())
|
||||
if (!path.exists()) {
|
||||
// Free file handle
|
||||
filehandles[fh_i] = NULL;
|
||||
return -1;
|
||||
else if (path.isFile()) {
|
||||
} else if (path.isFile()) {
|
||||
res = path.file();
|
||||
} else {
|
||||
FileSystemLike *fs = path.fileSystem();
|
||||
if (fs == NULL) return -1;
|
||||
if (fs == NULL) {
|
||||
// Free file handle
|
||||
filehandles[fh_i] = NULL;
|
||||
return -1;
|
||||
}
|
||||
int posix_mode = openmode_to_posix(openmode);
|
||||
res = fs->open(path.fileName(), posix_mode); /* NULL if fails */
|
||||
}
|
||||
}
|
||||
|
||||
if (res == NULL) return -1;
|
||||
if (res == NULL) {
|
||||
// Free file handle
|
||||
filehandles[fh_i] = NULL;
|
||||
return -1;
|
||||
}
|
||||
filehandles[fh_i] = res;
|
||||
|
||||
return fh_i + 3; // +3 as filehandles 0-2 are stdin/out/err
|
||||
|
|
|
@ -42,6 +42,7 @@ time_t time(time_t *timer)
|
|||
#endif
|
||||
|
||||
{
|
||||
core_util_critical_section_enter();
|
||||
if (_rtc_isenabled != NULL) {
|
||||
if (!(_rtc_isenabled())) {
|
||||
set_time(0);
|
||||
|
@ -56,21 +57,26 @@ time_t time(time_t *timer)
|
|||
if (timer != NULL) {
|
||||
*timer = t;
|
||||
}
|
||||
core_util_critical_section_exit();
|
||||
return t;
|
||||
}
|
||||
|
||||
void set_time(time_t t) {
|
||||
core_util_critical_section_enter();
|
||||
if (_rtc_init != NULL) {
|
||||
_rtc_init();
|
||||
}
|
||||
if (_rtc_write != NULL) {
|
||||
_rtc_write(t);
|
||||
}
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
clock_t clock() {
|
||||
core_util_critical_section_enter();
|
||||
clock_t t = us_ticker_read();
|
||||
t /= 1000000 / CLOCKS_PER_SEC; // convert to processor time
|
||||
core_util_critical_section_exit();
|
||||
return t;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,12 +25,14 @@
|
|||
|
||||
using namespace mbed;
|
||||
|
||||
FATDirHandle::FATDirHandle(const FATFS_DIR &the_dir) {
|
||||
FATDirHandle::FATDirHandle(const FATFS_DIR &the_dir, PlatformMutex * mutex): _mutex(mutex) {
|
||||
dir = the_dir;
|
||||
}
|
||||
|
||||
int FATDirHandle::closedir() {
|
||||
lock();
|
||||
int retval = f_closedir(&dir);
|
||||
unlock();
|
||||
delete this;
|
||||
return retval;
|
||||
}
|
||||
|
@ -38,6 +40,7 @@ int FATDirHandle::closedir() {
|
|||
struct dirent *FATDirHandle::readdir() {
|
||||
FILINFO finfo;
|
||||
|
||||
lock();
|
||||
#if _USE_LFN
|
||||
finfo.lfname = cur_entry.d_name;
|
||||
finfo.lfsize = sizeof(cur_entry.d_name);
|
||||
|
@ -47,33 +50,52 @@ struct dirent *FATDirHandle::readdir() {
|
|||
|
||||
#if _USE_LFN
|
||||
if(res != 0 || finfo.fname[0]==0) {
|
||||
unlock();
|
||||
return NULL;
|
||||
} else {
|
||||
if(cur_entry.d_name[0]==0) {
|
||||
// No long filename so use short filename.
|
||||
memcpy(cur_entry.d_name, finfo.fname, sizeof(finfo.fname));
|
||||
}
|
||||
unlock();
|
||||
return &cur_entry;
|
||||
}
|
||||
#else
|
||||
if(res != 0 || finfo.fname[0]==0) {
|
||||
unlock();
|
||||
return NULL;
|
||||
} else {
|
||||
memcpy(cur_entry.d_name, finfo.fname, sizeof(finfo.fname));
|
||||
unlock();
|
||||
return &cur_entry;
|
||||
}
|
||||
#endif /* _USE_LFN */
|
||||
}
|
||||
|
||||
void FATDirHandle::rewinddir() {
|
||||
lock();
|
||||
dir.index = 0;
|
||||
unlock();
|
||||
}
|
||||
|
||||
off_t FATDirHandle::telldir() {
|
||||
return dir.index;
|
||||
lock();
|
||||
off_t offset = dir.index;
|
||||
unlock();
|
||||
return offset;
|
||||
}
|
||||
|
||||
void FATDirHandle::seekdir(off_t location) {
|
||||
lock();
|
||||
dir.index = location;
|
||||
unlock();
|
||||
}
|
||||
|
||||
void FATDirHandle::lock() {
|
||||
_mutex->lock();
|
||||
}
|
||||
|
||||
void FATDirHandle::unlock() {
|
||||
_mutex->unlock();
|
||||
}
|
||||
|
||||
|
|
|
@ -23,19 +23,27 @@
|
|||
#define MBED_FATDIRHANDLE_H
|
||||
|
||||
#include "DirHandle.h"
|
||||
#include "platform.h"
|
||||
|
||||
using namespace mbed;
|
||||
|
||||
class FATDirHandle : public DirHandle {
|
||||
|
||||
public:
|
||||
FATDirHandle(const FATFS_DIR &the_dir);
|
||||
FATDirHandle(const FATFS_DIR &the_dir, PlatformMutex * mutex);
|
||||
virtual int closedir();
|
||||
virtual struct dirent *readdir();
|
||||
virtual void rewinddir();
|
||||
virtual off_t telldir();
|
||||
virtual void seekdir(off_t location);
|
||||
|
||||
protected:
|
||||
|
||||
virtual void lock();
|
||||
virtual void unlock();
|
||||
|
||||
PlatformMutex * _mutex;
|
||||
|
||||
private:
|
||||
FATFS_DIR dir;
|
||||
struct dirent cur_entry;
|
||||
|
|
|
@ -25,34 +25,42 @@
|
|||
|
||||
#include "FATFileHandle.h"
|
||||
|
||||
FATFileHandle::FATFileHandle(FIL fh) {
|
||||
FATFileHandle::FATFileHandle(FIL fh, PlatformMutex * mutex): _mutex(mutex) {
|
||||
_fh = fh;
|
||||
}
|
||||
|
||||
int FATFileHandle::close() {
|
||||
lock();
|
||||
int retval = f_close(&_fh);
|
||||
unlock();
|
||||
delete this;
|
||||
return retval;
|
||||
}
|
||||
|
||||
ssize_t FATFileHandle::write(const void* buffer, size_t length) {
|
||||
lock();
|
||||
UINT n;
|
||||
FRESULT res = f_write(&_fh, buffer, length, &n);
|
||||
if (res) {
|
||||
debug_if(FFS_DBG, "f_write() failed: %d", res);
|
||||
unlock();
|
||||
return -1;
|
||||
}
|
||||
unlock();
|
||||
return n;
|
||||
}
|
||||
|
||||
ssize_t FATFileHandle::read(void* buffer, size_t length) {
|
||||
lock();
|
||||
debug_if(FFS_DBG, "read(%d)\n", length);
|
||||
UINT n;
|
||||
FRESULT res = f_read(&_fh, buffer, length, &n);
|
||||
if (res) {
|
||||
debug_if(FFS_DBG, "f_read() failed: %d\n", res);
|
||||
unlock();
|
||||
return -1;
|
||||
}
|
||||
unlock();
|
||||
return n;
|
||||
}
|
||||
|
||||
|
@ -61,6 +69,7 @@ int FATFileHandle::isatty() {
|
|||
}
|
||||
|
||||
off_t FATFileHandle::lseek(off_t position, int whence) {
|
||||
lock();
|
||||
if (whence == SEEK_END) {
|
||||
position += _fh.fsize;
|
||||
} else if(whence==SEEK_CUR) {
|
||||
|
@ -69,22 +78,38 @@ off_t FATFileHandle::lseek(off_t position, int whence) {
|
|||
FRESULT res = f_lseek(&_fh, position);
|
||||
if (res) {
|
||||
debug_if(FFS_DBG, "lseek failed: %d\n", res);
|
||||
unlock();
|
||||
return -1;
|
||||
} else {
|
||||
debug_if(FFS_DBG, "lseek OK, returning %i\n", _fh.fptr);
|
||||
unlock();
|
||||
return _fh.fptr;
|
||||
}
|
||||
}
|
||||
|
||||
int FATFileHandle::fsync() {
|
||||
lock();
|
||||
FRESULT res = f_sync(&_fh);
|
||||
if (res) {
|
||||
debug_if(FFS_DBG, "f_sync() failed: %d\n", res);
|
||||
unlock();
|
||||
return -1;
|
||||
}
|
||||
unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
off_t FATFileHandle::flen() {
|
||||
return _fh.fsize;
|
||||
lock();
|
||||
off_t size = _fh.fsize;
|
||||
unlock();
|
||||
return size;
|
||||
}
|
||||
|
||||
void FATFileHandle::lock() {
|
||||
_mutex->lock();
|
||||
}
|
||||
|
||||
void FATFileHandle::unlock() {
|
||||
_mutex->unlock();
|
||||
}
|
||||
|
|
|
@ -23,13 +23,14 @@
|
|||
#define MBED_FATFILEHANDLE_H
|
||||
|
||||
#include "FileHandle.h"
|
||||
#include "platform.h"
|
||||
|
||||
using namespace mbed;
|
||||
|
||||
class FATFileHandle : public FileHandle {
|
||||
public:
|
||||
|
||||
FATFileHandle(FIL fh);
|
||||
FATFileHandle(FIL fh, PlatformMutex * mutex);
|
||||
virtual int close();
|
||||
virtual ssize_t write(const void* buffer, size_t length);
|
||||
virtual ssize_t read(void* buffer, size_t length);
|
||||
|
@ -40,7 +41,11 @@ public:
|
|||
|
||||
protected:
|
||||
|
||||
virtual void lock();
|
||||
virtual void unlock();
|
||||
|
||||
FIL _fh;
|
||||
PlatformMutex * _mutex;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
#include "FATFileSystem.h"
|
||||
#include "FATFileHandle.h"
|
||||
#include "FATDirHandle.h"
|
||||
#include "critical.h"
|
||||
|
||||
DWORD get_fattime(void) {
|
||||
time_t rawtime;
|
||||
|
@ -41,33 +42,55 @@ DWORD get_fattime(void) {
|
|||
}
|
||||
|
||||
FATFileSystem *FATFileSystem::_ffs[_VOLUMES] = {0};
|
||||
static PlatformMutex * mutex = NULL;
|
||||
|
||||
FATFileSystem::FATFileSystem(const char* n) : FileSystemLike(n) {
|
||||
PlatformMutex * get_fat_mutex() {
|
||||
PlatformMutex * new_mutex = new PlatformMutex;
|
||||
|
||||
core_util_critical_section_enter();
|
||||
if (NULL == mutex) {
|
||||
mutex = new_mutex;
|
||||
}
|
||||
core_util_critical_section_exit();
|
||||
|
||||
if (mutex != new_mutex) {
|
||||
delete new_mutex;
|
||||
}
|
||||
return mutex;
|
||||
}
|
||||
|
||||
FATFileSystem::FATFileSystem(const char* n) : FileSystemLike(n), _mutex(get_fat_mutex()) {
|
||||
lock();
|
||||
debug_if(FFS_DBG, "FATFileSystem(%s)\n", n);
|
||||
for(int i=0; i<_VOLUMES; i++) {
|
||||
if(_ffs[i] == 0) {
|
||||
_ffs[i] = this;
|
||||
_fsid[0] = '0' + i;
|
||||
_fsid[1] = '\0';
|
||||
debug_if(FFS_DBG, "Mounting [%s] on ffs drive [%s]\n", _name, _fsid);
|
||||
debug_if(FFS_DBG, "Mounting [%s] on ffs drive [%s]\n", getName(), _fsid);
|
||||
f_mount(&_fs, _fsid, 0);
|
||||
unlock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
error("Couldn't create %s in FATFileSystem::FATFileSystem\n", n);
|
||||
unlock();
|
||||
}
|
||||
|
||||
FATFileSystem::~FATFileSystem() {
|
||||
lock();
|
||||
for (int i=0; i<_VOLUMES; i++) {
|
||||
if (_ffs[i] == this) {
|
||||
_ffs[i] = 0;
|
||||
f_mount(NULL, _fsid, 0);
|
||||
}
|
||||
}
|
||||
unlock();
|
||||
}
|
||||
|
||||
FileHandle *FATFileSystem::open(const char* name, int flags) {
|
||||
debug_if(FFS_DBG, "open(%s) on filesystem [%s], drv [%s]\n", name, _name, _fsid);
|
||||
lock();
|
||||
debug_if(FFS_DBG, "open(%s) on filesystem [%s], drv [%s]\n", name, getName(), _fsid);
|
||||
char n[64];
|
||||
sprintf(n, "%s:/%s", _fsid, name);
|
||||
|
||||
|
@ -92,63 +115,95 @@ FileHandle *FATFileSystem::open(const char* name, int flags) {
|
|||
FRESULT res = f_open(&fh, n, openmode);
|
||||
if (res) {
|
||||
debug_if(FFS_DBG, "f_open('w') failed: %d\n", res);
|
||||
unlock();
|
||||
return NULL;
|
||||
}
|
||||
if (flags & O_APPEND) {
|
||||
f_lseek(&fh, fh.fsize);
|
||||
}
|
||||
return new FATFileHandle(fh);
|
||||
FATFileHandle * handle = new FATFileHandle(fh, _mutex);
|
||||
unlock();
|
||||
return handle;
|
||||
}
|
||||
|
||||
int FATFileSystem::remove(const char *filename) {
|
||||
lock();
|
||||
FRESULT res = f_unlink(filename);
|
||||
if (res) {
|
||||
debug_if(FFS_DBG, "f_unlink() failed: %d\n", res);
|
||||
unlock();
|
||||
return -1;
|
||||
}
|
||||
unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FATFileSystem::rename(const char *oldname, const char *newname) {
|
||||
lock();
|
||||
FRESULT res = f_rename(oldname, newname);
|
||||
if (res) {
|
||||
debug_if(FFS_DBG, "f_rename() failed: %d\n", res);
|
||||
unlock();
|
||||
return -1;
|
||||
}
|
||||
unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int FATFileSystem::format() {
|
||||
lock();
|
||||
FRESULT res = f_mkfs(_fsid, 0, 512); // Logical drive number, Partitioning rule, Allocation unit size (bytes per cluster)
|
||||
if (res) {
|
||||
debug_if(FFS_DBG, "f_mkfs() failed: %d\n", res);
|
||||
unlock();
|
||||
return -1;
|
||||
}
|
||||
unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
DirHandle *FATFileSystem::opendir(const char *name) {
|
||||
lock();
|
||||
FATFS_DIR dir;
|
||||
FRESULT res = f_opendir(&dir, name);
|
||||
if (res != 0) {
|
||||
unlock();
|
||||
return NULL;
|
||||
}
|
||||
return new FATDirHandle(dir);
|
||||
FATDirHandle *handle = new FATDirHandle(dir, _mutex);
|
||||
unlock();
|
||||
return handle;
|
||||
}
|
||||
|
||||
int FATFileSystem::mkdir(const char *name, mode_t mode) {
|
||||
lock();
|
||||
FRESULT res = f_mkdir(name);
|
||||
unlock();
|
||||
return res == 0 ? 0 : -1;
|
||||
}
|
||||
|
||||
int FATFileSystem::mount() {
|
||||
lock();
|
||||
FRESULT res = f_mount(&_fs, _fsid, 1);
|
||||
unlock();
|
||||
return res == 0 ? 0 : -1;
|
||||
}
|
||||
|
||||
int FATFileSystem::unmount() {
|
||||
if (disk_sync())
|
||||
lock();
|
||||
if (disk_sync()) {
|
||||
unlock();
|
||||
return -1;
|
||||
}
|
||||
FRESULT res = f_mount(NULL, _fsid, 0);
|
||||
unlock();
|
||||
return res == 0 ? 0 : -1;
|
||||
}
|
||||
|
||||
void FATFileSystem::lock() {
|
||||
_mutex->lock();
|
||||
}
|
||||
|
||||
void FATFileSystem::unlock() {
|
||||
_mutex->unlock();
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "FileHandle.h"
|
||||
#include "ff.h"
|
||||
#include <stdint.h>
|
||||
#include "platform.h"
|
||||
|
||||
using namespace mbed;
|
||||
|
||||
|
@ -89,6 +90,15 @@ public:
|
|||
virtual int disk_sync() { return 0; }
|
||||
virtual uint32_t disk_sectors() = 0;
|
||||
|
||||
protected:
|
||||
|
||||
virtual void lock();
|
||||
virtual void unlock();
|
||||
|
||||
private:
|
||||
|
||||
PlatformMutex *_mutex;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -148,11 +148,13 @@ SDFileSystem::SDFileSystem(PinName mosi, PinName miso, PinName sclk, PinName cs,
|
|||
|
||||
int SDFileSystem::initialise_card() {
|
||||
// Set to SCK for initialisation, and clock card with cs = 1
|
||||
_spi.lock();
|
||||
_spi.frequency(_init_sck);
|
||||
_cs = 1;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
_spi.write(0xFF);
|
||||
}
|
||||
_spi.unlock();
|
||||
|
||||
// send CMD0, should return with all zeros except IDLE STATE set (bit 0)
|
||||
if (_cmd(0, 0) != R1_IDLE_STATE) {
|
||||
|
@ -204,9 +206,11 @@ int SDFileSystem::initialise_card_v2() {
|
|||
}
|
||||
|
||||
int SDFileSystem::disk_initialize() {
|
||||
lock();
|
||||
_is_initialized = initialise_card();
|
||||
if (_is_initialized == 0) {
|
||||
debug("Fail to initialize card\n");
|
||||
unlock();
|
||||
return 1;
|
||||
}
|
||||
debug_if(SD_DBG, "init card = %d\n", _is_initialized);
|
||||
|
@ -215,22 +219,27 @@ int SDFileSystem::disk_initialize() {
|
|||
// Set block length to 512 (CMD16)
|
||||
if (_cmd(16, 512) != 0) {
|
||||
debug("Set 512-byte block timed out\n");
|
||||
unlock();
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Set SCK for data transfer
|
||||
_spi.frequency(_transfer_sck);
|
||||
unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SDFileSystem::disk_write(const uint8_t* buffer, uint32_t block_number, uint32_t count) {
|
||||
lock();
|
||||
if (!_is_initialized) {
|
||||
unlock();
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (uint32_t b = block_number; b < block_number + count; b++) {
|
||||
// set write address for single block (CMD24)
|
||||
if (_cmd(24, b * cdv) != 0) {
|
||||
unlock();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -239,17 +248,21 @@ int SDFileSystem::disk_write(const uint8_t* buffer, uint32_t block_number, uint3
|
|||
buffer += 512;
|
||||
}
|
||||
|
||||
unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SDFileSystem::disk_read(uint8_t* buffer, uint32_t block_number, uint32_t count) {
|
||||
lock();
|
||||
if (!_is_initialized) {
|
||||
unlock();
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (uint32_t b = block_number; b < block_number + count; b++) {
|
||||
// set read address for single block (CMD17)
|
||||
if (_cmd(17, b * cdv) != 0) {
|
||||
unlock();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -258,24 +271,30 @@ int SDFileSystem::disk_read(uint8_t* buffer, uint32_t block_number, uint32_t cou
|
|||
buffer += 512;
|
||||
}
|
||||
|
||||
unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SDFileSystem::disk_status() {
|
||||
lock();
|
||||
// FATFileSystem::disk_status() returns 0 when initialized
|
||||
if (_is_initialized) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
int ret = _is_initialized ? 0 : 1;
|
||||
unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SDFileSystem::disk_sync() { return 0; }
|
||||
uint32_t SDFileSystem::disk_sectors() { return _sectors; }
|
||||
uint32_t SDFileSystem::disk_sectors() {
|
||||
lock();
|
||||
uint32_t sectors = _sectors;
|
||||
unlock();
|
||||
return sectors;
|
||||
}
|
||||
|
||||
|
||||
// PRIVATE FUNCTIONS
|
||||
int SDFileSystem::_cmd(int cmd, int arg) {
|
||||
_spi.lock();
|
||||
_cs = 0;
|
||||
|
||||
// send a command
|
||||
|
@ -292,14 +311,17 @@ int SDFileSystem::_cmd(int cmd, int arg) {
|
|||
if (!(response & 0x80)) {
|
||||
_cs = 1;
|
||||
_spi.write(0xFF);
|
||||
_spi.unlock();
|
||||
return response;
|
||||
}
|
||||
}
|
||||
_cs = 1;
|
||||
_spi.write(0xFF);
|
||||
_spi.unlock();
|
||||
return -1; // timeout
|
||||
}
|
||||
int SDFileSystem::_cmdx(int cmd, int arg) {
|
||||
_spi.lock();
|
||||
_cs = 0;
|
||||
|
||||
// send a command
|
||||
|
@ -314,16 +336,20 @@ int SDFileSystem::_cmdx(int cmd, int arg) {
|
|||
for (int i = 0; i < SD_COMMAND_TIMEOUT; i++) {
|
||||
int response = _spi.write(0xFF);
|
||||
if (!(response & 0x80)) {
|
||||
_cs = 1;
|
||||
_spi.unlock();
|
||||
return response;
|
||||
}
|
||||
}
|
||||
_cs = 1;
|
||||
_spi.write(0xFF);
|
||||
_spi.unlock();
|
||||
return -1; // timeout
|
||||
}
|
||||
|
||||
|
||||
int SDFileSystem::_cmd58() {
|
||||
_spi.lock();
|
||||
_cs = 0;
|
||||
int arg = 0;
|
||||
|
||||
|
@ -345,15 +371,18 @@ int SDFileSystem::_cmd58() {
|
|||
ocr |= _spi.write(0xFF) << 0;
|
||||
_cs = 1;
|
||||
_spi.write(0xFF);
|
||||
_spi.unlock();
|
||||
return response;
|
||||
}
|
||||
}
|
||||
_cs = 1;
|
||||
_spi.write(0xFF);
|
||||
_spi.unlock();
|
||||
return -1; // timeout
|
||||
}
|
||||
|
||||
int SDFileSystem::_cmd8() {
|
||||
_spi.lock();
|
||||
_cs = 0;
|
||||
|
||||
// send a command
|
||||
|
@ -374,15 +403,18 @@ int SDFileSystem::_cmd8() {
|
|||
}
|
||||
_cs = 1;
|
||||
_spi.write(0xFF);
|
||||
_spi.unlock();
|
||||
return response[0];
|
||||
}
|
||||
}
|
||||
_cs = 1;
|
||||
_spi.write(0xFF);
|
||||
_spi.unlock();
|
||||
return -1; // timeout
|
||||
}
|
||||
|
||||
int SDFileSystem::_read(uint8_t *buffer, uint32_t length) {
|
||||
_spi.lock();
|
||||
_cs = 0;
|
||||
|
||||
// read until start byte (0xFF)
|
||||
|
@ -397,10 +429,12 @@ int SDFileSystem::_read(uint8_t *buffer, uint32_t length) {
|
|||
|
||||
_cs = 1;
|
||||
_spi.write(0xFF);
|
||||
_spi.unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SDFileSystem::_write(const uint8_t*buffer, uint32_t length) {
|
||||
_spi.lock();
|
||||
_cs = 0;
|
||||
|
||||
// indicate start of block
|
||||
|
@ -419,6 +453,7 @@ int SDFileSystem::_write(const uint8_t*buffer, uint32_t length) {
|
|||
if ((_spi.write(0xFF) & 0x1F) != 0x05) {
|
||||
_cs = 1;
|
||||
_spi.write(0xFF);
|
||||
_spi.unlock();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -427,6 +462,7 @@ int SDFileSystem::_write(const uint8_t*buffer, uint32_t length) {
|
|||
|
||||
_cs = 1;
|
||||
_spi.write(0xFF);
|
||||
_spi.unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue