Make core mbed API thread safe

Make the mbed C++ API thread safe by adding a combination of
mutexes and critical sections.  Stub out all mutexes when the
RTOS is not present.
pull/1863/head
Russ Butler 2016-05-31 17:57:41 -05:00
parent 52e93aebd0
commit feb60784e9
49 changed files with 807 additions and 112 deletions

View File

@ -53,7 +53,9 @@ public:
* @param name (optional) A string to identify the object
*/
AnalogIn(PinName pin) {
_mutex.lock();
analogin_init(&_adc, pin);
_mutex.unlock();
}
/** Read the input voltage, represented as a float in the range [0.0, 1.0]
@ -61,7 +63,10 @@ public:
* @returns A floating-point value representing the current input voltage, measured as a percentage
*/
float read() {
return analogin_read(&_adc);
_mutex.lock();
float ret = analogin_read(&_adc);
_mutex.unlock();
return ret;
}
/** Read the input voltage, represented as an unsigned short in the range [0x0, 0xFFFF]
@ -70,7 +75,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);
_mutex.lock();
unsigned short ret = analogin_read_u16(&_adc);
_mutex.unlock();
return ret;
}
#ifdef MBED_OPERATORS
@ -88,12 +96,14 @@ public:
* @endcode
*/
operator float() {
// Underlying call is thread safe
return read();
}
#endif
protected:
analogin_t _adc;
static PlatformMutex _mutex;
};
} // namespace mbed

View File

@ -64,7 +64,9 @@ public:
* Values outside this range will be saturated to 0.0f or 1.0f.
*/
void write(float value) {
_mutex.lock();
analogout_write(&_dac, value);
_mutex.unlock();
}
/** Set the output voltage, represented as an unsigned short in the range [0x0, 0xFFFF]
@ -73,7 +75,9 @@ public:
* normalised to a 16-bit value (0x0000 = 0v, 0xFFFF = 3.3v)
*/
void write_u16(unsigned short value) {
_mutex.lock();
analogout_write_u16(&_dac, value);
_mutex.unlock();
}
/** Return the current output voltage setting, measured as a percentage (float)
@ -87,18 +91,23 @@ public:
* This value may not match exactly the value set by a previous write().
*/
float read() {
return analogout_read(&_dac);
_mutex.lock();
float ret = analogout_read(&_dac);
_mutex.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 +115,14 @@ public:
/** An operator shorthand for read()
*/
operator float() {
// Underlying read call is thread safe
return read();
}
#endif
protected:
dac_t _dac;
PlatformMutex _mutex;
};
} // namespace mbed

View File

@ -65,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;
}
@ -87,6 +88,8 @@ protected:
*/
int _nc_mask;
PlatformMutex _mutex;
/* disallow copy constructor and assignment operators */
private:
BusIn(const BusIn&);

View File

@ -79,6 +79,7 @@ public:
* Binary mask of connected pins
*/
int mask() {
// No lock needed since _nc_mask is not modified outside the constructor
return _nc_mask;
}
@ -106,6 +107,8 @@ protected:
*/
int _nc_mask;
PlatformMutex _mutex;
/* disallow copy constructor and assignment operators */
private:
BusInOut(const BusInOut&);

View File

@ -63,6 +63,7 @@ public:
* Binary mask of connected pins
*/
int mask() {
// No lock needed since _nc_mask is not modified outside the constructor
return _nc_mask;
}
@ -90,6 +91,8 @@ protected:
*/
int _nc_mask;
PlatformMutex _mutex;
/* disallow copy constructor and assignment operators */
private:
BusOut(const BusOut&);

View File

@ -220,6 +220,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,6 +233,7 @@ public:
*/
template<typename T>
void attach(T* obj, void (*method)(T*), IrqType type=RxIrq) {
// Underlying call thread safe
attach(Callback<void()>(obj, method), type);
}
@ -240,6 +242,7 @@ public:
protected:
can_t _can;
Callback<void()> _irq[9];
PlatformMutex _mutex;
};
} // namespace mbed

View File

@ -58,6 +58,7 @@ namespace mbed {
*/
typedef Callback<void()> *pFunctionPointer_t;
class CallChainLink;
class CallChain {
public:
@ -160,17 +161,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

View File

@ -16,6 +16,8 @@
#ifndef MBED_CIRCULARBUFFER_H
#define MBED_CIRCULARBUFFER_H
#include "critical.h"
namespace mbed {
/** Templated Circular buffer class
@ -35,6 +37,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 +47,7 @@ public:
if (_head == _tail) {
_full = true;
}
core_util_critical_section_exit();
}
/** Pop the transaction from the buffer
@ -52,13 +56,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 +73,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 +84,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:

View File

@ -19,6 +19,7 @@
#include "platform.h"
#include "gpio_api.h"
#include "critical.h"
namespace mbed {
@ -51,6 +52,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 +62,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 +72,7 @@ public:
* 0 for logical 0, 1 for logical 1
*/
int read() {
// Thread safe / atomic HAL call
return gpio_read(&gpio);
}
@ -77,7 +81,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 +93,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 +101,7 @@ public:
/** An operator shorthand for read()
*/
operator int() {
// Underlying read is thread safe
return read();
}
#endif

View File

@ -19,6 +19,7 @@
#include "platform.h"
#include "gpio_api.h"
#include "critical.h"
namespace mbed {
@ -32,6 +33,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 +45,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 +55,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 +66,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 +91,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 +103,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 +111,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

View File

@ -18,6 +18,7 @@
#include "platform.h"
#include "gpio_api.h"
#include "critical.h"
namespace mbed {
@ -46,6 +47,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 +57,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 +67,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 +78,7 @@ public:
* 0 for logical 0, 1 for logical 1
*/
int read() {
// Thread safe / atomic HAL call
return gpio_read(&gpio);
}
@ -84,6 +89,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 +97,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

View File

@ -85,6 +85,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

View File

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

View File

@ -101,17 +101,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

View File

@ -37,6 +37,7 @@ public:
FileLike(const char *name);
virtual ~FileLike();
};
} // namespace mbed

View File

@ -135,6 +135,14 @@ public:
*/
void stop(void);
/** Acquire exclusive access to this I2C bus
*/
void lock(void);
/** Release exclusive access to this I2C bus
*/
void unlock(void);
#if DEVICE_I2C_ASYNCH
/** Start non-blocking I2C transfer.
@ -167,6 +175,7 @@ protected:
i2c_t _i2c;
static I2C *_owner;
int _hz;
static PlatformMutex _mutex;
};
} // namespace mbed

View File

@ -23,6 +23,7 @@
#include "gpio_api.h"
#include "gpio_irq_api.h"
#include "Callback.h"
#include "critical.h"
namespace mbed {
@ -81,7 +82,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 +100,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

View File

@ -1,6 +1,8 @@
#ifndef MBED_INTERRUPTMANAGER_H
#define MBED_INTERRUPTMANAGER_H
#include "platform.h"
#include "cmsis.h"
#include "CallChain.h"
#include <string.h>
@ -52,6 +54,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 +67,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 +82,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 +97,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);
}
@ -117,12 +123,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 +143,7 @@ private:
CallChain* _chains[NVIC_NUM_VECTORS];
static InterruptManager* _instance;
PlatformMutex _mutex;
};
} // namespace mbed

View File

@ -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
@ -85,6 +88,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) {

View File

@ -21,6 +21,7 @@
#if DEVICE_PORTIN
#include "port_api.h"
#include "critical.h"
namespace mbed {
@ -56,7 +57,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 +76,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()

View File

@ -21,6 +21,7 @@
#if DEVICE_PORTINOUT
#include "port_api.h"
#include "critical.h"
namespace mbed {
@ -35,7 +36,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 +61,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 +79,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()

View File

@ -21,6 +21,7 @@
#if DEVICE_PORTOUT
#include "port_api.h"
#include "critical.h"
namespace mbed {
/** A multiple pin digital out
@ -55,7 +56,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

View File

@ -20,6 +20,7 @@
#if DEVICE_PWMOUT
#include "pwmout_api.h"
#include "critical.h"
namespace mbed {
@ -59,7 +60,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 +73,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 +89,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 +102,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 +165,7 @@ public:
/** An operator shorthand for read()
*/
operator float() {
// Underlying call is thread safe
return read();
}
#endif

View File

@ -81,6 +81,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

View File

@ -56,10 +56,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 +112,14 @@ public:
*/
virtual int write(int value);
/** Acquire exclusive access to this SPI bus
*/
void lock(void);
/** Release exclusive access to this SPI bus
*/
void unlock(void);
#if DEVICE_SPI_ASYNCH
/** Start non-blocking SPI transfer using 8bit buffers.
@ -233,6 +244,7 @@ protected:
void aquire(void);
static SPI *_owner;
PlatformMutex _mutex;
int _bits;
int _mode;
int _hz;

View File

@ -65,6 +65,10 @@ public:
protected:
virtual int _getc();
virtual int _putc(int c);
virtual void lock();
virtual void unlock();
PlatformMutex _mutex;
};
} // namespace mbed

View File

@ -120,6 +120,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
*

View File

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

29
hal/common/AnalogIn.cpp Normal file
View File

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

View File

@ -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,34 @@ BusIn::~BusIn() {
int BusIn::read() {
int v = 0;
_mutex.lock();
for (int i=0; i<16; i++) {
if (_pin[i] != 0) {
v |= _pin[i]->read() << i;
}
}
_mutex.unlock();
return v;
}
void BusIn::mode(PinMode pull) {
_mutex.lock();
for (int i=0; i<16; i++) {
if (_pin[i] != 0) {
_pin[i]->mode(pull);
}
}
_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];

View File

@ -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,65 +52,79 @@ BusInOut::~BusInOut() {
}
void BusInOut::write(int value) {
_mutex.lock();
for (int i=0; i<16; i++) {
if (_pin[i] != 0) {
_pin[i]->write((value >> i) & 1);
}
}
_mutex.unlock();
}
int BusInOut::read() {
_mutex.lock();
int v = 0;
for (int i=0; i<16; i++) {
if (_pin[i] != 0) {
v |= _pin[i]->read() << i;
}
}
_mutex.unlock();
return v;
}
void BusInOut::output() {
_mutex.lock();
for (int i=0; i<16; i++) {
if (_pin[i] != 0) {
_pin[i]->output();
}
}
_mutex.unlock();
}
void BusInOut::input() {
_mutex.lock();
for (int i=0; i<16; i++) {
if (_pin[i] != 0) {
_pin[i]->input();
}
}
_mutex.unlock();
}
void BusInOut::mode(PinMode pull) {
_mutex.lock();
for (int i=0; i<16; i++) {
if (_pin[i] != 0) {
_pin[i]->mode(pull);
}
}
_mutex.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

View File

@ -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,41 +52,49 @@ BusOut::~BusOut() {
}
void BusOut::write(int value) {
_mutex.lock();
for (int i=0; i<16; i++) {
if (_pin[i] != 0) {
_pin[i]->write((value >> i) & 1);
}
}
_mutex.unlock();
}
int BusOut::read() {
_mutex.lock();
int v = 0;
for (int i=0; i<16; i++) {
if (_pin[i] != 0) {
v |= _pin[i]->read() << i;
}
}
_mutex.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

View File

@ -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);
_mutex.lock();
int ret = can_frequency(&_can, f);
_mutex.unlock();
return ret;
}
int CAN::write(CANMessage msg) {
return can_write(&_can, msg, 0);
_mutex.lock();
int ret = can_write(&_can, msg, 0);
_mutex.unlock();
return ret;
}
int CAN::read(CANMessage &msg, int handle) {
return can_read(&_can, &msg, handle);
_mutex.lock();
int ret = can_read(&_can, &msg, handle);
_mutex.unlock();
return ret;
}
void CAN::reset() {
_mutex.lock();
can_reset(&_can);
_mutex.unlock();
}
unsigned char CAN::rderror() {
return can_rderror(&_can);
_mutex.lock();
int ret = can_rderror(&_can);
_mutex.unlock();
return ret;
}
unsigned char CAN::tderror() {
return can_tderror(&_can);
_mutex.lock();
int ret = can_tderror(&_can);
_mutex.unlock();
return ret;
}
void CAN::monitor(bool silent) {
_mutex.lock();
can_monitor(&_can, (silent) ? 1 : 0);
_mutex.unlock();
}
int CAN::mode(Mode mode) {
return can_mode(&_can, (CanMode)mode);
_mutex.lock();
int ret = can_mode(&_can, (CanMode)mode);
_mutex.unlock();
return ret;
}
int CAN::filter(unsigned int id, unsigned int mask, CANFormat format, int handle) {
return can_filter(&_can, id, mask, format, handle);
_mutex.lock();
int ret = can_filter(&_can, id, mask, format, handle);
_mutex.unlock();
return ret;
}
void CAN::attach(Callback<void()> func, IrqType type) {
_mutex.lock();
if (func) {
_irq[(CanIrqType)type].attach(func);
can_irq_set(&_can, (CanIrqType)type, 1);
} else {
can_irq_set(&_can, (CanIrqType)type, 0);
}
_mutex.unlock();
}
void CAN::_irq_handler(uint32_t id, CanIrqType type) {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
_mutex.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;
_mutex.unlock();
return ret;
}
pFunctionPointer_t InterruptManager::add_common(void (*function)(void), IRQn_Type irq, bool front) {
_mutex.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);
_mutex.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;
_mutex.lock();
if (_chains[irq_pos] != NULL) {
if (_chains[irq_pos]->remove(handler)) {
ret = true;
}
}
_mutex.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;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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