diff --git a/inc/core/CodalAssert.h b/inc/core/CodalAssert.h index cf68d3a3..f0b8f1b7 100644 --- a/inc/core/CodalAssert.h +++ b/inc/core/CodalAssert.h @@ -27,7 +27,7 @@ DEALINGS IN THE SOFTWARE. /** * Intended for use in test suites - should not be used in production code! - * + * * (although they will compile to nothing if assertions are disabled...) */ @@ -39,19 +39,19 @@ DEALINGS IN THE SOFTWARE. #endif #if CONFIG_ENABLED(CODAL_ENABLE_ASSERT) - void __codal_assert__( const char * file, const int line, bool condition, const char * expr, const char * message ); - void __codal_fault__( const char * file, const int line, const char * message ); - void __codal_assert_pass__( const char * file, const int line, const char * message ); - void __codal_assert_fail__( const char * file, const int line, const char * message ); - #define assert(condition, message) __codal_assert__( __FILENAME__, __LINE__, (condition) == true, #condition, message ) - #define assert_fault(message) __codal_fault__( __FILENAME__, __LINE__, message ) - #define assert_pass(message) __codal_assert_pass__( __FILENAME__, __LINE__, message ) - #define assert_fail(message) __codal_assert_fail__( __FILENAME__, __LINE__, message ) +void __codal_assert__(const char* file, const int line, bool condition, const char* expr, const char* message); +void __codal_fault__(const char* file, const int line, const char* message); +void __codal_assert_pass__(const char* file, const int line, const char* message); +void __codal_assert_fail__(const char* file, const int line, const char* message); +#define assert(condition, message) __codal_assert__(__FILENAME__, __LINE__, (condition) == true, #condition, message) +#define assert_fault(message) __codal_fault__(__FILENAME__, __LINE__, message) +#define assert_pass(message) __codal_assert_pass__(__FILENAME__, __LINE__, message) +#define assert_fail(message) __codal_assert_fail__(__FILENAME__, __LINE__, message) #else - #define assert(x,y) - #define assert_fault(message) - #define assert_pass(message) - #define assert_fail(message) +#define assert(x, y) +#define assert_fault(message) +#define assert_pass(message) +#define assert_fail(message) #endif #endif \ No newline at end of file diff --git a/inc/core/CodalCompat.h b/inc/core/CodalCompat.h index 1f429b16..723e232c 100644 --- a/inc/core/CodalCompat.h +++ b/inc/core/CodalCompat.h @@ -23,9 +23,9 @@ DEALINGS IN THE SOFTWARE. */ /** - * This file contains functions used to maintain compatability and portability. - * It also contains constants that are used elsewhere in the DAL. - */ + * This file contains functions used to maintain compatability and portability. + * It also contains constants that are used elsewhere in the DAL. + */ #ifndef DEVICE_COMPAT_H #define DEVICE_COMPAT_H @@ -40,123 +40,122 @@ DEALINGS IN THE SOFTWARE. #undef min #undef max -namespace codal +namespace codal { +/** + * Determines the smallest of the two numbers + * + * @param a the first number + * + * @param b the second number + * + * @return The smallest of the two given values. + */ +inline int min(int a, int b) +{ + return (a < b ? a : b); +} + +/** + * Determines the largest of the two numbers + * + * @param a the first number + * + * @param b the second number + * + * @return The larger of the two given values. + */ +inline int max(int a, int b) { - /** - * Determines the smallest of the two numbers - * - * @param a the first number - * - * @param b the second number - * - * @return The smallest of the two given values. - */ - inline int min(int a, int b) - { - return (a < b ? a : b); - } - - /** - * Determines the largest of the two numbers - * - * @param a the first number - * - * @param b the second number - * - * @return The larger of the two given values. - */ - inline int max(int a, int b) - { - return (a > b ? a : b); - } - - /** - * Sets a given area of memory to zero. - * - * @param a the pointer to the beginning of the memory to clear - * - * @param b the number of bytes to clear. - */ - inline void *memclr(void *a, size_t b) - { - return memset(a,0,b); - } - - /** - * Determines if the given character is a printable ASCII/UTF8 decimal digit (0..9). - * - * @param c the character to check - * - * @return true if the character is a digit, false otherwise. - */ - inline bool isdigit(char c) - { - return (c > 47 && c < 58); - } - - /** - * Extracts the upper 8 bits of a 16 bit integer - * - * @param val the 16 bit value. - * - * @return the upper 8 bits of the given val. - */ - inline uint8_t high(uint16_t val) - { - return val >> 8; - } - - /** - * Extracts the lower 8 bits of a 16 bit integer - * - * @param val the 16 bit value. - * - * @return the lower 8 bits of the given val. - */ - inline uint8_t low(uint16_t val) - { - return val & 0xFF; - } - - /** - * Performs an in buffer reverse of a given char array. - * - * @param s the string to reverse. - * - * @return DEVICE_OK, or DEVICE_INVALID_PARAMETER. - */ - int string_reverse(char *s); - - /** - * Converts a given integer into a string representation. - * - * @param n The number to convert. - * - * @param s A pointer to the buffer where the resulting string will be stored. - * - * @return DEVICE_OK, or DEVICE_INVALID_PARAMETER. - */ - int itoa(int n, char *s); - - /** - * Seed the random number generator (RNG). - * - * @param seed an unsigned 32 bit value used to seed codal's lightweight Galois LFSR. - * @return DEVICE_OK on success - */ - int seed_random(uint32_t random); - - /** - * Generate a random number in the given range. - * default: A simple Galois LFSR random number generator. - * A well seeded Galois LFSR is sufficient for most applications, and much more lightweight - * than hardware random number generators often built int processor, which takes - * a long time and uses a lot of energy. - * - * @param max the upper range to generate a number for. This number cannot be negative. - * @return A random, natural number between 0 and the max-1. Or DEVICE_INVALID_VALUE if max is <= 0. - */ - int random(int max); + return (a > b ? a : b); } +/** + * Sets a given area of memory to zero. + * + * @param a the pointer to the beginning of the memory to clear + * + * @param b the number of bytes to clear. + */ +inline void* memclr(void* a, size_t b) +{ + return memset(a, 0, b); +} + +/** + * Determines if the given character is a printable ASCII/UTF8 decimal digit (0..9). + * + * @param c the character to check + * + * @return true if the character is a digit, false otherwise. + */ +inline bool isdigit(char c) +{ + return (c > 47 && c < 58); +} + +/** + * Extracts the upper 8 bits of a 16 bit integer + * + * @param val the 16 bit value. + * + * @return the upper 8 bits of the given val. + */ +inline uint8_t high(uint16_t val) +{ + return val >> 8; +} + +/** + * Extracts the lower 8 bits of a 16 bit integer + * + * @param val the 16 bit value. + * + * @return the lower 8 bits of the given val. + */ +inline uint8_t low(uint16_t val) +{ + return val & 0xFF; +} + +/** + * Performs an in buffer reverse of a given char array. + * + * @param s the string to reverse. + * + * @return DEVICE_OK, or DEVICE_INVALID_PARAMETER. + */ +int string_reverse(char* s); + +/** + * Converts a given integer into a string representation. + * + * @param n The number to convert. + * + * @param s A pointer to the buffer where the resulting string will be stored. + * + * @return DEVICE_OK, or DEVICE_INVALID_PARAMETER. + */ +int itoa(int n, char* s); + +/** + * Seed the random number generator (RNG). + * + * @param seed an unsigned 32 bit value used to seed codal's lightweight Galois LFSR. + * @return DEVICE_OK on success + */ +int seed_random(uint32_t random); + +/** + * Generate a random number in the given range. + * default: A simple Galois LFSR random number generator. + * A well seeded Galois LFSR is sufficient for most applications, and much more lightweight + * than hardware random number generators often built int processor, which takes + * a long time and uses a lot of energy. + * + * @param max the upper range to generate a number for. This number cannot be negative. + * @return A random, natural number between 0 and the max-1. Or DEVICE_INVALID_VALUE if max is <= 0. + */ +int random(int max); +} // namespace codal + #endif diff --git a/inc/core/CodalComponent.h b/inc/core/CodalComponent.h index ec1755d5..0732364c 100644 --- a/inc/core/CodalComponent.h +++ b/inc/core/CodalComponent.h @@ -30,48 +30,48 @@ DEALINGS IN THE SOFTWARE. #include "ErrorNo.h" // Enumeration of core components. -#define DEVICE_ID_BUTTON_A 1 // IDs used by commonly used components. Used by convention. -#define DEVICE_ID_BUTTON_B 2 -#define DEVICE_ID_BUTTON_AB 3 -#define DEVICE_ID_BUTTON_RESET 4 -#define DEVICE_ID_ACCELEROMETER 5 -#define DEVICE_ID_COMPASS 6 -#define DEVICE_ID_DISPLAY 7 -#define DEVICE_ID_THERMOMETER 8 -#define DEVICE_ID_RADIO 9 -#define DEVICE_ID_RADIO_DATA_READY 10 -#define DEVICE_ID_MULTIBUTTON_ATTACH 11 -#define DEVICE_ID_SERIAL 12 -#define DEVICE_ID_GESTURE 13 -#define DEVICE_ID_SYSTEM_TIMER 14 -#define DEVICE_ID_SCHEDULER 15 -#define DEVICE_ID_COMPONENT 16 -#define DEVICE_ID_LIGHT_SENSOR 17 -#define DEVICE_ID_TOUCH_SENSOR 18 -#define DEVICE_ID_SYSTEM_DAC 19 -#define DEVICE_ID_SYSTEM_MICROPHONE 20 -#define DEVICE_ID_SYSTEM_LEVEL_DETECTOR 21 +#define DEVICE_ID_BUTTON_A 1 // IDs used by commonly used components. Used by convention. +#define DEVICE_ID_BUTTON_B 2 +#define DEVICE_ID_BUTTON_AB 3 +#define DEVICE_ID_BUTTON_RESET 4 +#define DEVICE_ID_ACCELEROMETER 5 +#define DEVICE_ID_COMPASS 6 +#define DEVICE_ID_DISPLAY 7 +#define DEVICE_ID_THERMOMETER 8 +#define DEVICE_ID_RADIO 9 +#define DEVICE_ID_RADIO_DATA_READY 10 +#define DEVICE_ID_MULTIBUTTON_ATTACH 11 +#define DEVICE_ID_SERIAL 12 +#define DEVICE_ID_GESTURE 13 +#define DEVICE_ID_SYSTEM_TIMER 14 +#define DEVICE_ID_SCHEDULER 15 +#define DEVICE_ID_COMPONENT 16 +#define DEVICE_ID_LIGHT_SENSOR 17 +#define DEVICE_ID_TOUCH_SENSOR 18 +#define DEVICE_ID_SYSTEM_DAC 19 +#define DEVICE_ID_SYSTEM_MICROPHONE 20 +#define DEVICE_ID_SYSTEM_LEVEL_DETECTOR 21 #define DEVICE_ID_SYSTEM_LEVEL_DETECTOR_SPL 22 -#define DEVICE_ID_MSC 23 -#define DEVICE_ID_SPI 24 - -#define DEVICE_ID_DISTANCE 25 -#define DEVICE_ID_GYROSCOPE 26 -#define DEVICE_ID_HUMIDITY 27 -#define DEVICE_ID_PRESSURE 28 - -#define DEVICE_ID_SINGLE_WIRE_SERIAL 29 -#define DEVICE_ID_JACDAC 30 -#define DEVICE_ID_JACDAC_PHYS 31 -#define DEVICE_ID_JACDAC_CONTROL_SERVICE 32 +#define DEVICE_ID_MSC 23 +#define DEVICE_ID_SPI 24 + +#define DEVICE_ID_DISTANCE 25 +#define DEVICE_ID_GYROSCOPE 26 +#define DEVICE_ID_HUMIDITY 27 +#define DEVICE_ID_PRESSURE 28 + +#define DEVICE_ID_SINGLE_WIRE_SERIAL 29 +#define DEVICE_ID_JACDAC 30 +#define DEVICE_ID_JACDAC_PHYS 31 +#define DEVICE_ID_JACDAC_CONTROL_SERVICE 32 #define DEVICE_ID_JACDAC_CONFIGURATION_SERVICE 33 -#define DEVICE_ID_SYSTEM_ADC 34 -#define DEVICE_ID_PULSE_IN 35 -#define DEVICE_ID_USB 36 -#define DEVICE_ID_SPLITTER 37 -#define DEVICE_ID_AUDIO_PROCESSOR 38 -#define DEVICE_ID_TAP 39 -#define DEVICE_ID_POWER_MANAGER 40 +#define DEVICE_ID_SYSTEM_ADC 34 +#define DEVICE_ID_PULSE_IN 35 +#define DEVICE_ID_USB 36 +#define DEVICE_ID_SPLITTER 37 +#define DEVICE_ID_AUDIO_PROCESSOR 38 +#define DEVICE_ID_TAP 39 +#define DEVICE_ID_POWER_MANAGER 40 // Slightly dubious IDs, moved here for now to remove conflicts #define DEVICE_ID_PARTIAL_FLASHING 41 @@ -84,15 +84,16 @@ DEALINGS IN THE SOFTWARE. // Range 80-99 - RESERVED (deprecated space, do not use!) -#define DEVICE_ID_IO_P0 100 // IDs 100-227 are reserved for I/O Pin IDs. +#define DEVICE_ID_IO_P0 100 // IDs 100-227 are reserved for I/O Pin IDs. -#define DEVICE_ID_MESSAGE_BUS_LISTENER 1021 // Message bus indication that a handler for a given ID has been registered. -#define DEVICE_ID_NOTIFY_ONE 1022 // Notfication channel, for general purpose synchronisation -#define DEVICE_ID_NOTIFY 1023 // Notfication channel, for general purpose synchronisation +#define DEVICE_ID_MESSAGE_BUS_LISTENER \ + 1021 // Message bus indication that a handler for a given ID has been registered. +#define DEVICE_ID_NOTIFY_ONE 1022 // Notfication channel, for general purpose synchronisation +#define DEVICE_ID_NOTIFY 1023 // Notfication channel, for general purpose synchronisation -#define DEVICE_ID_BUTTON_UP 2000 -#define DEVICE_ID_BUTTON_DOWN 2001 -#define DEVICE_ID_BUTTON_LEFT 2002 +#define DEVICE_ID_BUTTON_UP 2000 +#define DEVICE_ID_BUTTON_DOWN 2001 +#define DEVICE_ID_BUTTON_LEFT 2002 #define DEVICE_ID_BUTTON_RIGHT 2003 // jacadac reserved from 3000 - 4000 @@ -103,163 +104,159 @@ DEALINGS IN THE SOFTWARE. #define DEVICE_ID_DYNAMIC_MAX 65000 // Universal flags used as part of the status field -#define DEVICE_COMPONENT_RUNNING 0x1000 +#define DEVICE_COMPONENT_RUNNING 0x1000 -#define DEVICE_COMPONENT_STATUS_SYSTEM_TICK 0x2000 -#define DEVICE_COMPONENT_STATUS_IDLE_TICK 0x4000 +#define DEVICE_COMPONENT_STATUS_SYSTEM_TICK 0x2000 +#define DEVICE_COMPONENT_STATUS_IDLE_TICK 0x4000 -#define DEVICE_COMPONENT_LISTENERS_CONFIGURED 0x01 +#define DEVICE_COMPONENT_LISTENERS_CONFIGURED 0x01 -#define DEVICE_COMPONENT_EVT_SYSTEM_TICK 1 +#define DEVICE_COMPONENT_EVT_SYSTEM_TICK 1 /** - * Class definition for CodalComponent. - * - * All components should inherit from this class. - * - * If a component requires regular updates, then that component can be added to the - * to the periodicCallback and/or idleCallback queues. This provides a simple, extensible mechanism - * for code that requires periodic/occasional background processing but does not warrant - * the complexity of maintaining its own thread. - * - * Two levels of support are available. - * - * periodicCallback() provides a periodic callback during the - * codal device's system timer interrupt. This provides a guaranteed periodic callback, but in interrupt context - * and is suitable for code with lightweight processing requirements, but strict time constraints. - * - * idleCallback() provides a periodic callback whenever the scheduler is idle. This provides occasional, callbacks - * in the main thread context, but with no guarantees of frequency. This is suitable for non-urgent background tasks. - * - * Components wishing to use these facilities should override the periodicCallback and/or idleCallback functions defined here, and - * register their components using system_timer_add_component() fiber_add_idle_component() respectively. - * - */ -namespace codal -{ - class CodalComponent + * Class definition for CodalComponent. + * + * All components should inherit from this class. + * + * If a component requires regular updates, then that component can be added to the + * to the periodicCallback and/or idleCallback queues. This provides a simple, extensible mechanism + * for code that requires periodic/occasional background processing but does not warrant + * the complexity of maintaining its own thread. + * + * Two levels of support are available. + * + * periodicCallback() provides a periodic callback during the + * codal device's system timer interrupt. This provides a guaranteed periodic callback, but in interrupt context + * and is suitable for code with lightweight processing requirements, but strict time constraints. + * + * idleCallback() provides a periodic callback whenever the scheduler is idle. This provides occasional, callbacks + * in the main thread context, but with no guarantees of frequency. This is suitable for non-urgent background tasks. + * + * Components wishing to use these facilities should override the periodicCallback and/or idleCallback functions defined + * here, and register their components using system_timer_add_component() fiber_add_idle_component() respectively. + * + */ +namespace codal { +class CodalComponent { + static uint8_t configuration; + + public: + /** + * @brief Generates a new component ID from the dynamic block. + * + * There are some cases where multiple instances of the same component need unique IDs, this + * static method allows application code to request a safe (unused) globally unique ID for + * this purpose. + * + * This currently creates monotonically incrementing IDs, with no reuse. When they're gone + * they're gone! + * + * @note While currently monotonic, this may change in the future for more complex schemes. + * + * @note The dynamic block is a finite resource, and may eventually be exhausted causing a PANIC. + * + * @return uint16_t A new, unique component ID, until the ID space is exhausted. + */ + static uint16_t generateDynamicID(); + + /** + * Adds the current CodalComponent instance to our array of components. + */ + void addComponent(); + + /** + * Removes the current CodalComponent instance from our array of components. + */ + void removeComponent(); + + static CodalComponent* components[DEVICE_COMPONENT_COUNT]; + + uint16_t id; // Event Bus ID of this component + uint16_t status; // Component defined state. + + /** + * The default constructor of a CodalComponent + */ + CodalComponent() { - static uint8_t configuration; - - public: - /** - * @brief Generates a new component ID from the dynamic block. - * - * There are some cases where multiple instances of the same component need unique IDs, this - * static method allows application code to request a safe (unused) globally unique ID for - * this purpose. - * - * This currently creates monotonically incrementing IDs, with no reuse. When they're gone - * they're gone! - * - * @note While currently monotonic, this may change in the future for more complex schemes. - * - * @note The dynamic block is a finite resource, and may eventually be exhausted causing a PANIC. - * - * @return uint16_t A new, unique component ID, until the ID space is exhausted. - */ - static uint16_t generateDynamicID(); - - /** - * Adds the current CodalComponent instance to our array of components. - */ - void addComponent(); - - /** - * Removes the current CodalComponent instance from our array of components. - */ - void removeComponent(); - - static CodalComponent* components[DEVICE_COMPONENT_COUNT]; - - uint16_t id; // Event Bus ID of this component - uint16_t status; // Component defined state. - - /** - * The default constructor of a CodalComponent - */ - CodalComponent() - { - this->id = 0; - this->status = 0; - - addComponent(); - } - - CodalComponent(uint16_t id, uint16_t status) - { - this->id = id; - this->status = status; - - addComponent(); - } - - /** - * Implement this function to receive a function call after the devices' - * device model has been instantiated. - */ - virtual int init() { return DEVICE_NOT_SUPPORTED; } - - /** - * Implement this function to receive a callback every SCHEDULER_TICK_PERIOD_MS. - */ - virtual void periodicCallback() {} - - /** - * Implement this function to receive a callback when the device is idling. - */ - virtual void idleCallback() {} - - /** - * Puts the component in (or out of) sleep (low power) mode. - */ - virtual int setSleep(bool doSleep) { return DEVICE_NOT_SUPPORTED; } - - /** - * Puts all components in (or out of) sleep (low power) mode. - */ - static void setAllSleep(bool doSleep); - - typedef enum deepSleepCallbackReason - { - deepSleepCallbackPrepare, //Prepare for sleep - deepSleepCallbackBegin, //Puts the component in sleep (low power) mode. - deepSleepCallbackBeginWithWakeUps, //and enable wake-up sources - deepSleepCallbackEnd, //Brings the component out of sleep (low power) mode. - deepSleepCallbackEndWithWakeUps, //and disable wake-up sources - deepSleepCallbackCountWakeUps, //Count deep sleep wake-up sources. - deepSleepCallbackClearWakeUps //Clear deep sleep wake up sources - } deepSleepCallbackReason; - - typedef struct deepSleepCallbackData - { - int count; - - void init() { count = 0; } - - deepSleepCallbackData() { init(); } - } deepSleepCallbackData; - - /** - * Perform functions related to deep sleep. - */ - virtual int deepSleepCallback( deepSleepCallbackReason reason, deepSleepCallbackData *data); - - /** - * Perform functions related to deep sleep. - */ - static void deepSleepAll( deepSleepCallbackReason reason, deepSleepCallbackData *data); - - /** - * If you have added your component to the idle or system tick component arrays, - * you must remember to remove your component from them if your component is destructed. - */ - virtual ~CodalComponent() - { - status = 0; - removeComponent(); - } - }; -} + this->id = 0; + this->status = 0; + + addComponent(); + } + + CodalComponent(uint16_t id, uint16_t status) + { + this->id = id; + this->status = status; + + addComponent(); + } + + /** + * Implement this function to receive a function call after the devices' + * device model has been instantiated. + */ + virtual int init() { return DEVICE_NOT_SUPPORTED; } + + /** + * Implement this function to receive a callback every SCHEDULER_TICK_PERIOD_MS. + */ + virtual void periodicCallback() {} + + /** + * Implement this function to receive a callback when the device is idling. + */ + virtual void idleCallback() {} + + /** + * Puts the component in (or out of) sleep (low power) mode. + */ + virtual int setSleep(bool doSleep) { return DEVICE_NOT_SUPPORTED; } + + /** + * Puts all components in (or out of) sleep (low power) mode. + */ + static void setAllSleep(bool doSleep); + + typedef enum deepSleepCallbackReason { + deepSleepCallbackPrepare, // Prepare for sleep + deepSleepCallbackBegin, // Puts the component in sleep (low power) mode. + deepSleepCallbackBeginWithWakeUps, // and enable wake-up sources + deepSleepCallbackEnd, // Brings the component out of sleep (low power) mode. + deepSleepCallbackEndWithWakeUps, // and disable wake-up sources + deepSleepCallbackCountWakeUps, // Count deep sleep wake-up sources. + deepSleepCallbackClearWakeUps // Clear deep sleep wake up sources + } deepSleepCallbackReason; + + typedef struct deepSleepCallbackData { + int count; + + void init() { count = 0; } + + deepSleepCallbackData() { init(); } + } deepSleepCallbackData; + + /** + * Perform functions related to deep sleep. + */ + virtual int deepSleepCallback(deepSleepCallbackReason reason, deepSleepCallbackData* data); + + /** + * Perform functions related to deep sleep. + */ + static void deepSleepAll(deepSleepCallbackReason reason, deepSleepCallbackData* data); + + /** + * If you have added your component to the idle or system tick component arrays, + * you must remember to remove your component from them if your component is destructed. + */ + virtual ~CodalComponent() + { + status = 0; + removeComponent(); + } +}; +} // namespace codal #endif diff --git a/inc/core/CodalConfig.h b/inc/core/CodalConfig.h index af76a3ae..1944615f 100644 --- a/inc/core/CodalConfig.h +++ b/inc/core/CodalConfig.h @@ -23,8 +23,8 @@ DEALINGS IN THE SOFTWARE. */ /** - * Compile time configuration options for the codal device runtime. - */ + * Compile time configuration options for the codal device runtime. + */ #ifndef CODAL_CONFIG_H #define CODAL_CONFIG_H @@ -36,26 +36,24 @@ DEALINGS IN THE SOFTWARE. // 2: Heap allocaion diagnostics // #ifndef CODAL_DEBUG_DISABLED -#define CODAL_DEBUG_DISABLED 0 -#define CODAL_DEBUG_DIAGNOSTICS 1 -#define CODAL_DEBUG_HEAP 2 +#define CODAL_DEBUG_DISABLED 0 +#define CODAL_DEBUG_DIAGNOSTICS 1 +#define CODAL_DEBUG_HEAP 2 #endif +#define CODAL_ASSERT(cond, panic_num) \ + { \ + if (!(cond)) target_panic(panic_num); \ + } -#define CODAL_ASSERT(cond, panic_num) {\ - if (!(cond)) \ - target_panic(panic_num);\ -} - - -#include "platform_includes.h" #include "codal_version.h" +#include "platform_includes.h" // Enables or disables the DeviceHeapllocator. Note that if disabled, no reuse of the SRAM normally // reserved for SoftDevice is possible, and out of memory condition will no longer be trapped... // i.e. panic() will no longer be triggered on memory full conditions. #ifndef DEVICE_HEAP_ALLOCATOR -#define DEVICE_HEAP_ALLOCATOR 1 +#define DEVICE_HEAP_ALLOCATOR 1 #endif // @@ -64,17 +62,17 @@ DEALINGS IN THE SOFTWARE. // n.b. Setting this option to '1' will also optimise the heap allocator for code space. // #ifndef DEVICE_MAXIMUM_HEAPS -#define DEVICE_MAXIMUM_HEAPS 1 +#define DEVICE_MAXIMUM_HEAPS 1 #endif // If enabled, RefCounted objects include a constant tag at the beginning. // Set '1' to enable. #ifndef DEVICE_TAG -#define DEVICE_TAG 0 +#define DEVICE_TAG 0 #endif #ifndef CODAL_TIMESTAMP -#define CODAL_TIMESTAMP uint32_t +#define CODAL_TIMESTAMP uint32_t #endif // @@ -82,10 +80,9 @@ DEALINGS IN THE SOFTWARE. // risk of a race condition. Can be overridden in a target config.json. // #ifndef CODAL_TIMER_MINIMUM_PERIOD -#define CODAL_TIMER_MINIMUM_PERIOD 10 +#define CODAL_TIMER_MINIMUM_PERIOD 10 #endif - // // Fiber scheduler configuration // @@ -93,11 +90,11 @@ DEALINGS IN THE SOFTWARE. // Scheduling quantum (milliseconds) // Also used to drive the codal device runtime system ticker. #ifndef SCHEDULER_TICK_PERIOD_US -#define SCHEDULER_TICK_PERIOD_US 6000 +#define SCHEDULER_TICK_PERIOD_US 6000 #endif #ifndef DEVICE_FIBER_USER_DATA -#define DEVICE_FIBER_USER_DATA 1 +#define DEVICE_FIBER_USER_DATA 1 #endif // @@ -111,7 +108,7 @@ DEALINGS IN THE SOFTWARE. // MESSAGE_BUS_LISTENER_IMMEDIATE #ifndef EVENT_LISTENER_DEFAULT_FLAGS -#define EVENT_LISTENER_DEFAULT_FLAGS MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY +#define EVENT_LISTENER_DEFAULT_FLAGS MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY #endif // @@ -119,26 +116,26 @@ DEALINGS IN THE SOFTWARE. // Used to prevent message queues growing uncontrollably due to badly behaved user code and causing panic conditions. // #ifndef MESSAGE_BUS_LISTENER_MAX_QUEUE_DEPTH -#define MESSAGE_BUS_LISTENER_MAX_QUEUE_DEPTH 10 +#define MESSAGE_BUS_LISTENER_MAX_QUEUE_DEPTH 10 #endif -//Configures the default serial mode used by serial read and send calls. +// Configures the default serial mode used by serial read and send calls. #ifndef DEVICE_DEFAULT_SERIAL_MODE -#define DEVICE_DEFAULT_SERIAL_MODE SYNC_SLEEP +#define DEVICE_DEFAULT_SERIAL_MODE SYNC_SLEEP #endif // // I/O Options // #ifndef DEVICE_COMPONENT_COUNT -#define DEVICE_COMPONENT_COUNT 100 +#define DEVICE_COMPONENT_COUNT 100 #endif // // Define the default mode in which the digital input pins are configured. // valid options are PullDown, PullUp and PullNone. // #ifndef DEVICE_DEFAULT_PULLMODE -#define DEVICE_DEFAULT_PULLMODE PullMode::None +#define DEVICE_DEFAULT_PULLMODE PullMode::None #endif // @@ -148,38 +145,38 @@ DEALINGS IN THE SOFTWARE. // Enable this to invoke a panic on out of memory conditions. // Set '1' to enable. #ifndef DEVICE_PANIC_HEAP_FULL -#define DEVICE_PANIC_HEAP_FULL 1 +#define DEVICE_PANIC_HEAP_FULL 1 #endif // // Debug options // #ifndef DMESG_SERIAL_DEBUG - #define DMESG_SERIAL_DEBUG 0 +#define DMESG_SERIAL_DEBUG 0 #else - // Automatically enable DMESG_ENABLE if DMESG_SERIAL_DEBUG is set - #if DMESG_SERIAL_DEBUG > 0 - #define DMESG_ENABLE 1 - #endif +// Automatically enable DMESG_ENABLE if DMESG_SERIAL_DEBUG is set +#if DMESG_SERIAL_DEBUG > 0 +#define DMESG_ENABLE 1 +#endif #endif #ifndef DMESG_ENABLE -#define DMESG_ENABLE 0 +#define DMESG_ENABLE 0 #endif // When non-zero internal debug messages (DMESG() macro) go to a in-memory buffer of this size (in bytes). // It can be inspected from GDB (with 'print codalLogStore'), or accessed by the application. // Typical size range between 512 and 4096. Set to 0 to disable. #ifndef DEVICE_DMESG_BUFFER_SIZE - #if DMESG_ENABLE > 0 - #define DEVICE_DMESG_BUFFER_SIZE 1024 - #else - #define DEVICE_DMESG_BUFFER_SIZE 0 - #endif +#if DMESG_ENABLE > 0 +#define DEVICE_DMESG_BUFFER_SIZE 1024 +#else +#define DEVICE_DMESG_BUFFER_SIZE 0 +#endif #endif #ifndef CODAL_DEBUG -#define CODAL_DEBUG CODAL_DEBUG_DISABLED +#define CODAL_DEBUG CODAL_DEBUG_DISABLED #endif // When set to '1', this option enables parameter validation checking into low level system modules @@ -187,7 +184,7 @@ DEALINGS IN THE SOFTWARE. // lower code size and faster operation of low level component. // #ifndef CODAL_LOW_LEVEL_VALIDATION -#define CODAL_LOW_LEVEL_VALIDATION 0 +#define CODAL_LOW_LEVEL_VALIDATION 0 #endif // Versioning options. @@ -195,24 +192,24 @@ DEALINGS IN THE SOFTWARE. // if this isn't available, it can be defined manually as a configuration option. // #ifndef DEVICE_DAL_VERSION - #ifdef CODAL_VERSION - #define DEVICE_DAL_VERSION CODAL_VERSION - #else - #define DEVICE_DAL_VERSION "unknown" - #endif +#ifdef CODAL_VERSION +#define DEVICE_DAL_VERSION CODAL_VERSION +#else +#define DEVICE_DAL_VERSION "unknown" +#endif #endif #ifndef DEVICE_USB -#define DEVICE_USB 0 +#define DEVICE_USB 0 #endif // If USB enabled, also enable WebUSB by default #ifndef DEVICE_WEBUSB -#define DEVICE_WEBUSB 1 +#define DEVICE_WEBUSB 1 #endif #ifndef CODAL_PROVIDE_PRINTF -#define CODAL_PROVIDE_PRINTF 1 +#define CODAL_PROVIDE_PRINTF 1 #endif // @@ -221,11 +218,11 @@ DEALINGS IN THE SOFTWARE. // Do not set this to less than 2, otherwise events will spuriously trigger #ifndef CODAL_DATASTREAM_HIGH_WATER_MARK - #define CODAL_DATASTREAM_HIGH_WATER_MARK 4 +#define CODAL_DATASTREAM_HIGH_WATER_MARK 4 #endif #ifndef CODAL_STREAM_IDLE_TIMEOUT_MS - #define CODAL_STREAM_IDLE_TIMEOUT_MS 75 +#define CODAL_STREAM_IDLE_TIMEOUT_MS 75 #endif // During early CODAL development there was some misuse of `using namespace codal;` in header files. @@ -234,13 +231,13 @@ DEALINGS IN THE SOFTWARE. // This global namespace can be a problem when using CODAL together with other libraries/frameworks. // So we can use this flag to enable/disable whether to use the codal namespace globally or not. #ifndef CODAL_USE_GLOBAL_NAMESPACE - #define CODAL_USE_GLOBAL_NAMESPACE 1 +#define CODAL_USE_GLOBAL_NAMESPACE 1 #endif // // Helper macro used by the codal device runtime to determine if a boolean configuration option is set. // -#define CONFIG_ENABLED(X) (X == 1) +#define CONFIG_ENABLED(X) (X == 1) #define CONFIG_DISABLED(X) (X != 1) #if CONFIG_ENABLED(DEVICE_DBG) diff --git a/inc/core/CodalDevice.h b/inc/core/CodalDevice.h index a81b4fb8..6f5d1fe5 100644 --- a/inc/core/CodalDevice.h +++ b/inc/core/CodalDevice.h @@ -26,119 +26,94 @@ DEALINGS IN THE SOFTWARE. #define CODAL_DEVICE_H #include "CodalConfig.h" +#include "CodalFiber.h" #include "ErrorNo.h" #include "codal_target_hal.h" -#include "CodalFiber.h" /** - * Class definition for CodalDevice. - * - * All devices should inherit from this class, and override any of the methods below - * to provide define core functionality needed by codal. - * - */ -namespace codal -{ - class CodalDevice - { - public: - - /** - * The default constructor of a DeviceComponent - */ - CodalDevice() - { - } - - /** - * Perform a hard reset of the device. - * default: Use CMSIS NVIC reset vector. - */ - virtual void reset() - { - target_reset(); - } - - /** - * Delay execution for the given amount of time. - * - * If the scheduler is running, this will deschedule the current fiber and perform - * a power efficient, concurrent sleep operation. - * - * If the scheduler is disabled or we're running in an interrupt context, this - * will revert to a busy wait. - * - * Alternatively: wait, wait_ms, wait_us can be used which will perform a blocking sleep - * operation. - * - * @param milliseconds the amount of time, in ms, to wait for. This number cannot be negative. - */ - virtual void sleep(unsigned long milliseconds); - - /** - * A blocking pause without using the fiber scheduler - * @param milliseconds the time to wait in milliseconds - */ - virtual void wait(uint32_t milliseconds) - { - target_wait(milliseconds); - } - - /** - * Determine the version of system software currently running. - * default: The version of the codal runtime being used. - * @return a pointer to a NULL terminated character buffer containing a representation of the current version using semantic versioning. - */ - virtual const char * - getVersion() - { - return DEVICE_DAL_VERSION; - } - - /** - * Determines a unique 32 bit ID for this device, if provided by the hardware. - * @return A 32 bit unique identifier. - */ - virtual uint64_t getSerialNumber() - { - return target_get_serial(); - } - - /** - * Default: Disables all interrupts and user processing and periodically outputs the status code over the default USB serial port. - * @param statusCode the appropriate status code, must be in the range 0-999. - */ - virtual void panic(int statusCode) - { - target_panic(statusCode); - } - - /** - * Generate a random number in the given range. - * default: A simple Galois LFSR random number generator. - * A well seeded Galois LFSR is sufficient for most applications, and much more lightweight - * than hardware random number generators often built int processor, which takes - * a long time and uses a lot of energy. - * - * @param max the upper range to generate a number for. This number cannot be negative. - * @return A random, natural number between 0 and the max-1. Or DEVICE_INVALID_VALUE if max is <= 0. - */ - int random(int max) - { - return target_random(max); - } - - /** - * Seed the random number generator (RNG). - * - * @param seed an unsigned 32 bit value used to seed codal's lightweight Galois LFSR. - * @return DEVICE_OK on success - */ - virtual int seedRandom(uint32_t seed) - { - return target_seed_random(seed); - } - }; -} + * Class definition for CodalDevice. + * + * All devices should inherit from this class, and override any of the methods below + * to provide define core functionality needed by codal. + * + */ +namespace codal { +class CodalDevice { + public: + /** + * The default constructor of a DeviceComponent + */ + CodalDevice() {} + + /** + * Perform a hard reset of the device. + * default: Use CMSIS NVIC reset vector. + */ + virtual void reset() { target_reset(); } + + /** + * Delay execution for the given amount of time. + * + * If the scheduler is running, this will deschedule the current fiber and perform + * a power efficient, concurrent sleep operation. + * + * If the scheduler is disabled or we're running in an interrupt context, this + * will revert to a busy wait. + * + * Alternatively: wait, wait_ms, wait_us can be used which will perform a blocking sleep + * operation. + * + * @param milliseconds the amount of time, in ms, to wait for. This number cannot be negative. + */ + virtual void sleep(unsigned long milliseconds); + + /** + * A blocking pause without using the fiber scheduler + * @param milliseconds the time to wait in milliseconds + */ + virtual void wait(uint32_t milliseconds) { target_wait(milliseconds); } + + /** + * Determine the version of system software currently running. + * default: The version of the codal runtime being used. + * @return a pointer to a NULL terminated character buffer containing a representation of the current version using + * semantic versioning. + */ + virtual const char* getVersion() { return DEVICE_DAL_VERSION; } + + /** + * Determines a unique 32 bit ID for this device, if provided by the hardware. + * @return A 32 bit unique identifier. + */ + virtual uint64_t getSerialNumber() { return target_get_serial(); } + + /** + * Default: Disables all interrupts and user processing and periodically outputs the status code over the default + * USB serial port. + * @param statusCode the appropriate status code, must be in the range 0-999. + */ + virtual void panic(int statusCode) { target_panic(statusCode); } + + /** + * Generate a random number in the given range. + * default: A simple Galois LFSR random number generator. + * A well seeded Galois LFSR is sufficient for most applications, and much more lightweight + * than hardware random number generators often built int processor, which takes + * a long time and uses a lot of energy. + * + * @param max the upper range to generate a number for. This number cannot be negative. + * @return A random, natural number between 0 and the max-1. Or DEVICE_INVALID_VALUE if max is <= 0. + */ + int random(int max) { return target_random(max); } + + /** + * Seed the random number generator (RNG). + * + * @param seed an unsigned 32 bit value used to seed codal's lightweight Galois LFSR. + * @return DEVICE_OK on success + */ + virtual int seedRandom(uint32_t seed) { return target_seed_random(seed); } +}; +} // namespace codal #endif diff --git a/inc/core/CodalDmesg.h b/inc/core/CodalDmesg.h index 2482ddc1..b9e61d41 100644 --- a/inc/core/CodalDmesg.h +++ b/inc/core/CodalDmesg.h @@ -25,9 +25,10 @@ DEALINGS IN THE SOFTWARE. #ifndef CODAL_DMESG_H #define CODAL_DMESG_H -#include "CodalConfig.h" #include +#include "CodalConfig.h" + #if DEVICE_DMESG_BUFFER_SIZE > 0 #if DEVICE_DMESG_BUFFER_SIZE < 256 @@ -38,47 +39,46 @@ DEALINGS IN THE SOFTWARE. extern "C" { #endif -struct CodalLogStore -{ +struct CodalLogStore { uint32_t ptr; char buffer[DEVICE_DMESG_BUFFER_SIZE]; }; extern struct CodalLogStore codalLogStore; /** - * Log formatted message to an internal buffer. - * - * Supported format strings: - * %c - single character - * %d - decimal number - * %x - hexadecimal number (with 0x) - * %p - hexadecimal number padded with zeros (and with 0x) - * %X - hexadecimal number padded with zeros (and with 0x) - * %s - '\0'-terminated string - * %% - literal % - * Typically used via the DMESG() macro. - * - * @param format Format string - * - * @code - * uint32_t k; - * void *ptr; - * ... - * DMESG("USB: Error #%d at %X", k, ptr); - * @endcode - */ -void codal_dmesg(const char *format, ...); -void codal_dmesg_nocrlf(const char *format, ...); -void codal_dmesg_with_flush(const char *format, ...); + * Log formatted message to an internal buffer. + * + * Supported format strings: + * %c - single character + * %d - decimal number + * %x - hexadecimal number (with 0x) + * %p - hexadecimal number padded with zeros (and with 0x) + * %X - hexadecimal number padded with zeros (and with 0x) + * %s - '\0'-terminated string + * %% - literal % + * Typically used via the DMESG() macro. + * + * @param format Format string + * + * @code + * uint32_t k; + * void *ptr; + * ... + * DMESG("USB: Error #%d at %X", k, ptr); + * @endcode + */ +void codal_dmesg(const char* format, ...); +void codal_dmesg_nocrlf(const char* format, ...); +void codal_dmesg_with_flush(const char* format, ...); void codal_dmesg_set_flush_fn(void (*fn)(void)); void codal_dmesg_flush(); -void codal_vdmesg(const char *format, bool crlf, va_list ap); +void codal_vdmesg(const char* format, bool crlf, va_list ap); -#define DMESG codal_dmesg -#define DMESGN codal_dmesg_nocrlf -#define DMESGF codal_dmesg_with_flush +#define DMESG codal_dmesg +#define DMESGN codal_dmesg_nocrlf +#define DMESGF codal_dmesg_with_flush #ifdef __cplusplus } @@ -86,7 +86,7 @@ void codal_vdmesg(const char *format, bool crlf, va_list ap); #else -#define DMESG(...) ((void)0) +#define DMESG(...) ((void)0) #define DMESGN(...) ((void)0) #define DMESGF(...) ((void)0) diff --git a/inc/core/CodalFiber.h b/inc/core/CodalFiber.h index a64a06cb..f23c9e43 100644 --- a/inc/core/CodalFiber.h +++ b/inc/core/CodalFiber.h @@ -23,16 +23,16 @@ DEALINGS IN THE SOFTWARE. */ /** - * Functionality definitions for the Device Fiber scheduler. - * - * This lightweight, non-preemptive scheduler provides a simple threading mechanism for two main purposes: - * - * 1) To provide a clean abstraction for application languages to use when building async behaviour (callbacks). - * 2) To provide ISR decoupling for EventModel events generated in an ISR context. - * - * TODO: Consider a split mode scheduler, that monitors used stack size, and maintains a dedicated, persistent - * stack for any long lived fibers with large stack - */ + * Functionality definitions for the Device Fiber scheduler. + * + * This lightweight, non-preemptive scheduler provides a simple threading mechanism for two main purposes: + * + * 1) To provide a clean abstraction for application languages to use when building async behaviour (callbacks). + * 2) To provide ISR decoupling for EventModel events generated in an ISR context. + * + * TODO: Consider a split mode scheduler, that monitors used stack size, and maintains a dedicated, persistent + * stack for any long lived fibers with large stack + */ #ifndef CODAL_FIBER_H #define CODAL_FIBER_H @@ -42,370 +42,361 @@ DEALINGS IN THE SOFTWARE. #include "codal_target_hal.h" // Fiber Scheduler Flags -#define DEVICE_SCHEDULER_RUNNING 0x01 -#define DEVICE_SCHEDULER_IDLE 0x02 -#define DEVICE_SCHEDULER_DEEPSLEEP 0x04 +#define DEVICE_SCHEDULER_RUNNING 0x01 +#define DEVICE_SCHEDULER_IDLE 0x02 +#define DEVICE_SCHEDULER_DEEPSLEEP 0x04 // Fiber Flags -#define DEVICE_FIBER_FLAG_FOB 0x01 -#define DEVICE_FIBER_FLAG_PARENT 0x02 -#define DEVICE_FIBER_FLAG_CHILD 0x04 -#define DEVICE_FIBER_FLAG_DO_NOT_PAGE 0x08 +#define DEVICE_FIBER_FLAG_FOB 0x01 +#define DEVICE_FIBER_FLAG_PARENT 0x02 +#define DEVICE_FIBER_FLAG_CHILD 0x04 +#define DEVICE_FIBER_FLAG_DO_NOT_PAGE 0x08 -#define DEVICE_SCHEDULER_EVT_TICK 1 -#define DEVICE_SCHEDULER_EVT_IDLE 2 +#define DEVICE_SCHEDULER_EVT_TICK 1 +#define DEVICE_SCHEDULER_EVT_IDLE 2 -#define DEVICE_GET_FIBER_LIST_AVAILABLE 1 +#define DEVICE_GET_FIBER_LIST_AVAILABLE 1 +namespace codal { +/** + * Representation of a single Fiber + */ +struct Fiber { + void* tcb; // Thread context when last scheduled out. + PROCESSOR_WORD_TYPE + stack_bottom; // The start address of this Fiber's stack. The stack is heap allocated, and full descending. + PROCESSOR_WORD_TYPE stack_top; // The end address of this Fiber's stack. + uint32_t context; // Context specific information. + uint32_t flags; // Information about this fiber. + Fiber** queue; // The queue this fiber is stored on. + Fiber *qnext, *qprev; // Position of this Fiber on the run queue. + Fiber* next; // Position of this Fiber on the global list of fibers. +#if CONFIG_ENABLED(DEVICE_FIBER_USER_DATA) + void* user_data; +#endif +}; -namespace codal -{ - /** - * Representation of a single Fiber - */ - struct Fiber - { - void* tcb; // Thread context when last scheduled out. - PROCESSOR_WORD_TYPE stack_bottom; // The start address of this Fiber's stack. The stack is heap allocated, and full descending. - PROCESSOR_WORD_TYPE stack_top; // The end address of this Fiber's stack. - uint32_t context; // Context specific information. - uint32_t flags; // Information about this fiber. - Fiber **queue; // The queue this fiber is stored on. - Fiber *qnext, *qprev; // Position of this Fiber on the run queue. - Fiber *next; // Position of this Fiber on the global list of fibers. - #if CONFIG_ENABLED(DEVICE_FIBER_USER_DATA) - void *user_data; - #endif - }; - - enum FiberLockMode { - MUTEX = 0, - SEMAPHORE = 1 - }; - - extern Fiber *currentFiber; +enum FiberLockMode { MUTEX = 0, SEMAPHORE = 1 }; - /** - * Initialises the Fiber scheduler. - * Creates a Fiber context around the calling thread, and adds it to the run queue as the current thread. - * - * This function must be called once only from the main thread, and before any other Fiber operation. - * - * @param _messageBus An event model, used to direct the priorities of the scheduler. - */ - void scheduler_init(EventModel &_messageBus); +extern Fiber* currentFiber; - /** - * Determines if the fiber scheduler is operational. - * - * @return 1 if the fiber scheduler is running, 0 otherwise. - */ - int fiber_scheduler_running(); +/** + * Initialises the Fiber scheduler. + * Creates a Fiber context around the calling thread, and adds it to the run queue as the current thread. + * + * This function must be called once only from the main thread, and before any other Fiber operation. + * + * @param _messageBus An event model, used to direct the priorities of the scheduler. + */ +void scheduler_init(EventModel& _messageBus); - /** - * Provides a list of all active fibers. - * - * @return A pointer to the head of the list of all active fibers. - */ - Fiber* get_fiber_list(); +/** + * Determines if the fiber scheduler is operational. + * + * @return 1 if the fiber scheduler is running, 0 otherwise. + */ +int fiber_scheduler_running(); - /** - * Exit point for all fibers. - * - * Any fiber reaching the end of its entry function will return here for recycling. - */ - void release_fiber(void); - void release_fiber(void *param); +/** + * Provides a list of all active fibers. + * + * @return A pointer to the head of the list of all active fibers. + */ +Fiber* get_fiber_list(); - /** - * Launches a fiber. - * - * @param ep the entry point for the fiber. - * - * @param cp the completion routine after ep has finished execution - */ - void launch_new_fiber(void (*ep)(void), void (*cp)(void)) - #ifdef __GCC__ - __attribute__((naked)) - #endif +/** + * Exit point for all fibers. + * + * Any fiber reaching the end of its entry function will return here for recycling. + */ +void release_fiber(void); +void release_fiber(void* param); + +/** + * Launches a fiber. + * + * @param ep the entry point for the fiber. + * + * @param cp the completion routine after ep has finished execution + */ +void launch_new_fiber(void (*ep)(void), void (*cp)(void)) +#ifdef __GCC__ + __attribute__((naked)) +#endif ; - /** - * Launches a fiber with a parameter - * - * @param ep the entry point for the fiber. - * - * @param cp the completion routine after ep has finished execution - * - * @param pm the parameter to provide to ep and cp. - */ - void launch_new_fiber_param(void (*ep)(void *), void (*cp)(void *), void *pm) - #ifdef __GCC__ - __attribute__((naked)) - #endif +/** + * Launches a fiber with a parameter + * + * @param ep the entry point for the fiber. + * + * @param cp the completion routine after ep has finished execution + * + * @param pm the parameter to provide to ep and cp. + */ +void launch_new_fiber_param(void (*ep)(void*), void (*cp)(void*), void* pm) +#ifdef __GCC__ + __attribute__((naked)) +#endif ; - /** - * Creates a new Fiber, and launches it. - * - * @param entry_fn The function the new Fiber will begin execution in. - * - * @param completion_fn The function called when the thread completes execution of entry_fn. - * Defaults to release_fiber. - * - * @return The new Fiber, or NULL if the operation could not be completed. - */ - Fiber *create_fiber(void (*entry_fn)(void), void (*completion_fn)(void) = release_fiber); +/** + * Creates a new Fiber, and launches it. + * + * @param entry_fn The function the new Fiber will begin execution in. + * + * @param completion_fn The function called when the thread completes execution of entry_fn. + * Defaults to release_fiber. + * + * @return The new Fiber, or NULL if the operation could not be completed. + */ +Fiber* create_fiber(void (*entry_fn)(void), void (*completion_fn)(void) = release_fiber); +/** + * Creates a new parameterised Fiber, and launches it. + * + * @param entry_fn The function the new Fiber will begin execution in. + * + * @param param an untyped parameter passed into the entry_fn and completion_fn. + * + * @param completion_fn The function called when the thread completes execution of entry_fn. + * Defaults to release_fiber. + * + * @return The new Fiber, or NULL if the operation could not be completed. + */ +Fiber* create_fiber(void (*entry_fn)(void*), void* param, void (*completion_fn)(void*) = release_fiber); - /** - * Creates a new parameterised Fiber, and launches it. - * - * @param entry_fn The function the new Fiber will begin execution in. - * - * @param param an untyped parameter passed into the entry_fn and completion_fn. - * - * @param completion_fn The function called when the thread completes execution of entry_fn. - * Defaults to release_fiber. - * - * @return The new Fiber, or NULL if the operation could not be completed. - */ - Fiber *create_fiber(void (*entry_fn)(void *), void *param, void (*completion_fn)(void *) = release_fiber); +/** + * Calls the Fiber scheduler. + * The calling Fiber will likely be blocked, and control given to another waiting fiber. + * Call this function to yield control of the processor when you have nothing more to do. + */ +void schedule() +#ifdef __GCC__ + __attribute__((naked)) +#endif + ; +/** + * Blocks the calling thread for the given period of time. + * The calling thread will be immediateley descheduled, and placed onto a + * wait queue until the requested amount of time has elapsed. + * + * @param t The period of time to sleep, in milliseconds. + * + * @note the fiber will not be be made runnable until after the elapsed time, but there + * are no guarantees precisely when the fiber will next be scheduled. + */ +void fiber_sleep(unsigned long t); - /** - * Calls the Fiber scheduler. - * The calling Fiber will likely be blocked, and control given to another waiting fiber. - * Call this function to yield control of the processor when you have nothing more to do. - */ - void schedule() - #ifdef __GCC__ - __attribute__((naked)) - #endif - ; +/** + * The timer callback, called from interrupt context once every SYSTEM_TICK_PERIOD_MS milliseconds. + * This function checks to determine if any fibers blocked on the sleep queue need to be woken up + * and made runnable. + */ +void scheduler_tick(Event); - /** - * Blocks the calling thread for the given period of time. - * The calling thread will be immediateley descheduled, and placed onto a - * wait queue until the requested amount of time has elapsed. - * - * @param t The period of time to sleep, in milliseconds. - * - * @note the fiber will not be be made runnable until after the elapsed time, but there - * are no guarantees precisely when the fiber will next be scheduled. - */ - void fiber_sleep(unsigned long t); +/** + * Blocks the calling thread until the specified event is raised. + * The calling thread will be immediateley descheduled, and placed onto a + * wait queue until the requested event is received. + * + * @param id The ID field of the event to listen for (e.g. DEVICE_ID_BUTTON_A) + * + * @param value The value of the event to listen for (e.g. DEVICE_BUTTON_EVT_CLICK) + * + * @return DEVICE_OK, or DEVICE_NOT_SUPPORTED if the fiber scheduler is not running, or associated with an EventModel. + * + * @code + * fiber_wait_for_event(DEVICE_ID_BUTTON_A, DEVICE_BUTTON_EVT_CLICK); + * @endcode + * + * @note the fiber will not be be made runnable until after the event is raised, but there + * are no guarantees precisely when the fiber will next be scheduled. + */ +int fiber_wait_for_event(uint16_t id, uint16_t value); - /** - * The timer callback, called from interrupt context once every SYSTEM_TICK_PERIOD_MS milliseconds. - * This function checks to determine if any fibers blocked on the sleep queue need to be woken up - * and made runnable. - */ - void scheduler_tick(Event); +/** + * Configures the fiber context for the current fiber to block on an event ID + * and value, but does not deschedule the fiber. + * + * @param id The ID field of the event to listen for (e.g. DEVICE_ID_BUTTON_A) + * + * @param value The value of the event to listen for (e.g. DEVICE_BUTTON_EVT_CLICK) + * + * @return DEVICE_OK, or DEVICE_NOT_SUPPORTED if the fiber scheduler is not running, or associated with an EventModel. + * + * @code + * fiber_wake_on_event(DEVICE_ID_BUTTON_A, DEVICE_BUTTON_EVT_CLICK); + * + * //perform some time critical operation. + * + * //deschedule the current fiber manually, waiting for the previously configured event. + * schedule(); + * @endcode + */ +int fiber_wake_on_event(uint16_t id, uint16_t value); - /** - * Blocks the calling thread until the specified event is raised. - * The calling thread will be immediateley descheduled, and placed onto a - * wait queue until the requested event is received. - * - * @param id The ID field of the event to listen for (e.g. DEVICE_ID_BUTTON_A) - * - * @param value The value of the event to listen for (e.g. DEVICE_BUTTON_EVT_CLICK) - * - * @return DEVICE_OK, or DEVICE_NOT_SUPPORTED if the fiber scheduler is not running, or associated with an EventModel. - * - * @code - * fiber_wait_for_event(DEVICE_ID_BUTTON_A, DEVICE_BUTTON_EVT_CLICK); - * @endcode - * - * @note the fiber will not be be made runnable until after the event is raised, but there - * are no guarantees precisely when the fiber will next be scheduled. - */ - int fiber_wait_for_event(uint16_t id, uint16_t value); +/** + * Executes the given function asynchronously if necessary. + * + * Fibers are often used to run event handlers, however many of these event handlers are very simple functions + * that complete very quickly, bringing unecessary RAM overhead. + * + * This function takes a snapshot of the current processor context, then attempts to optimistically call the given + * function directly. We only create an additional fiber if that function performs a block operation. + * + * @param entry_fn The function to execute. + * + * @return DEVICE_OK, or DEVICE_INVALID_PARAMETER. + */ +int invoke(void (*entry_fn)(void)); - /** - * Configures the fiber context for the current fiber to block on an event ID - * and value, but does not deschedule the fiber. - * - * @param id The ID field of the event to listen for (e.g. DEVICE_ID_BUTTON_A) - * - * @param value The value of the event to listen for (e.g. DEVICE_BUTTON_EVT_CLICK) - * - * @return DEVICE_OK, or DEVICE_NOT_SUPPORTED if the fiber scheduler is not running, or associated with an EventModel. - * - * @code - * fiber_wake_on_event(DEVICE_ID_BUTTON_A, DEVICE_BUTTON_EVT_CLICK); - * - * //perform some time critical operation. - * - * //deschedule the current fiber manually, waiting for the previously configured event. - * schedule(); - * @endcode - */ - int fiber_wake_on_event(uint16_t id, uint16_t value); +/** + * Executes the given function asynchronously if necessary, and offers the ability to provide a parameter. + * + * Fibers are often used to run event handlers, however many of these event handlers are very simple functions + * that complete very quickly, bringing unecessary RAM. overhead + * + * This function takes a snapshot of the current fiber context, then attempt to optimistically call the given function + * directly. We only create an additional fiber if that function performs a block operation. + * + * @param entry_fn The function to execute. + * + * @param param an untyped parameter passed into the entry_fn and completion_fn. + * + * @return DEVICE_OK, or DEVICE_INVALID_PARAMETER. + */ +int invoke(void (*entry_fn)(void*), void* param); - /** - * Executes the given function asynchronously if necessary. - * - * Fibers are often used to run event handlers, however many of these event handlers are very simple functions - * that complete very quickly, bringing unecessary RAM overhead. - * - * This function takes a snapshot of the current processor context, then attempts to optimistically call the given function directly. - * We only create an additional fiber if that function performs a block operation. - * - * @param entry_fn The function to execute. - * - * @return DEVICE_OK, or DEVICE_INVALID_PARAMETER. - */ - int invoke(void (*entry_fn)(void)); +/** + * Resizes the stack allocation of the current fiber if necessary to hold the system stack. + * + * If the stack allocation is large enough to hold the current system stack, then this function does nothing. + * Otherwise, the the current allocation of the fiber is freed, and a larger block is allocated. + * + * @param f The fiber context to verify. + * + * @return The stack depth of the given fiber. + */ +inline void verify_stack_size(Fiber* f); - /** - * Executes the given function asynchronously if necessary, and offers the ability to provide a parameter. - * - * Fibers are often used to run event handlers, however many of these event handlers are very simple functions - * that complete very quickly, bringing unecessary RAM. overhead - * - * This function takes a snapshot of the current fiber context, then attempt to optimistically call the given function directly. - * We only create an additional fiber if that function performs a block operation. - * - * @param entry_fn The function to execute. - * - * @param param an untyped parameter passed into the entry_fn and completion_fn. - * - * @return DEVICE_OK, or DEVICE_INVALID_PARAMETER. - */ - int invoke(void (*entry_fn)(void *), void *param); +/** + * Event callback. Called from an instance of DeviceMessageBus whenever an event is raised. + * + * This function checks to determine if any fibers blocked on the wait queue need to be woken up + * and made runnable due to the event. + * + * @param evt the event that has just been raised on an instance of DeviceMessageBus. + */ +void scheduler_event(Event evt); - /** - * Resizes the stack allocation of the current fiber if necessary to hold the system stack. - * - * If the stack allocation is large enough to hold the current system stack, then this function does nothing. - * Otherwise, the the current allocation of the fiber is freed, and a larger block is allocated. - * - * @param f The fiber context to verify. - * - * @return The stack depth of the given fiber. - */ - inline void verify_stack_size(Fiber *f); +/** + * Determines if any fibers are waiting to be scheduled. + * + * @return The number of fibers currently on the run queue + */ +int scheduler_runqueue_empty(); - /** - * Event callback. Called from an instance of DeviceMessageBus whenever an event is raised. - * - * This function checks to determine if any fibers blocked on the wait queue need to be woken up - * and made runnable due to the event. - * - * @param evt the event that has just been raised on an instance of DeviceMessageBus. - */ - void scheduler_event(Event evt); +/** + * Determines if any fibers are waiting for events. + * + * @return 1 if there are no fibers currently waiting for events; otherwise 0 + */ +int scheduler_waitqueue_empty(); - /** - * Determines if any fibers are waiting to be scheduled. - * - * @return The number of fibers currently on the run queue - */ - int scheduler_runqueue_empty(); +/** + * Utility function to add the currenty running fiber to the given queue. + * + * Perform a simple add at the head, to avoid complexity, + * + * Queues are normally very short, so maintaining a doubly linked, sorted list typically outweighs the cost of + * brute force searching. + * + * @param f The fiber to add to the queue + * + * @param queue The run queue to add the fiber to. + */ +void queue_fiber(Fiber* f, Fiber** queue); - /** - * Determines if any fibers are waiting for events. - * - * @return 1 if there are no fibers currently waiting for events; otherwise 0 - */ - int scheduler_waitqueue_empty(); +/** + * Utility function to the given fiber from whichever queue it is currently stored on. + * + * @param f the fiber to remove. + */ +void dequeue_fiber(Fiber* f); - /** - * Utility function to add the currenty running fiber to the given queue. - * - * Perform a simple add at the head, to avoid complexity, - * - * Queues are normally very short, so maintaining a doubly linked, sorted list typically outweighs the cost of - * brute force searching. - * - * @param f The fiber to add to the queue - * - * @param queue The run queue to add the fiber to. - */ - void queue_fiber(Fiber *f, Fiber **queue); +/** + * Set of tasks to perform when idle. + * Service any background tasks that are required, and attempt a power efficient sleep. + */ +void idle(); - /** - * Utility function to the given fiber from whichever queue it is currently stored on. - * - * @param f the fiber to remove. - */ - void dequeue_fiber(Fiber *f); +/** + * The idle task, which is called when the runtime has no fibers that require execution. + * + * This function typically calls idle(). + */ +void idle_task(); +/** + * Determines if deep sleep is pending. + * + * @return 1 if deep sleep is pending, 0 otherwise. + */ +int fiber_scheduler_get_deepsleep_pending(); + +/** + * Flag if deep sleep is pending. + * + * @param pending 1 if deep sleep is pending, 0 otherwise. + */ +void fiber_scheduler_set_deepsleep_pending(int pending); + +class FiberLock { + private: + int locked; + int resetTo; + FiberLockMode mode; + Fiber* queue; + + public: /** - * Set of tasks to perform when idle. - * Service any background tasks that are required, and attempt a power efficient sleep. - */ - void idle(); + * Create a new lock that can be used for mutual exclusion and condition synchronisation. + * + * @param initial The number of access requests to grant before blocking + * @param mode The mode to operate in - either FiberLockMode::MUTEX or FiberLockMode::SEMAPHORE + */ + FiberLock(int initial = 1, FiberLockMode mode = FiberLockMode::MUTEX); /** - * The idle task, which is called when the runtime has no fibers that require execution. - * - * This function typically calls idle(). - */ - void idle_task(); + * Block the calling fiber until the lock is available + **/ + void wait(); /** - * Determines if deep sleep is pending. - * - * @return 1 if deep sleep is pending, 0 otherwise. - */ - int fiber_scheduler_get_deepsleep_pending(); + * Release the lock, and signal to one waiting fiber to continue + */ + void notify(); /** - * Flag if deep sleep is pending. - * - * @param pending 1 if deep sleep is pending, 0 otherwise. - */ - void fiber_scheduler_set_deepsleep_pending( int pending); - - class FiberLock - { - private: - int locked; - int resetTo; - FiberLockMode mode; - Fiber *queue; - - public: - - /** - * Create a new lock that can be used for mutual exclusion and condition synchronisation. - * - * @param initial The number of access requests to grant before blocking - * @param mode The mode to operate in - either FiberLockMode::MUTEX or FiberLockMode::SEMAPHORE - */ - FiberLock( int initial = 1, FiberLockMode mode = FiberLockMode::MUTEX ); - - /** - * Block the calling fiber until the lock is available - **/ - void wait(); - - /** - * Release the lock, and signal to one waiting fiber to continue - */ - void notify(); - - /** - * Release the lock, and signal to all waiting fibers to continue - */ - void notifyAll(); - - /** - * Determine the number of fibers currently blocked on this lock - */ - int getWaitCount(); - }; -} + * Release the lock, and signal to all waiting fibers to continue + */ + void notifyAll(); + /** + * Determine the number of fibers currently blocked on this lock + */ + int getWaitCount(); +}; +} // namespace codal /** - * Assembler Context switch routing. - * Defined in CortexContextSwitch.s. - */ -extern "C" void swap_context(void* from_tcb, PROCESSOR_WORD_TYPE from_stack, void* to_tcb, PROCESSOR_WORD_TYPE to_stack); + * Assembler Context switch routing. + * Defined in CortexContextSwitch.s. + */ +extern "C" void swap_context(void* from_tcb, PROCESSOR_WORD_TYPE from_stack, void* to_tcb, + PROCESSOR_WORD_TYPE to_stack); extern "C" void save_context(void* tcb, PROCESSOR_WORD_TYPE stack); extern "C" void save_register_context(void* tcb); extern "C" void restore_register_context(void* tcb); diff --git a/inc/core/CodalHeapAllocator.h b/inc/core/CodalHeapAllocator.h index 09e6935b..8c09a0b3 100644 --- a/inc/core/CodalHeapAllocator.h +++ b/inc/core/CodalHeapAllocator.h @@ -23,29 +23,29 @@ DEALINGS IN THE SOFTWARE. */ /** - * A simple 32 bit block based memory allocator. This allows one or more memory segments to - * be designated as heap storage, and is designed to run in a static memory area or inside the standard C - * heap for use by the codal device runtime. This is required for several reasons: - * - * 1) It reduces memory fragmentation due to the high churn sometime placed on the heap - * by ManagedTypes, fibers and user code. Underlying heap implentations are often have very simplistic - * allocation pilicies and suffer from fragmentation in prolonged use - which can cause programs to - * stop working after a period of time. The algorithm implemented here is simple, but highly tolerant to - * large amounts of churn. - * - * 2) It allows us to reuse the 8K of SRAM set aside for SoftDevice as additional heap storage - * when BLE is not in use. - * - * 3) It gives a simple example of how memory allocation works! :-) - * - * P.S. This is a very simple allocator, therefore not without its weaknesses. Why don't you consider - * what these are, and consider the tradeoffs against simplicity... - * - * @note The need for this should be reviewed in the future, if a different memory allocator is - * made available in the mbed platform. - * - * TODO: Consider caching recently freed blocks to improve allocation time. - */ + * A simple 32 bit block based memory allocator. This allows one or more memory segments to + * be designated as heap storage, and is designed to run in a static memory area or inside the standard C + * heap for use by the codal device runtime. This is required for several reasons: + * + * 1) It reduces memory fragmentation due to the high churn sometime placed on the heap + * by ManagedTypes, fibers and user code. Underlying heap implentations are often have very simplistic + * allocation pilicies and suffer from fragmentation in prolonged use - which can cause programs to + * stop working after a period of time. The algorithm implemented here is simple, but highly tolerant to + * large amounts of churn. + * + * 2) It allows us to reuse the 8K of SRAM set aside for SoftDevice as additional heap storage + * when BLE is not in use. + * + * 3) It gives a simple example of how memory allocation works! :-) + * + * P.S. This is a very simple allocator, therefore not without its weaknesses. Why don't you consider + * what these are, and consider the tradeoffs against simplicity... + * + * @note The need for this should be reviewed in the future, if a different memory allocator is + * made available in the mbed platform. + * + * TODO: Consider caching recently freed blocks to improve allocation time. + */ #ifndef DEVICE_HEAP_ALLOCTOR_H #define DEVICE_HEAP_ALLOCTOR_H @@ -53,66 +53,64 @@ DEALINGS IN THE SOFTWARE. #include "CodalConfig.h" // Flag to indicate that a given block is FREE/USED (top bit of a CPU word) -#define DEVICE_HEAP_BLOCK_FREE (1 << (sizeof(PROCESSOR_WORD_TYPE) * 8 - 1)) -#define DEVICE_HEAP_BLOCK_SIZE (sizeof(PROCESSOR_WORD_TYPE)) +#define DEVICE_HEAP_BLOCK_FREE (1 << (sizeof(PROCESSOR_WORD_TYPE) * 8 - 1)) +#define DEVICE_HEAP_BLOCK_SIZE (sizeof(PROCESSOR_WORD_TYPE)) -struct HeapDefinition -{ - PROCESSOR_WORD_TYPE *heap_start; // Physical address of the start of this heap. - PROCESSOR_WORD_TYPE *heap_end; // Physical address of the end of this heap. +struct HeapDefinition { + PROCESSOR_WORD_TYPE* heap_start; // Physical address of the start of this heap. + PROCESSOR_WORD_TYPE* heap_end; // Physical address of the end of this heap. }; extern PROCESSOR_WORD_TYPE codal_heap_start; /** - * Create and initialise a given memory region as for heap storage. - * After this is called, any future calls to malloc, new, free or delete may use the new heap. - * The heap allocator will attempt to allocate memory from heaps in the order that they are created. - * i.e. memory will be allocated from first heap created until it is full, then the second heap, and so on. - * - * @param start The start address of memory to use as a heap region. - * - * @param end The end address of memory to use as a heap region. - * - * @return DEVICE_OK on success, or DEVICE_NO_RESOURCES if the heap could not be allocated. - * - * @note Only code that #includes DeviceHeapAllocator.h will use this heap. This includes all codal device runtime - * code, and user code targetting the runtime. External code can choose to include this file, or - * simply use the standard heap. - */ + * Create and initialise a given memory region as for heap storage. + * After this is called, any future calls to malloc, new, free or delete may use the new heap. + * The heap allocator will attempt to allocate memory from heaps in the order that they are created. + * i.e. memory will be allocated from first heap created until it is full, then the second heap, and so on. + * + * @param start The start address of memory to use as a heap region. + * + * @param end The end address of memory to use as a heap region. + * + * @return DEVICE_OK on success, or DEVICE_NO_RESOURCES if the heap could not be allocated. + * + * @note Only code that #includes DeviceHeapAllocator.h will use this heap. This includes all codal device runtime + * code, and user code targetting the runtime. External code can choose to include this file, or + * simply use the standard heap. + */ int device_create_heap(PROCESSOR_WORD_TYPE start, PROCESSOR_WORD_TYPE end); /** * Returns the size of a given heap. - * + * * @param heap_index index between 0 and DEVICE_MAXIMUM_HEAPS-1 - * + * * @return the size of heap in bytes, or zero if no such heap exists. */ uint32_t device_heap_size(uint8_t heap_index); - /** - * Attempt to allocate a given amount of memory from any of our configured heap areas. - * - * @param size The amount of memory, in bytes, to allocate. - * - * @return A pointer to the allocated memory, or NULL if insufficient memory is available. - */ + * Attempt to allocate a given amount of memory from any of our configured heap areas. + * + * @param size The amount of memory, in bytes, to allocate. + * + * @return A pointer to the allocated memory, or NULL if insufficient memory is available. + */ extern "C" void* device_malloc(size_t size); /** - * Release a given area of memory from the heap. - * - * @param mem The memory area to release. - */ -extern "C" void device_free(void *mem); + * Release a given area of memory from the heap. + * + * @param mem The memory area to release. + */ +extern "C" void device_free(void* mem); /** - * Copy existing contents of ptr to a new memory block of given size. - * - * @param ptr The existing memory block (can be NULL) - * @param size The size of new block (can be smaller or larger than the old one) - */ + * Copy existing contents of ptr to a new memory block of given size. + * + * @param ptr The existing memory block (can be NULL) + * @param size The size of new block (can be smaller or larger than the old one) + */ extern "C" void* device_realloc(void* ptr, size_t size); #endif diff --git a/inc/core/CodalListener.h b/inc/core/CodalListener.h index 2b4ba911..5e847ca9 100644 --- a/inc/core/CodalListener.h +++ b/inc/core/CodalListener.h @@ -30,140 +30,138 @@ DEALINGS IN THE SOFTWARE. #include "MemberFunctionCallback.h" // Listener flags... -#define MESSAGE_BUS_LISTENER_PARAMETERISED 0x0001 -#define MESSAGE_BUS_LISTENER_METHOD 0x0002 -#define MESSAGE_BUS_LISTENER_BUSY 0x0004 -#define MESSAGE_BUS_LISTENER_REENTRANT 0x0008 -#define MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY 0x0010 -#define MESSAGE_BUS_LISTENER_DROP_IF_BUSY 0x0020 -#define MESSAGE_BUS_LISTENER_NONBLOCKING 0x0040 -#define MESSAGE_BUS_LISTENER_URGENT 0x0080 -#define MESSAGE_BUS_LISTENER_DELETING 0x8000 - -#define MESSAGE_BUS_LISTENER_IMMEDIATE (MESSAGE_BUS_LISTENER_NONBLOCKING | MESSAGE_BUS_LISTENER_URGENT) +#define MESSAGE_BUS_LISTENER_PARAMETERISED 0x0001 +#define MESSAGE_BUS_LISTENER_METHOD 0x0002 +#define MESSAGE_BUS_LISTENER_BUSY 0x0004 +#define MESSAGE_BUS_LISTENER_REENTRANT 0x0008 +#define MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY 0x0010 +#define MESSAGE_BUS_LISTENER_DROP_IF_BUSY 0x0020 +#define MESSAGE_BUS_LISTENER_NONBLOCKING 0x0040 +#define MESSAGE_BUS_LISTENER_URGENT 0x0080 +#define MESSAGE_BUS_LISTENER_DELETING 0x8000 + +#define MESSAGE_BUS_LISTENER_IMMEDIATE (MESSAGE_BUS_LISTENER_NONBLOCKING | MESSAGE_BUS_LISTENER_URGENT) /** - * This structure defines a Listener used to invoke functions, or member - * functions if an instance of EventModel receives an event whose id and value - * match this Listener's id and value. - */ -namespace codal -{ - struct Listener - { - uint16_t id; // The ID of the component that this listener is interested in. - uint16_t value; // Value this listener is interested in receiving. - uint16_t flags; // Status and configuration options codes for this listener. - - union - { - void (*cb)(Event); - void (*cb_param)(Event, void *); - MemberFunctionCallback *cb_method; - }; - - void* cb_arg; // Optional argument to be passed to the caller. - - Event evt; - EventQueueItem *evt_queue; - - Listener *next; - - /** - * Constructor. - * - * Create a new Message Bus Listener. - * - * @param id The ID of the component you want to listen to. - * - * @param value The event value you would like to listen to from that component - * - * @param handler A function pointer to call when the event is detected. - * - * @param flags User specified, implementation specific flags, that allow behaviour of this events listener - * to be tuned. - */ - Listener(uint16_t id, uint16_t value, void (*handler)(Event), uint16_t flags = EVENT_LISTENER_DEFAULT_FLAGS); - - /** - * Constructor. - * - * Create a new Message Bus Listener, this constructor accepts an additional - * parameter "arg", which is passed to the handler. - * - * @param id The ID of the component you want to listen to. - * - * @param value The event value you would like to listen to from that component - * - * @param handler A function pointer to call when the event is detected. - * - * @param arg A pointer to some data that will be given to the handler. - * - * @param flags User specified, implementation specific flags, that allow behaviour of this events listener - * to be tuned. - */ - Listener(uint16_t id, uint16_t value, void (*handler)(Event, void *), void* arg, uint16_t flags = EVENT_LISTENER_DEFAULT_FLAGS); - - - /** - * Constructor. - * - * Create a new Message Bus Listener, with a callback to a C++ member function. - * - * @param id The ID of the component you want to listen to. - * - * @param value The event value you would like to listen to from that component - * - * @param object The C++ object on which to call the event handler. - * - * @param method The method within the C++ object to call. - * - * @param flags User specified, implementation specific flags, that allow behaviour of this events listener - * to be tuned. - */ - template - Listener(uint16_t id, uint16_t value, T* object, void (T::*method)(Event), uint16_t flags = EVENT_LISTENER_DEFAULT_FLAGS); - - /** - * Destructor. Ensures all resources used by this listener are freed. - */ - ~Listener(); - - /** - * Queues and event up to be processed. - * - * @param e The event to queue - */ - void queue(Event e); + * This structure defines a Listener used to invoke functions, or member + * functions if an instance of EventModel receives an event whose id and value + * match this Listener's id and value. + */ +namespace codal { +struct Listener { + uint16_t id; // The ID of the component that this listener is interested in. + uint16_t value; // Value this listener is interested in receiving. + uint16_t flags; // Status and configuration options codes for this listener. + + union { + void (*cb)(Event); + void (*cb_param)(Event, void*); + MemberFunctionCallback* cb_method; }; + void* cb_arg; // Optional argument to be passed to the caller. + + Event evt; + EventQueueItem* evt_queue; + + Listener* next; + + /** + * Constructor. + * + * Create a new Message Bus Listener. + * + * @param id The ID of the component you want to listen to. + * + * @param value The event value you would like to listen to from that component + * + * @param handler A function pointer to call when the event is detected. + * + * @param flags User specified, implementation specific flags, that allow behaviour of this events listener + * to be tuned. + */ + Listener(uint16_t id, uint16_t value, void (*handler)(Event), uint16_t flags = EVENT_LISTENER_DEFAULT_FLAGS); + + /** + * Constructor. + * + * Create a new Message Bus Listener, this constructor accepts an additional + * parameter "arg", which is passed to the handler. + * + * @param id The ID of the component you want to listen to. + * + * @param value The event value you would like to listen to from that component + * + * @param handler A function pointer to call when the event is detected. + * + * @param arg A pointer to some data that will be given to the handler. + * + * @param flags User specified, implementation specific flags, that allow behaviour of this events listener + * to be tuned. + */ + Listener(uint16_t id, uint16_t value, void (*handler)(Event, void*), void* arg, + uint16_t flags = EVENT_LISTENER_DEFAULT_FLAGS); + /** - * Constructor. - * - * Create a new Message Bus Listener, with a callback to a C++ member function. - * - * @param id The ID of the component you want to listen to. - * - * @param value The event value you would like to listen to from that component - * - * @param object The C++ object on which to call the event handler. - * - * @param method The method within the C++ object to call. - * - * @param flags User specified, implementation specific flags, that allow behaviour of this events listener - * to be tuned. - */ + * Constructor. + * + * Create a new Message Bus Listener, with a callback to a C++ member function. + * + * @param id The ID of the component you want to listen to. + * + * @param value The event value you would like to listen to from that component + * + * @param object The C++ object on which to call the event handler. + * + * @param method The method within the C++ object to call. + * + * @param flags User specified, implementation specific flags, that allow behaviour of this events listener + * to be tuned. + */ template - Listener::Listener(uint16_t id, uint16_t value, T* object, void (T::*method)(Event), uint16_t flags) - { - this->id = id; - this->value = value; - this->cb_method = new MemberFunctionCallback(object, method); - this->cb_arg = NULL; - this->flags = flags | MESSAGE_BUS_LISTENER_METHOD; - this->evt_queue = NULL; - this->next = NULL; - } + Listener(uint16_t id, uint16_t value, T* object, void (T::*method)(Event), + uint16_t flags = EVENT_LISTENER_DEFAULT_FLAGS); + + /** + * Destructor. Ensures all resources used by this listener are freed. + */ + ~Listener(); + + /** + * Queues and event up to be processed. + * + * @param e The event to queue + */ + void queue(Event e); +}; + +/** + * Constructor. + * + * Create a new Message Bus Listener, with a callback to a C++ member function. + * + * @param id The ID of the component you want to listen to. + * + * @param value The event value you would like to listen to from that component + * + * @param object The C++ object on which to call the event handler. + * + * @param method The method within the C++ object to call. + * + * @param flags User specified, implementation specific flags, that allow behaviour of this events listener + * to be tuned. + */ +template +Listener::Listener(uint16_t id, uint16_t value, T* object, void (T::*method)(Event), uint16_t flags) +{ + this->id = id; + this->value = value; + this->cb_method = new MemberFunctionCallback(object, method); + this->cb_arg = NULL; + this->flags = flags | MESSAGE_BUS_LISTENER_METHOD; + this->evt_queue = NULL; + this->next = NULL; } +} // namespace codal #endif diff --git a/inc/core/CodalUtil.h b/inc/core/CodalUtil.h index 98e29c39..dcf4ab0a 100644 --- a/inc/core/CodalUtil.h +++ b/inc/core/CodalUtil.h @@ -23,42 +23,39 @@ DEALINGS IN THE SOFTWARE. */ /** - * This file contains functions used to maintain compatability and portability. - * It also contains constants that are used elsewhere in the DAL. - */ + * This file contains functions used to maintain compatability and portability. + * It also contains constants that are used elsewhere in the DAL. + */ #ifndef CODAL_UTIL_H #define CODAL_UTIL_H #include "CodalConfig.h" -#define CREATE_KEY_VALUE_TABLE(NAME, PAIRS) const KeyValueTable NAME { PAIRS, sizeof(PAIRS) / sizeof(KeyValueTableEntry) }; +#define CREATE_KEY_VALUE_TABLE(NAME, PAIRS) const KeyValueTable NAME{PAIRS, sizeof(PAIRS) / sizeof(KeyValueTableEntry)}; -namespace codal -{ - /** - * Provides a simple key/value pair lookup table with range lookup support. - * Normally stored in FLASH to reduce RAM usage. Keys should be pre-sorted - * in ascending order. - */ - - struct KeyValueTableEntry - { - const uint32_t key; - const uint32_t value; - }; - - struct KeyValueTable - { - const KeyValueTableEntry *data; - const int length; - - KeyValueTableEntry* find(const uint32_t key) const; - uint32_t get(const uint32_t key) const; - uint32_t getKey(const uint32_t key) const; - bool hasKey(const uint32_t key) const; - }; - -} +namespace codal { +/** + * Provides a simple key/value pair lookup table with range lookup support. + * Normally stored in FLASH to reduce RAM usage. Keys should be pre-sorted + * in ascending order. + */ + +struct KeyValueTableEntry { + const uint32_t key; + const uint32_t value; +}; + +struct KeyValueTable { + const KeyValueTableEntry* data; + const int length; + + KeyValueTableEntry* find(const uint32_t key) const; + uint32_t get(const uint32_t key) const; + uint32_t getKey(const uint32_t key) const; + bool hasKey(const uint32_t key) const; +}; + +} // namespace codal #endif diff --git a/inc/core/ErrorNo.h b/inc/core/ErrorNo.h index a5a73a75..440ff1cd 100644 --- a/inc/core/ErrorNo.h +++ b/inc/core/ErrorNo.h @@ -28,10 +28,10 @@ DEALINGS IN THE SOFTWARE. #include "CodalConfig.h" /** - * Error codes used in the codal device runtime. - * These may be returned from functions implemented in the codal device runtime. - */ -enum ErrorCode{ + * Error codes used in the codal device runtime. + * These may be returned from functions implemented in the codal device runtime. + */ +enum ErrorCode { // No error occurred. DEVICE_OK = 0, @@ -44,9 +44,10 @@ enum ErrorCode{ // Device calibration errors DEVICE_CALIBRATION_IN_PROGRESS = -1003, - DEVICE_CALIBRATION_REQUIRED = -1004, + DEVICE_CALIBRATION_REQUIRED = -1004, - // The requested operation could not be performed as the device has run out of some essential resource (e.g. allocated memory) + // The requested operation could not be performed as the device has run out of some essential resource (e.g. + // allocated memory) DEVICE_NO_RESOURCES = -1005, // The requested operation could not be performed as some essential resource is busy (e.g. the display) @@ -75,9 +76,9 @@ enum ErrorCode{ }; /** - * Error codes used in the codal device runtime. - */ -enum PanicCode{ + * Error codes used in the codal device runtime. + */ +enum PanicCode { // PANIC Codes. These are not return codes, but are terminal conditions. // These induce a panic operation, where all code stops executing, and a panic state is // entered where the panic code is diplayed. diff --git a/inc/core/EventModel.h b/inc/core/EventModel.h index 157514d4..7fafcd85 100644 --- a/inc/core/EventModel.h +++ b/inc/core/EventModel.h @@ -25,673 +25,649 @@ DEALINGS IN THE SOFTWARE. #ifndef EVENT_MODEL_H #define EVENT_MODEL_H -#include "CodalConfig.h" #include "CodalComponent.h" -#include "Event.h" +#include "CodalConfig.h" #include "CodalListener.h" #include "ErrorNo.h" +#include "Event.h" /** - * Class definition for the codal device EventModel. - * - * It is common to need to send events from one part of a program (or system) to another. - * The way that these events are stored and delivered is known as an Event Model... - * - * The codal device can be programmed in a number of languages, and it not be good to - * constrain those languages to any particular event model (e.g. they may have their own already). - * - * This class defines the functionality an event model needs to have to be able to interact - * with events generated and/or used by the codal device runtime. Programmer may choose to implement - * such functionality to integrate their own event models. - * - * This is an example of a key principle in computing - ABSTRACTION. This is now part of the - * UK's Computing curriculum in schools... so ask your teacher about it. :-) - * - * An EventModel implementation is provided in the DeviceMessageBus class. - */ -namespace codal -{ - class EventModel + * Class definition for the codal device EventModel. + * + * It is common to need to send events from one part of a program (or system) to another. + * The way that these events are stored and delivered is known as an Event Model... + * + * The codal device can be programmed in a number of languages, and it not be good to + * constrain those languages to any particular event model (e.g. they may have their own already). + * + * This class defines the functionality an event model needs to have to be able to interact + * with events generated and/or used by the codal device runtime. Programmer may choose to implement + * such functionality to integrate their own event models. + * + * This is an example of a key principle in computing - ABSTRACTION. This is now part of the + * UK's Computing curriculum in schools... so ask your teacher about it. :-) + * + * An EventModel implementation is provided in the DeviceMessageBus class. + */ +namespace codal { +class EventModel { + uint16_t eventHandle; + + protected: + void (*listener_deletion_callback)( + Listener*); // An optional callback function that is invoked when a listener is removed. + + public: + static EventModel* defaultEventBus; + + EventModel() : listener_deletion_callback(NULL) {} + /** + * Queues the given event to be sent to all registered recipients. + * The method of delivery will vary depending on the underlying implementation. + * + * @param The event to send. + * + * @return This default implementation simply returns DEVICE_NOT_SUPPORTED. + */ + virtual int send(Event) { return DEVICE_NOT_SUPPORTED; } + + /** + * Add the given Listener to the list of event handlers, unconditionally. + * + * @param listener The Listener to validate. + * + * @return This default implementation simply returns DEVICE_NOT_SUPPORTED. + */ + virtual int add(Listener*) { return DEVICE_NOT_SUPPORTED; } + + /** + * Remove the given Listener from the list of event handlers. + * + * @param listener The Listener to remove. + * + * @return This default implementation simply returns DEVICE_NOT_SUPPORTED. + */ + virtual int remove(Listener*) { return DEVICE_NOT_SUPPORTED; } + + /** + * Returns the Listener at the given position in the list. + * + * @param n The index of the desired Listener. + * + * @return This default implementation simply returns NULL. + */ + virtual Listener* elementAt(int) { return NULL; } + + /** + * Define the default EventModel to use for events raised and consumed by the codal runtime. + * The default EventModel may be changed at any time. + * + * @param model A new instance of an EventModel to use as the default. + * + * @return DEVICE_OK on success. + * + * Example: + * @code + * DeviceMessageBus b(); + * EventModel:setDefaultEventModel(b); + * @endcode + */ + static int setDefaultEventModel(EventModel& model) { - uint16_t eventHandle; - - protected: - - void (*listener_deletion_callback)(Listener *); // An optional callback function that is invoked when a listener is removed. - - public: - - static EventModel *defaultEventBus; - - EventModel() : listener_deletion_callback(NULL) {} - /** - * Queues the given event to be sent to all registered recipients. - * The method of delivery will vary depending on the underlying implementation. - * - * @param The event to send. - * - * @return This default implementation simply returns DEVICE_NOT_SUPPORTED. - */ - virtual int send(Event) - { - return DEVICE_NOT_SUPPORTED; - } - - /** - * Add the given Listener to the list of event handlers, unconditionally. - * - * @param listener The Listener to validate. - * - * @return This default implementation simply returns DEVICE_NOT_SUPPORTED. - */ - virtual int add(Listener*) - { - return DEVICE_NOT_SUPPORTED; - } - - /** - * Remove the given Listener from the list of event handlers. - * - * @param listener The Listener to remove. - * - * @return This default implementation simply returns DEVICE_NOT_SUPPORTED. - */ - virtual int remove(Listener *) - { - return DEVICE_NOT_SUPPORTED; - } - - /** - * Returns the Listener at the given position in the list. - * - * @param n The index of the desired Listener. - * - * @return This default implementation simply returns NULL. - */ - virtual Listener *elementAt(int) - { - return NULL; - } - - /** - * Define the default EventModel to use for events raised and consumed by the codal runtime. - * The default EventModel may be changed at any time. - * - * @param model A new instance of an EventModel to use as the default. - * - * @return DEVICE_OK on success. - * - * Example: - * @code - * DeviceMessageBus b(); - * EventModel:setDefaultEventModel(b); - * @endcode - */ - static int setDefaultEventModel(EventModel &model) - { - EventModel::defaultEventBus = &model; - return DEVICE_OK; - } - - /** - * Sets a pointer to a handler that is invoked when any listener is deleted. - * - * @returns DEVICE_OK on success. - **/ - int setListenerDeletionCallback(void (*listener_deletion_callback)(Listener *)) - { - this->listener_deletion_callback = listener_deletion_callback; - return DEVICE_OK; - } - - /** - * Register a listener function. - * - * An EventModel implementing this interface may optionally choose to override this method, - * if that EventModel supports asynchronous callbacks to user code, but there is no - * requirement to do so. - * - * @param id The source of messages to listen for. Events sent from any other IDs will be filtered. - * Use DEVICE_ID_ANY to receive events from all components. - * - * @param value The value of messages to listen for. Events with any other values will be filtered. - * Use DEVICE_EVT_ANY to receive events of any value. - * - * @param handler The function to call when an event is received. - * - * @param flags User specified, implementation specific flags, that allow behaviour of this events listener - * to be tuned. - * - * @return DEVICE_OK on success, or any valid error code defined in "ErrNo.h". The default implementation - * simply returns DEVICE_NOT_SUPPORTED. - * - * @code - * void onButtonBClicked(Event) - * { - * //do something - * } - * - * // call onButtonBClicked when ever a click event from buttonB is detected. - * uBit.messageBus.listen(DEVICE_ID_BUTTON_B, DEVICE_BUTTON_EVT_CLICK, onButtonBClick); - * @endcode - */ - int listen(int id, int value, void (*handler)(Event), uint16_t flags = EVENT_LISTENER_DEFAULT_FLAGS) - { - if (handler == NULL) - return DEVICE_INVALID_PARAMETER; - - if(id == DEVICE_ID_SCHEDULER && flags != MESSAGE_BUS_LISTENER_IMMEDIATE) - return DEVICE_INVALID_PARAMETER; - - Listener *newListener = new Listener(id, value, handler, flags); - - if(add(newListener) == DEVICE_OK) - return DEVICE_OK; - - delete newListener; - - return DEVICE_NOT_SUPPORTED; - } - - /** - * Register a listener function. - * - * An EventModel implementing this interface may optionally choose to override this method, - * if that EventModel supports asynchronous callbacks to user code, but there is no - * requirement to do so. - * - * @param id The source of messages to listen for. Events sent from any other IDs will be filtered. - * Use DEVICE_ID_ANY to receive events from all components. - * - * @param value The value of messages to listen for. Events with any other values will be filtered. - * Use DEVICE_EVT_ANY to receive events of any value. - * - * @param handler The function to call when an event is received. - * - * @param arg Provide the callback with in an additional argument. - * - * @param flags User specified, implementation specific flags, that allow behaviour of this events listener - * to be tuned. - * - * @return DEVICE_OK on success, or any valid error code defined in "ErrNo.h". The default implementation - * simply returns DEVICE_NOT_SUPPORTED. - * - * @code - * void onButtonBClicked(Event, void* data) - * { - * //do something - * } - * - * // call onButtonBClicked when ever a click event from buttonB is detected. - * uBit.messageBus.listen(DEVICE_ID_BUTTON_B, DEVICE_BUTTON_EVT_CLICK, onButtonBClick); - * @endcode - */ - int listen(int id, int value, void (*handler)(Event, void*), void* arg, uint16_t flags = EVENT_LISTENER_DEFAULT_FLAGS) - { - if (handler == NULL) - return DEVICE_INVALID_PARAMETER; - - if(id == DEVICE_ID_SCHEDULER && flags != MESSAGE_BUS_LISTENER_IMMEDIATE) - return DEVICE_INVALID_PARAMETER; - - Listener *newListener = new Listener(id, value, handler, arg, flags); - - if(add(newListener) == DEVICE_OK) - return DEVICE_OK; - - delete newListener; - - return DEVICE_NOT_SUPPORTED; - } - - /** - * Register a listener function. - * - * @param id The source of messages to listen for. Events sent from any other IDs will be filtered. - * Use DEVICE_ID_ANY to receive events from all components. - * - * @param value The value of messages to listen for. Events with any other values will be filtered. - * Use DEVICE_EVT_ANY to receive events of any value. - * - * @param hander The function to call when an event is received. - * - * @param flags User specified, implementation specific flags, that allow behaviour of this events listener - * to be tuned. - * - * @return DEVICE_OK on success or DEVICE_INVALID_PARAMETER if the handler or object - * pointers are NULL. - * - * @code - * void SomeClass::onButtonBClicked(Event) - * { - * //do something - * } - * - * SomeClass s = new SomeClass(); - * - * uBit.messageBus.listen(DEVICE_ID_BUTTON_B, DEVICE_BUTTON_EVT_CLICK, s, &SomeClass::onButtonBClick); - * @endcode - */ - template - int listen(uint16_t id, uint16_t value, T* object, void (T::*handler)(Event), uint16_t flags = EVENT_LISTENER_DEFAULT_FLAGS); - - /** - * Register a listener function. - * - * An EventModel implementing this interface may optionally choose to override this method, - * if that EventModel supports asynchronous callbacks to user code, but there is no - * requirement to do so. - * - * @param component The source component of messages to listen for. - * - * @param value The value of messages to listen for. Events with any other values will be filtered. - * Use DEVICE_EVT_ANY to receive events of any value. - * - * @param handler The function to call when an event is received. - * - * @param flags User specified, implementation specific flags, that allow behaviour of this events listener - * to be tuned. - * - * @return DEVICE_OK on success, or any valid error code defined in "ErrNo.h". The default implementation - * simply returns DEVICE_NOT_SUPPORTED. - * - * @code - * void onButtonBClicked(Event) - * { - * //do something - * } - * - * // call onButtonBClicked when ever a click event from buttonB is detected. - * uBit.messageBus.listen(device.buttonB, DEVICE_BUTTON_EVT_CLICK, onButtonBClick); - * @endcode - */ - int listen(CodalComponent& component, int value, void (*handler)(Event), uint16_t flags = EVENT_LISTENER_DEFAULT_FLAGS) - { - return listen(component.id, value, handler, flags); - } - - /** - * Register a listener function. - * - * An EventModel implementing this interface may optionally choose to override this method, - * if that EventModel supports asynchronous callbacks to user code, but there is no - * requirement to do so. - * - * @param component The source component of messages to listen for. - * - * @param value The value of messages to listen for. Events with any other values will be filtered. - * Use DEVICE_EVT_ANY to receive events of any value. - * - * @param handler The function to call when an event is received. - * - * @param arg Provide the callback with in an additional argument. - * - * @param flags User specified, implementation specific flags, that allow behaviour of this events listener - * to be tuned. - * - * @return DEVICE_OK on success, or any valid error code defined in "ErrNo.h". The default implementation - * simply returns DEVICE_NOT_SUPPORTED. - * - * @code - * void onButtonBClicked(Event, void* data) - * { - * //do something - * } - * - * // call onButtonBClicked when ever a click event from buttonB is detected. - * uBit.messageBus.listen(device.buttonB, DEVICE_BUTTON_EVT_CLICK, onButtonBClick); - * @endcode - */ - int listen(CodalComponent& component, int value, void (*handler)(Event, void*), void* arg, uint16_t flags = EVENT_LISTENER_DEFAULT_FLAGS) - { - return listen(component.id, value, handler, arg, flags); - } - - /** - * Register a listener function. - * - * @param component The source component of messages to listen for. - * - * @param value The value of messages to listen for. Events with any other values will be filtered. - * Use DEVICE_EVT_ANY to receive events of any value. - * - * @param hander The function to call when an event is received. - * - * @param flags User specified, implementation specific flags, that allow behaviour of this events listener - * to be tuned. - * - * @return DEVICE_OK on success or DEVICE_INVALID_PARAMETER if the handler or object - * pointers are NULL. - * - * @code - * void SomeClass::onButtonBClicked(Event) - * { - * //do something - * } - * - * SomeClass s = new SomeClass(); - * - * uBit.messageBus.listen(device.buttonB, DEVICE_BUTTON_EVT_CLICK, s, &SomeClass::onButtonBClick); - * @endcode - */ - template - int listen(CodalComponent& component, uint16_t value, T* object, void (T::*handler)(Event), uint16_t flags = EVENT_LISTENER_DEFAULT_FLAGS); - - - /** - * Unregister a listener function. - * Listeners are identified by the Event ID, Event value and handler registered using listen(). - * - * @param id The Event ID used to register the listener. - * @param value The Event value used to register the listener. - * @param handler The function used to register the listener. - * - * @return DEVICE_OK on success or DEVICE_INVALID_PARAMETER if the handler - * given is NULL. - * - * Example: - * @code - * void onButtonBClick(Event) - * { - * //do something - * } - * - * uBit.messageBus.listen(DEVICE_ID_BUTTON_B, DEVICE_BUTTON_EVT_CLICK, onButtonBClick); - * - * // the previously created listener is now ignored. - * uBit.messageBus.ignore(DEVICE_ID_BUTTON_B, DEVICE_BUTTON_EVT_CLICK, onButtonBClick); - * @endcode - */ - int ignore(int id, int value, void (*handler)(Event)) - { - if (handler == NULL) - return DEVICE_INVALID_PARAMETER; - - Listener listener(id, value, handler); - remove(&listener); - - return DEVICE_OK; - } - - /** - * Unregister a listener function. - * Listeners are identified by the Event ID, Event value and handler registered using listen(). - * - * @param id The Event ID used to register the listener. - * @param value The Event value used to register the listener. - * @param handler The function used to register the listener. - * - * @return DEVICE_OK on success or DEVICE_INVALID_PARAMETER if the handler - * given is NULL. - * - * Example: - * @code - * void onButtonBClick(Event, void* data) - * { - * //do something - * } - * - * uBit.messageBus.listen(DEVICE_ID_BUTTON_B, DEVICE_BUTTON_EVT_CLICK, onButtonBClick); - * - * // the previously created listener is now ignored. - * uBit.messageBus.ignore(DEVICE_ID_BUTTON_B, DEVICE_BUTTON_EVT_CLICK, onButtonBClick); - * @endcode - */ - int ignore(int id, int value, void (*handler)(Event, void*)) - { - if (handler == NULL) - return DEVICE_INVALID_PARAMETER; - - Listener listener(id, value, handler, NULL); - remove(&listener); - - return DEVICE_OK; - } - - /** - * Unregister a listener function. - * Listners are identified by the Event ID, Event value and handler registered using listen(). - * - * @param id The Event ID used to register the listener. - * @param value The Event value used to register the listener. - * @param handler The function used to register the listener. - * - * @return DEVICE_OK on success or DEVICE_INVALID_PARAMETER if the handler or object - * pointers are NULL. - * - * Example: - * @code - * - * void SomeClass::onButtonBClick() - * { - * //do something - * } - * - * SomeClass s = new SomeClass(); - * uBit.messageBus.listen(DEVICE_ID_BUTTON_B, DEVICE_BUTTON_EVT_CLICK, s, &SomeClass::onButtonBClick); - * - * // the previously created listener is now ignored. - * uBit.messageBus.ignore(DEVICE_ID_BUTTON_B, DEVICE_BUTTON_EVT_CLICK, s, &SomeClass::onButtonBClick); - * @endcode - */ - template - int ignore(uint16_t id, uint16_t value, T* object, void (T::*handler)(Event)); - - /** - * Unregister a listener function. - * Listeners are identified by the Event ID, Event value and handler registered using listen(). - * - * @param component The source component used to register the listener - * @param value The Event value used to register the listener. - * @param handler The function used to register the listener. - * - * @return DEVICE_OK on success or DEVICE_INVALID_PARAMETER if the handler - * given is NULL. - * - * Example: - * @code - * void onButtonBClick(Event) - * { - * //do something - * } - * - * uBit.messageBus.listen(device.buttonB, DEVICE_BUTTON_EVT_CLICK, onButtonBClick); - * - * // the previously created listener is now ignored. - * uBit.messageBus.ignore(device.buttonB, DEVICE_BUTTON_EVT_CLICK, onButtonBClick); - * @endcode - */ - int ignore(CodalComponent& component, int value, void (*handler)(Event)) - { - return ignore(component.id, value, handler); - } - - /** - * Unregister a listener function. - * Listeners are identified by the Event ID, Event value and handler registered using listen(). - * - * @param component The source component used to register the listener - * @param value The Event value used to register the listener. - * @param handler The function used to register the listener. - * - * @return DEVICE_OK on success or DEVICE_INVALID_PARAMETER if the handler - * given is NULL. - * - * Example: - * @code - * void onButtonBClick(Event, void* data) - * { - * //do something - * } - * - * uBit.messageBus.listen(device.buttonB, DEVICE_BUTTON_EVT_CLICK, onButtonBClick); - * - * // the previously created listener is now ignored. - * uBit.messageBus.ignore(device.buttonB, DEVICE_BUTTON_EVT_CLICK, onButtonBClick); - * @endcode - */ - int ignore(CodalComponent& component, int value, void (*handler)(Event, void*)) - { - return ignore(component.id, value, handler); - } - - /** - * Unregister a listener function. - * Listners are identified by the Event ID, Event value and handler registered using listen(). - * - * @param component The source component used to register the listener - * @param value The Event value used to register the listener. - * @param handler The function used to register the listener. - * - * @return DEVICE_OK on success or DEVICE_INVALID_PARAMETER if the handler or object - * pointers are NULL. - * - * Example: - * @code - * - * void SomeClass::onButtonBClick() - * { - * //do something - * } - * - * SomeClass s = new SomeClass(); - * uBit.messageBus.listen(device.buttonB, DEVICE_BUTTON_EVT_CLICK, s, &SomeClass::onButtonBClick); - * - * // the previously created listener is now ignored. - * uBit.messageBus.ignore(device.buttonB, DEVICE_BUTTON_EVT_CLICK, s, &SomeClass::onButtonBClick); - * @endcode - */ - template - int ignore(CodalComponent& component, uint16_t value, T* object, void (T::*handler)(Event)); - - }; + EventModel::defaultEventBus = &model; + return DEVICE_OK; + } /** - * A registration function to allow C++ member functions (methods) to be registered as an event - * listener. - * - * @param id The source of messages to listen for. Events sent from any other IDs will be filtered. - * Use DEVICE_ID_ANY to receive events from all components. - * - * @param value The value of messages to listen for. Events with any other values will be filtered. - * Use DEVICE_EVT_ANY to receive events of any value. - * - * @param object The object on which the method should be invoked. - * - * @param handler The method to call when an event is received. - * - * @return DEVICE_OK on success or DEVICE_INVALID_PARAMETER if the handler or object - * pointers are NULL. - */ - template - int EventModel::listen(uint16_t id, uint16_t value, T* object, void (T::*handler)(Event), uint16_t flags) + * Sets a pointer to a handler that is invoked when any listener is deleted. + * + * @returns DEVICE_OK on success. + **/ + int setListenerDeletionCallback(void (*listener_deletion_callback)(Listener*)) + { + this->listener_deletion_callback = listener_deletion_callback; + return DEVICE_OK; + } + + /** + * Register a listener function. + * + * An EventModel implementing this interface may optionally choose to override this method, + * if that EventModel supports asynchronous callbacks to user code, but there is no + * requirement to do so. + * + * @param id The source of messages to listen for. Events sent from any other IDs will be filtered. + * Use DEVICE_ID_ANY to receive events from all components. + * + * @param value The value of messages to listen for. Events with any other values will be filtered. + * Use DEVICE_EVT_ANY to receive events of any value. + * + * @param handler The function to call when an event is received. + * + * @param flags User specified, implementation specific flags, that allow behaviour of this events listener + * to be tuned. + * + * @return DEVICE_OK on success, or any valid error code defined in "ErrNo.h". The default implementation + * simply returns DEVICE_NOT_SUPPORTED. + * + * @code + * void onButtonBClicked(Event) + * { + * //do something + * } + * + * // call onButtonBClicked when ever a click event from buttonB is detected. + * uBit.messageBus.listen(DEVICE_ID_BUTTON_B, DEVICE_BUTTON_EVT_CLICK, onButtonBClick); + * @endcode + */ + int listen(int id, int value, void (*handler)(Event), uint16_t flags = EVENT_LISTENER_DEFAULT_FLAGS) + { + if (handler == NULL) return DEVICE_INVALID_PARAMETER; + + if (id == DEVICE_ID_SCHEDULER && flags != MESSAGE_BUS_LISTENER_IMMEDIATE) return DEVICE_INVALID_PARAMETER; + + Listener* newListener = new Listener(id, value, handler, flags); + + if (add(newListener) == DEVICE_OK) return DEVICE_OK; + + delete newListener; + + return DEVICE_NOT_SUPPORTED; + } + + /** + * Register a listener function. + * + * An EventModel implementing this interface may optionally choose to override this method, + * if that EventModel supports asynchronous callbacks to user code, but there is no + * requirement to do so. + * + * @param id The source of messages to listen for. Events sent from any other IDs will be filtered. + * Use DEVICE_ID_ANY to receive events from all components. + * + * @param value The value of messages to listen for. Events with any other values will be filtered. + * Use DEVICE_EVT_ANY to receive events of any value. + * + * @param handler The function to call when an event is received. + * + * @param arg Provide the callback with in an additional argument. + * + * @param flags User specified, implementation specific flags, that allow behaviour of this events listener + * to be tuned. + * + * @return DEVICE_OK on success, or any valid error code defined in "ErrNo.h". The default implementation + * simply returns DEVICE_NOT_SUPPORTED. + * + * @code + * void onButtonBClicked(Event, void* data) + * { + * //do something + * } + * + * // call onButtonBClicked when ever a click event from buttonB is detected. + * uBit.messageBus.listen(DEVICE_ID_BUTTON_B, DEVICE_BUTTON_EVT_CLICK, onButtonBClick); + * @endcode + */ + int listen(int id, int value, void (*handler)(Event, void*), void* arg, + uint16_t flags = EVENT_LISTENER_DEFAULT_FLAGS) { - if (object == NULL || handler == NULL) - return DEVICE_INVALID_PARAMETER; + if (handler == NULL) return DEVICE_INVALID_PARAMETER; - if(id == DEVICE_ID_SCHEDULER && flags != MESSAGE_BUS_LISTENER_IMMEDIATE) - return DEVICE_INVALID_PARAMETER; + if (id == DEVICE_ID_SCHEDULER && flags != MESSAGE_BUS_LISTENER_IMMEDIATE) return DEVICE_INVALID_PARAMETER; - Listener *newListener = new Listener(id, value, object, handler, flags); + Listener* newListener = new Listener(id, value, handler, arg, flags); - if(add(newListener) == DEVICE_OK) - return DEVICE_OK; + if (add(newListener) == DEVICE_OK) return DEVICE_OK; delete newListener; + return DEVICE_NOT_SUPPORTED; } /** - * A registration function to allow C++ member functions (methods) to be registered as an event - * listener. - * - * @param component The source component of messages to listen for. - * - * @param value The value of messages to listen for. Events with any other values will be filtered. - * Use DEVICE_EVT_ANY to receive events of any value. - * - * @param object The object on which the method should be invoked. - * - * @param handler The method to call when an event is received. - * - * @return DEVICE_OK on success or DEVICE_INVALID_PARAMETER if the handler or object - * pointers are NULL. - */ + * Register a listener function. + * + * @param id The source of messages to listen for. Events sent from any other IDs will be filtered. + * Use DEVICE_ID_ANY to receive events from all components. + * + * @param value The value of messages to listen for. Events with any other values will be filtered. + * Use DEVICE_EVT_ANY to receive events of any value. + * + * @param hander The function to call when an event is received. + * + * @param flags User specified, implementation specific flags, that allow behaviour of this events listener + * to be tuned. + * + * @return DEVICE_OK on success or DEVICE_INVALID_PARAMETER if the handler or object + * pointers are NULL. + * + * @code + * void SomeClass::onButtonBClicked(Event) + * { + * //do something + * } + * + * SomeClass s = new SomeClass(); + * + * uBit.messageBus.listen(DEVICE_ID_BUTTON_B, DEVICE_BUTTON_EVT_CLICK, s, &SomeClass::onButtonBClick); + * @endcode + */ template - int EventModel::listen(CodalComponent& component, uint16_t value, T* object, void (T::*handler)(Event), uint16_t flags) + int listen(uint16_t id, uint16_t value, T* object, void (T::*handler)(Event), + uint16_t flags = EVENT_LISTENER_DEFAULT_FLAGS); + + /** + * Register a listener function. + * + * An EventModel implementing this interface may optionally choose to override this method, + * if that EventModel supports asynchronous callbacks to user code, but there is no + * requirement to do so. + * + * @param component The source component of messages to listen for. + * + * @param value The value of messages to listen for. Events with any other values will be filtered. + * Use DEVICE_EVT_ANY to receive events of any value. + * + * @param handler The function to call when an event is received. + * + * @param flags User specified, implementation specific flags, that allow behaviour of this events listener + * to be tuned. + * + * @return DEVICE_OK on success, or any valid error code defined in "ErrNo.h". The default implementation + * simply returns DEVICE_NOT_SUPPORTED. + * + * @code + * void onButtonBClicked(Event) + * { + * //do something + * } + * + * // call onButtonBClicked when ever a click event from buttonB is detected. + * uBit.messageBus.listen(device.buttonB, DEVICE_BUTTON_EVT_CLICK, onButtonBClick); + * @endcode + */ + int listen(CodalComponent& component, int value, void (*handler)(Event), + uint16_t flags = EVENT_LISTENER_DEFAULT_FLAGS) + { + return listen(component.id, value, handler, flags); + } + + /** + * Register a listener function. + * + * An EventModel implementing this interface may optionally choose to override this method, + * if that EventModel supports asynchronous callbacks to user code, but there is no + * requirement to do so. + * + * @param component The source component of messages to listen for. + * + * @param value The value of messages to listen for. Events with any other values will be filtered. + * Use DEVICE_EVT_ANY to receive events of any value. + * + * @param handler The function to call when an event is received. + * + * @param arg Provide the callback with in an additional argument. + * + * @param flags User specified, implementation specific flags, that allow behaviour of this events listener + * to be tuned. + * + * @return DEVICE_OK on success, or any valid error code defined in "ErrNo.h". The default implementation + * simply returns DEVICE_NOT_SUPPORTED. + * + * @code + * void onButtonBClicked(Event, void* data) + * { + * //do something + * } + * + * // call onButtonBClicked when ever a click event from buttonB is detected. + * uBit.messageBus.listen(device.buttonB, DEVICE_BUTTON_EVT_CLICK, onButtonBClick); + * @endcode + */ + int listen(CodalComponent& component, int value, void (*handler)(Event, void*), void* arg, + uint16_t flags = EVENT_LISTENER_DEFAULT_FLAGS) { - return listen(component.id, value, object, handler, flags); + return listen(component.id, value, handler, arg, flags); } /** - * Unregister a listener function. - * Listners are identified by the Event ID, Event value and handler registered using listen(). - * - * @param id The Event ID used to register the listener. - * @param value The Event value used to register the listener. - * @param handler The function used to register the listener. - * - * @return DEVICE_OK on success or DEVICE_INVALID_PARAMETER if the handler or object - * pointers are NULL. - * - * Example: - * @code - * - * void SomeClass::onButtonBClick() - * { - * //do something - * } - * - * SomeClass s = new SomeClass(); - * uBit.messageBus.listen(DEVICE_ID_BUTTON_B, DEVICE_BUTTON_EVT_CLICK, s, &SomeClass::onButtonBClick); - * - * // the previously created listener is now ignored. - * uBit.messageBus.ignore(DEVICE_ID_BUTTON_B, DEVICE_BUTTON_EVT_CLICK, s, &SomeClass::onButtonBClick); - * @endcode - */ + * Register a listener function. + * + * @param component The source component of messages to listen for. + * + * @param value The value of messages to listen for. Events with any other values will be filtered. + * Use DEVICE_EVT_ANY to receive events of any value. + * + * @param hander The function to call when an event is received. + * + * @param flags User specified, implementation specific flags, that allow behaviour of this events listener + * to be tuned. + * + * @return DEVICE_OK on success or DEVICE_INVALID_PARAMETER if the handler or object + * pointers are NULL. + * + * @code + * void SomeClass::onButtonBClicked(Event) + * { + * //do something + * } + * + * SomeClass s = new SomeClass(); + * + * uBit.messageBus.listen(device.buttonB, DEVICE_BUTTON_EVT_CLICK, s, &SomeClass::onButtonBClick); + * @endcode + */ template - int EventModel::ignore(uint16_t id, uint16_t value, T* object, void (T::*handler)(Event)) + int listen(CodalComponent& component, uint16_t value, T* object, void (T::*handler)(Event), + uint16_t flags = EVENT_LISTENER_DEFAULT_FLAGS); + + /** + * Unregister a listener function. + * Listeners are identified by the Event ID, Event value and handler registered using listen(). + * + * @param id The Event ID used to register the listener. + * @param value The Event value used to register the listener. + * @param handler The function used to register the listener. + * + * @return DEVICE_OK on success or DEVICE_INVALID_PARAMETER if the handler + * given is NULL. + * + * Example: + * @code + * void onButtonBClick(Event) + * { + * //do something + * } + * + * uBit.messageBus.listen(DEVICE_ID_BUTTON_B, DEVICE_BUTTON_EVT_CLICK, onButtonBClick); + * + * // the previously created listener is now ignored. + * uBit.messageBus.ignore(DEVICE_ID_BUTTON_B, DEVICE_BUTTON_EVT_CLICK, onButtonBClick); + * @endcode + */ + int ignore(int id, int value, void (*handler)(Event)) + { + if (handler == NULL) return DEVICE_INVALID_PARAMETER; + + Listener listener(id, value, handler); + remove(&listener); + + return DEVICE_OK; + } + + /** + * Unregister a listener function. + * Listeners are identified by the Event ID, Event value and handler registered using listen(). + * + * @param id The Event ID used to register the listener. + * @param value The Event value used to register the listener. + * @param handler The function used to register the listener. + * + * @return DEVICE_OK on success or DEVICE_INVALID_PARAMETER if the handler + * given is NULL. + * + * Example: + * @code + * void onButtonBClick(Event, void* data) + * { + * //do something + * } + * + * uBit.messageBus.listen(DEVICE_ID_BUTTON_B, DEVICE_BUTTON_EVT_CLICK, onButtonBClick); + * + * // the previously created listener is now ignored. + * uBit.messageBus.ignore(DEVICE_ID_BUTTON_B, DEVICE_BUTTON_EVT_CLICK, onButtonBClick); + * @endcode + */ + int ignore(int id, int value, void (*handler)(Event, void*)) { - if (handler == NULL) - return DEVICE_INVALID_PARAMETER; + if (handler == NULL) return DEVICE_INVALID_PARAMETER; - Listener listener(id, value, object, handler); + Listener listener(id, value, handler, NULL); remove(&listener); return DEVICE_OK; } /** - * Unregister a listener function. - * Listners are identified by the Event ID, Event value and handler registered using listen(). - * - * @param component The source component used to register the listener - * @param value The Event value used to register the listener. - * @param handler The function used to register the listener. - * - * @return DEVICE_OK on success or DEVICE_INVALID_PARAMETER if the handler or object - * pointers are NULL. - * - * Example: - * @code - * - * void SomeClass::onButtonBClick() - * { - * //do something - * } - * - * SomeClass s = new SomeClass(); - * uBit.messageBus.listen(device.buttonB, DEVICE_BUTTON_EVT_CLICK, s, &SomeClass::onButtonBClick); - * - * // the previously created listener is now ignored. - * uBit.messageBus.ignore(device.buttonB, DEVICE_BUTTON_EVT_CLICK, s, &SomeClass::onButtonBClick); - * @endcode - */ + * Unregister a listener function. + * Listners are identified by the Event ID, Event value and handler registered using listen(). + * + * @param id The Event ID used to register the listener. + * @param value The Event value used to register the listener. + * @param handler The function used to register the listener. + * + * @return DEVICE_OK on success or DEVICE_INVALID_PARAMETER if the handler or object + * pointers are NULL. + * + * Example: + * @code + * + * void SomeClass::onButtonBClick() + * { + * //do something + * } + * + * SomeClass s = new SomeClass(); + * uBit.messageBus.listen(DEVICE_ID_BUTTON_B, DEVICE_BUTTON_EVT_CLICK, s, &SomeClass::onButtonBClick); + * + * // the previously created listener is now ignored. + * uBit.messageBus.ignore(DEVICE_ID_BUTTON_B, DEVICE_BUTTON_EVT_CLICK, s, &SomeClass::onButtonBClick); + * @endcode + */ template - int EventModel::ignore(CodalComponent& component, uint16_t value, T* object, void (T::*handler)(Event)) + int ignore(uint16_t id, uint16_t value, T* object, void (T::*handler)(Event)); + + /** + * Unregister a listener function. + * Listeners are identified by the Event ID, Event value and handler registered using listen(). + * + * @param component The source component used to register the listener + * @param value The Event value used to register the listener. + * @param handler The function used to register the listener. + * + * @return DEVICE_OK on success or DEVICE_INVALID_PARAMETER if the handler + * given is NULL. + * + * Example: + * @code + * void onButtonBClick(Event) + * { + * //do something + * } + * + * uBit.messageBus.listen(device.buttonB, DEVICE_BUTTON_EVT_CLICK, onButtonBClick); + * + * // the previously created listener is now ignored. + * uBit.messageBus.ignore(device.buttonB, DEVICE_BUTTON_EVT_CLICK, onButtonBClick); + * @endcode + */ + int ignore(CodalComponent& component, int value, void (*handler)(Event)) + { + return ignore(component.id, value, handler); + } + + /** + * Unregister a listener function. + * Listeners are identified by the Event ID, Event value and handler registered using listen(). + * + * @param component The source component used to register the listener + * @param value The Event value used to register the listener. + * @param handler The function used to register the listener. + * + * @return DEVICE_OK on success or DEVICE_INVALID_PARAMETER if the handler + * given is NULL. + * + * Example: + * @code + * void onButtonBClick(Event, void* data) + * { + * //do something + * } + * + * uBit.messageBus.listen(device.buttonB, DEVICE_BUTTON_EVT_CLICK, onButtonBClick); + * + * // the previously created listener is now ignored. + * uBit.messageBus.ignore(device.buttonB, DEVICE_BUTTON_EVT_CLICK, onButtonBClick); + * @endcode + */ + int ignore(CodalComponent& component, int value, void (*handler)(Event, void*)) { - return ignore(component.id, value, object, handler); + return ignore(component.id, value, handler); } + + /** + * Unregister a listener function. + * Listners are identified by the Event ID, Event value and handler registered using listen(). + * + * @param component The source component used to register the listener + * @param value The Event value used to register the listener. + * @param handler The function used to register the listener. + * + * @return DEVICE_OK on success or DEVICE_INVALID_PARAMETER if the handler or object + * pointers are NULL. + * + * Example: + * @code + * + * void SomeClass::onButtonBClick() + * { + * //do something + * } + * + * SomeClass s = new SomeClass(); + * uBit.messageBus.listen(device.buttonB, DEVICE_BUTTON_EVT_CLICK, s, &SomeClass::onButtonBClick); + * + * // the previously created listener is now ignored. + * uBit.messageBus.ignore(device.buttonB, DEVICE_BUTTON_EVT_CLICK, s, &SomeClass::onButtonBClick); + * @endcode + */ + template + int ignore(CodalComponent& component, uint16_t value, T* object, void (T::*handler)(Event)); +}; + +/** + * A registration function to allow C++ member functions (methods) to be registered as an event + * listener. + * + * @param id The source of messages to listen for. Events sent from any other IDs will be filtered. + * Use DEVICE_ID_ANY to receive events from all components. + * + * @param value The value of messages to listen for. Events with any other values will be filtered. + * Use DEVICE_EVT_ANY to receive events of any value. + * + * @param object The object on which the method should be invoked. + * + * @param handler The method to call when an event is received. + * + * @return DEVICE_OK on success or DEVICE_INVALID_PARAMETER if the handler or object + * pointers are NULL. + */ +template +int EventModel::listen(uint16_t id, uint16_t value, T* object, void (T::*handler)(Event), uint16_t flags) +{ + if (object == NULL || handler == NULL) return DEVICE_INVALID_PARAMETER; + + if (id == DEVICE_ID_SCHEDULER && flags != MESSAGE_BUS_LISTENER_IMMEDIATE) return DEVICE_INVALID_PARAMETER; + + Listener* newListener = new Listener(id, value, object, handler, flags); + + if (add(newListener) == DEVICE_OK) return DEVICE_OK; + + delete newListener; + return DEVICE_NOT_SUPPORTED; +} + +/** + * A registration function to allow C++ member functions (methods) to be registered as an event + * listener. + * + * @param component The source component of messages to listen for. + * + * @param value The value of messages to listen for. Events with any other values will be filtered. + * Use DEVICE_EVT_ANY to receive events of any value. + * + * @param object The object on which the method should be invoked. + * + * @param handler The method to call when an event is received. + * + * @return DEVICE_OK on success or DEVICE_INVALID_PARAMETER if the handler or object + * pointers are NULL. + */ +template +int EventModel::listen(CodalComponent& component, uint16_t value, T* object, void (T::*handler)(Event), uint16_t flags) +{ + return listen(component.id, value, object, handler, flags); +} + +/** + * Unregister a listener function. + * Listners are identified by the Event ID, Event value and handler registered using listen(). + * + * @param id The Event ID used to register the listener. + * @param value The Event value used to register the listener. + * @param handler The function used to register the listener. + * + * @return DEVICE_OK on success or DEVICE_INVALID_PARAMETER if the handler or object + * pointers are NULL. + * + * Example: + * @code + * + * void SomeClass::onButtonBClick() + * { + * //do something + * } + * + * SomeClass s = new SomeClass(); + * uBit.messageBus.listen(DEVICE_ID_BUTTON_B, DEVICE_BUTTON_EVT_CLICK, s, &SomeClass::onButtonBClick); + * + * // the previously created listener is now ignored. + * uBit.messageBus.ignore(DEVICE_ID_BUTTON_B, DEVICE_BUTTON_EVT_CLICK, s, &SomeClass::onButtonBClick); + * @endcode + */ +template +int EventModel::ignore(uint16_t id, uint16_t value, T* object, void (T::*handler)(Event)) +{ + if (handler == NULL) return DEVICE_INVALID_PARAMETER; + + Listener listener(id, value, object, handler); + remove(&listener); + + return DEVICE_OK; +} + +/** + * Unregister a listener function. + * Listners are identified by the Event ID, Event value and handler registered using listen(). + * + * @param component The source component used to register the listener + * @param value The Event value used to register the listener. + * @param handler The function used to register the listener. + * + * @return DEVICE_OK on success or DEVICE_INVALID_PARAMETER if the handler or object + * pointers are NULL. + * + * Example: + * @code + * + * void SomeClass::onButtonBClick() + * { + * //do something + * } + * + * SomeClass s = new SomeClass(); + * uBit.messageBus.listen(device.buttonB, DEVICE_BUTTON_EVT_CLICK, s, &SomeClass::onButtonBClick); + * + * // the previously created listener is now ignored. + * uBit.messageBus.ignore(device.buttonB, DEVICE_BUTTON_EVT_CLICK, s, &SomeClass::onButtonBClick); + * @endcode + */ +template +int EventModel::ignore(CodalComponent& component, uint16_t value, T* object, void (T::*handler)(Event)) +{ + return ignore(component.id, value, object, handler); } +} // namespace codal #endif diff --git a/inc/core/MemberFunctionCallback.h b/inc/core/MemberFunctionCallback.h index df14bf44..543e02d6 100644 --- a/inc/core/MemberFunctionCallback.h +++ b/inc/core/MemberFunctionCallback.h @@ -25,91 +25,90 @@ DEALINGS IN THE SOFTWARE. #ifndef MEMBER_FUNCTION_CALLBACK_H #define MEMBER_FUNCTION_CALLBACK_H +#include "CodalCompat.h" #include "CodalConfig.h" #include "Event.h" -#include "CodalCompat.h" /** - * Class definition for a MemberFunctionCallback. - * - * C++ member functions (also known as methods) have a more complex - * representation than normal C functions. This class allows a reference to - * a C++ member function to be stored then called at a later date. - * - * This class is used extensively by the DeviceMessageBus to deliver - * events to C++ methods. - */ -namespace codal -{ - class MemberFunctionCallback - { - private: - void* object; - uint32_t method[4]; - void (*invoke)(void *object, uint32_t *method, Event e); - template static void methodCall(void* object, uint32_t*method, Event e); - - public: - - /** - * Constructor. Creates a MemberFunctionCallback based on a pointer to given method. - * - * @param object The object the callback method should be invooked on. - * - * @param method The method to invoke. - */ - template MemberFunctionCallback(T* object, void (T::*method)(Event e)); - - /** - * A comparison of two MemberFunctionCallback objects. - * - * @return true if the given MemberFunctionCallback is equivalent to this one, false otherwise. - */ - bool operator==(const MemberFunctionCallback &mfc); - - /** - * Calls the method reference held by this MemberFunctionCallback. - * - * @param e The event to deliver to the method - */ - void fire(Event e); - }; + * Class definition for a MemberFunctionCallback. + * + * C++ member functions (also known as methods) have a more complex + * representation than normal C functions. This class allows a reference to + * a C++ member function to be stored then called at a later date. + * + * This class is used extensively by the DeviceMessageBus to deliver + * events to C++ methods. + */ +namespace codal { +class MemberFunctionCallback { + private: + void* object; + uint32_t method[4]; + void (*invoke)(void* object, uint32_t* method, Event e); + template + static void methodCall(void* object, uint32_t* method, Event e); + public: /** - * Constructor. Creates a MemberFunctionCallback based on a pointer to given method. - * - * @param object The object the callback method should be invooked on. - * - * @param method The method to invoke. - */ + * Constructor. Creates a MemberFunctionCallback based on a pointer to given method. + * + * @param object The object the callback method should be invooked on. + * + * @param method The method to invoke. + */ template - MemberFunctionCallback::MemberFunctionCallback(T* object, void (T::*method)(Event e)) - { - this->object = object; - memclr(this->method, sizeof(this->method)); - memcpy(this->method, &method, sizeof(method)); - invoke = &MemberFunctionCallback::methodCall; - } + MemberFunctionCallback(T* object, void (T::*method)(Event e)); /** - * A template used to create a static method capable of invoking a C++ member function (method) - * based on the given parameters. - * - * @param object The object the callback method should be invooked on. - * - * @param method The method to invoke. - * - * @param method The Event to supply to the given member function. - */ - template - void MemberFunctionCallback::methodCall(void *object, uint32_t *method, Event e) - { - T* o = (T*)object; - void (T::*m)(Event); - memcpy(&m, method, sizeof(m)); + * A comparison of two MemberFunctionCallback objects. + * + * @return true if the given MemberFunctionCallback is equivalent to this one, false otherwise. + */ + bool operator==(const MemberFunctionCallback& mfc); + + /** + * Calls the method reference held by this MemberFunctionCallback. + * + * @param e The event to deliver to the method + */ + void fire(Event e); +}; + +/** + * Constructor. Creates a MemberFunctionCallback based on a pointer to given method. + * + * @param object The object the callback method should be invooked on. + * + * @param method The method to invoke. + */ +template +MemberFunctionCallback::MemberFunctionCallback(T* object, void (T::*method)(Event e)) +{ + this->object = object; + memclr(this->method, sizeof(this->method)); + memcpy(this->method, &method, sizeof(method)); + invoke = &MemberFunctionCallback::methodCall; +} + +/** + * A template used to create a static method capable of invoking a C++ member function (method) + * based on the given parameters. + * + * @param object The object the callback method should be invooked on. + * + * @param method The method to invoke. + * + * @param method The Event to supply to the given member function. + */ +template +void MemberFunctionCallback::methodCall(void* object, uint32_t* method, Event e) +{ + T* o = (T*)object; + void (T::*m)(Event); + memcpy(&m, method, sizeof(m)); - (o->*m)(e); - } + (o->*m)(e); } +} // namespace codal #endif diff --git a/inc/core/NotifyEvents.h b/inc/core/NotifyEvents.h index 12601b6f..05f24650 100644 --- a/inc/core/NotifyEvents.h +++ b/inc/core/NotifyEvents.h @@ -26,16 +26,16 @@ DEALINGS IN THE SOFTWARE. #define NOTIFY_EVENTS_H /** - * This file contains events used on the general purpose Eventing channel - * DEVICE_ID_NOTIFY, new events should be added here, to prevent duplication. - */ -#define DISPLAY_EVT_FREE 1 -#define CODAL_SERIAL_EVT_TX_EMPTY 2 -#define BLE_EVT_SERIAL_TX_EMPTY 3 -#define ARCADE_PLAYER_JOIN_RESULT 4 -#define POWER_EVT_CANCEL_DEEPSLEEP 5 + * This file contains events used on the general purpose Eventing channel + * DEVICE_ID_NOTIFY, new events should be added here, to prevent duplication. + */ +#define DISPLAY_EVT_FREE 1 +#define CODAL_SERIAL_EVT_TX_EMPTY 2 +#define BLE_EVT_SERIAL_TX_EMPTY 3 +#define ARCADE_PLAYER_JOIN_RESULT 4 +#define POWER_EVT_CANCEL_DEEPSLEEP 5 // Any values after 1024 are available for application use -#define DEVICE_NOTIFY_USER_EVENT_BASE 1024 +#define DEVICE_NOTIFY_USER_EVENT_BASE 1024 #endif diff --git a/inc/core/codal_target_hal.h b/inc/core/codal_target_hal.h index 91905fd6..ab08a5c7 100644 --- a/inc/core/codal_target_hal.h +++ b/inc/core/codal_target_hal.h @@ -28,85 +28,85 @@ DEALINGS IN THE SOFTWARE. #include "platform_includes.h" #ifdef __cplusplus - extern "C" { +extern "C" { #endif - void target_init(); +void target_init(); - void target_enable_irq(); +void target_enable_irq(); - void target_disable_irq(); +void target_disable_irq(); - void target_reset(); +void target_reset(); - void target_wait(uint32_t milliseconds); +void target_wait(uint32_t milliseconds); - void target_wait_us(uint32_t us); +void target_wait_us(uint32_t us); - int target_seed_random(uint32_t rand); +int target_seed_random(uint32_t rand); - int target_random(int max); +int target_random(int max); - uint64_t target_get_serial(); +uint64_t target_get_serial(); - void target_scheduler_idle(); +void target_scheduler_idle(); - void target_wait_for_event(); - - void target_deepsleep(); +void target_wait_for_event(); - void target_panic(int statusCode); +void target_deepsleep(); - PROCESSOR_WORD_TYPE fiber_initial_stack_base(); - /** - * Configures the link register of the given tcb to have the value function. - * - * @param tcb The tcb to modify - * @param function the function the link register should point to. - */ - void tcb_configure_lr(void* tcb, PROCESSOR_WORD_TYPE function); +void target_panic(int statusCode); - void* tcb_allocate(); +PROCESSOR_WORD_TYPE fiber_initial_stack_base(); +/** + * Configures the link register of the given tcb to have the value function. + * + * @param tcb The tcb to modify + * @param function the function the link register should point to. + */ +void tcb_configure_lr(void* tcb, PROCESSOR_WORD_TYPE function); - /** - * Configures the link register of the given tcb to have the value function. - * - * @param tcb The tcb to modify - * @param function the function the link register should point to. - */ - void tcb_configure_sp(void* tcb, PROCESSOR_WORD_TYPE sp); +void* tcb_allocate(); - void tcb_configure_stack_base(void* tcb, PROCESSOR_WORD_TYPE stack_base); +/** + * Configures the link register of the given tcb to have the value function. + * + * @param tcb The tcb to modify + * @param function the function the link register should point to. + */ +void tcb_configure_sp(void* tcb, PROCESSOR_WORD_TYPE sp); - PROCESSOR_WORD_TYPE tcb_get_stack_base(void* tcb); +void tcb_configure_stack_base(void* tcb, PROCESSOR_WORD_TYPE stack_base); - PROCESSOR_WORD_TYPE get_current_sp(); +PROCESSOR_WORD_TYPE tcb_get_stack_base(void* tcb); - PROCESSOR_WORD_TYPE tcb_get_sp(void* tcb); +PROCESSOR_WORD_TYPE get_current_sp(); - void tcb_configure_args(void* tcb, PROCESSOR_WORD_TYPE ep, PROCESSOR_WORD_TYPE cp, PROCESSOR_WORD_TYPE pm); +PROCESSOR_WORD_TYPE tcb_get_sp(void* tcb); - // Preprocessor Directive to ignore redecleration when using clang - #ifndef __clang__ - /** - * Default implementation of atomic fetch and add opertaion. - * GCC provides this where possible, but this is not supported on some CPU architectures... - * - * @param ptr pointer to the memory to access. - * @param value the value to add to the memory location. - * @return the value of th ememory location BEFORE the add operation took place. - */ - short unsigned int __sync_fetch_and_add_2 (volatile void *ptr, short unsigned int value); - - #endif - /** - * Default implementation of atomic fetch and add opertaion. - * GCC provides this where possible, but this is not supported on some CPU architectures... - * - * @param ptr pointer to the memory to access. - * @param value the value to add to the memory location. - * @return the value of th ememory location BEFORE the add operation took place. - */ - short unsigned int __sync_fetch_and_add_2 (volatile void *ptr, short unsigned int value); +void tcb_configure_args(void* tcb, PROCESSOR_WORD_TYPE ep, PROCESSOR_WORD_TYPE cp, PROCESSOR_WORD_TYPE pm); + +// Preprocessor Directive to ignore redecleration when using clang +#ifndef __clang__ +/** + * Default implementation of atomic fetch and add opertaion. + * GCC provides this where possible, but this is not supported on some CPU architectures... + * + * @param ptr pointer to the memory to access. + * @param value the value to add to the memory location. + * @return the value of th ememory location BEFORE the add operation took place. + */ +short unsigned int __sync_fetch_and_add_2(volatile void* ptr, short unsigned int value); + +#endif +/** + * Default implementation of atomic fetch and add opertaion. + * GCC provides this where possible, but this is not supported on some CPU architectures... + * + * @param ptr pointer to the memory to access. + * @param value the value to add to the memory location. + * @return the value of th ememory location BEFORE the add operation took place. + */ +short unsigned int __sync_fetch_and_add_2(volatile void* ptr, short unsigned int value); #ifdef __cplusplus } diff --git a/inc/core/gcc_compat.h b/inc/core/gcc_compat.h index 3bf4f0e3..6ef16ece 100644 --- a/inc/core/gcc_compat.h +++ b/inc/core/gcc_compat.h @@ -3,12 +3,12 @@ #if __GNUC__ > 11 extern "C" { - int _close( int fd ) __attribute__((weak)); - int _getpid() __attribute__((weak)); - int _kill(int pid, int sig) __attribute__((weak)); - int _lseek(int file, int ptr, int dir) __attribute__((weak)); - int _read(int file, char *ptr, int len) __attribute__((weak)); - int _write(int file, char *ptr, int len) __attribute__((weak)); +int _close(int fd) __attribute__((weak)); +int _getpid() __attribute__((weak)); +int _kill(int pid, int sig) __attribute__((weak)); +int _lseek(int file, int ptr, int dir) __attribute__((weak)); +int _read(int file, char* ptr, int len) __attribute__((weak)); +int _write(int file, char* ptr, int len) __attribute__((weak)); } #endif diff --git a/inc/driver-models/AbstractButton.h b/inc/driver-models/AbstractButton.h index 446feed9..8acd19d5 100644 --- a/inc/driver-models/AbstractButton.h +++ b/inc/driver-models/AbstractButton.h @@ -25,104 +25,94 @@ DEALINGS IN THE SOFTWARE. #ifndef ABSTRACT_BUTTON_H #define ABSTRACT_BUTTON_H -#include "CodalConfig.h" #include "CodalComponent.h" +#include "CodalConfig.h" #include "Event.h" -#define DEVICE_BUTTON_EVT_DOWN 1 -#define DEVICE_BUTTON_EVT_UP 2 -#define DEVICE_BUTTON_EVT_CLICK 3 -#define DEVICE_BUTTON_EVT_LONG_CLICK 4 -#define DEVICE_BUTTON_EVT_HOLD 5 -#define DEVICE_BUTTON_EVT_DOUBLE_CLICK 6 - -#define DEVICE_BUTTON_LONG_CLICK_TIME 1000 -#define DEVICE_BUTTON_HOLD_TIME 1500 - -#define DEVICE_BUTTON_STATE 0x01 -#define DEVICE_BUTTON_STATE_HOLD_TRIGGERED 0x02 -#define DEVICE_BUTTON_STATE_CLICK 0x04 -#define DEVICE_BUTTON_STATE_LONG_CLICK 0x08 - -#define DEVICE_BUTTON_SIGMA_MIN 0 -#define DEVICE_BUTTON_SIGMA_MAX 12 -#define DEVICE_BUTTON_SIGMA_THRESH_HI 8 -#define DEVICE_BUTTON_SIGMA_THRESH_LO 2 -#define DEVICE_BUTTON_DOUBLE_CLICK_THRESH 50 - -enum ButtonEventConfiguration -{ - DEVICE_BUTTON_SIMPLE_EVENTS, - DEVICE_BUTTON_ALL_EVENTS -}; +#define DEVICE_BUTTON_EVT_DOWN 1 +#define DEVICE_BUTTON_EVT_UP 2 +#define DEVICE_BUTTON_EVT_CLICK 3 +#define DEVICE_BUTTON_EVT_LONG_CLICK 4 +#define DEVICE_BUTTON_EVT_HOLD 5 +#define DEVICE_BUTTON_EVT_DOUBLE_CLICK 6 + +#define DEVICE_BUTTON_LONG_CLICK_TIME 1000 +#define DEVICE_BUTTON_HOLD_TIME 1500 + +#define DEVICE_BUTTON_STATE 0x01 +#define DEVICE_BUTTON_STATE_HOLD_TRIGGERED 0x02 +#define DEVICE_BUTTON_STATE_CLICK 0x04 +#define DEVICE_BUTTON_STATE_LONG_CLICK 0x08 + +#define DEVICE_BUTTON_SIGMA_MIN 0 +#define DEVICE_BUTTON_SIGMA_MAX 12 +#define DEVICE_BUTTON_SIGMA_THRESH_HI 8 +#define DEVICE_BUTTON_SIGMA_THRESH_LO 2 +#define DEVICE_BUTTON_DOUBLE_CLICK_THRESH 50 + +enum ButtonEventConfiguration { DEVICE_BUTTON_SIMPLE_EVENTS, DEVICE_BUTTON_ALL_EVENTS }; + +enum ButtonPolarity { ACTIVE_LOW = 0, ACTIVE_HIGH = 1 }; + +namespace codal { +/** + * Class definition for Device Button. + * + * Represents a single, generic button on the device. + */ +class AbstractButton : public CodalComponent { + public: + uint16_t clickCount; -enum ButtonPolarity -{ - ACTIVE_LOW = 0, - ACTIVE_HIGH = 1 -}; + /** + * Constructor. + * + * Create a abstract software representation of a button. + */ + AbstractButton(); + + /** + * Tests if this Button is currently pressed. + * + * @code + * if(buttonA.isPressed()) + * display.scroll("Pressed!"); + * @endcode + * + * @return 1 if this button is pressed, 0 otherwise. + */ + virtual int isPressed() = 0; -namespace codal -{ /** - * Class definition for Device Button. - * - * Represents a single, generic button on the device. - */ - class AbstractButton : public CodalComponent - { - public: - - uint16_t clickCount; - - /** - * Constructor. - * - * Create a abstract software representation of a button. - */ - AbstractButton(); - - /** - * Tests if this Button is currently pressed. - * - * @code - * if(buttonA.isPressed()) - * display.scroll("Pressed!"); - * @endcode - * - * @return 1 if this button is pressed, 0 otherwise. - */ - virtual int isPressed() = 0; - - /** - * Determines if this button has been pressed. - * - * @code - * if(buttonA.wasPressed()) - * display.scroll("Pressed!"); - * @endcode - * - * @return the number of time this button has been pressed since the last time wasPressed() has been called. - */ - int wasPressed(); - - /** - * Enables this button. - * Buttons are normally created in an enabled state, but use this function to re-enable a previously disabled button. - */ - void enable(); - - /** - * Disable this button. - * Buttons are normally created in an enabled state. Use this function to disable this button. - */ - void disable(); - - /** - * Destructor - */ - ~AbstractButton(); - }; -} + * Determines if this button has been pressed. + * + * @code + * if(buttonA.wasPressed()) + * display.scroll("Pressed!"); + * @endcode + * + * @return the number of time this button has been pressed since the last time wasPressed() has been called. + */ + int wasPressed(); + + /** + * Enables this button. + * Buttons are normally created in an enabled state, but use this function to re-enable a previously disabled + * button. + */ + void enable(); + + /** + * Disable this button. + * Buttons are normally created in an enabled state. Use this function to disable this button. + */ + void disable(); + + /** + * Destructor + */ + ~AbstractButton(); +}; +} // namespace codal #endif diff --git a/inc/driver-models/Accelerometer.h b/inc/driver-models/Accelerometer.h index ff955bf3..08e6129d 100644 --- a/inc/driver-models/Accelerometer.h +++ b/inc/driver-models/Accelerometer.h @@ -25,332 +25,321 @@ DEALINGS IN THE SOFTWARE. #ifndef CODAL_ACCELEROMETER_H #define CODAL_ACCELEROMETER_H -#include "CodalConfig.h" #include "CodalComponent.h" -#include "Pin.h" -#include "CoordinateSystem.h" +#include "CodalConfig.h" #include "CodalUtil.h" +#include "CoordinateSystem.h" +#include "Pin.h" + +/** + * Status flags + */ +#define ACCELEROMETER_IMU_DATA_VALID 0x02 /** - * Status flags - */ -#define ACCELEROMETER_IMU_DATA_VALID 0x02 + * Accelerometer events + */ +#define ACCELEROMETER_EVT_DATA_UPDATE 1 /** - * Accelerometer events - */ -#define ACCELEROMETER_EVT_DATA_UPDATE 1 + * Gesture events + */ +#define ACCELEROMETER_EVT_NONE 0 +#define ACCELEROMETER_EVT_TILT_UP 1 +#define ACCELEROMETER_EVT_TILT_DOWN 2 +#define ACCELEROMETER_EVT_TILT_LEFT 3 +#define ACCELEROMETER_EVT_TILT_RIGHT 4 +#define ACCELEROMETER_EVT_FACE_UP 5 +#define ACCELEROMETER_EVT_FACE_DOWN 6 +#define ACCELEROMETER_EVT_FREEFALL 7 +#define ACCELEROMETER_EVT_3G 8 +#define ACCELEROMETER_EVT_6G 9 +#define ACCELEROMETER_EVT_8G 10 +#define ACCELEROMETER_EVT_SHAKE 11 +#define ACCELEROMETER_EVT_2G 12 /** - * Gesture events - */ -#define ACCELEROMETER_EVT_NONE 0 -#define ACCELEROMETER_EVT_TILT_UP 1 -#define ACCELEROMETER_EVT_TILT_DOWN 2 -#define ACCELEROMETER_EVT_TILT_LEFT 3 -#define ACCELEROMETER_EVT_TILT_RIGHT 4 -#define ACCELEROMETER_EVT_FACE_UP 5 -#define ACCELEROMETER_EVT_FACE_DOWN 6 -#define ACCELEROMETER_EVT_FREEFALL 7 -#define ACCELEROMETER_EVT_3G 8 -#define ACCELEROMETER_EVT_6G 9 -#define ACCELEROMETER_EVT_8G 10 -#define ACCELEROMETER_EVT_SHAKE 11 -#define ACCELEROMETER_EVT_2G 12 + * Gesture recogniser constants + */ +#define ACCELEROMETER_REST_TOLERANCE 200 +#define ACCELEROMETER_TILT_TOLERANCE 200 +#define ACCELEROMETER_FREEFALL_TOLERANCE 400 +#define ACCELEROMETER_SHAKE_TOLERANCE 400 +#define ACCELEROMETER_2G_TOLERANCE 2048 +#define ACCELEROMETER_3G_TOLERANCE 3072 +#define ACCELEROMETER_6G_TOLERANCE 6144 +#define ACCELEROMETER_8G_TOLERANCE 8192 +#define ACCELEROMETER_GESTURE_DAMPING 5 +#define ACCELEROMETER_SHAKE_DAMPING 10 +#define ACCELEROMETER_SHAKE_RTX 30 + +#define ACCELEROMETER_REST_THRESHOLD (ACCELEROMETER_REST_TOLERANCE * ACCELEROMETER_REST_TOLERANCE) +#define ACCELEROMETER_FREEFALL_THRESHOLD \ + ((uint32_t)ACCELEROMETER_FREEFALL_TOLERANCE * (uint32_t)ACCELEROMETER_FREEFALL_TOLERANCE) +#define ACCELEROMETER_2G_THRESHOLD ((uint32_t)ACCELEROMETER_2G_TOLERANCE * (uint32_t)ACCELEROMETER_2G_TOLERANCE) +#define ACCELEROMETER_3G_THRESHOLD ((uint32_t)ACCELEROMETER_3G_TOLERANCE * (uint32_t)ACCELEROMETER_3G_TOLERANCE) +#define ACCELEROMETER_6G_THRESHOLD ((uint32_t)ACCELEROMETER_6G_TOLERANCE * (uint32_t)ACCELEROMETER_6G_TOLERANCE) +#define ACCELEROMETER_8G_THRESHOLD ((uint32_t)ACCELEROMETER_8G_TOLERANCE * (uint32_t)ACCELEROMETER_8G_TOLERANCE) +#define ACCELEROMETER_SHAKE_COUNT_THRESHOLD 4 + +namespace codal { +struct ShakeHistory { + uint16_t shaken : 1, x : 1, y : 1, z : 1, impulse_2, impulse_3, impulse_6, impulse_8, count : 8; + + uint16_t timer; +}; /** - * Gesture recogniser constants - */ -#define ACCELEROMETER_REST_TOLERANCE 200 -#define ACCELEROMETER_TILT_TOLERANCE 200 -#define ACCELEROMETER_FREEFALL_TOLERANCE 400 -#define ACCELEROMETER_SHAKE_TOLERANCE 400 -#define ACCELEROMETER_2G_TOLERANCE 2048 -#define ACCELEROMETER_3G_TOLERANCE 3072 -#define ACCELEROMETER_6G_TOLERANCE 6144 -#define ACCELEROMETER_8G_TOLERANCE 8192 -#define ACCELEROMETER_GESTURE_DAMPING 5 -#define ACCELEROMETER_SHAKE_DAMPING 10 -#define ACCELEROMETER_SHAKE_RTX 30 - -#define ACCELEROMETER_REST_THRESHOLD (ACCELEROMETER_REST_TOLERANCE * ACCELEROMETER_REST_TOLERANCE) -#define ACCELEROMETER_FREEFALL_THRESHOLD ((uint32_t)ACCELEROMETER_FREEFALL_TOLERANCE * (uint32_t)ACCELEROMETER_FREEFALL_TOLERANCE) -#define ACCELEROMETER_2G_THRESHOLD ((uint32_t)ACCELEROMETER_2G_TOLERANCE * (uint32_t)ACCELEROMETER_2G_TOLERANCE) -#define ACCELEROMETER_3G_THRESHOLD ((uint32_t)ACCELEROMETER_3G_TOLERANCE * (uint32_t)ACCELEROMETER_3G_TOLERANCE) -#define ACCELEROMETER_6G_THRESHOLD ((uint32_t)ACCELEROMETER_6G_TOLERANCE * (uint32_t)ACCELEROMETER_6G_TOLERANCE) -#define ACCELEROMETER_8G_THRESHOLD ((uint32_t)ACCELEROMETER_8G_TOLERANCE * (uint32_t)ACCELEROMETER_8G_TOLERANCE) -#define ACCELEROMETER_SHAKE_COUNT_THRESHOLD 4 - -namespace codal -{ - struct ShakeHistory - { - uint16_t shaken:1, - x:1, - y:1, - z:1, - impulse_2, - impulse_3, - impulse_6, - impulse_8, - count:8; - - uint16_t timer; - }; + * Class definition for Accelerometer. + */ +class Accelerometer : public CodalComponent { + protected: + uint16_t samplePeriod; // The time between samples, in milliseconds. + uint8_t sampleRange; // The sample range of the accelerometer in g. + Sample3D sample; // The last sample read, in the coordinate system specified by the coordinateSpace variable. + Sample3D sampleENU; // The last sample read, in raw ENU format (stored in case requests are made for data in other + // coordinate spaces) + CoordinateSpace& + coordinateSpace; // The coordinate space transform (if any) to apply to the raw data from the hardware. + + float pitch; // Pitch of the device, in radians. + float roll; // Roll of the device, in radians. + + uint8_t sigma; // the number of ticks that the instantaneous gesture has been stable. + uint8_t impulseSigma; // the number of ticks since an impulse event has been generated. + uint16_t lastGesture; // the last, stable gesture recorded. + uint16_t currentGesture; // the instantaneous, unfiltered gesture detected. + ShakeHistory shake; // State information needed to detect shake events. + + public: + /** + * Constructor. + * Create a software abstraction of an accelerometer. + * + * @param coordinateSpace the orientation of the sensor. Defaults to: SIMPLE_CARTESIAN + * @param id the unique EventModel id of this component. Defaults to: DEVICE_ID_ACCELEROMETER + * + */ + Accelerometer(CoordinateSpace& coordinateSpace, uint16_t id = DEVICE_ID_ACCELEROMETER); + + /** + * Attempts to set the sample rate of the accelerometer to the specified value (in ms). + * + * @param period the requested time between samples, in milliseconds. + * @return DEVICE_OK on success, DEVICE_I2C_ERROR is the request fails. + * + * @note The requested rate may not be possible on the hardware. In this case, the + * nearest lower rate is chosen. + * + * @note This method should be overriden (if supported) by specific accelerometer device drivers. + */ + virtual int setPeriod(int period); + + /** + * Reads the currently configured sample rate of the accelerometer. + * + * @return The time between samples, in milliseconds. + */ + virtual int getPeriod(); + + /** + * Attempts to set the sample range of the accelerometer to the specified value (in g). + * + * @param range The requested sample range of samples, in g. + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR is the request fails. + * + * @note The requested range may not be possible on the hardware. In this case, the + * nearest lower range is chosen. + * + * @note This method should be overriden (if supported) by specific accelerometer device drivers. + */ + virtual int setRange(int range); + + /** + * Reads the currently configured sample range of the accelerometer. + * + * @return The sample range, in g. + */ + virtual int getRange(); + + /** + * Configures the accelerometer for G range and sample rate defined + * in this object. The nearest values are chosen to those defined + * that are supported by the hardware. The instance variables are then + * updated to reflect reality. + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the accelerometer could not be configured. + * + * @note This method should be overridden by the hardware driver to implement the requested + * changes in hardware. + */ + virtual int configure() = 0; + + /** + * Poll to see if new data is available from the hardware. If so, update it. + * n.b. it is not necessary to explicitly call this function to update data + * (it normally happens in the background when the scheduler is idle), but a check is performed + * if the user explicitly requests up to date data. + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the update fails. + * + * @note This method should be overridden by the hardware driver to implement the requested + * changes in hardware. + */ + virtual int requestUpdate() = 0; + + /** + * Stores data from the accelerometer sensor in our buffer, and perform gesture tracking. + * + * On first use, this member function will attempt to add this component to the + * list of fiber components in order to constantly update the values stored + * by this object. + * + * This lazy instantiation means that we do not + * obtain the overhead from non-chalantly adding this component to fiber components. + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the read request fails. + */ + virtual int update(); + + /** + * Reads the last accelerometer value stored, and provides it in the coordinate system requested. + * + * @param coordinateSpace The coordinate system to use. + * @return The force measured in each axis, in milli-g. + */ + Sample3D getSample(CoordinateSystem coordinateSystem); + + /** + * Reads the last accelerometer value stored, and in the coordinate system defined in the constructor. + * @return The force measured in each axis, in milli-g. + */ + Sample3D getSample(); + + /** + * reads the value of the x axis from the latest update retrieved from the accelerometer, + * using the default coordinate system as specified in the constructor. + * + * @return the force measured in the x axis, in milli-g. + */ + int getX(); + + /** + * reads the value of the y axis from the latest update retrieved from the accelerometer, + * using the default coordinate system as specified in the constructor. + * + * @return the force measured in the y axis, in milli-g. + */ + int getY(); + + /** + * reads the value of the z axis from the latest update retrieved from the accelerometer, + * using the default coordinate system as specified in the constructor. + * + * @return the force measured in the z axis, in milli-g. + */ + int getZ(); + + /** + * Provides a rotation compensated pitch of the device, based on the latest update retrieved from the accelerometer. + * + * @return The pitch of the device, in degrees. + * + * @code + * accelerometer.getPitch(); + * @endcode + */ + int getPitch(); + + /** + * Provides a rotation compensated pitch of the device, based on the latest update retrieved from the accelerometer. + * + * @return The pitch of the device, in radians. + * + * @code + * accelerometer.getPitchRadians(); + * @endcode + */ + float getPitchRadians(); + + /** + * Provides a rotation compensated roll of the device, based on the latest update retrieved from the accelerometer. + * + * @return The roll of the device, in degrees. + * + * @code + * accelerometer.getRoll(); + * @endcode + */ + int getRoll(); + + /** + * Provides a rotation compensated roll of the device, based on the latest update retrieved from the accelerometer. + * + * @return The roll of the device, in radians. + * + * @code + * accelerometer.getRollRadians(); + * @endcode + */ + float getRollRadians(); + + /** + * Retrieves the last recorded gesture. + * + * @return The last gesture that was detected. + * + * Example: + * @code + * + * if (accelerometer.getGesture() == SHAKE) + * display.scroll("SHAKE!"); + * @endcode + */ + uint16_t getGesture(); + + /** + * Destructor. + */ + ~Accelerometer(); + + private: + /** + * Recalculate roll and pitch values for the current sample. + * + * @note We only do this at most once per sample, as the necessary trigonemteric functions are rather + * heavyweight for a CPU without a floating point unit. + */ + void recalculatePitchRoll(); + + /** + * Updates the basic gesture recognizer. This performs instantaneous pose recognition, and also some low pass + * filtering to promote stability. + */ + void updateGesture(); + + /** + * A service function. + * It calculates the current scalar acceleration of the device (x^2 + y^2 + z^2). + * It does not, however, square root the result, as this is a relatively high cost operation. + * + * This is left to application code should it be needed. + * + * @return the sum of the square of the acceleration of the device across all axes. + */ + uint32_t instantaneousAccelerationSquared(); /** - * Class definition for Accelerometer. + * Service function. + * Determines a 'best guess' posture of the device based on instantaneous data. + * + * This makes no use of historic data, and forms this input to the filter implemented in updateGesture(). + * + * @return A 'best guess' of the current posture of the device, based on instanataneous data. */ - class Accelerometer : public CodalComponent - { - protected: - - uint16_t samplePeriod; // The time between samples, in milliseconds. - uint8_t sampleRange; // The sample range of the accelerometer in g. - Sample3D sample; // The last sample read, in the coordinate system specified by the coordinateSpace variable. - Sample3D sampleENU; // The last sample read, in raw ENU format (stored in case requests are made for data in other coordinate spaces) - CoordinateSpace &coordinateSpace; // The coordinate space transform (if any) to apply to the raw data from the hardware. - - float pitch; // Pitch of the device, in radians. - float roll; // Roll of the device, in radians. - - uint8_t sigma; // the number of ticks that the instantaneous gesture has been stable. - uint8_t impulseSigma; // the number of ticks since an impulse event has been generated. - uint16_t lastGesture; // the last, stable gesture recorded. - uint16_t currentGesture; // the instantaneous, unfiltered gesture detected. - ShakeHistory shake; // State information needed to detect shake events. - - public: - - /** - * Constructor. - * Create a software abstraction of an accelerometer. - * - * @param coordinateSpace the orientation of the sensor. Defaults to: SIMPLE_CARTESIAN - * @param id the unique EventModel id of this component. Defaults to: DEVICE_ID_ACCELEROMETER - * - */ - Accelerometer(CoordinateSpace &coordinateSpace, uint16_t id = DEVICE_ID_ACCELEROMETER); - - /** - * Attempts to set the sample rate of the accelerometer to the specified value (in ms). - * - * @param period the requested time between samples, in milliseconds. - * @return DEVICE_OK on success, DEVICE_I2C_ERROR is the request fails. - * - * @note The requested rate may not be possible on the hardware. In this case, the - * nearest lower rate is chosen. - * - * @note This method should be overriden (if supported) by specific accelerometer device drivers. - */ - virtual int setPeriod(int period); - - /** - * Reads the currently configured sample rate of the accelerometer. - * - * @return The time between samples, in milliseconds. - */ - virtual int getPeriod(); - - /** - * Attempts to set the sample range of the accelerometer to the specified value (in g). - * - * @param range The requested sample range of samples, in g. - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR is the request fails. - * - * @note The requested range may not be possible on the hardware. In this case, the - * nearest lower range is chosen. - * - * @note This method should be overriden (if supported) by specific accelerometer device drivers. - */ - virtual int setRange(int range); - - /** - * Reads the currently configured sample range of the accelerometer. - * - * @return The sample range, in g. - */ - virtual int getRange(); - - /** - * Configures the accelerometer for G range and sample rate defined - * in this object. The nearest values are chosen to those defined - * that are supported by the hardware. The instance variables are then - * updated to reflect reality. - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the accelerometer could not be configured. - * - * @note This method should be overridden by the hardware driver to implement the requested - * changes in hardware. - */ - virtual int configure() = 0; - - /** - * Poll to see if new data is available from the hardware. If so, update it. - * n.b. it is not necessary to explicitly call this function to update data - * (it normally happens in the background when the scheduler is idle), but a check is performed - * if the user explicitly requests up to date data. - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the update fails. - * - * @note This method should be overridden by the hardware driver to implement the requested - * changes in hardware. - */ - virtual int requestUpdate() = 0; - - /** - * Stores data from the accelerometer sensor in our buffer, and perform gesture tracking. - * - * On first use, this member function will attempt to add this component to the - * list of fiber components in order to constantly update the values stored - * by this object. - * - * This lazy instantiation means that we do not - * obtain the overhead from non-chalantly adding this component to fiber components. - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the read request fails. - */ - virtual int update(); - - /** - * Reads the last accelerometer value stored, and provides it in the coordinate system requested. - * - * @param coordinateSpace The coordinate system to use. - * @return The force measured in each axis, in milli-g. - */ - Sample3D getSample(CoordinateSystem coordinateSystem); - - /** - * Reads the last accelerometer value stored, and in the coordinate system defined in the constructor. - * @return The force measured in each axis, in milli-g. - */ - Sample3D getSample(); - - /** - * reads the value of the x axis from the latest update retrieved from the accelerometer, - * using the default coordinate system as specified in the constructor. - * - * @return the force measured in the x axis, in milli-g. - */ - int getX(); - - /** - * reads the value of the y axis from the latest update retrieved from the accelerometer, - * using the default coordinate system as specified in the constructor. - * - * @return the force measured in the y axis, in milli-g. - */ - int getY(); - - /** - * reads the value of the z axis from the latest update retrieved from the accelerometer, - * using the default coordinate system as specified in the constructor. - * - * @return the force measured in the z axis, in milli-g. - */ - int getZ(); - - /** - * Provides a rotation compensated pitch of the device, based on the latest update retrieved from the accelerometer. - * - * @return The pitch of the device, in degrees. - * - * @code - * accelerometer.getPitch(); - * @endcode - */ - int getPitch(); - - /** - * Provides a rotation compensated pitch of the device, based on the latest update retrieved from the accelerometer. - * - * @return The pitch of the device, in radians. - * - * @code - * accelerometer.getPitchRadians(); - * @endcode - */ - float getPitchRadians(); - - /** - * Provides a rotation compensated roll of the device, based on the latest update retrieved from the accelerometer. - * - * @return The roll of the device, in degrees. - * - * @code - * accelerometer.getRoll(); - * @endcode - */ - int getRoll(); - - /** - * Provides a rotation compensated roll of the device, based on the latest update retrieved from the accelerometer. - * - * @return The roll of the device, in radians. - * - * @code - * accelerometer.getRollRadians(); - * @endcode - */ - float getRollRadians(); - - /** - * Retrieves the last recorded gesture. - * - * @return The last gesture that was detected. - * - * Example: - * @code - * - * if (accelerometer.getGesture() == SHAKE) - * display.scroll("SHAKE!"); - * @endcode - */ - uint16_t getGesture(); - - /** - * Destructor. - */ - ~Accelerometer(); - - private: - - /** - * Recalculate roll and pitch values for the current sample. - * - * @note We only do this at most once per sample, as the necessary trigonemteric functions are rather - * heavyweight for a CPU without a floating point unit. - */ - void recalculatePitchRoll(); - - /** - * Updates the basic gesture recognizer. This performs instantaneous pose recognition, and also some low pass filtering to promote - * stability. - */ - void updateGesture(); - - /** - * A service function. - * It calculates the current scalar acceleration of the device (x^2 + y^2 + z^2). - * It does not, however, square root the result, as this is a relatively high cost operation. - * - * This is left to application code should it be needed. - * - * @return the sum of the square of the acceleration of the device across all axes. - */ - uint32_t instantaneousAccelerationSquared(); - - /** - * Service function. - * Determines a 'best guess' posture of the device based on instantaneous data. - * - * This makes no use of historic data, and forms this input to the filter implemented in updateGesture(). - * - * @return A 'best guess' of the current posture of the device, based on instanataneous data. - */ - uint16_t instantaneousPosture(); - }; -} + uint16_t instantaneousPosture(); +}; +} // namespace codal #endif diff --git a/inc/driver-models/CodalUSB.h b/inc/driver-models/CodalUSB.h index 47ca2ce7..4321b3b5 100644 --- a/inc/driver-models/CodalUSB.h +++ b/inc/driver-models/CodalUSB.h @@ -25,83 +25,83 @@ DEALINGS IN THE SOFTWARE. #ifndef CODAL_USB_H #define CODAL_USB_H -#include "CodalConfig.h" #include "CodalComponent.h" +#include "CodalConfig.h" #if CONFIG_ENABLED(DEVICE_USB) // define usb events for the CODAL message bus -#define USB_EVT_CONNECTED 1 // powered usb cable has been plugged into the device -#define USB_EVT_REMOVED 2 // powered usb cable has been removed from the device -#define USB_EVT_READY 3 // powered usb cable with data connection has been plugged into the device, and the usb peripheral is ready! +#define USB_EVT_CONNECTED 1 // powered usb cable has been plugged into the device +#define USB_EVT_REMOVED 2 // powered usb cable has been removed from the device +#define USB_EVT_READY \ + 3 // powered usb cable with data connection has been plugged into the device, and the usb peripheral is ready! #include + #include "ErrorNo.h" -#define USB_CONFIG_POWERED_MASK 0x40 -#define USB_CONFIG_BUS_POWERED 0x80 -#define USB_CONFIG_SELF_POWERED 0xC0 +#define USB_CONFIG_POWERED_MASK 0x40 +#define USB_CONFIG_BUS_POWERED 0x80 +#define USB_CONFIG_SELF_POWERED 0xC0 #define USB_CONFIG_REMOTE_WAKEUP 0x20 -#define USB_DEVICE_DESCRIPTOR_TYPE 1 +#define USB_DEVICE_DESCRIPTOR_TYPE 1 #define USB_CONFIGURATION_DESCRIPTOR_TYPE 2 -#define USB_STRING_DESCRIPTOR_TYPE 3 -#define USB_INTERFACE_DESCRIPTOR_TYPE 4 -#define USB_ENDPOINT_DESCRIPTOR_TYPE 5 -#define USB_BOS_DESCRIPTOR_TYPE 15 +#define USB_STRING_DESCRIPTOR_TYPE 3 +#define USB_INTERFACE_DESCRIPTOR_TYPE 4 +#define USB_ENDPOINT_DESCRIPTOR_TYPE 5 +#define USB_BOS_DESCRIPTOR_TYPE 15 #define USB_REQ_HOSTTODEVICE 0x00 #define USB_REQ_DEVICETOHOST 0x80 -#define USB_REQ_DIRECTION 0x80 +#define USB_REQ_DIRECTION 0x80 #define USB_REQ_STANDARD 0x00 -#define USB_REQ_CLASS 0x20 -#define USB_REQ_VENDOR 0x40 -#define USB_REQ_TYPE 0x60 +#define USB_REQ_CLASS 0x20 +#define USB_REQ_VENDOR 0x40 +#define USB_REQ_TYPE 0x60 #define USB_REQ_DESTINATION 0x1F -#define USB_REQ_DEVICE 0x00 -#define USB_REQ_INTERFACE 0x01 -#define USB_REQ_ENDPOINT 0x02 -#define USB_REQ_OTHER 0x03 - -#define USB_REQ_GET_STATUS 0x00 -#define USB_REQ_CLEAR_FEATURE 0x01 -#define USB_REQ_SET_FEATURE 0x03 -#define USB_REQ_SET_ADDRESS 5 -#define USB_REQ_GET_DESCRIPTOR 6 -#define USB_REQ_SET_DESCRIPTOR 7 +#define USB_REQ_DEVICE 0x00 +#define USB_REQ_INTERFACE 0x01 +#define USB_REQ_ENDPOINT 0x02 +#define USB_REQ_OTHER 0x03 + +#define USB_REQ_GET_STATUS 0x00 +#define USB_REQ_CLEAR_FEATURE 0x01 +#define USB_REQ_SET_FEATURE 0x03 +#define USB_REQ_SET_ADDRESS 5 +#define USB_REQ_GET_DESCRIPTOR 6 +#define USB_REQ_SET_DESCRIPTOR 7 #define USB_REQ_GET_CONFIGURATION 8 #define USB_REQ_SET_CONFIGURATION 9 -#define USB_REQ_GET_INTERFACE 10 -#define USB_REQ_SET_INTERFACE 11 -#define USB_REQ_SYNCH_FRAME 12 +#define USB_REQ_GET_INTERFACE 10 +#define USB_REQ_SET_INTERFACE 11 +#define USB_REQ_SYNCH_FRAME 12 -#define USB_DEVICE_REMOTE_WAKEUP 1 -#define USB_FEATURE_SELFPOWERED_ENABLED (1 << 0) +#define USB_DEVICE_REMOTE_WAKEUP 1 +#define USB_FEATURE_SELFPOWERED_ENABLED (1 << 0) #define USB_FEATURE_REMOTE_WAKEUP_ENABLED (1 << 1) -enum usb_ep_type -{ - USB_EP_TYPE_CONTROL = 0x00, +enum usb_ep_type { + USB_EP_TYPE_CONTROL = 0x00, USB_EP_TYPE_ISOCHRONOUS = 0x01, - USB_EP_TYPE_BULK = 0x02, - USB_EP_TYPE_INTERRUPT = 0x03, + USB_EP_TYPE_BULK = 0x02, + USB_EP_TYPE_INTERRUPT = 0x03, }; // Device -typedef struct -{ - uint8_t len; // 18 - uint8_t dtype; // 1 USB_DEVICE_DESCRIPTOR_TYPE - uint16_t usbVersion; // 0x200 or 0x210 +typedef struct { + uint8_t len; // 18 + uint8_t dtype; // 1 USB_DEVICE_DESCRIPTOR_TYPE + uint16_t usbVersion; // 0x200 or 0x210 uint8_t deviceClass; uint8_t deviceSubClass; uint8_t deviceProtocol; - uint8_t packetSize0; // Packet 0 + uint8_t packetSize0; // Packet 0 uint16_t idVendor; uint16_t idProduct; - uint16_t deviceVersion; // 0x100 + uint16_t deviceVersion; // 0x100 uint8_t iManufacturer; uint8_t iProduct; uint8_t iSerialNumber; @@ -109,11 +109,10 @@ typedef struct } __attribute__((packed)) DeviceDescriptor; // Config -typedef struct -{ - uint8_t len; // 9 - uint8_t dtype; // 2 - uint16_t clen; // total length +typedef struct { + uint8_t len; // 9 + uint8_t dtype; // 2 + uint16_t clen; // total length uint8_t numInterfaces; uint8_t config; uint8_t iconfig; @@ -122,8 +121,7 @@ typedef struct } __attribute__((packed)) ConfigDescriptor; // Interface -typedef struct -{ +typedef struct { uint8_t len; uint8_t dtype; uint8_t number; @@ -135,8 +133,7 @@ typedef struct uint8_t iInterface; } __attribute__((packed)) InterfaceDescriptor; -typedef struct -{ +typedef struct { uint8_t numEndpoints; uint8_t interfaceClass; uint8_t interfaceSubClass; @@ -145,15 +142,13 @@ typedef struct uint8_t alternate; } InterfaceDescriptorInfo; -typedef struct -{ +typedef struct { uint8_t attr; uint8_t interval; } EndpointDescriptorInfo; -typedef struct -{ - const void *supplementalDescriptor; +typedef struct { + const void* supplementalDescriptor; uint16_t supplementalDescriptorSize; // For interrupt endpoints, this will be 1, even if iface.numEndpoints is 2. // This is because a single USB endpoint address will be used for both. @@ -164,8 +159,7 @@ typedef struct } InterfaceInfo; // Endpoint -typedef struct -{ +typedef struct { uint8_t len; uint8_t dtype; uint8_t addr; @@ -174,11 +168,13 @@ typedef struct uint8_t interval; } __attribute__((packed)) EndpointDescriptor; -#define EP_DESC2(tp, interval) \ - {7, 5, 0x80, tp, USB_MAX_PKT_SIZE, interval}, { 7, 5, 0x00, tp, USB_MAX_PKT_SIZE, interval } +#define EP_DESC2(tp, interval) \ + {7, 5, 0x80, tp, USB_MAX_PKT_SIZE, interval}, \ + { \ + 7, 5, 0x00, tp, USB_MAX_PKT_SIZE, interval \ + } -typedef struct -{ +typedef struct { uint8_t bmRequestType; uint8_t bRequest; uint8_t wValueL; @@ -188,8 +184,7 @@ typedef struct } __attribute__((packed)) USBSetup; // String -typedef struct -{ +typedef struct { uint8_t len; uint8_t type; // some reasonable size; it gets stack allocated @@ -198,10 +193,10 @@ typedef struct #pragma GCC diagnostic ignored "-Wunused-parameter" -class UsbEndpointIn -{ +class UsbEndpointIn { uint8_t buf[USB_MAX_PKT_SIZE]; -public: + + public: volatile uint32_t userdata; uint8_t ep; uint8_t flags; @@ -209,7 +204,7 @@ class UsbEndpointIn int stall(); int clearStall(); int reset(); - int write(const void *buf, int length); + int write(const void* buf, int length); #ifdef USB_EP_FLAG_ASYNC bool canWrite(); #endif @@ -217,17 +212,16 @@ class UsbEndpointIn UsbEndpointIn(uint8_t idx, uint8_t type, uint8_t size = USB_MAX_PKT_SIZE); }; -class UsbEndpointOut -{ +class UsbEndpointOut { uint8_t buf[USB_MAX_PKT_SIZE]; -public: + public: volatile uint32_t userdata; uint8_t ep; int stall(); int reset(); int clearStall(); - int read(void *buf, int maxlength); // up to packet size + int read(void* buf, int maxlength); // up to packet size // when IRQ disabled, endpointRequest() callback will not be called (generally) int disableIRQ(); int enableIRQ(); @@ -240,82 +234,79 @@ void usb_configure(uint8_t numEndpoints); void usb_set_address(uint16_t wValue); void usb_set_address_pre(uint16_t wValue); -class CodalUSBInterface -{ -public: +class CodalUSBInterface { + public: uint8_t interfaceIdx; - UsbEndpointIn *in; - UsbEndpointOut *out; - CodalUSBInterface *next; + UsbEndpointIn* in; + UsbEndpointOut* out; + CodalUSBInterface* next; CodalUSBInterface() { - in = 0; - out = 0; + in = 0; + out = 0; interfaceIdx = 0; - next = NULL; + next = NULL; } - virtual int classRequest(UsbEndpointIn &ctrl, USBSetup &setup) { return DEVICE_NOT_SUPPORTED; } + virtual int classRequest(UsbEndpointIn& ctrl, USBSetup& setup) { return DEVICE_NOT_SUPPORTED; } // standard request to interface (eg USB_REQ_GET_DESCRIPTOR) - virtual int stdRequest(UsbEndpointIn &ctrl, USBSetup &setup) { return DEVICE_NOT_SUPPORTED; } + virtual int stdRequest(UsbEndpointIn& ctrl, USBSetup& setup) { return DEVICE_NOT_SUPPORTED; } virtual int endpointRequest() { return DEVICE_NOT_SUPPORTED; } - virtual const InterfaceInfo *getInterfaceInfo() { return NULL; } - void fillInterfaceInfo(InterfaceDescriptor *desc); + virtual const InterfaceInfo* getInterfaceInfo() { return NULL; } + void fillInterfaceInfo(InterfaceDescriptor* desc); virtual bool enableWebUSB() { return false; } }; class CodalDummyUSBInterface : public CodalUSBInterface { public: - virtual const InterfaceInfo *getInterfaceInfo(); + virtual const InterfaceInfo* getInterfaceInfo(); }; -class CodalUSB : public codal::CodalComponent -{ +class CodalUSB : public codal::CodalComponent { uint8_t endpointsUsed; uint8_t startDelayCount; uint8_t numWebUSBInterfaces; int sendConfig(); - int sendDescriptors(USBSetup &setup); - int interfaceRequest(USBSetup &setup, bool isClass); + int sendDescriptors(USBSetup& setup); + int interfaceRequest(USBSetup& setup, bool isClass); -public: - static CodalUSB *usbInstance; - CodalUSBInterface *interfaces; + public: + static CodalUSB* usbInstance; + CodalUSBInterface* interfaces; // initialized by constructor, can be overriden before start() uint8_t numStringDescriptors; uint8_t maxPower; - const char **stringDescriptors; - const DeviceDescriptor *deviceDescriptor; + const char** stringDescriptors; + const DeviceDescriptor* deviceDescriptor; - UsbEndpointIn *ctrlIn; - UsbEndpointOut *ctrlOut; + UsbEndpointIn* ctrlIn; + UsbEndpointOut* ctrlOut; CodalUSB(uint16_t id = DEVICE_ID_USB); - int add(CodalUSBInterface &interface); + int add(CodalUSBInterface& interface); int isInitialised(); - CodalUSB *getInstance(); + CodalUSB* getInstance(); int start(); // an interface can call it and, at some later point, call start() void delayStart() { startDelayCount++; } // Called from USB.cpp - void setupRequest(USBSetup &setup); + void setupRequest(USBSetup& setup); void interruptHandler(); void initEndpoints(); }; void usb_panic(int lineNumber); -#define usb_assert(cond) \ - if (!(cond)) \ - usb_panic(__LINE__) +#define usb_assert(cond) \ + if (!(cond)) usb_panic(__LINE__) #endif diff --git a/inc/driver-models/DMASingleWireSerial.h b/inc/driver-models/DMASingleWireSerial.h index 80681d4c..faf43cbc 100644 --- a/inc/driver-models/DMASingleWireSerial.h +++ b/inc/driver-models/DMASingleWireSerial.h @@ -1,26 +1,19 @@ #ifndef DMA_SINGLE_WIRE_SERIAL_H #define DMA_SINGLE_WIRE_SERIAL_H -#include "SingleWireSerial.h" #include "DMASingleWireSerial.h" #include "MemberFunctionCallback.h" +#include "SingleWireSerial.h" -namespace codal -{ - class DMASingleWireSerial : public SingleWireSerial - { - - public: - - DMASingleWireSerial(Pin& p) : SingleWireSerial(p) - { - cb = NULL; - } +namespace codal { +class DMASingleWireSerial : public SingleWireSerial { + public: + DMASingleWireSerial(Pin& p) : SingleWireSerial(p) { cb = NULL; } - virtual int sendDMA(uint8_t* data, int len) = 0; - virtual int receiveDMA(uint8_t* data, int len) = 0; - virtual int abortDMA() = 0; - }; -} + virtual int sendDMA(uint8_t* data, int len) = 0; + virtual int receiveDMA(uint8_t* data, int len) = 0; + virtual int abortDMA() = 0; +}; +} // namespace codal #endif \ No newline at end of file diff --git a/inc/driver-models/Display.h b/inc/driver-models/Display.h index 90f877bb..7d7468f3 100644 --- a/inc/driver-models/Display.h +++ b/inc/driver-models/Display.h @@ -28,87 +28,84 @@ DEALINGS IN THE SOFTWARE. #include "CodalConfig.h" #include "Image.h" -namespace codal -{ +namespace codal { +/** + * Class definition for an abstract Display. + */ +class Display : public CodalComponent { + protected: + uint16_t width; + uint16_t height; + uint8_t brightness; + + public: + // A mutable bitmap buffer being rendered to the display. + Image image; + + /** + * Constructor. + * + * Create a software representation an abstract display. + * The display is initially blank. + * + * @param id The id the display should use when sending events on the MessageBus. Defaults to DEVICE_ID_DISPLAY. + */ + Display(int width, int height, uint16_t id = DEVICE_ID_DISPLAY); + + /** + * Returns the width of the display + * + * @return display width + * + */ + virtual int getWidth(); + + /** + * Returns the height of the display + * + * @return display height + * + */ + virtual int getHeight(); + + /** + * Configures the brightness of the display. + * + * @param b The brightness to set the brightness to, in the range 0 - 255. + * + * @return DEVICE_OK, or DEVICE_INVALID_PARAMETER + */ + virtual int setBrightness(int b); + + /** + * Fetches the current brightness of this display. + * + * @return the brightness of this display, in the range 0..255. + */ + virtual int getBrightness(); + + /** + * Enables the display, should only be called if the display is disabled. + */ + virtual void enable(); + + /** + * Disables the display. + */ + virtual void disable(); + + /** + * Captures the bitmap currently being rendered on the display. + * + * @return a Image containing the captured data. + */ + virtual Image screenShot(); + /** - * Class definition for an abstract Display. + * Destructor for CodalDisplay, where we deregister this instance from the array of system components. */ - class Display : public CodalComponent - { - protected: - uint16_t width; - uint16_t height; - uint8_t brightness; - - public: - - // A mutable bitmap buffer being rendered to the display. - Image image; - - /** - * Constructor. - * - * Create a software representation an abstract display. - * The display is initially blank. - * - * @param id The id the display should use when sending events on the MessageBus. Defaults to DEVICE_ID_DISPLAY. - */ - Display (int width, int height, uint16_t id = DEVICE_ID_DISPLAY); - - /** - * Returns the width of the display - * - * @return display width - * - */ - virtual int getWidth(); - - /** - * Returns the height of the display - * - * @return display height - * - */ - virtual int getHeight(); - - /** - * Configures the brightness of the display. - * - * @param b The brightness to set the brightness to, in the range 0 - 255. - * - * @return DEVICE_OK, or DEVICE_INVALID_PARAMETER - */ - virtual int setBrightness(int b); - - /** - * Fetches the current brightness of this display. - * - * @return the brightness of this display, in the range 0..255. - */ - virtual int getBrightness(); - - /** - * Enables the display, should only be called if the display is disabled. - */ - virtual void enable(); - - /** - * Disables the display. - */ - virtual void disable(); - - /** - * Captures the bitmap currently being rendered on the display. - * - * @return a Image containing the captured data. - */ - virtual Image screenShot(); - - /** - * Destructor for CodalDisplay, where we deregister this instance from the array of system components. - */ - ~Display(); - }; -} + ~Display(); +}; +} // namespace codal #endif \ No newline at end of file diff --git a/inc/driver-models/Gyroscope.h b/inc/driver-models/Gyroscope.h index aaacb86d..35f53da5 100644 --- a/inc/driver-models/Gyroscope.h +++ b/inc/driver-models/Gyroscope.h @@ -26,188 +26,184 @@ DEALINGS IN THE SOFTWARE. #ifndef CODAL_GYROSCOPE_H #define CODAL_GYROSCOPE_H -#include "CodalConfig.h" #include "CodalComponent.h" -#include "Pin.h" -#include "CoordinateSystem.h" +#include "CodalConfig.h" #include "CodalUtil.h" +#include "CoordinateSystem.h" +#include "Pin.h" /** - * Status flags - */ -#define GYROSCOPE_IMU_DATA_VALID 0x02 + * Status flags + */ +#define GYROSCOPE_IMU_DATA_VALID 0x02 /** - * Gyroscope events - */ -#define GYROSCOPE_EVT_DATA_UPDATE 1 + * Gyroscope events + */ +#define GYROSCOPE_EVT_DATA_UPDATE 1 + +namespace codal { -namespace codal -{ +/** + * Class definition for Gyroscope. + */ +class Gyroscope : public CodalComponent { + protected: + uint16_t samplePeriod; // The time between samples, in milliseconds. + uint8_t sampleRange; // The sample range of the gyroscope in g. + Sample3D sample; // The last sample read, in the coordinate system specified by the coordinateSpace variable. + Sample3D sampleENU; // The last sample read, in raw ENU format (stored in case requests are made for data in other + // coordinate spaces) + CoordinateSpace& + coordinateSpace; // The coordinate space transform (if any) to apply to the raw data from the hardware. + + public: + /** + * Constructor. + * Create a software abstraction of an gyroscope. + * + * @param coordinateSpace the orientation of the sensor. Defaults to: SIMPLE_CARTESIAN + * @param id the unique EventModel id of this component. Defaults to: DEVICE_ID_GYROSCOPE + * + */ + Gyroscope(CoordinateSpace& coordinateSpace, uint16_t id = DEVICE_ID_GYROSCOPE); + + /** + * Attempts to set the sample rate of the gyroscope to the specified value (in ms). + * + * @param period the requested time between samples, in milliseconds. + * @return DEVICE_OK on success, DEVICE_I2C_ERROR is the request fails. + * + * @note The requested rate may not be possible on the hardware. In this case, the + * nearest lower rate is chosen. + * + * @note This method should be overriden (if supported) by specific gyroscope device drivers. + */ + virtual int setPeriod(int period); + + /** + * Reads the currently configured sample rate of the gyroscope. + * + * @return The time between samples, in milliseconds. + */ + virtual int getPeriod(); + + /** + * Attempts to set the sample range of the gyroscope to the specified value (in dps). + * + * @param range The requested sample range of samples, in dps. + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR is the request fails. + * + * @note The requested range may not be possible on the hardware. In this case, the + * nearest lower range is chosen. + * + * @note This method should be overriden (if supported) by specific gyroscope device drivers. + */ + virtual int setRange(int range); + + /** + * Reads the currently configured sample range of the gyroscope. + * + * @return The sample range, in g. + */ + virtual int getRange(); + + /** + * Configures the gyroscope for dps range and sample rate defined + * in this object. The nearest values are chosen to those defined + * that are supported by the hardware. The instance variables are then + * updated to reflect reality. + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the gyroscope could not be configured. + * + * @note This method should be overridden by the hardware driver to implement the requested + * changes in hardware. + */ + virtual int configure() = 0; + + /** + * Poll to see if new data is available from the hardware. If so, update it. + * n.b. it is not necessary to explicitly call this function to update data + * (it normally happens in the background when the scheduler is idle), but a check is performed + * if the user explicitly requests up to date data. + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the update fails. + * + * @note This method should be overridden by the hardware driver to implement the requested + * changes in hardware. + */ + virtual int requestUpdate() = 0; + + /** + * Stores data from the gyroscope sensor in our buffer, and perform gesture tracking. + * + * On first use, this member function will attempt to add this component to the + * list of fiber components in order to constantly update the values stored + * by this object. + * + * This lazy instantiation means that we do not + * obtain the overhead from non-chalantly adding this component to fiber components. + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the read request fails. + */ + virtual int update(Sample3D s); + + /** + * Reads the last gyroscope value stored, and provides it in the coordinate system requested. + * + * @param coordinateSpace The coordinate system to use. + * @return The force measured in each axis, in dps. + */ + Sample3D getSample(CoordinateSystem coordinateSystem); + + /** + * Reads the last gyroscope value stored, and in the coordinate system defined in the constructor. + * @return The force measured in each axis, in dps. + */ + Sample3D getSample(); + + /** + * reads the value of the x axis from the latest update retrieved from the gyroscope, + * using the default coordinate system as specified in the constructor. + * + * @return the force measured in the x axis, in dps. + */ + int getX(); + + /** + * reads the value of the y axis from the latest update retrieved from the gyroscope, + * using the default coordinate system as specified in the constructor. + * + * @return the force measured in the y axis, in dps. + */ + int getY(); + + /** + * reads the value of the z axis from the latest update retrieved from the gyroscope, + * using the default coordinate system as specified in the constructor. + * + * @return the force measured in the z axis, in dps. + */ + int getZ(); + + /** + * Destructor. + */ + ~Gyroscope(); + private: /** - * Class definition for Gyroscope. + * A service function. + * It calculates the current angular velocity of the device (x^2 + y^2 + z^2). + * It does not, however, square root the result, as this is a relatively high cost operation. + * + * This is left to application code should it be needed. + * + * @return the sum of the square of the angular velocity of the device across all axes. */ - class Gyroscope : public CodalComponent - { - protected: - - uint16_t samplePeriod; // The time between samples, in milliseconds. - uint8_t sampleRange; // The sample range of the gyroscope in g. - Sample3D sample; // The last sample read, in the coordinate system specified by the coordinateSpace variable. - Sample3D sampleENU; // The last sample read, in raw ENU format (stored in case requests are made for data in other coordinate spaces) - CoordinateSpace &coordinateSpace; // The coordinate space transform (if any) to apply to the raw data from the hardware. - - public: - - /** - * Constructor. - * Create a software abstraction of an gyroscope. - * - * @param coordinateSpace the orientation of the sensor. Defaults to: SIMPLE_CARTESIAN - * @param id the unique EventModel id of this component. Defaults to: DEVICE_ID_GYROSCOPE - * - */ - Gyroscope(CoordinateSpace &coordinateSpace, uint16_t id = DEVICE_ID_GYROSCOPE); - - /** - * Attempts to set the sample rate of the gyroscope to the specified value (in ms). - * - * @param period the requested time between samples, in milliseconds. - * @return DEVICE_OK on success, DEVICE_I2C_ERROR is the request fails. - * - * @note The requested rate may not be possible on the hardware. In this case, the - * nearest lower rate is chosen. - * - * @note This method should be overriden (if supported) by specific gyroscope device drivers. - */ - virtual int setPeriod(int period); - - /** - * Reads the currently configured sample rate of the gyroscope. - * - * @return The time between samples, in milliseconds. - */ - virtual int getPeriod(); - - /** - * Attempts to set the sample range of the gyroscope to the specified value (in dps). - * - * @param range The requested sample range of samples, in dps. - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR is the request fails. - * - * @note The requested range may not be possible on the hardware. In this case, the - * nearest lower range is chosen. - * - * @note This method should be overriden (if supported) by specific gyroscope device drivers. - */ - virtual int setRange(int range); - - /** - * Reads the currently configured sample range of the gyroscope. - * - * @return The sample range, in g. - */ - virtual int getRange(); - - /** - * Configures the gyroscope for dps range and sample rate defined - * in this object. The nearest values are chosen to those defined - * that are supported by the hardware. The instance variables are then - * updated to reflect reality. - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the gyroscope could not be configured. - * - * @note This method should be overridden by the hardware driver to implement the requested - * changes in hardware. - */ - virtual int configure() = 0; - - /** - * Poll to see if new data is available from the hardware. If so, update it. - * n.b. it is not necessary to explicitly call this function to update data - * (it normally happens in the background when the scheduler is idle), but a check is performed - * if the user explicitly requests up to date data. - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the update fails. - * - * @note This method should be overridden by the hardware driver to implement the requested - * changes in hardware. - */ - virtual int requestUpdate() = 0; - - /** - * Stores data from the gyroscope sensor in our buffer, and perform gesture tracking. - * - * On first use, this member function will attempt to add this component to the - * list of fiber components in order to constantly update the values stored - * by this object. - * - * This lazy instantiation means that we do not - * obtain the overhead from non-chalantly adding this component to fiber components. - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the read request fails. - */ - virtual int update(Sample3D s); - - /** - * Reads the last gyroscope value stored, and provides it in the coordinate system requested. - * - * @param coordinateSpace The coordinate system to use. - * @return The force measured in each axis, in dps. - */ - Sample3D getSample(CoordinateSystem coordinateSystem); - - /** - * Reads the last gyroscope value stored, and in the coordinate system defined in the constructor. - * @return The force measured in each axis, in dps. - */ - Sample3D getSample(); - - /** - * reads the value of the x axis from the latest update retrieved from the gyroscope, - * using the default coordinate system as specified in the constructor. - * - * @return the force measured in the x axis, in dps. - */ - int getX(); - - /** - * reads the value of the y axis from the latest update retrieved from the gyroscope, - * using the default coordinate system as specified in the constructor. - * - * @return the force measured in the y axis, in dps. - */ - int getY(); - - /** - * reads the value of the z axis from the latest update retrieved from the gyroscope, - * using the default coordinate system as specified in the constructor. - * - * @return the force measured in the z axis, in dps. - */ - int getZ(); - - /** - * Destructor. - */ - ~Gyroscope(); - - private: - - /** - * A service function. - * It calculates the current angular velocity of the device (x^2 + y^2 + z^2). - * It does not, however, square root the result, as this is a relatively high cost operation. - * - * This is left to application code should it be needed. - * - * @return the sum of the square of the angular velocity of the device across all axes. - */ - uint32_t instantaneousAccelerationSquared(); - - }; -} + uint32_t instantaneousAccelerationSquared(); +}; +} // namespace codal #endif diff --git a/inc/driver-models/I2C.h b/inc/driver-models/I2C.h index 542412f5..674f1a46 100644 --- a/inc/driver-models/I2C.h +++ b/inc/driver-models/I2C.h @@ -29,26 +29,24 @@ DEALINGS IN THE SOFTWARE. #include "ErrorNo.h" #include "Pin.h" -namespace codal -{ +namespace codal { /** - * Class definition for an I2C interface. - */ + * Class definition for an I2C interface. + */ -enum AcknowledgeType {ACK, NACK}; +enum AcknowledgeType { ACK, NACK }; -class I2C : public PinPeripheral -{ -public: - I2C(Pin &sda, Pin &scl); +class I2C : public PinPeripheral { + public: + I2C(Pin& sda, Pin& scl); /** Set the frequency of the I2C interface - * - * @param frequency The bus frequency in hertz - */ + * + * @param frequency The bus frequency in hertz + */ virtual int setFrequency(uint32_t frequency); -protected: + protected: /** * Issues a START condition on the I2C bus * @return DEVICE_OK on success, or an error code @@ -62,132 +60,134 @@ class I2C : public PinPeripheral virtual int stop(); /** - * Writes the given byte to the I2C bus. - * - * The CPU will busy wait until the transmission is complete. - * - * @param data The byte to write. - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the the write request failed. - */ + * Writes the given byte to the I2C bus. + * + * The CPU will busy wait until the transmission is complete. + * + * @param data The byte to write. + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the the write request failed. + */ virtual int write(uint8_t data); /** - * Reads a single byte from the I2C bus. - * The CPU will busy wait until the transmission is complete. - * - * @return the byte read from the I2C bus, or DEVICE_I2C_ERROR if the the write request failed. - */ + * Reads a single byte from the I2C bus. + * The CPU will busy wait until the transmission is complete. + * + * @return the byte read from the I2C bus, or DEVICE_I2C_ERROR if the the write request failed. + */ virtual int read(AcknowledgeType ack = ACK); -public: + public: /** - * Change the pins used by this I2C peripheral to those provided. - * - * @param sda the Pin to use for the I2C SDA line. - * @param scl the Pin to use for the I2C SCL line. - * @return DEVICE_OK on success, or DEVICE_NOT_IMPLEMENTED / DEVICE_NOT_SUPPORTED if the request cannot be performed. - */ - virtual int redirect(Pin &sda, Pin &scl); + * Change the pins used by this I2C peripheral to those provided. + * + * @param sda the Pin to use for the I2C SDA line. + * @param scl the Pin to use for the I2C SCL line. + * @return DEVICE_OK on success, or DEVICE_NOT_IMPLEMENTED / DEVICE_NOT_SUPPORTED if the request cannot be + * performed. + */ + virtual int redirect(Pin& sda, Pin& scl); /** - * Issues a standard, 2 byte I2C command write to the I2C bus. - * This consists of: - * - Asserting a Start condition on the bus - * - Selecting the Slave address (as an 8 bit address) - * - Writing the raw 8 bit data provided - * - Asserting a Stop condition on the bus - * - * The CPU will busy wait until the transmission is complete. - * - * @param address The 8bit I2C address of the device to write to - * @param data the byte command to write - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the the write request failed. - */ + * Issues a standard, 2 byte I2C command write to the I2C bus. + * This consists of: + * - Asserting a Start condition on the bus + * - Selecting the Slave address (as an 8 bit address) + * - Writing the raw 8 bit data provided + * - Asserting a Stop condition on the bus + * + * The CPU will busy wait until the transmission is complete. + * + * @param address The 8bit I2C address of the device to write to + * @param data the byte command to write + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the the write request failed. + */ virtual int write(uint16_t address, uint8_t data); /** - * Issues a standard, I2C command write to the I2C bus. - * This consists of: - * - Asserting a Start condition on the bus - * - Selecting the Slave address (as an 8 bit address) - * - Writing a number of raw data bytes provided - * - Asserting a Stop condition on the bus - * - * The CPU will busy wait until the transmission is complete. - * - * @param address The 8bit I2C address of the device to write to - * @param data pointer to the bytes to write - * @param len the number of bytes to write - * @param repeated Suppresses the generation of a STOP condition if set. Default: false; - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the the write request failed. - */ - virtual int write(uint16_t address, uint8_t *data, int len, bool repeated = false); - int write(int address, char *data, int len, bool repeated = false); + * Issues a standard, I2C command write to the I2C bus. + * This consists of: + * - Asserting a Start condition on the bus + * - Selecting the Slave address (as an 8 bit address) + * - Writing a number of raw data bytes provided + * - Asserting a Stop condition on the bus + * + * The CPU will busy wait until the transmission is complete. + * + * @param address The 8bit I2C address of the device to write to + * @param data pointer to the bytes to write + * @param len the number of bytes to write + * @param repeated Suppresses the generation of a STOP condition if set. Default: false; + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the the write request failed. + */ + virtual int write(uint16_t address, uint8_t* data, int len, bool repeated = false); + int write(int address, char* data, int len, bool repeated = false); /** - * Performs a typical register write operation to the I2C slave device provided. - * This consists of: - * - Asserting a Start condition on the bus - * - Selecting the Slave address (as an 8 bit address) - * - Writing the 8 bit register address provided - * - Writing the 8 bit value provided - * - Asserting a Stop condition on the bus - * - * The CPU will busy wait until the transmission is complete.. - * - * @param address 8bit address of the device to write to - * @param reg The 8bit address of the register to write to. - * @param value The value to write. - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the the write request failed. - */ + * Performs a typical register write operation to the I2C slave device provided. + * This consists of: + * - Asserting a Start condition on the bus + * - Selecting the Slave address (as an 8 bit address) + * - Writing the 8 bit register address provided + * - Writing the 8 bit value provided + * - Asserting a Stop condition on the bus + * + * The CPU will busy wait until the transmission is complete.. + * + * @param address 8bit address of the device to write to + * @param reg The 8bit address of the register to write to. + * @param value The value to write. + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the the write request failed. + */ virtual int writeRegister(uint16_t address, uint8_t reg, uint8_t value); /** - * Issues a standard, 2 byte I2C command read to the I2C bus. - * This consists of: - * - Asserting a Start condition on the bus - * - Selecting the Slave address (as an 8 bit address) - * - reading "len" bytes of raw 8 bit data into the buffer provided - * - Asserting a Stop condition on the bus - * - * The CPU will busy wait until the transmission is complete. - * - * @param address The 8bit I2C address of the device to read from - * @param data pointer to store the the bytes read - * @param len the number of bytes to read into the buffer - * @param repeated Suppresses the generation of a STOP condition if set. Default: false; - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the the read request failed. - */ - virtual int read(uint16_t address, uint8_t *data, int len, bool repeated = false); - int read(int address, char *data, int len, bool repeated = false); + * Issues a standard, 2 byte I2C command read to the I2C bus. + * This consists of: + * - Asserting a Start condition on the bus + * - Selecting the Slave address (as an 8 bit address) + * - reading "len" bytes of raw 8 bit data into the buffer provided + * - Asserting a Stop condition on the bus + * + * The CPU will busy wait until the transmission is complete. + * + * @param address The 8bit I2C address of the device to read from + * @param data pointer to store the the bytes read + * @param len the number of bytes to read into the buffer + * @param repeated Suppresses the generation of a STOP condition if set. Default: false; + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the the read request failed. + */ + virtual int read(uint16_t address, uint8_t* data, int len, bool repeated = false); + int read(int address, char* data, int len, bool repeated = false); /** - * Performs a typical register read operation to the I2C slave device provided. - * This consists of: - * - Asserting a Start condition on the bus - * - Selecting the Slave address (as an 8 bit address, I2C WRITE) - * - Selecting a RAM register address in the slave - * - Asserting a Stop condition on the bus - * - Asserting a Start condition on the bus - * - Selecting the Slave address (as an 8 bit address, I2C READ) - * - Performing an 8 bit read operation (of the requested register) - * - Asserting a Stop condition on the bus - * - * The CPU will busy wait until the transmission is complete.. - * - * @param address 8bit I2C address of the device to read from - * @param reg The 8bit register address of the to read. - * @param data A pointer to a memory location to store the result of the read operation - * @param length The number of mytes to read - * @param repeated Use a repeated START/START/STOP transaction if true, or independent START/STOP/START/STOP transactions if fasle. Default: true - * - * @return DEVICE_OK or DEVICE_I2C_ERROR if the the read request failed. - */ - virtual int readRegister(uint16_t address, uint8_t reg, uint8_t *data, int length, bool repeated = true); + * Performs a typical register read operation to the I2C slave device provided. + * This consists of: + * - Asserting a Start condition on the bus + * - Selecting the Slave address (as an 8 bit address, I2C WRITE) + * - Selecting a RAM register address in the slave + * - Asserting a Stop condition on the bus + * - Asserting a Start condition on the bus + * - Selecting the Slave address (as an 8 bit address, I2C READ) + * - Performing an 8 bit read operation (of the requested register) + * - Asserting a Stop condition on the bus + * + * The CPU will busy wait until the transmission is complete.. + * + * @param address 8bit I2C address of the device to read from + * @param reg The 8bit register address of the to read. + * @param data A pointer to a memory location to store the result of the read operation + * @param length The number of mytes to read + * @param repeated Use a repeated START/START/STOP transaction if true, or independent START/STOP/START/STOP + * transactions if fasle. Default: true + * + * @return DEVICE_OK or DEVICE_I2C_ERROR if the the read request failed. + */ + virtual int readRegister(uint16_t address, uint8_t reg, uint8_t* data, int length, bool repeated = true); /** * Issues a single byte read command, and returns the value read, or an error. @@ -201,6 +201,6 @@ class I2C : public PinPeripheral */ virtual int readRegister(uint8_t address, uint8_t reg); }; -} +} // namespace codal #endif diff --git a/inc/driver-models/LowLevelTimer.h b/inc/driver-models/LowLevelTimer.h index dacf7b1e..2803a144 100644 --- a/inc/driver-models/LowLevelTimer.h +++ b/inc/driver-models/LowLevelTimer.h @@ -1,64 +1,52 @@ #ifndef LOW_LEVEL_TIMER_H #define LOW_LEVEL_TIMER_H -#include "CodalConfig.h" #include "CodalComponent.h" +#include "CodalConfig.h" #include "codal_target_hal.h" -#define CODAL_LOWLEVELTIMER_STATUS_SLEEP_IRQENABLE 0x01 +#define CODAL_LOWLEVELTIMER_STATUS_SLEEP_IRQENABLE 0x01 -namespace codal -{ +namespace codal { /** * An enumeration that represents the current mode of the timer. **/ -enum TimerMode -{ - TimerModeTimer = 0, - TimerModeCounter, - TimerModeAlternateFunction -}; +enum TimerMode { TimerModeTimer = 0, TimerModeCounter, TimerModeAlternateFunction }; /** * An enumeration that represents the number of bits (i.e. the top) used to count. * * This enumeration is used to compute roll over calculations and must be accurate. **/ -enum TimerBitMode -{ - BitMode8 = 0, - BitMode16, - BitMode24, - BitMode32 -}; +enum TimerBitMode { BitMode8 = 0, BitMode16, BitMode24, BitMode32 }; /** - * This class represents a timer in its rawest form, it allows direct manipulation of timer registers through a common API. + * This class represents a timer in its rawest form, it allows direct manipulation of timer registers through a common + *API. * * Higher level drivers can then use / layer on top of the low level timer interface. **/ -class LowLevelTimer : public CodalComponent -{ - protected: - TimerBitMode bitMode; // the current bitMode of the timer. - uint8_t channel_count; // the number of channels this timer instance has. - - public: +class LowLevelTimer : public CodalComponent { + protected: + TimerBitMode bitMode; // the current bitMode of the timer. + uint8_t channel_count; // the number of channels this timer instance has. + public: /** * A function pointer that it is invoked from the Low Level Timer interrupt context. * - * @param channel_bitmsk A 16 bit number that represents the channels that have triggered a match. I.e. if CC register 0 is set, bit 0 will be set to one. + * @param channel_bitmsk A 16 bit number that represents the channels that have triggered a match. I.e. if CC + *register 0 is set, bit 0 will be set to one. **/ - void (*timer_pointer) (uint16_t channel_bitmsk); + void (*timer_pointer)(uint16_t channel_bitmsk); /** * Sets the timer_pointer member variable. * * @returns DEVICE_OK on success. **/ - virtual int setIRQ(void (*timer_pointer) (uint16_t channel_bitmsk)) + virtual int setIRQ(void (*timer_pointer)(uint16_t channel_bitmsk)) { this->timer_pointer = timer_pointer; return DEVICE_OK; @@ -89,9 +77,7 @@ class LowLevelTimer : public CodalComponent /** * Destructor **/ - virtual ~LowLevelTimer() - { - } + virtual ~LowLevelTimer() {} /** * Enables this timer instance and begins counting @@ -132,7 +118,7 @@ class LowLevelTimer : public CodalComponent * * @param value the value to load into the capture compare register **/ - virtual int setCompare(uint8_t channel, uint32_t value)= 0; + virtual int setCompare(uint8_t channel, uint32_t value) = 0; /** * Offsets the compare value of a capture compare register in the underlying hardware @@ -172,20 +158,13 @@ class LowLevelTimer : public CodalComponent /** * Returns the current bit mode of the timer. **/ - virtual TimerBitMode getBitMode() - { - return bitMode; - } + virtual TimerBitMode getBitMode() { return bitMode; } /** * Returns the number of channels this timer has for use. **/ - int getChannelCount() - { - return channel_count; - } + int getChannelCount() { return channel_count; } }; -} - +} // namespace codal #endif diff --git a/inc/driver-models/NVMController.h b/inc/driver-models/NVMController.h index de241ca5..76c3475f 100644 --- a/inc/driver-models/NVMController.h +++ b/inc/driver-models/NVMController.h @@ -4,71 +4,67 @@ #include "CodalConfig.h" #include "ErrorNo.h" -namespace codal -{ - class NVMController - { - public: +namespace codal { +class NVMController { + public: + NVMController(){}; - NVMController(){}; + /** + * Determines the logical address of the start of non-volatile memory region + * + * @return The logical address of the first valid logical address in the region of non-volatile memory + */ + virtual uint32_t getFlashStart() = 0; - /** - * Determines the logical address of the start of non-volatile memory region - * - * @return The logical address of the first valid logical address in the region of non-volatile memory - */ - virtual uint32_t getFlashStart() =0; + /** + * Determines the logical address of the end of the non-volatile memory region + * + * @return The logical address of the first invalid logical address beyond + * the non-volatile memory. + */ + virtual uint32_t getFlashEnd() = 0; - /** - * Determines the logical address of the end of the non-volatile memory region - * - * @return The logical address of the first invalid logical address beyond - * the non-volatile memory. - */ - virtual uint32_t getFlashEnd() = 0; + /** + * Determines the size of a non-volatile memory page. A page is defined as + * the block of memory the can be efficiently erased without impacted on + * other regions of memory. + * + * @return The size of a single page in bytes. + */ + virtual uint32_t getPageSize() = 0; - /** - * Determines the size of a non-volatile memory page. A page is defined as - * the block of memory the can be efficiently erased without impacted on - * other regions of memory. - * - * @return The size of a single page in bytes. - */ - virtual uint32_t getPageSize() = 0; + /** + * Determines the amount of available storage. + * + * @return the amount of available storage, in bytes. + */ + virtual uint32_t getFlashSize() = 0; - /** - * Determines the amount of available storage. - * - * @return the amount of available storage, in bytes. - */ - virtual uint32_t getFlashSize() = 0; + /** + * Reads a block of memory from non-volatile memory into RAM + * + * @param dest The address in RAM in which to store the result of the read operation + * @param source The logical address in non-voltile memory to read from + * @param size The number 32-bit words to read. + */ + virtual int read(uint32_t* dest, uint32_t source, uint32_t size) = 0; - /** - * Reads a block of memory from non-volatile memory into RAM - * - * @param dest The address in RAM in which to store the result of the read operation - * @param source The logical address in non-voltile memory to read from - * @param size The number 32-bit words to read. - */ - virtual int read(uint32_t* dest, uint32_t source, uint32_t size) = 0; + /** + * Writes a block of memory to non-volatile memory. + * + * @param dest The logical address in non-voltile memory to write to + * @param source The address in RAM of the data to write to non-volatile memory + * @param size The number 32-bit words to write. + */ + virtual int write(uint32_t dest, uint32_t* source, uint32_t size) = 0; - /** - * Writes a block of memory to non-volatile memory. - * - * @param dest The logical address in non-voltile memory to write to - * @param source The address in RAM of the data to write to non-volatile memory - * @param size The number 32-bit words to write. - */ - virtual int write(uint32_t dest, uint32_t* source, uint32_t size) = 0; - - /** - * Erases a given page in non-volatile memory. - * - * @param page The address of the page to erase (logical address of the start of the page). - */ - virtual int erase(uint32_t page) = 0; - - }; -} + /** + * Erases a given page in non-volatile memory. + * + * @param page The address of the page to erase (logical address of the start of the page). + */ + virtual int erase(uint32_t page) = 0; +}; +} // namespace codal #endif \ No newline at end of file diff --git a/inc/driver-models/Pin.h b/inc/driver-models/Pin.h index b6f8f4de..a93d7da0 100644 --- a/inc/driver-models/Pin.h +++ b/inc/driver-models/Pin.h @@ -25,546 +25,467 @@ DEALINGS IN THE SOFTWARE. #ifndef CODAL_PIN_H #define CODAL_PIN_H -#include "CodalConfig.h" #include "CodalComponent.h" +#include "CodalConfig.h" #include "PinPeripheral.h" - // Status Field flags... -#define IO_STATUS_DIGITAL_IN 0x0001 // Pin is configured as a digital input, with no pull up. -#define IO_STATUS_DIGITAL_OUT 0x0002 // Pin is configured as a digital output -#define IO_STATUS_ANALOG_IN 0x0004 // Pin is Analog in -#define IO_STATUS_ANALOG_OUT 0x0008 // Pin is Analog out -#define IO_STATUS_TOUCH_IN 0x0010 // Pin is a makey-makey style touch sensor -#define IO_STATUS_EVENT_ON_EDGE 0x0020 // Pin will generate events on pin change -#define IO_STATUS_EVENT_PULSE_ON_EDGE 0x0040 // Pin will generate events on pin change -#define IO_STATUS_INTERRUPT_ON_EDGE 0x0080 // Pin will generate events on pin change -#define IO_STATUS_ACTIVE_HI 0x0100 // Pin is ACTIVE_HI if set, or ACTIVE_LO if clear -#define IO_STATUS_WAKE_ON_ACTIVE 0x0200 // Pin should trigger power manager wake-up -#define IO_STATUS_DISCONNECTING 0x0400 // Pin is currently in the process of disconnecting from a peripheral - -#define DEVICE_PIN_MAX_OUTPUT 1023 - -#define DEVICE_PIN_MAX_SERVO_RANGE 180 -#define DEVICE_PIN_DEFAULT_SERVO_RANGE 2000 -#define DEVICE_PIN_DEFAULT_SERVO_CENTER 1500 - -#define DEVICE_PIN_EVENT_NONE 0 -#define DEVICE_PIN_INTERRUPT_ON_EDGE 1 -#define DEVICE_PIN_EVENT_ON_EDGE 2 -#define DEVICE_PIN_EVENT_ON_PULSE 3 -#define DEVICE_PIN_EVENT_ON_TOUCH 4 - -#define DEVICE_PIN_EVT_RISE 2 -#define DEVICE_PIN_EVT_FALL 3 -#define DEVICE_PIN_EVT_PULSE_HI 4 -#define DEVICE_PIN_EVT_PULSE_LO 5 - -namespace codal -{ - /** - * Pin capabilities enum. - * Used to determine the capabilities of each Pin as some can only be digital, or can be both digital and analogue. - */ - enum PinCapability: uint8_t - { - PIN_CAPABILITY_DIGITAL = 0x01, - PIN_CAPABILITY_ANALOG = 0x02, - PIN_CAPABILITY_AD = PIN_CAPABILITY_DIGITAL | PIN_CAPABILITY_ANALOG, - PIN_CAPABILITY_ALL = PIN_CAPABILITY_DIGITAL | PIN_CAPABILITY_ANALOG - }; +// Status Field flags... +#define IO_STATUS_DIGITAL_IN 0x0001 // Pin is configured as a digital input, with no pull up. +#define IO_STATUS_DIGITAL_OUT 0x0002 // Pin is configured as a digital output +#define IO_STATUS_ANALOG_IN 0x0004 // Pin is Analog in +#define IO_STATUS_ANALOG_OUT 0x0008 // Pin is Analog out +#define IO_STATUS_TOUCH_IN 0x0010 // Pin is a makey-makey style touch sensor +#define IO_STATUS_EVENT_ON_EDGE 0x0020 // Pin will generate events on pin change +#define IO_STATUS_EVENT_PULSE_ON_EDGE 0x0040 // Pin will generate events on pin change +#define IO_STATUS_INTERRUPT_ON_EDGE 0x0080 // Pin will generate events on pin change +#define IO_STATUS_ACTIVE_HI 0x0100 // Pin is ACTIVE_HI if set, or ACTIVE_LO if clear +#define IO_STATUS_WAKE_ON_ACTIVE 0x0200 // Pin should trigger power manager wake-up +#define IO_STATUS_DISCONNECTING 0x0400 // Pin is currently in the process of disconnecting from a peripheral + +#define DEVICE_PIN_MAX_OUTPUT 1023 + +#define DEVICE_PIN_MAX_SERVO_RANGE 180 +#define DEVICE_PIN_DEFAULT_SERVO_RANGE 2000 +#define DEVICE_PIN_DEFAULT_SERVO_CENTER 1500 + +#define DEVICE_PIN_EVENT_NONE 0 +#define DEVICE_PIN_INTERRUPT_ON_EDGE 1 +#define DEVICE_PIN_EVENT_ON_EDGE 2 +#define DEVICE_PIN_EVENT_ON_PULSE 3 +#define DEVICE_PIN_EVENT_ON_TOUCH 4 + +#define DEVICE_PIN_EVT_RISE 2 +#define DEVICE_PIN_EVT_FALL 3 +#define DEVICE_PIN_EVT_PULSE_HI 4 +#define DEVICE_PIN_EVT_PULSE_LO 5 + +namespace codal { +using namespace codal; + +/** + * Pin capabilities enum. + * Used to determine the capabilities of each Pin as some can only be digital, or can be both digital and analogue. + */ +enum PinCapability : uint8_t { + PIN_CAPABILITY_DIGITAL = 0x01, + PIN_CAPABILITY_ANALOG = 0x02, + PIN_CAPABILITY_AD = PIN_CAPABILITY_DIGITAL | PIN_CAPABILITY_ANALOG, + PIN_CAPABILITY_ALL = PIN_CAPABILITY_DIGITAL | PIN_CAPABILITY_ANALOG +}; + +enum class PinNumber : uint16_t; + +enum class PullMode : uint8_t { None = 0, Down, Up }; + +/** + * Class definition for Pin. + * + * Commonly represents an I/O pin on the edge connector. + */ +class Pin { + protected: + PinCapability capability; + PullMode pullMode; + + public: + uint16_t status; + uint16_t id; + PinPeripheral* obj; + + void (*gpio_irq)(int state); + + // the name of this pin, a number that maps to hardware. + PinNumber name; - enum class PinNumber:uint16_t; - - enum class PullMode : uint8_t + /** + * Constructor. + * Create a Pin instance, generally used to represent a pin on the edge connector. + * + * @param id the unique EventModel id of this component. + * + * @param name the PinNumber for this Pin instance. + * + * @param capability the capabilities this Pin instance should have. + * (PIN_CAPABILITY_DIGITAL, PIN_CAPABILITY_ANALOG, PIN_CAPABILITY_AD, PIN_CAPABILITY_ALL) + * + * @code + * Pin P0(DEVICE_ID_IO_P0, DEVICE_PIN_P0, PIN_CAPABILITY_ALL); + * @endcode + */ + Pin(int id, PinNumber name, PinCapability capability) { - None = 0, - Down, - Up - }; + this->status = IO_STATUS_ACTIVE_HI; + this->id = id; + this->name = name; + this->capability = capability; + this->gpio_irq = NULL; + this->obj = NULL; + } /** - * Class definition for Pin. - * - * Commonly represents an I/O pin on the edge connector. - */ - class Pin - { - protected: - PinCapability capability; - PullMode pullMode; - - public: - uint16_t status; - uint16_t id; - PinPeripheral* obj; - - - void (*gpio_irq)(int state); - - // the name of this pin, a number that maps to hardware. - PinNumber name; - - /** - * Constructor. - * Create a Pin instance, generally used to represent a pin on the edge connector. - * - * @param id the unique EventModel id of this component. - * - * @param name the PinNumber for this Pin instance. - * - * @param capability the capabilities this Pin instance should have. - * (PIN_CAPABILITY_DIGITAL, PIN_CAPABILITY_ANALOG, PIN_CAPABILITY_AD, PIN_CAPABILITY_ALL) - * - * @code - * Pin P0(DEVICE_ID_IO_P0, DEVICE_PIN_P0, PIN_CAPABILITY_ALL); - * @endcode - */ - Pin(int id, PinNumber name, PinCapability capability) - { - this->status = IO_STATUS_ACTIVE_HI; - this->id = id; - this->name = name; - this->capability = capability; - this->gpio_irq = NULL; - this->obj = NULL; - } + * Configures this IO pin as a digital output (if necessary) and sets the pin to 'value'. + * + * @param value 0 (LO) or 1 (HI) + * + * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if value is out of range, or DEVICE_NOT_SUPPORTED + * if the given pin does not have digital capability. + * + * @code + * Pin P0(DEVICE_ID_IO_P0, DEVICE_PIN_P0, PIN_CAPABILITY_BOTH); + * P0.setDigitalValue(1); // P0 is now HI + * @endcode + */ + virtual int setDigitalValue(int value) { return DEVICE_NOT_IMPLEMENTED; } - /** - * Configures this IO pin as a digital output (if necessary) and sets the pin to 'value'. - * - * @param value 0 (LO) or 1 (HI) - * - * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if value is out of range, or DEVICE_NOT_SUPPORTED - * if the given pin does not have digital capability. - * - * @code - * Pin P0(DEVICE_ID_IO_P0, DEVICE_PIN_P0, PIN_CAPABILITY_BOTH); - * P0.setDigitalValue(1); // P0 is now HI - * @endcode - */ - virtual int setDigitalValue(int value) - { - return DEVICE_NOT_IMPLEMENTED; - } + /** + * Configures this IO pin as a digital input (if necessary) and tests its current value. + * + * + * @return 1 if this input is high, 0 if input is LO, or DEVICE_NOT_SUPPORTED + * if the given pin does not have digital capability. + * + * @code + * Pin P0(DEVICE_ID_IO_P0, DEVICE_PIN_P0, PIN_CAPABILITY_BOTH); + * P0.getDigitalValue(); // P0 is either 0 or 1; + * @endcode + */ + virtual int getDigitalValue() { return DEVICE_NOT_IMPLEMENTED; } - /** - * Configures this IO pin as a digital input (if necessary) and tests its current value. - * - * - * @return 1 if this input is high, 0 if input is LO, or DEVICE_NOT_SUPPORTED - * if the given pin does not have digital capability. - * - * @code - * Pin P0(DEVICE_ID_IO_P0, DEVICE_PIN_P0, PIN_CAPABILITY_BOTH); - * P0.getDigitalValue(); // P0 is either 0 or 1; - * @endcode - */ - virtual int getDigitalValue() - { - return DEVICE_NOT_IMPLEMENTED; - } + /** + * Configures this IO pin as a digital input with the specified internal pull-up/pull-down configuraiton (if + * necessary) and tests its current value. + * + * @param pull one of the mbed pull configurations: PullUp, PullDown, PullNone + * + * @return 1 if this input is high, 0 if input is LO, or DEVICE_NOT_SUPPORTED + * if the given pin does not have digital capability. + * + * @code + * Pin P0(DEVICE_ID_IO_P0, DEVICE_PIN_P0, PIN_CAPABILITY_BOTH); + * P0.getDigitalValue(PullUp); // P0 is either 0 or 1; + * @endcode + */ + virtual int getDigitalValue(PullMode pull) + { + setPull(pull); + return getDigitalValue(); + } - /** - * Configures this IO pin as a digital input with the specified internal pull-up/pull-down configuraiton (if necessary) and tests its current value. - * - * @param pull one of the mbed pull configurations: PullUp, PullDown, PullNone - * - * @return 1 if this input is high, 0 if input is LO, or DEVICE_NOT_SUPPORTED - * if the given pin does not have digital capability. - * - * @code - * Pin P0(DEVICE_ID_IO_P0, DEVICE_PIN_P0, PIN_CAPABILITY_BOTH); - * P0.getDigitalValue(PullUp); // P0 is either 0 or 1; - * @endcode - */ - virtual int getDigitalValue(PullMode pull) - { - setPull(pull); - return getDigitalValue(); - } + /** + * Configures this IO pin as an analog/pwm output, and change the output value to the given level. + * + * @param value the level to set on the output pin, in the range 0 - 1024 + * + * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if value is out of range, or DEVICE_NOT_SUPPORTED + * if the given pin does not have analog capability. + */ + virtual int setAnalogValue(int value) { return DEVICE_NOT_IMPLEMENTED; } - /** - * Configures this IO pin as an analog/pwm output, and change the output value to the given level. - * - * @param value the level to set on the output pin, in the range 0 - 1024 - * - * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if value is out of range, or DEVICE_NOT_SUPPORTED - * if the given pin does not have analog capability. - */ - virtual int setAnalogValue(int value) - { - return DEVICE_NOT_IMPLEMENTED; - } + /** + * Configures this IO pin as an analog/pwm output (if necessary) and configures the period to be 20ms, + * with a duty cycle between 500 us and 2500 us. + * + * A value of 180 sets the duty cycle to be 2500us, and a value of 0 sets the duty cycle to be 500us by default. + * + * This range can be modified to fine tune, and also tolerate different servos. + * + * @param value the level to set on the output pin, in the range 0 - 180. + * + * @param range which gives the span of possible values the i.e. the lower and upper bounds (center +/- range/2). + * Defaults to DEVICE_PIN_DEFAULT_SERVO_RANGE. + * + * @param center the center point from which to calculate the lower and upper bounds. Defaults to + * DEVICE_PIN_DEFAULT_SERVO_CENTER + * + * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if value is out of range, or DEVICE_NOT_SUPPORTED + * if the given pin does not have analog capability. + */ + virtual int setServoValue(int value, int range = DEVICE_PIN_DEFAULT_SERVO_RANGE, + int center = DEVICE_PIN_DEFAULT_SERVO_CENTER) + { + return DEVICE_NOT_IMPLEMENTED; + } - /** - * Configures this IO pin as an analog/pwm output (if necessary) and configures the period to be 20ms, - * with a duty cycle between 500 us and 2500 us. - * - * A value of 180 sets the duty cycle to be 2500us, and a value of 0 sets the duty cycle to be 500us by default. - * - * This range can be modified to fine tune, and also tolerate different servos. - * - * @param value the level to set on the output pin, in the range 0 - 180. - * - * @param range which gives the span of possible values the i.e. the lower and upper bounds (center +/- range/2). Defaults to DEVICE_PIN_DEFAULT_SERVO_RANGE. - * - * @param center the center point from which to calculate the lower and upper bounds. Defaults to DEVICE_PIN_DEFAULT_SERVO_CENTER - * - * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if value is out of range, or DEVICE_NOT_SUPPORTED - * if the given pin does not have analog capability. - */ - virtual int setServoValue(int value, int range = DEVICE_PIN_DEFAULT_SERVO_RANGE, int center = DEVICE_PIN_DEFAULT_SERVO_CENTER) - { - return DEVICE_NOT_IMPLEMENTED; - } + /** + * Configures this IO pin as an analogue input (if necessary), and samples the Pin for its analog value. + * + * @return the current analogue level on the pin, in the range 0 - 1024, or + * DEVICE_NOT_SUPPORTED if the given pin does not have analog capability. + * + * @code + * Pin P0(DEVICE_ID_IO_P0, DEVICE_PIN_P0, PIN_CAPABILITY_BOTH); + * P0.getAnalogValue(); // P0 is a value in the range of 0 - 1024 + * @endcode + */ + virtual int getAnalogValue() { return DEVICE_NOT_IMPLEMENTED; } - /** - * Configures this IO pin as an analogue input (if necessary), and samples the Pin for its analog value. - * - * @return the current analogue level on the pin, in the range 0 - 1024, or - * DEVICE_NOT_SUPPORTED if the given pin does not have analog capability. - * - * @code - * Pin P0(DEVICE_ID_IO_P0, DEVICE_PIN_P0, PIN_CAPABILITY_BOTH); - * P0.getAnalogValue(); // P0 is a value in the range of 0 - 1024 - * @endcode - */ - virtual int getAnalogValue() - { - return DEVICE_NOT_IMPLEMENTED; - } + /** + * Determines if this IO pin is currently configured as an input. + * + * @return 1 if pin is an analog or digital input, 0 otherwise. + */ + virtual int isInput() { return (status & (IO_STATUS_DIGITAL_IN | IO_STATUS_ANALOG_IN)) == 0 ? 0 : 1; } - /** - * Determines if this IO pin is currently configured as an input. - * - * @return 1 if pin is an analog or digital input, 0 otherwise. - */ - virtual int isInput() - { - return (status & (IO_STATUS_DIGITAL_IN | IO_STATUS_ANALOG_IN)) == 0 ? 0 : 1; - } + /** + * Determines if this IO pin is currently configured as an output. + * + * @return 1 if pin is an analog or digital output, 0 otherwise. + */ + virtual int isOutput() { return (status & (IO_STATUS_DIGITAL_OUT | IO_STATUS_ANALOG_OUT)) == 0 ? 0 : 1; } - /** - * Determines if this IO pin is currently configured as an output. - * - * @return 1 if pin is an analog or digital output, 0 otherwise. - */ - virtual int isOutput() - { - return (status & (IO_STATUS_DIGITAL_OUT | IO_STATUS_ANALOG_OUT)) == 0 ? 0 : 1; - } + /** + * Determines if this IO pin is currently configured for digital use. + * + * @return 1 if pin is digital, 0 otherwise. + */ + virtual int isDigital() { return (status & (IO_STATUS_DIGITAL_IN | IO_STATUS_DIGITAL_OUT)) == 0 ? 0 : 1; } - /** - * Determines if this IO pin is currently configured for digital use. - * - * @return 1 if pin is digital, 0 otherwise. - */ - virtual int isDigital() - { - return (status & (IO_STATUS_DIGITAL_IN | IO_STATUS_DIGITAL_OUT)) == 0 ? 0 : 1; - } + /** + * Determines if this IO pin is currently configured for analog use. + * + * @return 1 if pin is analog, 0 otherwise. + */ + virtual int isAnalog() { return (status & (IO_STATUS_ANALOG_IN | IO_STATUS_ANALOG_OUT)) == 0 ? 0 : 1; } - /** - * Determines if this IO pin is currently configured for analog use. - * - * @return 1 if pin is analog, 0 otherwise. - */ - virtual int isAnalog() - { - return (status & (IO_STATUS_ANALOG_IN | IO_STATUS_ANALOG_OUT)) == 0 ? 0 : 1; - } + /** + * Determines if this IO pin is currently in the processing of being disconnected from a peripheral. + * + * @return 1 if pin is disconnecting, 0 otherwise. + */ + virtual int isDisconnecting() { return (status & IO_STATUS_DISCONNECTING) == 0 ? 0 : 1; } - /** - * Determines if this IO pin is currently in the processing of being disconnected from a peripheral. - * - * @return 1 if pin is disconnecting, 0 otherwise. - */ - virtual int isDisconnecting() - { - return (status & IO_STATUS_DISCONNECTING) == 0 ? 0 : 1; - } + /** + * Configures this IO pin as a "makey makey" style touch sensor (if necessary) + * and tests its current debounced state. + * + * Users can also subscribe to DeviceButton events generated from this pin. + * + * @return 1 if pin is touched, 0 if not, or DEVICE_NOT_SUPPORTED if this pin does not support touch capability. + * + * @code + * DeviceMessageBus bus; + * + * Pin P0(DEVICE_ID_IO_P0, DEVICE_PIN_P0, PIN_CAPABILITY_ALL); + * if(P0.isTouched()) + * { + * //do something! + * } + * + * // subscribe to events generated by this pin! + * bus.listen(DEVICE_ID_IO_P0, DEVICE_BUTTON_EVT_CLICK, someFunction); + * @endcode + */ + virtual int isTouched() { return DEVICE_NOT_IMPLEMENTED; } + /** + * Configures this IO pin as an analog/pwm output if it isn't already, configures the period to be 20ms, + * and sets the pulse width, based on the value it is given. + * + * @param pulseWidth the desired pulse width in microseconds. + * + * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if value is out of range, or DEVICE_NOT_SUPPORTED + * if the given pin does not have analog capability. + */ + virtual int setServoPulseUs(uint32_t pulseWidth) { return DEVICE_NOT_IMPLEMENTED; } - /** - * Configures this IO pin as a "makey makey" style touch sensor (if necessary) - * and tests its current debounced state. - * - * Users can also subscribe to DeviceButton events generated from this pin. - * - * @return 1 if pin is touched, 0 if not, or DEVICE_NOT_SUPPORTED if this pin does not support touch capability. - * - * @code - * DeviceMessageBus bus; - * - * Pin P0(DEVICE_ID_IO_P0, DEVICE_PIN_P0, PIN_CAPABILITY_ALL); - * if(P0.isTouched()) - * { - * //do something! - * } - * - * // subscribe to events generated by this pin! - * bus.listen(DEVICE_ID_IO_P0, DEVICE_BUTTON_EVT_CLICK, someFunction); - * @endcode - */ - virtual int isTouched() - { - return DEVICE_NOT_IMPLEMENTED; - } + /** + * Configures the PWM period of the analog output to the given value. + * + * @param period The new period for the analog output in milliseconds. + * + * @return DEVICE_OK on success, or DEVICE_NOT_SUPPORTED if the + * given pin is not configured as an analog output. + */ + virtual int setAnalogPeriod(int period) { return setAnalogPeriodUs(((uint32_t)period) * 1000); } - /** - * Configures this IO pin as an analog/pwm output if it isn't already, configures the period to be 20ms, - * and sets the pulse width, based on the value it is given. - * - * @param pulseWidth the desired pulse width in microseconds. - * - * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if value is out of range, or DEVICE_NOT_SUPPORTED - * if the given pin does not have analog capability. - */ - virtual int setServoPulseUs(uint32_t pulseWidth) - { - return DEVICE_NOT_IMPLEMENTED; - } + /** + * Configures the PWM period of the analog output to the given value. + * + * @param period The new period for the analog output in microseconds. + * + * @return DEVICE_OK on success, or DEVICE_NOT_SUPPORTED if the + * given pin is not configured as an analog output. + */ + virtual int setAnalogPeriodUs(uint32_t period) { return DEVICE_NOT_IMPLEMENTED; } - /** - * Configures the PWM period of the analog output to the given value. - * - * @param period The new period for the analog output in milliseconds. - * - * @return DEVICE_OK on success, or DEVICE_NOT_SUPPORTED if the - * given pin is not configured as an analog output. - */ - virtual int setAnalogPeriod(int period) - { - return setAnalogPeriodUs(((uint32_t)period)*1000); - } + /** + * Obtains the PWM period of the analog output in microseconds. + * + * @return the period on success, or DEVICE_NOT_SUPPORTED if the + * given pin is not configured as an analog output. + */ + virtual uint32_t getAnalogPeriodUs() { return DEVICE_NOT_IMPLEMENTED; } - /** - * Configures the PWM period of the analog output to the given value. - * - * @param period The new period for the analog output in microseconds. - * - * @return DEVICE_OK on success, or DEVICE_NOT_SUPPORTED if the - * given pin is not configured as an analog output. - */ - virtual int setAnalogPeriodUs(uint32_t period) - { - return DEVICE_NOT_IMPLEMENTED; - } + /** + * Obtains the PWM period of the analog output in milliseconds. + * + * @return the period on success, or DEVICE_NOT_SUPPORTED if the + * given pin is not configured as an analog output. + */ + virtual int getAnalogPeriod() { return (int)(getAnalogPeriodUs() / 1000); } - /** - * Obtains the PWM period of the analog output in microseconds. - * - * @return the period on success, or DEVICE_NOT_SUPPORTED if the - * given pin is not configured as an analog output. - */ - virtual uint32_t getAnalogPeriodUs() - { - return DEVICE_NOT_IMPLEMENTED; - } + /** + * Configures the pull of this pin. + * + * @param pull one of the mbed pull configurations: PullUp, PullDown, PullNone + * + * @return DEVICE_NOT_SUPPORTED if the current pin configuration is anything other + * than a digital input, otherwise DEVICE_OK. + */ + virtual int setPull(PullMode pull) { return DEVICE_NOT_IMPLEMENTED; } - /** - * Obtains the PWM period of the analog output in milliseconds. - * - * @return the period on success, or DEVICE_NOT_SUPPORTED if the - * given pin is not configured as an analog output. - */ - virtual int getAnalogPeriod() - { - return (int) (getAnalogPeriodUs()/1000); - } + /** + * Utility function to drain any residual capacitative charge held on a pin. + * This is useful for applicaitons that measure rise/fall time of digital inputs, + * such as resititve touch sensors like makeymakey. + * + * @return DEVICE_NOT_SUPPORTED if the current pin configuration is anything other + * than a digital input, otherwise DEVICE_OK. + */ + virtual int drainPin() { return DEVICE_NOT_IMPLEMENTED; } + + virtual int setIRQ(void (*gpio_interrupt)(int)) + { + this->gpio_irq = gpio_interrupt; + return DEVICE_OK; + } - /** - * Configures the pull of this pin. - * - * @param pull one of the mbed pull configurations: PullUp, PullDown, PullNone - * - * @return DEVICE_NOT_SUPPORTED if the current pin configuration is anything other - * than a digital input, otherwise DEVICE_OK. - */ - virtual int setPull(PullMode pull) - { - return DEVICE_NOT_IMPLEMENTED; - } + /** + * Measures the period of the next digital pulse on this pin. + * The polarity of the detected pulse is defined by setPolarity(). + * The calling fiber is blocked until a pulse is received or the specified + * timeout passes. + * + * @param timeout The maximum period of time in microseconds to wait for a pulse. + * @return the period of the pulse in microseconds, or DEVICE_CANCELLED on timeout. + */ + virtual int getPulseUs(int timeout) { return DEVICE_NOT_IMPLEMENTED; } - /** - * Utility function to drain any residual capacitative charge held on a pin. - * This is useful for applicaitons that measure rise/fall time of digital inputs, - * such as resititve touch sensors like makeymakey. - * - * @return DEVICE_NOT_SUPPORTED if the current pin configuration is anything other - * than a digital input, otherwise DEVICE_OK. - */ - virtual int drainPin() - { - return DEVICE_NOT_IMPLEMENTED; - } + /** + * Configures the events generated by this Pin instance. + * + * DEVICE_PIN_INTERRUPT_ON_EDGE - Configures this pin to a digital input, and invokes gpio_irq with the new state, + * whenever a rise/fall is detected on this pin. DEVICE_PIN_EVENT_ON_EDGE - Configures this pin to a digital input, + * and generates events whenever a rise/fall is detected on this pin. (DEVICE_PIN_EVT_RISE, DEVICE_PIN_EVT_FALL) + * DEVICE_PIN_EVENT_ON_PULSE - Configures this pin to a digital input, and generates events where the timestamp is + * the duration that this pin was either HI or LO. (DEVICE_PIN_EVT_PULSE_HI, DEVICE_PIN_EVT_PULSE_LO) + * DEVICE_PIN_EVENT_ON_TOUCH - Configures this pin as a makey makey style touch sensor, in the form of a + * DeviceButton. Normal button events will be generated using the ID of this pin. DEVICE_PIN_EVENT_ON_TOUCH - + * Configures this pin as a makey makey style touch sensor, in the form of a DeviceButton. Normal button events will + * be generated using the ID of this pin. DEVICE_PIN_EVENT_NONE - Disables events for this pin. + * + * @param eventType One of: DEVICE_PIN_EVENT_ON_EDGE, DEVICE_PIN_EVENT_ON_PULSE, DEVICE_PIN_EVENT_ON_TOUCH, + * DEVICE_PIN_EVENT_NONE + * + * @code + * DeviceMessageBus bus; + * + * Pin P0(DEVICE_ID_IO_P0, DEVICE_PIN_P0, PIN_CAPABILITY_BOTH); + * P0.eventOn(DEVICE_PIN_EVENT_ON_PULSE); + * + * void onPulse(Event evt) + * { + * int duration = evt.timestamp; + * } + * + * bus.listen(DEVICE_ID_IO_P0, DEVICE_PIN_EVT_PULSE_HI, onPulse, MESSAGE_BUS_LISTENER_IMMEDIATE) + * @endcode + * + * @return DEVICE_OK on success, or DEVICE_INVALID_PARAMETER if the given eventype does not match + * + * @note In the DEVICE_PIN_EVENT_ON_PULSE mode, the smallest pulse that was reliably detected was 85us, around 5khz. + * If more precision is required, please use the InterruptIn class supplied by ARM mbed. + */ + virtual int eventOn(int eventType) { return DEVICE_NOT_IMPLEMENTED; } - virtual int setIRQ(void (*gpio_interrupt)(int)) - { - this->gpio_irq = gpio_interrupt; + /** + * Set pin value iff its current value as input is the opposite. + * + * If pin is configured as input and reads as !value, set it to value + * and return DEVICE_OK. + * Otherwise, do nothing and return DEVICE_BUSY. + * Note, that this is overwritten in hardware-specific classes to check the condition immedietly before changing the + * pin value. + */ + virtual int getAndSetDigitalValue(int value) + { + if (isInput() && getDigitalValue() == !value) { + setDigitalValue(value); return DEVICE_OK; } + return DEVICE_BUSY; + } - /** - * Measures the period of the next digital pulse on this pin. - * The polarity of the detected pulse is defined by setPolarity(). - * The calling fiber is blocked until a pulse is received or the specified - * timeout passes. - * - * @param timeout The maximum period of time in microseconds to wait for a pulse. - * @return the period of the pulse in microseconds, or DEVICE_CANCELLED on timeout. - */ - virtual int getPulseUs(int timeout) - { - return DEVICE_NOT_IMPLEMENTED; - } - - /** - * Configures the events generated by this Pin instance. - * - * DEVICE_PIN_INTERRUPT_ON_EDGE - Configures this pin to a digital input, and invokes gpio_irq with the new state, whenever a rise/fall is detected on this pin. - * DEVICE_PIN_EVENT_ON_EDGE - Configures this pin to a digital input, and generates events whenever a rise/fall is detected on this pin. (DEVICE_PIN_EVT_RISE, DEVICE_PIN_EVT_FALL) - * DEVICE_PIN_EVENT_ON_PULSE - Configures this pin to a digital input, and generates events where the timestamp is the duration that this pin was either HI or LO. (DEVICE_PIN_EVT_PULSE_HI, DEVICE_PIN_EVT_PULSE_LO) - * DEVICE_PIN_EVENT_ON_TOUCH - Configures this pin as a makey makey style touch sensor, in the form of a DeviceButton. Normal button events will be generated using the ID of this pin. - * DEVICE_PIN_EVENT_ON_TOUCH - Configures this pin as a makey makey style touch sensor, in the form of a DeviceButton. Normal button events will be generated using the ID of this pin. - * DEVICE_PIN_EVENT_NONE - Disables events for this pin. - * - * @param eventType One of: DEVICE_PIN_EVENT_ON_EDGE, DEVICE_PIN_EVENT_ON_PULSE, DEVICE_PIN_EVENT_ON_TOUCH, DEVICE_PIN_EVENT_NONE - * - * @code - * DeviceMessageBus bus; - * - * Pin P0(DEVICE_ID_IO_P0, DEVICE_PIN_P0, PIN_CAPABILITY_BOTH); - * P0.eventOn(DEVICE_PIN_EVENT_ON_PULSE); - * - * void onPulse(Event evt) - * { - * int duration = evt.timestamp; - * } - * - * bus.listen(DEVICE_ID_IO_P0, DEVICE_PIN_EVT_PULSE_HI, onPulse, MESSAGE_BUS_LISTENER_IMMEDIATE) - * @endcode - * - * @return DEVICE_OK on success, or DEVICE_INVALID_PARAMETER if the given eventype does not match - * - * @note In the DEVICE_PIN_EVENT_ON_PULSE mode, the smallest pulse that was reliably detected was 85us, around 5khz. If more precision is required, - * please use the InterruptIn class supplied by ARM mbed. - */ - virtual int eventOn(int eventType) - { - return DEVICE_NOT_IMPLEMENTED; - } - - /** - * Set pin value iff its current value as input is the opposite. - * - * If pin is configured as input and reads as !value, set it to value - * and return DEVICE_OK. - * Otherwise, do nothing and return DEVICE_BUSY. - * Note, that this is overwritten in hardware-specific classes to check the condition immedietly before changing the pin value. - */ - virtual int getAndSetDigitalValue(int value) - { - if (isInput() && getDigitalValue() == !value) - { - setDigitalValue(value); - return DEVICE_OK; - } - return DEVICE_BUSY; - } - - /** - * Determines if pin is active, taking into account polarity information - * defined by setActive(). - * - * By default, pins are ACTIVE_HI (a high voltage implies a TRUE logic state). - * - * @return 1 if the digital value read from this pin matches its active polarity state, and 0 otherwise. - */ - int isActive() - { - return !(status & IO_STATUS_ACTIVE_HI) == !getDigitalValue(); - } + /** + * Determines if pin is active, taking into account polarity information + * defined by setActive(). + * + * By default, pins are ACTIVE_HI (a high voltage implies a TRUE logic state). + * + * @return 1 if the digital value read from this pin matches its active polarity state, and 0 otherwise. + */ + int isActive() { return !(status & IO_STATUS_ACTIVE_HI) == !getDigitalValue(); } - /** - * Sets the polarity of the pin to be ACTIVE_HI or ATIVE_LO, depending on the given parameter. - * - * @param polarity The polarity of the pin - either 1 for ACTIVE_HI or 0 for ACTIVE_LO - */ - void setPolarity(int polarity) - { - if (polarity) - status |= IO_STATUS_ACTIVE_HI; - else - status &= ~IO_STATUS_ACTIVE_HI; - } + /** + * Sets the polarity of the pin to be ACTIVE_HI or ATIVE_LO, depending on the given parameter. + * + * @param polarity The polarity of the pin - either 1 for ACTIVE_HI or 0 for ACTIVE_LO + */ + void setPolarity(int polarity) + { + if (polarity) + status |= IO_STATUS_ACTIVE_HI; + else + status &= ~IO_STATUS_ACTIVE_HI; + } - /** - * Determines the polarity of the pin - either ACTIVE_HI or ATIVE_LO. - * - * @return 1 for ACTIVE_HI or 0 for ACTIVE_LO - */ - int getPolarity() - { - return (status & IO_STATUS_ACTIVE_HI) ? 1 : 0; - } + /** + * Determines the polarity of the pin - either ACTIVE_HI or ATIVE_LO. + * + * @return 1 for ACTIVE_HI or 0 for ACTIVE_LO + */ + int getPolarity() { return (status & IO_STATUS_ACTIVE_HI) ? 1 : 0; } - /** - * Sets the polarity of the pin to be ACTIVE_HI. - */ - void setActiveHi() - { - setPolarity(1); - } - /** - * Sets the polarity of the pin to be ACTIVE_LO. - */ - void setActiveLo() - { - setPolarity(0); - } + /** + * Sets the polarity of the pin to be ACTIVE_HI. + */ + void setActiveHi() { setPolarity(1); } + /** + * Sets the polarity of the pin to be ACTIVE_LO. + */ + void setActiveLo() { setPolarity(0); } - /** - * Sets whether the pin should trigger power manager wake-up. - * - * @param wake The action of the pin - either 1 to trigger wake-up or 0 for no wake-up - */ - void wakeOnActive(int wake) - { - if (wake) - status |= IO_STATUS_WAKE_ON_ACTIVE; - else - status &= ~IO_STATUS_WAKE_ON_ACTIVE; - } + /** + * Sets whether the pin should trigger power manager wake-up. + * + * @param wake The action of the pin - either 1 to trigger wake-up or 0 for no wake-up + */ + void wakeOnActive(int wake) + { + if (wake) + status |= IO_STATUS_WAKE_ON_ACTIVE; + else + status &= ~IO_STATUS_WAKE_ON_ACTIVE; + } - /** - * Deternine if the pin should trigger power manager wake-up. - * - * @param wake The action of the pin - either 1 to trigger wake up or 0 for no - */ - int isWakeOnActive() - { - return (status & IO_STATUS_WAKE_ON_ACTIVE) ? 1 : 0; - } + /** + * Deternine if the pin should trigger power manager wake-up. + * + * @param wake The action of the pin - either 1 to trigger wake up or 0 for no + */ + int isWakeOnActive() { return (status & IO_STATUS_WAKE_ON_ACTIVE) ? 1 : 0; } - /** - * Record that a given peripheral has been connected to this pin. - */ - virtual void connect(PinPeripheral &p, bool deleteOnRelease = false) - { - p.deleteOnRelease = deleteOnRelease; - } - /** - * Disconnect any attached peripherals from this pin. - */ - virtual void disconnect() - { - } + /** + * Record that a given peripheral has been connected to this pin. + */ + virtual void connect(PinPeripheral& p, bool deleteOnRelease = false) { p.deleteOnRelease = deleteOnRelease; } + /** + * Disconnect any attached peripherals from this pin. + */ + virtual void disconnect() {} - virtual ~Pin() - { - } - }; + virtual ~Pin() {} +}; -} +} // namespace codal #endif diff --git a/inc/driver-models/PinPeripheral.h b/inc/driver-models/PinPeripheral.h index a65b951a..a157ab2a 100644 --- a/inc/driver-models/PinPeripheral.h +++ b/inc/driver-models/PinPeripheral.h @@ -25,63 +25,61 @@ DEALINGS IN THE SOFTWARE. #ifndef PIN_PERIPHERAL_H #define PIN_PERIPHERAL_H -#include "CodalConfig.h" #include "CodalComponent.h" +#include "CodalConfig.h" -namespace codal -{ - /** - * Class definition for PinPeripheral. - * - * Serves as an abstract base class for any device driver that directly interacts with a Pin. - * Provides the necessary function to enable safe, dynamic rebinding of pins to peripherals at runtime - */ - class Pin; - class PinPeripheral - { - public: - bool deleteOnRelease = false; - bool pinLock = false; +namespace codal { +/** + * Class definition for PinPeripheral. + * + * Serves as an abstract base class for any device driver that directly interacts with a Pin. + * Provides the necessary function to enable safe, dynamic rebinding of pins to peripherals at runtime + */ +class Pin; +class PinPeripheral { + public: + bool deleteOnRelease = false; + bool pinLock = false; - /** - * Method to release the given pin from a peripheral, if already bound. - * Device drivers should override this method to disconnect themselves from the give pin - * to allow it to be used by a different peripheral. - * - * @param pin the Pin to be released - */ - virtual int releasePin(Pin &pin); + /** + * Method to release the given pin from a peripheral, if already bound. + * Device drivers should override this method to disconnect themselves from the give pin + * to allow it to be used by a different peripheral. + * + * @param pin the Pin to be released + */ + virtual int releasePin(Pin& pin); - /** - * Determines if this peripheral has locked any attached pins to this peripheral. - * During a locked period, any attempts to release or reassign those pins to a differnet peripheral are ignored. - * This mechanism is primarily useful to use functions such as Pin::setDigitalValue() within a peripheral driver, - * but without releasing the pin's binding to that peripheral. - * - * @return true if this peripherals pin bindings are locked, false otherwise. - */ - bool isPinLocked(); + /** + * Determines if this peripheral has locked any attached pins to this peripheral. + * During a locked period, any attempts to release or reassign those pins to a differnet peripheral are ignored. + * This mechanism is primarily useful to use functions such as Pin::setDigitalValue() within a peripheral driver, + * but without releasing the pin's binding to that peripheral. + * + * @return true if this peripherals pin bindings are locked, false otherwise. + */ + bool isPinLocked(); - /** - * Controls if this peripheral has locked any attached pins to this peripheral. - * During a locked period, any attempts to release or reassign those pins to a differnet peripheral are ignored. - * This mechanism is primarily useful to use functions such as Pin::setDigitalValue() within a peripheral driver, - * but without releasing the pin's binding to that peripheral. - * - * @param true if this peripherals pin bindings are to be locked, false otherwise. - */ - void setPinLock(bool locked); + /** + * Controls if this peripheral has locked any attached pins to this peripheral. + * During a locked period, any attempts to release or reassign those pins to a differnet peripheral are ignored. + * This mechanism is primarily useful to use functions such as Pin::setDigitalValue() within a peripheral driver, + * but without releasing the pin's binding to that peripheral. + * + * @param true if this peripherals pin bindings are to be locked, false otherwise. + */ + void setPinLock(bool locked); - /** - * Utility function, to assist in redirect() operations and consistent use of disconnect()/connect() by peripherals. - * Safely disconnects pin from any attached peripherals, upfates pin to the new pin, and attaches to the given peripheral. - * Also validates out NULL cases. - * - * @param pin Typically a mutable instance variable, holding the current pin used by a given peripheral. - * @param newPin The pin which is replacing the value of pin. - */ - int reassignPin(void *pin, Pin *newPin); - }; -} + /** + * Utility function, to assist in redirect() operations and consistent use of disconnect()/connect() by peripherals. + * Safely disconnects pin from any attached peripherals, upfates pin to the new pin, and attaches to the given + * peripheral. Also validates out NULL cases. + * + * @param pin Typically a mutable instance variable, holding the current pin used by a given peripheral. + * @param newPin The pin which is replacing the value of pin. + */ + int reassignPin(void* pin, Pin* newPin); +}; +} // namespace codal #endif diff --git a/inc/driver-models/Radio.h b/inc/driver-models/Radio.h index bd5d9601..cd80a0aa 100644 --- a/inc/driver-models/Radio.h +++ b/inc/driver-models/Radio.h @@ -4,53 +4,47 @@ #include "CodalComponent.h" #include "ManagedBuffer.h" -#define RADIO_EVT_DATA_READY 2 - -namespace codal -{ - class Radio : public CodalComponent - { - public: - - Radio(uint16_t id = DEVICE_ID_RADIO) - { - this->id = id; - } - - /** - * Initialises the radio for use as a multipoint sender/receiver - * - * @return DEVICE_OK on success, DEVICE_NOT_SUPPORTED if the BLE stack is running. - */ - virtual int enable() = 0; - - /** - * Disables the radio for use as a multipoint sender/receiver. - * - * @return DEVICE_OK on success, DEVICE_NOT_SUPPORTED if the BLE stack is running. - */ - virtual int disable() = 0; - - /** - * Transmits the given buffer onto the broadcast radio. - * The call will wait until the transmission of the packet has completed before returning. - * - * @param data The packet contents to transmit. - * - * @return DEVICE_OK on success, or DEVICE_NOT_SUPPORTED if the BLE stack is running. - */ - virtual ManagedBuffer recvBuffer() = 0; - - /** - * Transmits the given buffer onto the broadcast radio. - * The call will wait until the transmission of the packet has completed before returning. - * - * @param data The packet contents to transmit. - * - * @return DEVICE_OK on success, or DEVICE_NOT_SUPPORTED if the BLE stack is running. - */ - virtual int sendBuffer(ManagedBuffer) = 0; - }; -} +#define RADIO_EVT_DATA_READY 2 + +namespace codal { +class Radio : public CodalComponent { + public: + Radio(uint16_t id = DEVICE_ID_RADIO) { this->id = id; } + + /** + * Initialises the radio for use as a multipoint sender/receiver + * + * @return DEVICE_OK on success, DEVICE_NOT_SUPPORTED if the BLE stack is running. + */ + virtual int enable() = 0; + + /** + * Disables the radio for use as a multipoint sender/receiver. + * + * @return DEVICE_OK on success, DEVICE_NOT_SUPPORTED if the BLE stack is running. + */ + virtual int disable() = 0; + + /** + * Transmits the given buffer onto the broadcast radio. + * The call will wait until the transmission of the packet has completed before returning. + * + * @param data The packet contents to transmit. + * + * @return DEVICE_OK on success, or DEVICE_NOT_SUPPORTED if the BLE stack is running. + */ + virtual ManagedBuffer recvBuffer() = 0; + + /** + * Transmits the given buffer onto the broadcast radio. + * The call will wait until the transmission of the packet has completed before returning. + * + * @param data The packet contents to transmit. + * + * @return DEVICE_OK on success, or DEVICE_NOT_SUPPORTED if the BLE stack is running. + */ + virtual int sendBuffer(ManagedBuffer) = 0; +}; +} // namespace codal #endif \ No newline at end of file diff --git a/inc/driver-models/SPI.h b/inc/driver-models/SPI.h index c9b0ce06..7c4fc87a 100644 --- a/inc/driver-models/SPI.h +++ b/inc/driver-models/SPI.h @@ -29,29 +29,26 @@ DEALINGS IN THE SOFTWARE. #include "ErrorNo.h" #include "Pin.h" -namespace codal -{ +namespace codal { // TODO there should be some locking mechanism here -typedef void (*PVoidCallback)(void *); - +typedef void (*PVoidCallback)(void*); /** * Class definition for an SPI interface. */ -class SPI : public PinPeripheral -{ -public: - +class SPI : public PinPeripheral { + public: /** - * Change the pins used by this I2C peripheral to those provided. - * - * @param mosi the Pin to use for the SPI input line. - * @param miso the Pin to use for the SPI output line. - * @param sclk the Pin to use for the SPI clock line. - * @return DEVICE_OK on success, or DEVICE_NOT_IMPLEMENTED / DEVICE_NOT_SUPPORTED if the request cannot be performed. - */ - virtual int redirect(Pin &mosi, Pin &miso, Pin &sclk); + * Change the pins used by this I2C peripheral to those provided. + * + * @param mosi the Pin to use for the SPI input line. + * @param miso the Pin to use for the SPI output line. + * @param sclk the Pin to use for the SPI clock line. + * @return DEVICE_OK on success, or DEVICE_NOT_IMPLEMENTED / DEVICE_NOT_SUPPORTED if the request cannot be + * performed. + */ + virtual int redirect(Pin& mosi, Pin& miso, Pin& sclk); /** Set the frequency of the SPI interface * @@ -90,19 +87,18 @@ class SPI : public PinPeripheral * * Either buffer can be NULL. */ - virtual int transfer(const uint8_t *txBuffer, uint32_t txSize, uint8_t *rxBuffer, - uint32_t rxSize); + virtual int transfer(const uint8_t* txBuffer, uint32_t txSize, uint8_t* rxBuffer, uint32_t rxSize); /** * Writes and reads from the SPI bus concurrently. Finally, calls doneHandler (possibly in IRQ context). * * Either buffer can be NULL. */ - virtual int startTransfer(const uint8_t *txBuffer, uint32_t txSize, uint8_t *rxBuffer, - uint32_t rxSize, PVoidCallback doneHandler, void *arg); - + virtual int startTransfer(const uint8_t* txBuffer, uint32_t txSize, uint8_t* rxBuffer, uint32_t rxSize, + PVoidCallback doneHandler, void* arg); + virtual ~SPI() {} }; -} +} // namespace codal #endif diff --git a/inc/driver-models/SPIFlash.h b/inc/driver-models/SPIFlash.h index 23b86424..c1635dfd 100644 --- a/inc/driver-models/SPIFlash.h +++ b/inc/driver-models/SPIFlash.h @@ -29,25 +29,23 @@ DEALINGS IN THE SOFTWARE. // this seems common to many different SPI flash parts // they sometimes also have medium row of 32k -#define SPIFLASH_PAGE_SIZE 256 +#define SPIFLASH_PAGE_SIZE 256 #define SPIFLASH_SMALL_ROW_PAGES 16 -#define SPIFLASH_BIG_ROW_PAGES 256 -#define SPIFLASH_SMALL_ROW_SIZE (SPIFLASH_SMALL_ROW_PAGES * SPIFLASH_PAGE_SIZE) // 4k -#define SPIFLASH_BIG_ROW_SIZE (SPIFLASH_BIG_ROW_PAGES * SPIFLASH_PAGE_SIZE) // 64k - -namespace codal -{ -class SPIFlash -{ -public: - virtual int numPages() = 0; - virtual int readBytes(uint32_t addr, void *buffer, uint32_t len) = 0; +#define SPIFLASH_BIG_ROW_PAGES 256 +#define SPIFLASH_SMALL_ROW_SIZE (SPIFLASH_SMALL_ROW_PAGES * SPIFLASH_PAGE_SIZE) // 4k +#define SPIFLASH_BIG_ROW_SIZE (SPIFLASH_BIG_ROW_PAGES * SPIFLASH_PAGE_SIZE) // 64k + +namespace codal { +class SPIFlash { + public: + virtual int numPages() = 0; + virtual int readBytes(uint32_t addr, void* buffer, uint32_t len) = 0; // len <= SPIFLASH_PAGE_SIZE; block cannot span pages - virtual int writeBytes(uint32_t addr, const void *buffer, uint32_t len) = 0; - virtual int eraseSmallRow(uint32_t addr) = 0; - virtual int eraseBigRow(uint32_t addr) = 0; - virtual int eraseChip() = 0; + virtual int writeBytes(uint32_t addr, const void* buffer, uint32_t len) = 0; + virtual int eraseSmallRow(uint32_t addr) = 0; + virtual int eraseBigRow(uint32_t addr) = 0; + virtual int eraseChip() = 0; }; -} +} // namespace codal #endif diff --git a/inc/driver-models/ScreenIO.h b/inc/driver-models/ScreenIO.h index 737de7fa..4087e4c9 100644 --- a/inc/driver-models/ScreenIO.h +++ b/inc/driver-models/ScreenIO.h @@ -27,17 +27,14 @@ DEALINGS IN THE SOFTWARE. #include "CodalConfig.h" -namespace codal -{ - -class ScreenIO -{ -public: - virtual void send(const void *txBuffer, uint32_t txSize) = 0; - virtual void startSend(const void *txBuffer, uint32_t txSize, PVoidCallback doneHandler, - void *handlerArg) = 0; +namespace codal { + +class ScreenIO { + public: + virtual void send(const void* txBuffer, uint32_t txSize) = 0; + virtual void startSend(const void* txBuffer, uint32_t txSize, PVoidCallback doneHandler, void* handlerArg) = 0; }; -} // namespace codal +} // namespace codal #endif diff --git a/inc/driver-models/Sensor.h b/inc/driver-models/Sensor.h index 30a11c6e..4af2a082 100644 --- a/inc/driver-models/Sensor.h +++ b/inc/driver-models/Sensor.h @@ -26,151 +26,148 @@ DEALINGS IN THE SOFTWARE. #ifndef SENSOR_H #define SENSOR_H -#include "CodalConfig.h" #include "CodalComponent.h" +#include "CodalConfig.h" #include "Event.h" - /** - * Sensor events - */ -#define SENSOR_THRESHOLD_LOW 1 + * Sensor events + */ +#define SENSOR_THRESHOLD_LOW 1 #define SENSOR_THRESHOLD_HIGH 2 -#define SENSOR_UPDATE_NEEDED 3 +#define SENSOR_UPDATE_NEEDED 3 /** * Status values */ -#define SENSOR_INITIALISED 0x01 -#define SENSOR_HIGH_THRESHOLD_PASSED 0x02 -#define SENSOR_LOW_THRESHOLD_PASSED 0x04 -#define SENSOR_LOW_THRESHOLD_ENABLED 0x08 +#define SENSOR_INITIALISED 0x01 +#define SENSOR_HIGH_THRESHOLD_PASSED 0x02 +#define SENSOR_LOW_THRESHOLD_PASSED 0x04 +#define SENSOR_LOW_THRESHOLD_ENABLED 0x08 #define SENSOR_HIGH_THRESHOLD_ENABLED 0x10 -#define SENSOR_DEFAULT_SENSITIVITY 868 +#define SENSOR_DEFAULT_SENSITIVITY 868 #define SENSOR_DEFAULT_SAMPLE_PERIOD 500 -namespace codal -{ +namespace codal { +/** + * Class definition for a generic analog sensor, and performs periodic sampling, buffering and low pass filtering of the + * data. + */ +class Sensor : public CodalComponent { + protected: + uint16_t samplePeriod; // The time between samples, in milliseconds. + uint16_t sensitivity; // A value between 0..1023 used with a decay average to smooth the sample data. + uint16_t highThreshold; // threshold at which a HIGH event is generated + uint16_t lowThreshold; // threshold at which a LOW event is generated + uint16_t sensorValue; // Last sampled data. + + public: + /** + * Constructor. + * + * Creates a generic Sensor. + * + * @param pin The pin on which to sense + * @param id The ID of this compoenent e.g. DEVICE_ID_THERMOMETER + */ + Sensor(uint16_t id, uint16_t sensitivity = SENSOR_DEFAULT_SENSITIVITY, + uint16_t samplePeriod = SENSOR_DEFAULT_SAMPLE_PERIOD); + + /* + * Event Handler for periodic sample timer + */ + void onSampleEvent(Event); + + /** + * Updates the internal reading of the sensor. Typically called periodicaly. + * + * @return DEVICE_OK on success. + */ + virtual void updateSample(); + + /* + * Determines the instantaneous value of the sensor, in SI units, and returns it. + * + * @return The current value of the sensor. + */ + int getValue(); + + /** + * Set the automatic sample period of the accelerometer to the specified value (in ms). + * + * @param period the requested time between samples, in milliseconds. + * + * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if the request fails. + */ + int setPeriod(int period); + + /** + * Reads the currently configured sample period. + * + * @return The time between samples, in milliseconds. + */ + int getPeriod(); + + /** + * Set threshold to the given value. Events will be generated when these thresholds are crossed. + * + * @param value the LOW threshold at which a SENSOR_THRESHOLD_LOW will be generated. + * + * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if the request fails. + */ + int setLowThreshold(uint16_t value); + + /** + * Set threshold to the given value. Events will be generated when these thresholds are crossed. + * + * @param value the HIGH threshold at which a SENSOR_THRESHOLD_HIGH will be generated. + * + * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if the request fails. + */ + int setHighThreshold(uint16_t value); + + /** + * Determines the currently defined low threshold. + * + * @return The current low threshold. DEVICE_INVALID_PARAMETER if no threshold has been defined. + */ + int getLowThreshold(); + + /** + * Determines the currently defined high threshold. + * + * @return The current high threshold. DEVICE_INVALID_PARAMETER if no threshold has been defined. + */ + int getHighThreshold(); + + /** + * Set smoothing value for the data. A decay average is taken of sampled data to smooth it into more accurate + * information. + * + * @param value A value between 0..1023 that detemrines the level of smoothing. Set to 1023 to disable smoothing. + * Default value is 868 + * + * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if the request fails. + */ + int setSensitivity(uint16_t value); + + /** + * Destructor. + */ + virtual ~Sensor(); + + protected: + /** + * Determine if any thresholding events need to be generated, and if so, raise them. + */ + void checkThresholding(); + /** - * Class definition for a generic analog sensor, and performs periodic sampling, buffering and low pass filtering of the data. + * Read the value from underlying hardware. */ - class Sensor : public CodalComponent - { - protected: - - uint16_t samplePeriod; // The time between samples, in milliseconds. - uint16_t sensitivity; // A value between 0..1023 used with a decay average to smooth the sample data. - uint16_t highThreshold; // threshold at which a HIGH event is generated - uint16_t lowThreshold; // threshold at which a LOW event is generated - uint16_t sensorValue; // Last sampled data. - - public: - - /** - * Constructor. - * - * Creates a generic Sensor. - * - * @param pin The pin on which to sense - * @param id The ID of this compoenent e.g. DEVICE_ID_THERMOMETER - */ - Sensor(uint16_t id, uint16_t sensitivity = SENSOR_DEFAULT_SENSITIVITY, uint16_t samplePeriod = SENSOR_DEFAULT_SAMPLE_PERIOD); - - /* - * Event Handler for periodic sample timer - */ - void onSampleEvent(Event); - - /** - * Updates the internal reading of the sensor. Typically called periodicaly. - * - * @return DEVICE_OK on success. - */ - virtual void updateSample(); - - /* - * Determines the instantaneous value of the sensor, in SI units, and returns it. - * - * @return The current value of the sensor. - */ - int getValue(); - - /** - * Set the automatic sample period of the accelerometer to the specified value (in ms). - * - * @param period the requested time between samples, in milliseconds. - * - * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if the request fails. - */ - int setPeriod(int period); - - /** - * Reads the currently configured sample period. - * - * @return The time between samples, in milliseconds. - */ - int getPeriod(); - - /** - * Set threshold to the given value. Events will be generated when these thresholds are crossed. - * - * @param value the LOW threshold at which a SENSOR_THRESHOLD_LOW will be generated. - * - * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if the request fails. - */ - int setLowThreshold(uint16_t value); - - /** - * Set threshold to the given value. Events will be generated when these thresholds are crossed. - * - * @param value the HIGH threshold at which a SENSOR_THRESHOLD_HIGH will be generated. - * - * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if the request fails. - */ - int setHighThreshold(uint16_t value); - - /** - * Determines the currently defined low threshold. - * - * @return The current low threshold. DEVICE_INVALID_PARAMETER if no threshold has been defined. - */ - int getLowThreshold(); - - /** - * Determines the currently defined high threshold. - * - * @return The current high threshold. DEVICE_INVALID_PARAMETER if no threshold has been defined. - */ - int getHighThreshold(); - - /** - * Set smoothing value for the data. A decay average is taken of sampled data to smooth it into more accurate information. - * - * @param value A value between 0..1023 that detemrines the level of smoothing. Set to 1023 to disable smoothing. Default value is 868 - * - * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if the request fails. - */ - int setSensitivity(uint16_t value); - - /** - * Destructor. - */ - virtual ~Sensor(); - - protected: - - /** - * Determine if any thresholding events need to be generated, and if so, raise them. - */ - void checkThresholding(); - - /** - * Read the value from underlying hardware. - */ - virtual int readValue( ) = 0; - - }; -} + virtual int readValue() = 0; +}; +} // namespace codal #endif diff --git a/inc/driver-models/Serial.h b/inc/driver-models/Serial.h index 5569f123..427c991c 100644 --- a/inc/driver-models/Serial.h +++ b/inc/driver-models/Serial.h @@ -25,523 +25,512 @@ DEALINGS IN THE SOFTWARE. #ifndef CODAL_SERIAL_H #define CODAL_SERIAL_H -#include "ManagedString.h" #include "CodalComponent.h" +#include "ManagedString.h" #include "Pin.h" -#define CODAL_SERIAL_DEFAULT_BAUD_RATE 115200 -#define CODAL_SERIAL_DEFAULT_BUFFER_SIZE 20 - -#define CODAL_SERIAL_EVT_DELIM_MATCH 1 -#define CODAL_SERIAL_EVT_HEAD_MATCH 2 -#define CODAL_SERIAL_EVT_RX_FULL 3 -#define CODAL_SERIAL_EVT_DATA_RECEIVED 4 - -#define CODAL_SERIAL_STATUS_RX_IN_USE 0x01 -#define CODAL_SERIAL_STATUS_TX_IN_USE 0x02 -#define CODAL_SERIAL_STATUS_RX_BUFF_INIT 0x04 -#define CODAL_SERIAL_STATUS_TX_BUFF_INIT 0x08 -#define CODAL_SERIAL_STATUS_RXD 0x10 -#define CODAL_SERIAL_STATUS_DEEPSLEEP 0x20 - - -namespace codal -{ - enum SerialMode - { - ASYNC, - SYNC_SPINWAIT, - SYNC_SLEEP - }; - - enum SerialInterruptType - { - RxInterrupt = 0, - TxInterrupt - }; +#define CODAL_SERIAL_DEFAULT_BAUD_RATE 115200 +#define CODAL_SERIAL_DEFAULT_BUFFER_SIZE 20 + +#define CODAL_SERIAL_EVT_DELIM_MATCH 1 +#define CODAL_SERIAL_EVT_HEAD_MATCH 2 +#define CODAL_SERIAL_EVT_RX_FULL 3 +#define CODAL_SERIAL_EVT_DATA_RECEIVED 4 + +#define CODAL_SERIAL_STATUS_RX_IN_USE 0x01 +#define CODAL_SERIAL_STATUS_TX_IN_USE 0x02 +#define CODAL_SERIAL_STATUS_RX_BUFF_INIT 0x04 +#define CODAL_SERIAL_STATUS_TX_BUFF_INIT 0x08 +#define CODAL_SERIAL_STATUS_RXD 0x10 +#define CODAL_SERIAL_STATUS_DEEPSLEEP 0x20 + +namespace codal { +enum SerialMode { ASYNC, SYNC_SPINWAIT, SYNC_SLEEP }; + +enum SerialInterruptType { RxInterrupt = 0, TxInterrupt }; + +/** + * Class definition for DeviceSerial. + * + * Represents an instance of RawSerial which accepts codal device specific data types. + */ +class Serial : public PinPeripheral, public CodalComponent { + protected: + Pin* tx; + Pin* rx; + + // delimeters used for matching on receive. + ManagedString delimeters; + + // a variable used when a user calls the eventAfter() method. + int rxBuffHeadMatch; + + uint8_t* rxBuff; + uint8_t rxBuffSize; + volatile uint16_t rxBuffHead; + uint16_t rxBuffTail; + + uint8_t* txBuff; + uint8_t txBuffSize; + uint16_t txBuffHead; + volatile uint16_t txBuffTail; + + uint32_t baudrate; + + /** + * SUB CLASSES / IMPLEMENTATIONS DEFINE THE FOLLOWING METHODS: + **/ + virtual int enableInterrupt(SerialInterruptType t) = 0; + virtual int disableInterrupt(SerialInterruptType t) = 0; + virtual int setBaudrate(uint32_t baudrate) = 0; + virtual int configurePins(Pin& tx, Pin& rx) = 0; + + /** + * We do not want to always have our buffers initialised, especially if users to not + * use them. We only bring them up on demand. + */ + int initialiseRx(); + + /** + * We do not want to always have our buffers initialised, especially if users to not + * use them. We only bring them up on demand. + */ + int initialiseTx(); + + void circularCopy(uint8_t* circularBuff, uint8_t circularBuffSize, uint8_t* linearBuff, uint16_t tailPosition, + uint16_t headPosition); + + int setTxInterrupt(uint8_t* string, int len, SerialMode mode); + + public: + void dataTransmitted(); + void dataReceived(char c); + + virtual void idleCallback() override; + + /** + * SUB CLASSES / IMPLEMENTATIONS DEFINE THE FOLLOWING METHODS: + **/ + virtual int putc(char c) = 0; + virtual int getc() = 0; /** - * Class definition for DeviceSerial. - * - * Represents an instance of RawSerial which accepts codal device specific data types. - */ - class Serial : public PinPeripheral, public CodalComponent - { - protected: - - Pin* tx; - Pin* rx; - - //delimeters used for matching on receive. - ManagedString delimeters; - - //a variable used when a user calls the eventAfter() method. - int rxBuffHeadMatch; - - uint8_t *rxBuff; - uint8_t rxBuffSize; - volatile uint16_t rxBuffHead; - uint16_t rxBuffTail; - - uint8_t *txBuff; - uint8_t txBuffSize; - uint16_t txBuffHead; - volatile uint16_t txBuffTail; - - uint32_t baudrate; - - /** - * SUB CLASSES / IMPLEMENTATIONS DEFINE THE FOLLOWING METHODS: - **/ - virtual int enableInterrupt(SerialInterruptType t) = 0; - virtual int disableInterrupt(SerialInterruptType t) = 0; - virtual int setBaudrate(uint32_t baudrate) = 0; - virtual int configurePins(Pin& tx, Pin& rx) = 0; - - /** - * We do not want to always have our buffers initialised, especially if users to not - * use them. We only bring them up on demand. - */ - int initialiseRx(); - - /** - * We do not want to always have our buffers initialised, especially if users to not - * use them. We only bring them up on demand. - */ - int initialiseTx(); - - void circularCopy(uint8_t *circularBuff, uint8_t circularBuffSize, uint8_t *linearBuff, uint16_t tailPosition, uint16_t headPosition); - - int setTxInterrupt(uint8_t *string, int len, SerialMode mode); - - public: - - void dataTransmitted(); - void dataReceived(char c); - - virtual void idleCallback() override; - - /** - * SUB CLASSES / IMPLEMENTATIONS DEFINE THE FOLLOWING METHODS: - **/ - virtual int putc(char c) = 0; - virtual int getc() = 0; - - /** - * Constructor. - * Create an instance of DeviceSerial - * - * @param tx the Pin to be used for transmission - * - * @param rx the Pin to be used for receiving data - * - * @param rxBufferSize the size of the buffer to be used for receiving bytes - * - * @param txBufferSize the size of the buffer to be used for transmitting bytes - * - * @code - * DeviceSerial serial(USBTX, USBRX); - * @endcode - * @note the default baud rate is 115200. - * - * Buffers aren't allocated until the first send or receive respectively. - */ - Serial(Pin& tx, Pin& rx, uint8_t rxBufferSize = CODAL_SERIAL_DEFAULT_BUFFER_SIZE, uint8_t txBufferSize = CODAL_SERIAL_DEFAULT_BUFFER_SIZE, uint16_t id = DEVICE_ID_SERIAL); - - /** - * Sends a single character over the serial line. - * - * @param c the character to send - * - * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode - * gives a different behaviour: - * - * ASYNC - the character is copied into the txBuff and returns immediately. - * - * SYNC_SPINWAIT - the character is copied into the txBuff and this method - * will spin (lock up the processor) until the character has - * been sent. - * - * SYNC_SLEEP - the character is copied into the txBuff and the fiber sleeps - * until the character has been sent. This allows other fibers - * to continue execution. - * - * Defaults to SYNC_SLEEP. - * - * @return the number of bytes written, or CODAL_SERIAL_IN_USE if another fiber - * is using the serial instance for transmission. - */ - int sendChar(char c, SerialMode mode = DEVICE_DEFAULT_SERIAL_MODE); - - /** - * Sends a ManagedString over the serial line. - * - * @param s the string to send - * - * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode - * gives a different behaviour: - * - * ASYNC - bytes are copied into the txBuff and returns immediately. - * If there is insufficient space in txBuff, then only the first 'n' - * bytes will actually be sent, refer to the return value to get - * how many bytes were actually put in the buffer. - * To ensure all bytes are sent on an ASYNC call, set an appropriate - * buffer length beforehand using setTxBufferSize. - * - * SYNC_SPINWAIT - bytes are copied into the txBuff and this method - * will spin (lock up the processor) until all bytes - * have been sent. - * - * SYNC_SLEEP - bytes are copied into the txBuff and the fiber sleeps - * until all bytes have been sent. This allows other fibers - * to continue execution. - * - * Defaults to SYNC_SLEEP. - * - * @return the number of bytes written, CODAL_SERIAL_IN_USE if another fiber - * is using the serial instance for transmission, DEVICE_INVALID_PARAMETER - * if buffer is invalid, or the given bufferLen is <= 0. - */ - int send(ManagedString s, SerialMode mode = DEVICE_DEFAULT_SERIAL_MODE); - - /** - * Sends a buffer of known length over the serial line. - * - * @param buffer a pointer to the first character of the buffer - * - * @param len the number of bytes that are safely available to read. - * - * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode - * gives a different behaviour: - * - * ASYNC - bytes are copied into the txBuff and returns immediately. - * If there is insufficient space in txBuff, then only the first 'n' - * bytes will actually be sent, refer to the return value to get - * how many bytes were actually put in the buffer. - * To ensure all bytes are sent on an ASYNC call, set an appropriate - * buffer length beforehand using setTxBufferSize. - * - * SYNC_SPINWAIT - bytes are copied into the txBuff and this method - * will spin (lock up the processor) until all bytes - * have been sent. - * - * SYNC_SLEEP - bytes are copied into the txBuff and the fiber sleeps - * until all bytes have been sent. This allows other fibers - * to continue execution. - * - * Defaults to SYNC_SLEEP. - * - * @return the number of bytes written, CODAL_SERIAL_IN_USE if another fiber - * is using the serial instance for transmission, DEVICE_INVALID_PARAMETER - * if buffer is invalid, or the given bufferLen is <= 0. - */ - int send(uint8_t *buffer, int bufferLen, SerialMode mode = DEVICE_DEFAULT_SERIAL_MODE); - - /** - * Reads a single character from the rxBuff - * - * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode - * gives a different behaviour: - * - * ASYNC - A character is read from the rxBuff if available, if there - * are no characters to be read, a value of DEVICE_NO_DATA is returned immediately. - * - * SYNC_SPINWAIT - A character is read from the rxBuff if available, if there - * are no characters to be read, this method will spin - * (lock up the processor) until a character is available. - * - * SYNC_SLEEP - A character is read from the rxBuff if available, if there - * are no characters to be read, the calling fiber sleeps - * until there is a character available. - * - * Defaults to SYNC_SLEEP. - * - * @return a character, CODAL_SERIAL_IN_USE if another fiber is using the serial instance for reception, - * DEVICE_NO_RESOURCES if buffer allocation did not complete successfully, or DEVICE_NO_DATA if - * the rx buffer is empty and the mode given is ASYNC. - */ - int read(SerialMode mode = DEVICE_DEFAULT_SERIAL_MODE); + * Constructor. + * Create an instance of DeviceSerial + * + * @param tx the Pin to be used for transmission + * + * @param rx the Pin to be used for receiving data + * + * @param rxBufferSize the size of the buffer to be used for receiving bytes + * + * @param txBufferSize the size of the buffer to be used for transmitting bytes + * + * @code + * DeviceSerial serial(USBTX, USBRX); + * @endcode + * @note the default baud rate is 115200. + * + * Buffers aren't allocated until the first send or receive respectively. + */ + Serial(Pin& tx, Pin& rx, uint8_t rxBufferSize = CODAL_SERIAL_DEFAULT_BUFFER_SIZE, + uint8_t txBufferSize = CODAL_SERIAL_DEFAULT_BUFFER_SIZE, uint16_t id = DEVICE_ID_SERIAL); + + /** + * Sends a single character over the serial line. + * + * @param c the character to send + * + * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode + * gives a different behaviour: + * + * ASYNC - the character is copied into the txBuff and returns immediately. + * + * SYNC_SPINWAIT - the character is copied into the txBuff and this method + * will spin (lock up the processor) until the character has + * been sent. + * + * SYNC_SLEEP - the character is copied into the txBuff and the fiber sleeps + * until the character has been sent. This allows other fibers + * to continue execution. + * + * Defaults to SYNC_SLEEP. + * + * @return the number of bytes written, or CODAL_SERIAL_IN_USE if another fiber + * is using the serial instance for transmission. + */ + int sendChar(char c, SerialMode mode = DEVICE_DEFAULT_SERIAL_MODE); + + /** + * Sends a ManagedString over the serial line. + * + * @param s the string to send + * + * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode + * gives a different behaviour: + * + * ASYNC - bytes are copied into the txBuff and returns immediately. + * If there is insufficient space in txBuff, then only the first 'n' + * bytes will actually be sent, refer to the return value to get + * how many bytes were actually put in the buffer. + * To ensure all bytes are sent on an ASYNC call, set an appropriate + * buffer length beforehand using setTxBufferSize. + * + * SYNC_SPINWAIT - bytes are copied into the txBuff and this method + * will spin (lock up the processor) until all bytes + * have been sent. + * + * SYNC_SLEEP - bytes are copied into the txBuff and the fiber sleeps + * until all bytes have been sent. This allows other fibers + * to continue execution. + * + * Defaults to SYNC_SLEEP. + * + * @return the number of bytes written, CODAL_SERIAL_IN_USE if another fiber + * is using the serial instance for transmission, DEVICE_INVALID_PARAMETER + * if buffer is invalid, or the given bufferLen is <= 0. + */ + int send(ManagedString s, SerialMode mode = DEVICE_DEFAULT_SERIAL_MODE); + + /** + * Sends a buffer of known length over the serial line. + * + * @param buffer a pointer to the first character of the buffer + * + * @param len the number of bytes that are safely available to read. + * + * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode + * gives a different behaviour: + * + * ASYNC - bytes are copied into the txBuff and returns immediately. + * If there is insufficient space in txBuff, then only the first 'n' + * bytes will actually be sent, refer to the return value to get + * how many bytes were actually put in the buffer. + * To ensure all bytes are sent on an ASYNC call, set an appropriate + * buffer length beforehand using setTxBufferSize. + * + * SYNC_SPINWAIT - bytes are copied into the txBuff and this method + * will spin (lock up the processor) until all bytes + * have been sent. + * + * SYNC_SLEEP - bytes are copied into the txBuff and the fiber sleeps + * until all bytes have been sent. This allows other fibers + * to continue execution. + * + * Defaults to SYNC_SLEEP. + * + * @return the number of bytes written, CODAL_SERIAL_IN_USE if another fiber + * is using the serial instance for transmission, DEVICE_INVALID_PARAMETER + * if buffer is invalid, or the given bufferLen is <= 0. + */ + int send(uint8_t* buffer, int bufferLen, SerialMode mode = DEVICE_DEFAULT_SERIAL_MODE); + + /** + * Reads a single character from the rxBuff + * + * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode + * gives a different behaviour: + * + * ASYNC - A character is read from the rxBuff if available, if there + * are no characters to be read, a value of DEVICE_NO_DATA is returned immediately. + * + * SYNC_SPINWAIT - A character is read from the rxBuff if available, if there + * are no characters to be read, this method will spin + * (lock up the processor) until a character is available. + * + * SYNC_SLEEP - A character is read from the rxBuff if available, if there + * are no characters to be read, the calling fiber sleeps + * until there is a character available. + * + * Defaults to SYNC_SLEEP. + * + * @return a character, CODAL_SERIAL_IN_USE if another fiber is using the serial instance for reception, + * DEVICE_NO_RESOURCES if buffer allocation did not complete successfully, or DEVICE_NO_DATA if + * the rx buffer is empty and the mode given is ASYNC. + */ + int read(SerialMode mode = DEVICE_DEFAULT_SERIAL_MODE); #if CONFIG_ENABLED(CODAL_PROVIDE_PRINTF) - virtual void printf(const char* format, ...); + virtual void printf(const char* format, ...); #endif - int getChar(SerialMode mode); - - /** - * Reads multiple characters from the rxBuff and returns them as a ManagedString - * - * @param size the number of characters to read. - * - * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode - * gives a different behaviour: - * - * ASYNC - If the desired number of characters are available, this will return - * a ManagedString with the expected size. Otherwise, it will read however - * many characters there are available. - * - * SYNC_SPINWAIT - If the desired number of characters are available, this will return - * a ManagedString with the expected size. Otherwise, this method will spin - * (lock up the processor) until the desired number of characters have been read. - * - * SYNC_SLEEP - If the desired number of characters are available, this will return - * a ManagedString with the expected size. Otherwise, the calling fiber sleeps - * until the desired number of characters have been read. - * - * Defaults to SYNC_SLEEP. - * - * @return A ManagedString, or an empty ManagedString if an error was encountered during the read. - */ - ManagedString read(int size, SerialMode mode = DEVICE_DEFAULT_SERIAL_MODE); - - /** - * Reads multiple characters from the rxBuff and fills a user buffer. - * - * @param buffer a pointer to a user allocated buffer. - * - * @param bufferLen the amount of data that can be safely stored - * - * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode - * gives a different behaviour: - * - * ASYNC - If the desired number of characters are available, this will fill - * the given buffer. Otherwise, it will fill the buffer with however - * many characters there are available. - * - * SYNC_SPINWAIT - If the desired number of characters are available, this will fill - * the given buffer. Otherwise, this method will spin (lock up the processor) - * and fill the buffer until the desired number of characters have been read. - * - * SYNC_SLEEP - If the desired number of characters are available, this will fill - * the given buffer. Otherwise, the calling fiber sleeps - * until the desired number of characters have been read. - * - * Defaults to SYNC_SLEEP. - * - * @return the number of characters read, or CODAL_SERIAL_IN_USE if another fiber - * is using the instance for receiving. - */ - int read(uint8_t *buffer, int bufferLen, SerialMode mode = DEVICE_DEFAULT_SERIAL_MODE); - - /** - * Reads until one of the delimeters matches a character in the rxBuff - * - * @param delimeters a ManagedString containing a sequence of delimeter characters e.g. ManagedString("\r\n") - * - * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode - * gives a different behaviour: - * - * ASYNC - If one of the delimeters matches a character already in the rxBuff - * this method will return a ManagedString up to the delimeter. - * Otherwise, it will return an Empty ManagedString. - * - * SYNC_SPINWAIT - If one of the delimeters matches a character already in the rxBuff - * this method will return a ManagedString up to the delimeter. - * Otherwise, this method will spin (lock up the processor) until a - * received character matches one of the delimeters. - * - * SYNC_SLEEP - If one of the delimeters matches a character already in the rxBuff - * this method will return a ManagedString up to the delimeter. - * Otherwise, the calling fiber sleeps until a character matching one - * of the delimeters is seen. - * - * Defaults to SYNC_SLEEP. - * - * @return A ManagedString containing the characters up to a delimeter, or an Empty ManagedString, - * if another fiber is currently using this instance for reception. - * - * @note delimeters are matched on a per byte basis. - */ - virtual ManagedString readUntil(ManagedString delimeters, SerialMode mode = DEVICE_DEFAULT_SERIAL_MODE); - - /** - * A wrapper around the inherited method "baud" so we can trap the baud rate - * as it changes and restore it if redirect() is called. - * - * @param baudrate the new baudrate. See: - * - https://github.com/mbedmicro/mbed/blob/master/libraries/mbed/targets/hal/TARGET_NORDIC/TARGET_MCU_NRF51822/serial_api.c - * for permitted baud rates. - * - * @return DEVICE_INVALID_PARAMETER if baud rate is less than 0, otherwise DEVICE_OK. - * - * @note the underlying implementation chooses the first allowable rate at or above that requested. - */ - int setBaud(int baudrate); - - /** - * A way of dynamically configuring the serial instance to use pins other than USBTX and USBRX. - * - * @param tx the new transmission pin. - * - * @param rx the new reception pin. - * - * @return CODAL_SERIAL_IN_USE if another fiber is currently transmitting or receiving, otherwise DEVICE_OK. - */ - int redirect(Pin& tx, Pin& rx); - - /** - * Configures an event to be fired after "len" characters. - * - * Will generate an event with the ID: DEVICE_ID_SERIAL and the value CODAL_SERIAL_EVT_HEAD_MATCH. - * - * @param len the number of characters to wait before triggering the event. - * - * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode - * gives a different behaviour: - * - * ASYNC - Will configure the event and return immediately. - * - * SYNC_SPINWAIT - will return DEVICE_INVALID_PARAMETER - * - * SYNC_SLEEP - Will configure the event and block the current fiber until the - * event is received. - * - * @return DEVICE_INVALID_PARAMETER if the mode given is SYNC_SPINWAIT, otherwise DEVICE_OK. - */ - int eventAfter(int len, SerialMode mode = ASYNC); - - /** - * Configures an event to be fired on a match with one of the delimeters. - * - * Will generate an event with the ID: DEVICE_ID_SERIAL and the value CODAL_SERIAL_EVT_DELIM_MATCH. - * - * @param delimeters the characters to match received characters against e.g. ManagedString("\n") - * - * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode - * gives a different behaviour: - * - * ASYNC - Will configure the event and return immediately. - * - * SYNC_SPINWAIT - will return DEVICE_INVALID_PARAMETER - * - * SYNC_SLEEP - Will configure the event and block the current fiber until the - * event is received. - * - * @return DEVICE_INVALID_PARAMETER if the mode given is SYNC_SPINWAIT, otherwise DEVICE_OK. - * - * @note delimeters are matched on a per byte basis. - */ - int eventOn(ManagedString delimeters, SerialMode mode = ASYNC); - - /** - * Determines whether there is any data waiting in our Rx buffer. - * - * @return 1 if we have space, 0 if we do not. - * - * @note We do not wrap the super's readable() method as we don't want to - * interfere with communities that use manual calls to serial.readable(). - */ - int isReadable(); - - /** - * Determines if we have space in our txBuff. - * - * @return 1 if we have space, 0 if we do not. - * - * @note We do not wrap the super's writeable() method as we don't want to - * interfere with communities that use manual calls to serial.writeable(). - */ - int isWriteable(); - - /** - * Reconfigures the size of our rxBuff - * - * @param size the new size for our rxBuff - * - * @return CODAL_SERIAL_IN_USE if another fiber is currently using this instance - * for reception, otherwise DEVICE_OK. - */ - int setRxBufferSize(uint8_t size); - - /** - * Reconfigures the size of our txBuff - * - * @param size the new size for our txBuff - * - * @return CODAL_SERIAL_IN_USE if another fiber is currently using this instance - * for transmission, otherwise DEVICE_OK. - */ - int setTxBufferSize(uint8_t size); - - /** - * The size of our rx buffer in bytes. - * - * @return the current size of rxBuff in bytes - */ - int getRxBufferSize(); - - /** - * The size of our tx buffer in bytes. - * - * @return the current size of txBuff in bytes - */ - int getTxBufferSize(); - - /** - * Sets the tail to match the head of our circular buffer for reception, - * effectively clearing the reception buffer. - * - * @return CODAL_SERIAL_IN_USE if another fiber is currently using this instance - * for reception, otherwise DEVICE_OK. - */ - int clearRxBuffer(); - - /** - * Sets the tail to match the head of our circular buffer for transmission, - * effectively clearing the transmission buffer. - * - * @return CODAL_SERIAL_IN_USE if another fiber is currently using this instance - * for transmission, otherwise DEVICE_OK. - */ - int clearTxBuffer(); - - /** - * The number of bytes currently stored in our rx buffer waiting to be digested, - * by the user. - * - * @return The currently buffered number of bytes in our rxBuff. - */ - int rxBufferedSize(); - - /** - * The number of bytes currently stored in our tx buffer waiting to be transmitted - * by the hardware. - * - * @return The currently buffered number of bytes in our txBuff. - */ - int txBufferedSize(); - - /** - * Determines if the serial bus is currently in use by another fiber for reception. - * - * @return The state of our mutex lock for reception. - * - * @note Only one fiber can call read at a time - */ - int rxInUse(); - - /** - * Determines if the serial bus is currently in use by another fiber for transmission. - * - * @return The state of our mutex lock for transmition. - * - * @note Only one fiber can call send at a time - */ - int txInUse(); - - void lockRx(); - - void lockTx(); - - void unlockRx(); - - void unlockTx(); - - ~Serial(); - - private: - void writeNum(uint32_t n, bool full); - }; -} + int getChar(SerialMode mode); + + /** + * Reads multiple characters from the rxBuff and returns them as a ManagedString + * + * @param size the number of characters to read. + * + * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode + * gives a different behaviour: + * + * ASYNC - If the desired number of characters are available, this will return + * a ManagedString with the expected size. Otherwise, it will read however + * many characters there are available. + * + * SYNC_SPINWAIT - If the desired number of characters are available, this will return + * a ManagedString with the expected size. Otherwise, this method will spin + * (lock up the processor) until the desired number of characters have been read. + * + * SYNC_SLEEP - If the desired number of characters are available, this will return + * a ManagedString with the expected size. Otherwise, the calling fiber sleeps + * until the desired number of characters have been read. + * + * Defaults to SYNC_SLEEP. + * + * @return A ManagedString, or an empty ManagedString if an error was encountered during the read. + */ + ManagedString read(int size, SerialMode mode = DEVICE_DEFAULT_SERIAL_MODE); + + /** + * Reads multiple characters from the rxBuff and fills a user buffer. + * + * @param buffer a pointer to a user allocated buffer. + * + * @param bufferLen the amount of data that can be safely stored + * + * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode + * gives a different behaviour: + * + * ASYNC - If the desired number of characters are available, this will fill + * the given buffer. Otherwise, it will fill the buffer with however + * many characters there are available. + * + * SYNC_SPINWAIT - If the desired number of characters are available, this will fill + * the given buffer. Otherwise, this method will spin (lock up the processor) + * and fill the buffer until the desired number of characters have been read. + * + * SYNC_SLEEP - If the desired number of characters are available, this will fill + * the given buffer. Otherwise, the calling fiber sleeps + * until the desired number of characters have been read. + * + * Defaults to SYNC_SLEEP. + * + * @return the number of characters read, or CODAL_SERIAL_IN_USE if another fiber + * is using the instance for receiving. + */ + int read(uint8_t* buffer, int bufferLen, SerialMode mode = DEVICE_DEFAULT_SERIAL_MODE); + + /** + * Reads until one of the delimeters matches a character in the rxBuff + * + * @param delimeters a ManagedString containing a sequence of delimeter characters e.g. ManagedString("\r\n") + * + * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode + * gives a different behaviour: + * + * ASYNC - If one of the delimeters matches a character already in the rxBuff + * this method will return a ManagedString up to the delimeter. + * Otherwise, it will return an Empty ManagedString. + * + * SYNC_SPINWAIT - If one of the delimeters matches a character already in the rxBuff + * this method will return a ManagedString up to the delimeter. + * Otherwise, this method will spin (lock up the processor) until a + * received character matches one of the delimeters. + * + * SYNC_SLEEP - If one of the delimeters matches a character already in the rxBuff + * this method will return a ManagedString up to the delimeter. + * Otherwise, the calling fiber sleeps until a character matching one + * of the delimeters is seen. + * + * Defaults to SYNC_SLEEP. + * + * @return A ManagedString containing the characters up to a delimeter, or an Empty ManagedString, + * if another fiber is currently using this instance for reception. + * + * @note delimeters are matched on a per byte basis. + */ + virtual ManagedString readUntil(ManagedString delimeters, SerialMode mode = DEVICE_DEFAULT_SERIAL_MODE); + + /** + * A wrapper around the inherited method "baud" so we can trap the baud rate + * as it changes and restore it if redirect() is called. + * + * @param baudrate the new baudrate. See: + * - + * https://github.com/mbedmicro/mbed/blob/master/libraries/mbed/targets/hal/TARGET_NORDIC/TARGET_MCU_NRF51822/serial_api.c + * for permitted baud rates. + * + * @return DEVICE_INVALID_PARAMETER if baud rate is less than 0, otherwise DEVICE_OK. + * + * @note the underlying implementation chooses the first allowable rate at or above that requested. + */ + int setBaud(int baudrate); + + /** + * A way of dynamically configuring the serial instance to use pins other than USBTX and USBRX. + * + * @param tx the new transmission pin. + * + * @param rx the new reception pin. + * + * @return CODAL_SERIAL_IN_USE if another fiber is currently transmitting or receiving, otherwise DEVICE_OK. + */ + int redirect(Pin& tx, Pin& rx); + + /** + * Configures an event to be fired after "len" characters. + * + * Will generate an event with the ID: DEVICE_ID_SERIAL and the value CODAL_SERIAL_EVT_HEAD_MATCH. + * + * @param len the number of characters to wait before triggering the event. + * + * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode + * gives a different behaviour: + * + * ASYNC - Will configure the event and return immediately. + * + * SYNC_SPINWAIT - will return DEVICE_INVALID_PARAMETER + * + * SYNC_SLEEP - Will configure the event and block the current fiber until the + * event is received. + * + * @return DEVICE_INVALID_PARAMETER if the mode given is SYNC_SPINWAIT, otherwise DEVICE_OK. + */ + int eventAfter(int len, SerialMode mode = ASYNC); + + /** + * Configures an event to be fired on a match with one of the delimeters. + * + * Will generate an event with the ID: DEVICE_ID_SERIAL and the value CODAL_SERIAL_EVT_DELIM_MATCH. + * + * @param delimeters the characters to match received characters against e.g. ManagedString("\n") + * + * @param mode the selected mode, one of: ASYNC, SYNC_SPINWAIT, SYNC_SLEEP. Each mode + * gives a different behaviour: + * + * ASYNC - Will configure the event and return immediately. + * + * SYNC_SPINWAIT - will return DEVICE_INVALID_PARAMETER + * + * SYNC_SLEEP - Will configure the event and block the current fiber until the + * event is received. + * + * @return DEVICE_INVALID_PARAMETER if the mode given is SYNC_SPINWAIT, otherwise DEVICE_OK. + * + * @note delimeters are matched on a per byte basis. + */ + int eventOn(ManagedString delimeters, SerialMode mode = ASYNC); + + /** + * Determines whether there is any data waiting in our Rx buffer. + * + * @return 1 if we have space, 0 if we do not. + * + * @note We do not wrap the super's readable() method as we don't want to + * interfere with communities that use manual calls to serial.readable(). + */ + int isReadable(); + + /** + * Determines if we have space in our txBuff. + * + * @return 1 if we have space, 0 if we do not. + * + * @note We do not wrap the super's writeable() method as we don't want to + * interfere with communities that use manual calls to serial.writeable(). + */ + int isWriteable(); + + /** + * Reconfigures the size of our rxBuff + * + * @param size the new size for our rxBuff + * + * @return CODAL_SERIAL_IN_USE if another fiber is currently using this instance + * for reception, otherwise DEVICE_OK. + */ + int setRxBufferSize(uint8_t size); + + /** + * Reconfigures the size of our txBuff + * + * @param size the new size for our txBuff + * + * @return CODAL_SERIAL_IN_USE if another fiber is currently using this instance + * for transmission, otherwise DEVICE_OK. + */ + int setTxBufferSize(uint8_t size); + + /** + * The size of our rx buffer in bytes. + * + * @return the current size of rxBuff in bytes + */ + int getRxBufferSize(); + + /** + * The size of our tx buffer in bytes. + * + * @return the current size of txBuff in bytes + */ + int getTxBufferSize(); + + /** + * Sets the tail to match the head of our circular buffer for reception, + * effectively clearing the reception buffer. + * + * @return CODAL_SERIAL_IN_USE if another fiber is currently using this instance + * for reception, otherwise DEVICE_OK. + */ + int clearRxBuffer(); + + /** + * Sets the tail to match the head of our circular buffer for transmission, + * effectively clearing the transmission buffer. + * + * @return CODAL_SERIAL_IN_USE if another fiber is currently using this instance + * for transmission, otherwise DEVICE_OK. + */ + int clearTxBuffer(); + + /** + * The number of bytes currently stored in our rx buffer waiting to be digested, + * by the user. + * + * @return The currently buffered number of bytes in our rxBuff. + */ + int rxBufferedSize(); + + /** + * The number of bytes currently stored in our tx buffer waiting to be transmitted + * by the hardware. + * + * @return The currently buffered number of bytes in our txBuff. + */ + int txBufferedSize(); + + /** + * Determines if the serial bus is currently in use by another fiber for reception. + * + * @return The state of our mutex lock for reception. + * + * @note Only one fiber can call read at a time + */ + int rxInUse(); + + /** + * Determines if the serial bus is currently in use by another fiber for transmission. + * + * @return The state of our mutex lock for transmition. + * + * @note Only one fiber can call send at a time + */ + int txInUse(); + + void lockRx(); + + void lockTx(); + + void unlockRx(); + + void unlockTx(); + + ~Serial(); + + private: + void writeNum(uint32_t n, bool full); +}; +} // namespace codal #endif diff --git a/inc/driver-models/SingleWireSerial.h b/inc/driver-models/SingleWireSerial.h index 3dc2c3e8..c082ace2 100644 --- a/inc/driver-models/SingleWireSerial.h +++ b/inc/driver-models/SingleWireSerial.h @@ -1,93 +1,83 @@ #ifndef SINGLE_WIRE_SERIAL_H #define SINGLE_WIRE_SERIAL_H -#include "Pin.h" #include "CodalComponent.h" +#include "Pin.h" -#define SWS_EVT_DATA_RECEIVED 1 -#define SWS_EVT_DATA_SENT 2 -#define SWS_EVT_ERROR 3 -#define SWS_EVT_DATA_DROPPED 4 +#define SWS_EVT_DATA_RECEIVED 1 +#define SWS_EVT_DATA_SENT 2 +#define SWS_EVT_ERROR 3 +#define SWS_EVT_DATA_DROPPED 4 // required for gcc-6 (but not 7!) #undef putc #undef getc -namespace codal -{ - enum SingleWireMode - { - SingleWireRx = 0, - SingleWireTx, - SingleWireDisconnected - }; +namespace codal { +enum SingleWireMode { SingleWireRx = 0, SingleWireTx, SingleWireDisconnected }; + +class SingleWireSerial : public PinPeripheral, public CodalComponent { + protected: + virtual void configureRxInterrupt(int enable) = 0; + + virtual int configureTx(int) = 0; + + virtual int configureRx(int) = 0; + + public: + Pin& p; + void (*cb)(uint16_t errCode); // one of SWS_EVT... - class SingleWireSerial : public PinPeripheral, public CodalComponent + SingleWireSerial(Pin& p, uint16_t id = DEVICE_ID_SINGLE_WIRE_SERIAL) : p(p) { - protected: - virtual void configureRxInterrupt(int enable) = 0; + this->id = id; + this->cb = NULL; + p.connect(*this); + } + + /** + * Sets the timer_pointer member variable. + * + * @returns DEVICE_OK on success. + **/ + virtual int setIRQ(void (*cb)(uint16_t errCode)) + { + this->cb = cb; + return DEVICE_OK; + } - virtual int configureTx(int) = 0; + virtual int putc(char c) = 0; + virtual int getc() = 0; - virtual int configureRx(int) = 0; + virtual int send(uint8_t* buf, int len) = 0; + virtual int receive(uint8_t* buf, int len) = 0; - public: - Pin& p; - void (*cb) (uint16_t errCode); // one of SWS_EVT... + virtual int setBaud(uint32_t baud) = 0; + virtual uint32_t getBaud() = 0; - SingleWireSerial(Pin& p, uint16_t id = DEVICE_ID_SINGLE_WIRE_SERIAL) : p(p) - { - this->id = id; - this->cb = NULL; - p.connect(*this); - } + virtual int getBytesReceived() = 0; + virtual int getBytesTransmitted() = 0; - /** - * Sets the timer_pointer member variable. - * - * @returns DEVICE_OK on success. - **/ - virtual int setIRQ(void (*cb) (uint16_t errCode)) - { - this->cb = cb; - return DEVICE_OK; + virtual int setMode(SingleWireMode sw) + { + if (sw == SingleWireRx) { + configureTx(0); + configureRx(1); } - - virtual int putc(char c) = 0; - virtual int getc() = 0; - - virtual int send(uint8_t* buf, int len) = 0; - virtual int receive(uint8_t* buf, int len) = 0; - - virtual int setBaud(uint32_t baud) = 0; - virtual uint32_t getBaud() = 0; - - virtual int getBytesReceived() = 0; - virtual int getBytesTransmitted() = 0; - - virtual int setMode(SingleWireMode sw) - { - if (sw == SingleWireRx) - { - configureTx(0); - configureRx(1); - } - else if (sw == SingleWireTx) - { - configureRx(0); - configureTx(1); - } - else - { - configureTx(0); - configureRx(0); - } - - return DEVICE_OK; + else if (sw == SingleWireTx) { + configureRx(0); + configureTx(1); + } + else { + configureTx(0); + configureRx(0); } - virtual int sendBreak() = 0; - }; -} + return DEVICE_OK; + } + + virtual int sendBreak() = 0; +}; +} // namespace codal #endif \ No newline at end of file diff --git a/inc/driver-models/Timer.h b/inc/driver-models/Timer.h index d55b964e..eada265a 100644 --- a/inc/driver-models/Timer.h +++ b/inc/driver-models/Timer.h @@ -30,378 +30,382 @@ DEALINGS IN THE SOFTWARE. #include "LowLevelTimer.h" #ifndef CODAL_TIMER_DEFAULT_EVENT_LIST_SIZE -#define CODAL_TIMER_DEFAULT_EVENT_LIST_SIZE 10 +#define CODAL_TIMER_DEFAULT_EVENT_LIST_SIZE 10 #endif // // TimerEvent flags // -#define CODAL_TIMER_EVENT_FLAGS_NONE 0 -#define CODAL_TIMER_EVENT_FLAGS_WAKEUP 0x01 - -namespace codal -{ - struct TimerEvent - { - CODAL_TIMESTAMP period; - CODAL_TIMESTAMP timestamp; - uint16_t id; - uint16_t value; - uint32_t flags; // We only need one byte, but sizeof(TimerEvent) is still 24 - - void set(CODAL_TIMESTAMP timestamp, CODAL_TIMESTAMP period, uint16_t id, uint16_t value, uint32_t flags = CODAL_TIMER_EVENT_FLAGS_NONE) - { - this->timestamp = timestamp; - this->period = period; - this->id = id; - this->value = value; - this->flags = flags; - } - }; - - class Timer +#define CODAL_TIMER_EVENT_FLAGS_NONE 0 +#define CODAL_TIMER_EVENT_FLAGS_WAKEUP 0x01 + +namespace codal { +struct TimerEvent { + CODAL_TIMESTAMP period; + CODAL_TIMESTAMP timestamp; + uint16_t id; + uint16_t value; + uint32_t flags; // We only need one byte, but sizeof(TimerEvent) is still 24 + + void set(CODAL_TIMESTAMP timestamp, CODAL_TIMESTAMP period, uint16_t id, uint16_t value, + uint32_t flags = CODAL_TIMER_EVENT_FLAGS_NONE) { + this->timestamp = timestamp; + this->period = period; + this->id = id; + this->value = value; + this->flags = flags; + } +}; + +class Timer { #if CONFIG_ENABLED(CODAL_TIMER_32BIT) - uint32_t sigma; - uint32_t delta; + uint32_t sigma; + uint32_t delta; #else - uint16_t sigma; - uint16_t delta; + uint16_t sigma; + uint16_t delta; #endif - LowLevelTimer& timer; - - /** - * Synchronises low level timer counter with ours. - */ - void sync(); - - /** - * request to the physical timer implementation code to provide a trigger callback at the given time. - * @note it is perfectly legitimate for the implementation to trigger before this time if convenient. - * @param t Indication that t time units (typically microsends) have elapsed. - */ - void triggerIn(CODAL_TIMESTAMP t); - - /** - * Make sure nextTimerEvent is pointing the the right event. - */ - void recomputeNextTimerEvent(); - - public: - - uint8_t ccPeriodChannel; - uint8_t ccEventChannel; - - /** - * Constructor for a generic system clock interface. - * - * @param t A low-level timer instance that wraps a hardware timer. - * - * @param ccPeriodChannel The channel to use a a periodic interrupt as a fallback - * - * @param ccEventChannel The channel to use as the next TimerEvents' interrupt. - */ - Timer(LowLevelTimer& t, uint8_t ccPeriodChannel = 0, uint8_t ccEventChannel = 1); - - /** - * Retrieves the current time tracked by this Timer instance - * in milliseconds - * - * @return the timestamp in milliseconds - */ - CODAL_TIMESTAMP getTime(); - - /** - * Retrieves the current time tracked by this Timer instance - * in microseconds - * - * @return the timestamp in microseconds - */ - CODAL_TIMESTAMP getTimeUs(); - - /** - * Configures this Timer instance to fire an event after period - * milliseconds. - * - * @param period the period to wait until an event is triggered, in milliseconds. - * - * @param id the ID to be used in event generation. - * - * @param value the value to place into the Events' value field. - * - * @param flags CODAL_TIMER_EVENT_FLAGS_WAKEUP for event to trigger deep sleep wake-up. - */ - int eventAfter(CODAL_TIMESTAMP period, uint16_t id, uint16_t value, uint32_t flags = CODAL_TIMER_EVENT_FLAGS_NONE); - - /** - * Configures this Timer instance to fire an event after period - * microseconds. - * - * @param period the period to wait until an event is triggered, in microseconds. - * - * @param id the ID to be used in event generation. - * - * @param value the value to place into the Events' value field. - * - * @param flags CODAL_TIMER_EVENT_FLAGS_WAKEUP for event to trigger deep sleep wake-up. - */ - int eventAfterUs(CODAL_TIMESTAMP period, uint16_t id, uint16_t value, uint32_t flags = CODAL_TIMER_EVENT_FLAGS_NONE); - - /** - * Configures this Timer instance to fire an event every period - * milliseconds. - * - * @param period the period to wait until an event is triggered, in milliseconds. - * - * @param id the ID to be used in event generation. - * - * @param value the value to place into the Events' value field. - * - * @param flags CODAL_TIMER_EVENT_FLAGS_WAKEUP for event to trigger deep sleep wake-up. - */ - int eventEvery(CODAL_TIMESTAMP period, uint16_t id, uint16_t value, uint32_t flags = CODAL_TIMER_EVENT_FLAGS_NONE); - - /** - * Configures this Timer instance to fire an event every period - * microseconds. - * - * @param period the period to wait until an event is triggered, in microseconds. - * - * @param id the ID to be used in event generation. - * - * @param value the value to place into the Events' value field. - * - * @param flags CODAL_TIMER_EVENT_FLAGS_WAKEUP for event to trigger deep sleep wake-up. - */ - int eventEveryUs(CODAL_TIMESTAMP period, uint16_t id, uint16_t value, uint32_t flags = CODAL_TIMER_EVENT_FLAGS_NONE); - - /** - * Cancels any events matching the given id and value. - * - * @param id the ID that was given upon a previous call to eventEvery / eventAfter - * - * @param value the value that was given upon a previous call to eventEvery / eventAfter - */ - int cancel(uint16_t id, uint16_t value); - - /** - * Destructor for this Timer instance - */ - ~Timer(); - - /** - * Callback from physical timer implementation code, indicating a requested time span *may* have been completed. - */ - void trigger(bool isFallback); - - /** - * Called from power manager before sleep. - * @param counter reference to a variable to receive the current timer counter - * - * @return the current time since power on in microseconds - */ - CODAL_TIMESTAMP deepSleepBegin( CODAL_TIMESTAMP &counter); - - /** - * Called from power manager after sleep. - * @param counter the current timer counter - * @param micros time elapsed since deepSleepBegin - */ - void deepSleepEnd( CODAL_TIMESTAMP counter, CODAL_TIMESTAMP micros); - - /** - * Determine the time of the next wake up event. - * @param timestamp reference to a variable to receive the time. - * @return true if there is an event. - */ - bool deepSleepWakeUpTime( CODAL_TIMESTAMP ×tamp); - - /** - * Enables interrupts for this timer instance. - */ - virtual int enableInterrupts(); - - /** - * Disables interrupts for this timer instance. - */ - virtual int disableInterrupts(); - - protected: - CODAL_TIMESTAMP currentTime; - CODAL_TIMESTAMP currentTimeUs; - uint32_t overflow; - - TimerEvent *timerEventList; - TimerEvent *nextTimerEvent; - int eventListSize; - - TimerEvent *getTimerEvent(); - void releaseTimerEvent(TimerEvent *event); - int setEvent(CODAL_TIMESTAMP period, uint16_t id, uint16_t value, bool repeat, uint32_t flags); - TimerEvent *deepSleepWakeUpEvent(); - }; - - /* + LowLevelTimer& timer; + + /** + * Synchronises low level timer counter with ours. + */ + void sync(); + + /** + * request to the physical timer implementation code to provide a trigger callback at the given time. + * @note it is perfectly legitimate for the implementation to trigger before this time if convenient. + * @param t Indication that t time units (typically microsends) have elapsed. + */ + void triggerIn(CODAL_TIMESTAMP t); + + /** + * Make sure nextTimerEvent is pointing the the right event. + */ + void recomputeNextTimerEvent(); + + public: + uint8_t ccPeriodChannel; + uint8_t ccEventChannel; + + /** + * Constructor for a generic system clock interface. * - * Convenience C API Interface that wraps this class, using the first compatible timer that is created + * @param t A low-level timer instance that wraps a hardware timer. * + * @param ccPeriodChannel The channel to use a a periodic interrupt as a fallback + * + * @param ccEventChannel The channel to use as the next TimerEvents' interrupt. */ + Timer(LowLevelTimer& t, uint8_t ccPeriodChannel = 0, uint8_t ccEventChannel = 1); /** - * Determines the time since the device was powered on. + * Retrieves the current time tracked by this Timer instance + * in milliseconds * - * @return the current time since power on in milliseconds + * @return the timestamp in milliseconds */ - CODAL_TIMESTAMP system_timer_current_time(); + CODAL_TIMESTAMP getTime(); /** - * Determines the time since the device was powered on. + * Retrieves the current time tracked by this Timer instance + * in microseconds * - * @return the current time since power on in microseconds + * @return the timestamp in microseconds */ - CODAL_TIMESTAMP system_timer_current_time_us(); + CODAL_TIMESTAMP getTimeUs(); /** - * Configure an event to occur every given number of microseconds. + * Configures this Timer instance to fire an event after period + * milliseconds. * - * @param period the interval between events + * @param period the period to wait until an event is triggered, in milliseconds. * - * @param the value to fire against the current system_timer id. + * @param id the ID to be used in event generation. * - * @param flags CODAL_TIMER_EVENT_FLAGS_WAKEUP for event to trigger deep sleep wake-up. + * @param value the value to place into the Events' value field. * - * @return DEVICE_OK or DEVICE_NOT_SUPPORTED if no timer has been registered. + * @param flags CODAL_TIMER_EVENT_FLAGS_WAKEUP for event to trigger deep sleep wake-up. */ - int system_timer_event_every_us(CODAL_TIMESTAMP period, uint16_t id, uint16_t value, uint32_t flags = CODAL_TIMER_EVENT_FLAGS_NONE); + int eventAfter(CODAL_TIMESTAMP period, uint16_t id, uint16_t value, uint32_t flags = CODAL_TIMER_EVENT_FLAGS_NONE); /** - * Configure an event to occur every given number of milliseconds. + * Configures this Timer instance to fire an event after period + * microseconds. * - * @param period the interval between events + * @param period the period to wait until an event is triggered, in microseconds. * - * @param the value to fire against the current system_timer id. + * @param id the ID to be used in event generation. * - * @param flags CODAL_TIMER_EVENT_FLAGS_WAKEUP for event to trigger deep sleep wake-up. + * @param value the value to place into the Events' value field. * - * @return DEVICE_OK or DEVICE_NOT_SUPPORTED if no timer has been registered. + * @param flags CODAL_TIMER_EVENT_FLAGS_WAKEUP for event to trigger deep sleep wake-up. */ - int system_timer_event_every(CODAL_TIMESTAMP period, uint16_t id, uint16_t value, uint32_t flags = CODAL_TIMER_EVENT_FLAGS_NONE); + int eventAfterUs(CODAL_TIMESTAMP period, uint16_t id, uint16_t value, + uint32_t flags = CODAL_TIMER_EVENT_FLAGS_NONE); /** - * Configure an event to occur after a given number of microseconds. + * Configures this Timer instance to fire an event every period + * milliseconds. * - * @param period the interval between events + * @param period the period to wait until an event is triggered, in milliseconds. * - * @param the value to fire against the current system_timer id. + * @param id the ID to be used in event generation. * - * @param flags CODAL_TIMER_EVENT_FLAGS_WAKEUP for event to trigger deep sleep wake-up. + * @param value the value to place into the Events' value field. * - * @return DEVICE_OK or DEVICE_NOT_SUPPORTED if no timer has been registered. + * @param flags CODAL_TIMER_EVENT_FLAGS_WAKEUP for event to trigger deep sleep wake-up. */ - int system_timer_event_after(CODAL_TIMESTAMP period, uint16_t id, uint16_t value, uint32_t flags = CODAL_TIMER_EVENT_FLAGS_NONE); + int eventEvery(CODAL_TIMESTAMP period, uint16_t id, uint16_t value, uint32_t flags = CODAL_TIMER_EVENT_FLAGS_NONE); /** - * Configure an event to occur after a given number of milliseconds. + * Configures this Timer instance to fire an event every period + * microseconds. * - * @param period the interval between events + * @param period the period to wait until an event is triggered, in microseconds. * - * @param the value to fire against the current system_timer id. + * @param id the ID to be used in event generation. * - * @param flags CODAL_TIMER_EVENT_FLAGS_WAKEUP for event to trigger deep sleep wake-up. + * @param value the value to place into the Events' value field. * - * @return DEVICE_OK or DEVICE_NOT_SUPPORTED if no timer has been registered. + * @param flags CODAL_TIMER_EVENT_FLAGS_WAKEUP for event to trigger deep sleep wake-up. */ - int system_timer_event_after_us(CODAL_TIMESTAMP period, uint16_t id, uint16_t value, uint32_t flags = CODAL_TIMER_EVENT_FLAGS_NONE); - - /** - * Cancels any events matching the given id and value. - * - * @param id the ID that was given upon a previous call to eventEvery / eventAfter - * - * @param value the value that was given upon a previous call to eventEvery / eventAfter - */ - int system_timer_cancel_event(uint16_t id, uint16_t value); - - /** - * An auto calibration method that uses the hardware timer to compute the number of cycles - * per us. - * - * The result of this method is then used to compute accurate us waits using instruction counting in system_timer_wait_us. - * - * If this method is not called, a less accurate timer implementation is used in system_timer_wait_us. - * - * @return DEVICE_OK on success, and DEVICE_NOT_SUPPORTED if no system_timer yet exists. - */ - int system_timer_calibrate_cycles(); + int eventEveryUs(CODAL_TIMESTAMP period, uint16_t id, uint16_t value, + uint32_t flags = CODAL_TIMER_EVENT_FLAGS_NONE); /** - * Spin wait for a given number of cycles. + * Cancels any events matching the given id and value. * - * @param cycles the number of nops to execute - * @return DEVICE_OK + * @param id the ID that was given upon a previous call to eventEvery / eventAfter * - * @note the amount of cycles per iteration will vary between CPUs. + * @param value the value that was given upon a previous call to eventEvery / eventAfter */ - FORCE_RAM_FUNC - void system_timer_wait_cycles(uint32_t cycles); + int cancel(uint16_t id, uint16_t value); /** - * Spin wait for a given number of microseconds. - * - * @param period the interval between events - * @return DEVICE_OK or DEVICE_NOT_SUPPORTED if no timer has been registered. - * - * @note if system_timer_calibrate_cycles is not called, a hardware timer implementation will be used instead - * which is far less accurate than instruction counting. + * Destructor for this Timer instance */ - int system_timer_wait_us(uint32_t period); + ~Timer(); /** - * Spin wait for a given number of milliseconds. - * - * @param period the interval between events - * @return DEVICE_OK or DEVICE_NOT_SUPPORTED if no timer has been registered. + * Callback from physical timer implementation code, indicating a requested time span *may* have been completed. */ - int system_timer_wait_ms(uint32_t period); + void trigger(bool isFallback); /** - * Determine the current time and the corresponding timer counter, - * to enable the caller to take over tracking time. - * + * Called from power manager before sleep. * @param counter reference to a variable to receive the current timer counter * * @return the current time since power on in microseconds */ - CODAL_TIMESTAMP system_timer_deepsleep_begin( CODAL_TIMESTAMP &counter); + CODAL_TIMESTAMP deepSleepBegin(CODAL_TIMESTAMP& counter); /** - * After taking over time tracking with system_timer_deepsleep_begin, - * hand back control by supplying a new timer counter value with - * corresponding elapsed time since taking over tracking. - * - * The counter and elapsed time may be zero if the time has been maintained - * meanwhile by calling system_timer_current_time_us(). - * - * Event timestamps are are shifted towards the present. - * "after" and "every" events that would have fired during deep sleep - * will fire once as if firing late, then "every" events will - * resume the same relative timings. - * - * @param counter the current timer counter. - * @param micros time elapsed since system_timer_deepsleep_begin - * - * @return DEVICE_OK or DEVICE_NOT_SUPPORTED if no timer has been registered. - */ - int system_timer_deepsleep_end( CODAL_TIMESTAMP counter, CODAL_TIMESTAMP micros); + * Called from power manager after sleep. + * @param counter the current timer counter + * @param micros time elapsed since deepSleepBegin + */ + void deepSleepEnd(CODAL_TIMESTAMP counter, CODAL_TIMESTAMP micros); /** - * Determine the time of the next wake-up event. + * Determine the time of the next wake up event. * @param timestamp reference to a variable to receive the time. * @return true if there is an event. */ - bool system_timer_deepsleep_wakeup_time( CODAL_TIMESTAMP ×tamp); + bool deepSleepWakeUpTime(CODAL_TIMESTAMP& timestamp); - extern Timer* system_timer; -} + /** + * Enables interrupts for this timer instance. + */ + virtual int enableInterrupts(); + + /** + * Disables interrupts for this timer instance. + */ + virtual int disableInterrupts(); + + protected: + CODAL_TIMESTAMP currentTime; + CODAL_TIMESTAMP currentTimeUs; + uint32_t overflow; + + TimerEvent* timerEventList; + TimerEvent* nextTimerEvent; + int eventListSize; + + TimerEvent* getTimerEvent(); + void releaseTimerEvent(TimerEvent* event); + int setEvent(CODAL_TIMESTAMP period, uint16_t id, uint16_t value, bool repeat, uint32_t flags); + TimerEvent* deepSleepWakeUpEvent(); +}; + +/* + * + * Convenience C API Interface that wraps this class, using the first compatible timer that is created + * + */ + +/** + * Determines the time since the device was powered on. + * + * @return the current time since power on in milliseconds + */ +CODAL_TIMESTAMP system_timer_current_time(); + +/** + * Determines the time since the device was powered on. + * + * @return the current time since power on in microseconds + */ +CODAL_TIMESTAMP system_timer_current_time_us(); + +/** + * Configure an event to occur every given number of microseconds. + * + * @param period the interval between events + * + * @param the value to fire against the current system_timer id. + * + * @param flags CODAL_TIMER_EVENT_FLAGS_WAKEUP for event to trigger deep sleep wake-up. + * + * @return DEVICE_OK or DEVICE_NOT_SUPPORTED if no timer has been registered. + */ +int system_timer_event_every_us(CODAL_TIMESTAMP period, uint16_t id, uint16_t value, + uint32_t flags = CODAL_TIMER_EVENT_FLAGS_NONE); + +/** + * Configure an event to occur every given number of milliseconds. + * + * @param period the interval between events + * + * @param the value to fire against the current system_timer id. + * + * @param flags CODAL_TIMER_EVENT_FLAGS_WAKEUP for event to trigger deep sleep wake-up. + * + * @return DEVICE_OK or DEVICE_NOT_SUPPORTED if no timer has been registered. + */ +int system_timer_event_every(CODAL_TIMESTAMP period, uint16_t id, uint16_t value, + uint32_t flags = CODAL_TIMER_EVENT_FLAGS_NONE); + +/** + * Configure an event to occur after a given number of microseconds. + * + * @param period the interval between events + * + * @param the value to fire against the current system_timer id. + * + * @param flags CODAL_TIMER_EVENT_FLAGS_WAKEUP for event to trigger deep sleep wake-up. + * + * @return DEVICE_OK or DEVICE_NOT_SUPPORTED if no timer has been registered. + */ +int system_timer_event_after(CODAL_TIMESTAMP period, uint16_t id, uint16_t value, + uint32_t flags = CODAL_TIMER_EVENT_FLAGS_NONE); + +/** + * Configure an event to occur after a given number of milliseconds. + * + * @param period the interval between events + * + * @param the value to fire against the current system_timer id. + * + * @param flags CODAL_TIMER_EVENT_FLAGS_WAKEUP for event to trigger deep sleep wake-up. + * + * @return DEVICE_OK or DEVICE_NOT_SUPPORTED if no timer has been registered. + */ +int system_timer_event_after_us(CODAL_TIMESTAMP period, uint16_t id, uint16_t value, + uint32_t flags = CODAL_TIMER_EVENT_FLAGS_NONE); + +/** + * Cancels any events matching the given id and value. + * + * @param id the ID that was given upon a previous call to eventEvery / eventAfter + * + * @param value the value that was given upon a previous call to eventEvery / eventAfter + */ +int system_timer_cancel_event(uint16_t id, uint16_t value); + +/** + * An auto calibration method that uses the hardware timer to compute the number of cycles + * per us. + * + * The result of this method is then used to compute accurate us waits using instruction counting in + * system_timer_wait_us. + * + * If this method is not called, a less accurate timer implementation is used in system_timer_wait_us. + * + * @return DEVICE_OK on success, and DEVICE_NOT_SUPPORTED if no system_timer yet exists. + */ +int system_timer_calibrate_cycles(); + +/** + * Spin wait for a given number of cycles. + * + * @param cycles the number of nops to execute + * @return DEVICE_OK + * + * @note the amount of cycles per iteration will vary between CPUs. + */ +FORCE_RAM_FUNC +void system_timer_wait_cycles(uint32_t cycles); + +/** + * Spin wait for a given number of microseconds. + * + * @param period the interval between events + * @return DEVICE_OK or DEVICE_NOT_SUPPORTED if no timer has been registered. + * + * @note if system_timer_calibrate_cycles is not called, a hardware timer implementation will be used instead + * which is far less accurate than instruction counting. + */ +int system_timer_wait_us(uint32_t period); + +/** + * Spin wait for a given number of milliseconds. + * + * @param period the interval between events + * @return DEVICE_OK or DEVICE_NOT_SUPPORTED if no timer has been registered. + */ +int system_timer_wait_ms(uint32_t period); + +/** + * Determine the current time and the corresponding timer counter, + * to enable the caller to take over tracking time. + * + * @param counter reference to a variable to receive the current timer counter + * + * @return the current time since power on in microseconds + */ +CODAL_TIMESTAMP system_timer_deepsleep_begin(CODAL_TIMESTAMP& counter); + +/** + * After taking over time tracking with system_timer_deepsleep_begin, + * hand back control by supplying a new timer counter value with + * corresponding elapsed time since taking over tracking. + * + * The counter and elapsed time may be zero if the time has been maintained + * meanwhile by calling system_timer_current_time_us(). + * + * Event timestamps are are shifted towards the present. + * "after" and "every" events that would have fired during deep sleep + * will fire once as if firing late, then "every" events will + * resume the same relative timings. + * + * @param counter the current timer counter. + * @param micros time elapsed since system_timer_deepsleep_begin + * + * @return DEVICE_OK or DEVICE_NOT_SUPPORTED if no timer has been registered. + */ +int system_timer_deepsleep_end(CODAL_TIMESTAMP counter, CODAL_TIMESTAMP micros); + +/** + * Determine the time of the next wake-up event. + * @param timestamp reference to a variable to receive the time. + * @return true if there is an event. + */ +bool system_timer_deepsleep_wakeup_time(CODAL_TIMESTAMP& timestamp); + +extern Timer* system_timer; +} // namespace codal #endif diff --git a/inc/drivers/AnalogSensor.h b/inc/drivers/AnalogSensor.h index 910f7430..d50df4f4 100644 --- a/inc/drivers/AnalogSensor.h +++ b/inc/drivers/AnalogSensor.h @@ -26,60 +26,56 @@ DEALINGS IN THE SOFTWARE. #define ANALOG_SENSOR_H #include "CodalConfig.h" -#include "Pin.h" #include "Event.h" +#include "Pin.h" #include "Sensor.h" /** - * Sensor events deprecated, use SENSOR_* instead - */ -#define ANALOG_THRESHOLD_LOW SENSOR_THRESHOLD_LOW -#define ANALOG_THRESHOLD_HIGH SENSOR_THRESHOLD_HIGH + * Sensor events deprecated, use SENSOR_* instead + */ +#define ANALOG_THRESHOLD_LOW SENSOR_THRESHOLD_LOW +#define ANALOG_THRESHOLD_HIGH SENSOR_THRESHOLD_HIGH #define ANALOG_SENSOR_UPDATE_NEEDED SENSOR_UPDATE_NEEDED /** * Status values deprecated, use SENSOR_* instead */ -#define ANALOG_SENSOR_INITIALISED SENSOR_INITIALISED -#define ANALOG_SENSOR_HIGH_THRESHOLD_PASSED SENSOR_HIGH_THRESHOLD_PASSED -#define ANALOG_SENSOR_LOW_THRESHOLD_PASSED SENSOR_LOW_THRESHOLD_PASSED -#define ANALOG_SENSOR_LOW_THRESHOLD_ENABLED SENSOR_LOW_THRESHOLD_ENABLED +#define ANALOG_SENSOR_INITIALISED SENSOR_INITIALISED +#define ANALOG_SENSOR_HIGH_THRESHOLD_PASSED SENSOR_HIGH_THRESHOLD_PASSED +#define ANALOG_SENSOR_LOW_THRESHOLD_PASSED SENSOR_LOW_THRESHOLD_PASSED +#define ANALOG_SENSOR_LOW_THRESHOLD_ENABLED SENSOR_LOW_THRESHOLD_ENABLED #define ANALOG_SENSOR_HIGH_THRESHOLD_ENABLED SENSOR_HIGH_THRESHOLD_ENABLED -namespace codal -{ +namespace codal { +/** + * Class definition for a generic analog sensor, and performs periodic sampling, buffering and low pass filtering of the + * data. + */ +class AnalogSensor : public Sensor { + private: + Pin& pin; // Pin where the sensor is connected. + + public: /** - * Class definition for a generic analog sensor, and performs periodic sampling, buffering and low pass filtering of the data. + * Constructor. + * + * Creates a generic AnalogSensor. + * + * @param pin The pin on which to sense + * @param id The ID of this compoenent e.g. DEVICE_ID_THERMOMETER */ - class AnalogSensor : public Sensor - { - private: - - Pin& pin; // Pin where the sensor is connected. + AnalogSensor(Pin& pin, uint16_t id); - public: - - /** - * Constructor. - * - * Creates a generic AnalogSensor. - * - * @param pin The pin on which to sense - * @param id The ID of this compoenent e.g. DEVICE_ID_THERMOMETER - */ - AnalogSensor(Pin &pin, uint16_t id); - - /** - * Read the value from pin. - */ - virtual int readValue(); - - /** - * Destructor. - */ - ~AnalogSensor(); + /** + * Read the value from pin. + */ + virtual int readValue(); - }; -} + /** + * Destructor. + */ + ~AnalogSensor(); +}; +} // namespace codal #endif diff --git a/inc/drivers/AnimatedDisplay.h b/inc/drivers/AnimatedDisplay.h index 634f32bb..e87a79f9 100644 --- a/inc/drivers/AnimatedDisplay.h +++ b/inc/drivers/AnimatedDisplay.h @@ -25,447 +25,449 @@ DEALINGS IN THE SOFTWARE. #ifndef CODAL_ANIMATED_DISPLAY_H #define CODAL_ANIMATED_DISPLAY_H -#include "Display.h" #include "BitmapFont.h" +#include "Display.h" /** - * Event codes raised by a Display - */ -#define DISPLAY_EVT_ANIMATION_COMPLETE 1 + * Event codes raised by a Display + */ +#define DISPLAY_EVT_ANIMATION_COMPLETE 1 // // Internal constants // -#define DISPLAY_DEFAULT_AUTOCLEAR 1 -#define DISPLAY_SPACING 1 -#define DISPLAY_ANIMATE_DEFAULT_POS -255 +#define DISPLAY_DEFAULT_AUTOCLEAR 1 +#define DISPLAY_SPACING 1 +#define DISPLAY_ANIMATE_DEFAULT_POS -255 // // Compile time configuration options // // Defines the default scroll speed for the display, in the time taken to move a single pixel (ms). #ifndef DISPLAY_DEFAULT_SCROLL_SPEED -#define DISPLAY_DEFAULT_SCROLL_SPEED 120 +#define DISPLAY_DEFAULT_SCROLL_SPEED 120 #endif // Selects the number of pixels a scroll will move in each quantum. #ifndef DISPLAY_DEFAULT_SCROLL_STRIDE -#define DISPLAY_DEFAULT_SCROLL_STRIDE -1 +#define DISPLAY_DEFAULT_SCROLL_STRIDE -1 #endif // Selects the time each character will be shown on the display during print operations. // The time each character is shown on the screen (ms). #ifndef DISPLAY_DEFAULT_PRINT_SPEED -#define DISPLAY_DEFAULT_PRINT_SPEED 400 +#define DISPLAY_DEFAULT_PRINT_SPEED 400 #endif -namespace codal -{ - enum AnimationMode { - ANIMATION_MODE_NONE, - ANIMATION_MODE_STOPPED, - ANIMATION_MODE_SCROLL_TEXT, - ANIMATION_MODE_PRINT_TEXT, - ANIMATION_MODE_SCROLL_IMAGE, - ANIMATION_MODE_ANIMATE_IMAGE, - ANIMATION_MODE_ANIMATE_IMAGE_WITH_CLEAR, - ANIMATION_MODE_PRINT_CHARACTER - }; +namespace codal { +enum AnimationMode { + ANIMATION_MODE_NONE, + ANIMATION_MODE_STOPPED, + ANIMATION_MODE_SCROLL_TEXT, + ANIMATION_MODE_PRINT_TEXT, + ANIMATION_MODE_SCROLL_IMAGE, + ANIMATION_MODE_ANIMATE_IMAGE, + ANIMATION_MODE_ANIMATE_IMAGE_WITH_CLEAR, + ANIMATION_MODE_PRINT_CHARACTER +}; + +/** + * Class definition for AnimatedDisplay. + * + * This class provides a high level abstraction level to show text and graphic animations on a + * Display, e.g. on the LED matrix display. + */ +class AnimatedDisplay : public CodalComponent { + // The Display instance that is used to show the text and graphic animations of this class + Display& display; + + // The Font to use text operations (TODO: This is currently only partially implemented) + BitmapFont font; + + // + // State used by all animation routines. + // + + // The animation mode that's currently running (if any) + volatile AnimationMode animationMode; + + // The time in milliseconds between each frame update. + uint16_t animationDelay; + + // The time in milliseconds since the frame update. + uint16_t animationTick; + + // Stop playback of any animations + void stopAnimation(int delay); + + // + // State for scrollString() method. + // This is a surprisingly intricate method. + // + // The text being displayed. + ManagedString scrollingText; + + // The index of the character currently being displayed. + int16_t scrollingChar; + + // The number of pixels the current character has been shifted on the display. + int8_t scrollingPosition; + + // + // State for printString() method. + // + // The text being displayed. NULL if no message is scheduled for playback. + // We *could* get some reuse in here with the scroll* variables above, + // but best to keep it clean in case kids try concurrent operation (they will!), + // given the small RAM overhead needed to maintain orthogonality. + ManagedString printingText; + + // The index of the character currently being displayed. + int16_t printingChar; + + // + // State for scrollImage() method. + // + // The image being displayed. + Image scrollingImage; + + // The number of pixels the image has been shifted on the display. + int16_t scrollingImagePosition; + + // The number of pixels the image is shifted on the display in each quantum. + int8_t scrollingImageStride; + + // Flag to indicate if image has been rendered to screen yet (or not) + bool scrollingImageRendered; + + private: + // Internal methods to handle animation. + + /** + * Periodic callback, that we use to perform any animations we have running. + */ + void animationUpdate(); + + /** + * Internal scrollText update method. + * Shift the screen image by one pixel to the left. If necessary, paste in the next char. + */ + void updateScrollText(); + + /** + * Internal printText update method. + * Paste the next character in the string. + */ + void updatePrintText(); + + /** + * Internal scrollImage update method. + * Paste the stored bitmap at the appropriate point. + */ + void updateScrollImage(); + + /** + * Internal animateImage update method. + * Paste the stored bitmap at the appropriate point and stop on the last frame. + */ + void updateAnimateImage(); + + /** + * Broadcasts an event onto the default EventModel indicating that the + * current animation has completed. + */ + void sendAnimationCompleteEvent(); + + /** + * Blocks the current fiber until the display is available (i.e. does not effect is being displayed). + * Animations are queued until their time to display. + */ + void waitForFreeDisplay(); + + /** + * Blocks the current fiber until the current animation has finished. + * If the scheduler is not running, this call will essentially perform a spinning wait. + */ + void fiberWait(); + public: /** - * Class definition for AnimatedDisplay. + * Constructor. * + * Create a software representation of an animated display. * This class provides a high level abstraction level to show text and graphic animations on a - * Display, e.g. on the LED matrix display. + * CodalDisplay, e.g. on the LED matrix display. + * + * @param display The CodalDisplay instance that is used to show the text and graphic animations of this class + * + * @param id The id the display should use when sending events on the MessageBus. Defaults to DEVICE_ID_DISPLAY. + * + */ + AnimatedDisplay(Display& display, uint16_t id = DEVICE_ID_DISPLAY); + + /** + * Frame update method, invoked periodically to strobe the display. + */ + virtual void periodicCallback(); + + /** + * Stops any currently running animation, and any that are waiting to be displayed. + */ + void stopAnimation(); + + /** + * Prints the given character to the display, if it is not in use. + * + * @param c The character to display. + * + * @param delay Optional parameter - the time for which to show the character. Zero displays the character forever, + * or until the Displays next use. + * + * @return DEVICE_OK, DEVICE_BUSY is the screen is in use, or DEVICE_INVALID_PARAMETER. + * + * @code + * display.printCharAsync('p'); + * display.printCharAsync('p',100); + * @endcode + */ + int printCharAsync(char c, int delay = 0); + + /** + * Prints the given ManagedString to the display, one character at a time. + * Returns immediately, and executes the animation asynchronously. + * + * @param s The string to display. + * + * @param delay The time to delay between characters, in milliseconds. Must be > 0. + * Defaults to: DISPLAY_DEFAULT_PRINT_SPEED. + * + * @return DEVICE_OK, or DEVICE_INVALID_PARAMETER. + * + * @code + * display.printAsync("abc123",400); + * @endcode + */ + int printAsync(ManagedString s, int delay = DISPLAY_DEFAULT_PRINT_SPEED); + + /** + * Prints the given image to the display, if the display is not in use. + * Returns immediately, and executes the animation asynchronously. + * + * @param i The image to display. + * + * @param x The horizontal position on the screen to display the image. Defaults to 0. + * + * @param y The vertical position on the screen to display the image. Defaults to 0. + * + * @param alpha Treats the brightness level '0' as transparent. Defaults to 0. + * + * @param delay The time to delay between characters, in milliseconds. Defaults to 0. + * + * @code + * Image i("1,1,1,1,1\n1,1,1,1,1\n"); + * display.printAsync(i,400); + * @endcode + */ + int printAsync(Image i, int x = 0, int y = 0, int alpha = 0, int delay = 0); + + /** + * Prints the given character to the display. + * + * @param c The character to display. + * + * @param delay Optional parameter - the time for which to show the character. Zero displays the character forever, + * or until the Displays next use. + * + * @return DEVICE_OK, DEVICE_CANCELLED or DEVICE_INVALID_PARAMETER. + * + * @code + * display.printAsync('p'); + * display.printAsync('p',100); + * @endcode + */ + int printChar(char c, int delay = 0); + + /** + * Prints the given string to the display, one character at a time. + * + * Blocks the calling thread until all the text has been displayed. + * + * @param s The string to display. + * + * @param delay The time to delay between characters, in milliseconds. Defaults + * to: DISPLAY_DEFAULT_PRINT_SPEED. + * + * @return DEVICE_OK, DEVICE_CANCELLED or DEVICE_INVALID_PARAMETER. + * + * @code + * display.print("abc123",400); + * @endcode + */ + int print(ManagedString s, int delay = DISPLAY_DEFAULT_PRINT_SPEED); + + /** + * Prints the given image to the display. + * Blocks the calling thread until all the image has been displayed. + * + * @param i The image to display. + * + * @param x The horizontal position on the screen to display the image. Defaults to 0. + * + * @param y The vertical position on the screen to display the image. Defaults to 0. + * + * @param alpha Treats the brightness level '0' as transparent. Defaults to 0. + * + * @param delay The time to display the image for, or zero to show the image forever. Defaults to 0. + * + * @return DEVICE_OK, DEVICE_BUSY if the display is already in use, or DEVICE_INVALID_PARAMETER. + * + * @code + * Image i("1,1,1,1,1\n1,1,1,1,1\n"); + * display.print(i,400); + * @endcode + */ + int print(Image i, int x = 0, int y = 0, int alpha = 0, int delay = 0); + + /** + * Scrolls the given string to the display, from right to left. + * Returns immediately, and executes the animation asynchronously. + * + * @param s The string to display. + * + * @param delay The time to delay between characters, in milliseconds. Defaults + * to: DISPLAY_DEFAULT_SCROLL_SPEED. + * + * @return DEVICE_OK, DEVICE_BUSY if the display is already in use, or DEVICE_INVALID_PARAMETER. + * + * @code + * display.scrollAsync("abc123",100); + * @endcode + */ + int scrollAsync(ManagedString s, int delay = DISPLAY_DEFAULT_SCROLL_SPEED); + + /** + * Scrolls the given image across the display, from right to left. + * Returns immediately, and executes the animation asynchronously. + * + * @param image The image to display. + * + * @param delay The time between updates, in milliseconds. Defaults + * to: DISPLAY_DEFAULT_SCROLL_SPEED. + * + * @param stride The number of pixels to shift by in each update. Defaults to DISPLAY_DEFAULT_SCROLL_STRIDE. + * + * @return DEVICE_OK, DEVICE_BUSY if the display is already in use, or DEVICE_INVALID_PARAMETER. + * + * @code + * Image i("1,1,1,1,1\n1,1,1,1,1\n"); + * display.scrollAsync(i,100,1); + * @endcode + */ + int scrollAsync(Image image, int delay = DISPLAY_DEFAULT_SCROLL_SPEED, int stride = DISPLAY_DEFAULT_SCROLL_STRIDE); + + /** + * Scrolls the given string across the display, from right to left. + * Blocks the calling thread until all text has been displayed. + * + * @param s The string to display. + * + * @param delay The time to delay between characters, in milliseconds. Defaults + * to: DISPLAY_DEFAULT_SCROLL_SPEED. + * + * @return DEVICE_OK, DEVICE_CANCELLED or DEVICE_INVALID_PARAMETER. + * + * @code + * display.scroll("abc123",100); + * @endcode + */ + int scroll(ManagedString s, int delay = DISPLAY_DEFAULT_SCROLL_SPEED); + + /** + * Scrolls the given image across the display, from right to left. + * Blocks the calling thread until all the text has been displayed. + * + * @param image The image to display. + * + * @param delay The time between updates, in milliseconds. Defaults + * to: DISPLAY_DEFAULT_SCROLL_SPEED. + * + * @param stride The number of pixels to shift by in each update. Defaults to DISPLAY_DEFAULT_SCROLL_STRIDE. + * + * @return DEVICE_OK, DEVICE_CANCELLED or DEVICE_INVALID_PARAMETER. + * + * @code + * Image i("1,1,1,1,1\n1,1,1,1,1\n"); + * display.scroll(i,100,1); + * @endcode + */ + int scroll(Image image, int delay = DISPLAY_DEFAULT_SCROLL_SPEED, int stride = DISPLAY_DEFAULT_SCROLL_STRIDE); + + /** + * "Animates" the current image across the display with a given stride, finishing on the last frame of the + * animation. Returns immediately. + * + * @param image The image to display. + * + * @param delay The time to delay between each update of the display, in milliseconds. + * + * @param stride The number of pixels to shift by in each update. + * + * @param startingPosition the starting position on the display for the animation + * to begin at. Defaults to DISPLAY_ANIMATE_DEFAULT_POS. + * + * @param autoClear defines whether or not the display is automatically cleared once the animation is complete. By + * default, the display is cleared. Set this parameter to zero to disable the autoClear operation. + * + * @return DEVICE_OK, DEVICE_BUSY if the screen is in use, or DEVICE_INVALID_PARAMETER. + * + * @code + * const int heart_w = 10; + * const int heart_h = 5; + * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, + * 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; + * + * Image i(heart_w,heart_h,heart); + * display.animateAsync(i,100,5); + * @endcode + */ + int animateAsync(Image image, int delay, int stride, int startingPosition = DISPLAY_ANIMATE_DEFAULT_POS, + int autoClear = DISPLAY_DEFAULT_AUTOCLEAR); + + /** + * "Animates" the current image across the display with a given stride, finishing on the last frame of the + * animation. Blocks the calling thread until the animation is complete. + * + * + * @param delay The time to delay between each update of the display, in milliseconds. + * + * @param stride The number of pixels to shift by in each update. + * + * @param startingPosition the starting position on the display for the animation + * to begin at. Defaults to DISPLAY_ANIMATE_DEFAULT_POS. + * + * @param autoClear defines whether or not the display is automatically cleared once the animation is complete. By + * default, the display is cleared. Set this parameter to zero to disable the autoClear operation. + * + * @return DEVICE_OK, DEVICE_CANCELLED or DEVICE_INVALID_PARAMETER. + * + * @code + * const int heart_w = 10; + * const int heart_h = 5; + * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, + * 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; + * + * Image i(heart_w,heart_h,heart); + * display.animate(i,100,5); + * @endcode + */ + int animate(Image image, int delay, int stride, int startingPosition = DISPLAY_ANIMATE_DEFAULT_POS, + int autoClear = DISPLAY_DEFAULT_AUTOCLEAR); + + /** + * Destructor for AnimatedDisplay, where we deregister this instance from the array of system components. */ - class AnimatedDisplay : public CodalComponent - { - // The Display instance that is used to show the text and graphic animations of this class - Display& display; - - // The Font to use text operations (TODO: This is currently only partially implemented) - BitmapFont font; - - // - // State used by all animation routines. - // - - // The animation mode that's currently running (if any) - volatile AnimationMode animationMode; - - // The time in milliseconds between each frame update. - uint16_t animationDelay; - - // The time in milliseconds since the frame update. - uint16_t animationTick; - - // Stop playback of any animations - void stopAnimation(int delay); - - // - // State for scrollString() method. - // This is a surprisingly intricate method. - // - // The text being displayed. - ManagedString scrollingText; - - // The index of the character currently being displayed. - int16_t scrollingChar; - - // The number of pixels the current character has been shifted on the display. - int8_t scrollingPosition; - - // - // State for printString() method. - // - // The text being displayed. NULL if no message is scheduled for playback. - // We *could* get some reuse in here with the scroll* variables above, - // but best to keep it clean in case kids try concurrent operation (they will!), - // given the small RAM overhead needed to maintain orthogonality. - ManagedString printingText; - - // The index of the character currently being displayed. - int16_t printingChar; - - // - // State for scrollImage() method. - // - // The image being displayed. - Image scrollingImage; - - // The number of pixels the image has been shifted on the display. - int16_t scrollingImagePosition; - - // The number of pixels the image is shifted on the display in each quantum. - int8_t scrollingImageStride; - - // Flag to indicate if image has been rendered to screen yet (or not) - bool scrollingImageRendered; - - private: - // Internal methods to handle animation. - - /** - * Periodic callback, that we use to perform any animations we have running. - */ - void animationUpdate(); - - - /** - * Internal scrollText update method. - * Shift the screen image by one pixel to the left. If necessary, paste in the next char. - */ - void updateScrollText(); - - /** - * Internal printText update method. - * Paste the next character in the string. - */ - void updatePrintText(); - - /** - * Internal scrollImage update method. - * Paste the stored bitmap at the appropriate point. - */ - void updateScrollImage(); - - /** - * Internal animateImage update method. - * Paste the stored bitmap at the appropriate point and stop on the last frame. - */ - void updateAnimateImage(); - - /** - * Broadcasts an event onto the default EventModel indicating that the - * current animation has completed. - */ - void sendAnimationCompleteEvent(); - - /** - * Blocks the current fiber until the display is available (i.e. does not effect is being displayed). - * Animations are queued until their time to display. - */ - void waitForFreeDisplay(); - - /** - * Blocks the current fiber until the current animation has finished. - * If the scheduler is not running, this call will essentially perform a spinning wait. - */ - void fiberWait(); - - public: - /** - * Constructor. - * - * Create a software representation of an animated display. - * This class provides a high level abstraction level to show text and graphic animations on a - * CodalDisplay, e.g. on the LED matrix display. - * - * @param display The CodalDisplay instance that is used to show the text and graphic animations of this class - * - * @param id The id the display should use when sending events on the MessageBus. Defaults to DEVICE_ID_DISPLAY. - * - */ - AnimatedDisplay(Display& display, uint16_t id = DEVICE_ID_DISPLAY); - - /** - * Frame update method, invoked periodically to strobe the display. - */ - virtual void periodicCallback(); - - /** - * Stops any currently running animation, and any that are waiting to be displayed. - */ - void stopAnimation(); - - /** - * Prints the given character to the display, if it is not in use. - * - * @param c The character to display. - * - * @param delay Optional parameter - the time for which to show the character. Zero displays the character forever, - * or until the Displays next use. - * - * @return DEVICE_OK, DEVICE_BUSY is the screen is in use, or DEVICE_INVALID_PARAMETER. - * - * @code - * display.printCharAsync('p'); - * display.printCharAsync('p',100); - * @endcode - */ - int printCharAsync(char c, int delay = 0); - - /** - * Prints the given ManagedString to the display, one character at a time. - * Returns immediately, and executes the animation asynchronously. - * - * @param s The string to display. - * - * @param delay The time to delay between characters, in milliseconds. Must be > 0. - * Defaults to: DISPLAY_DEFAULT_PRINT_SPEED. - * - * @return DEVICE_OK, or DEVICE_INVALID_PARAMETER. - * - * @code - * display.printAsync("abc123",400); - * @endcode - */ - int printAsync(ManagedString s, int delay = DISPLAY_DEFAULT_PRINT_SPEED); - - /** - * Prints the given image to the display, if the display is not in use. - * Returns immediately, and executes the animation asynchronously. - * - * @param i The image to display. - * - * @param x The horizontal position on the screen to display the image. Defaults to 0. - * - * @param y The vertical position on the screen to display the image. Defaults to 0. - * - * @param alpha Treats the brightness level '0' as transparent. Defaults to 0. - * - * @param delay The time to delay between characters, in milliseconds. Defaults to 0. - * - * @code - * Image i("1,1,1,1,1\n1,1,1,1,1\n"); - * display.printAsync(i,400); - * @endcode - */ - int printAsync(Image i, int x = 0, int y = 0, int alpha = 0, int delay = 0); - - /** - * Prints the given character to the display. - * - * @param c The character to display. - * - * @param delay Optional parameter - the time for which to show the character. Zero displays the character forever, - * or until the Displays next use. - * - * @return DEVICE_OK, DEVICE_CANCELLED or DEVICE_INVALID_PARAMETER. - * - * @code - * display.printAsync('p'); - * display.printAsync('p',100); - * @endcode - */ - int printChar(char c, int delay = 0); - - /** - * Prints the given string to the display, one character at a time. - * - * Blocks the calling thread until all the text has been displayed. - * - * @param s The string to display. - * - * @param delay The time to delay between characters, in milliseconds. Defaults - * to: DISPLAY_DEFAULT_PRINT_SPEED. - * - * @return DEVICE_OK, DEVICE_CANCELLED or DEVICE_INVALID_PARAMETER. - * - * @code - * display.print("abc123",400); - * @endcode - */ - int print(ManagedString s, int delay = DISPLAY_DEFAULT_PRINT_SPEED); - - /** - * Prints the given image to the display. - * Blocks the calling thread until all the image has been displayed. - * - * @param i The image to display. - * - * @param x The horizontal position on the screen to display the image. Defaults to 0. - * - * @param y The vertical position on the screen to display the image. Defaults to 0. - * - * @param alpha Treats the brightness level '0' as transparent. Defaults to 0. - * - * @param delay The time to display the image for, or zero to show the image forever. Defaults to 0. - * - * @return DEVICE_OK, DEVICE_BUSY if the display is already in use, or DEVICE_INVALID_PARAMETER. - * - * @code - * Image i("1,1,1,1,1\n1,1,1,1,1\n"); - * display.print(i,400); - * @endcode - */ - int print(Image i, int x = 0, int y = 0, int alpha = 0, int delay = 0); - - /** - * Scrolls the given string to the display, from right to left. - * Returns immediately, and executes the animation asynchronously. - * - * @param s The string to display. - * - * @param delay The time to delay between characters, in milliseconds. Defaults - * to: DISPLAY_DEFAULT_SCROLL_SPEED. - * - * @return DEVICE_OK, DEVICE_BUSY if the display is already in use, or DEVICE_INVALID_PARAMETER. - * - * @code - * display.scrollAsync("abc123",100); - * @endcode - */ - int scrollAsync(ManagedString s, int delay = DISPLAY_DEFAULT_SCROLL_SPEED); - - /** - * Scrolls the given image across the display, from right to left. - * Returns immediately, and executes the animation asynchronously. - * - * @param image The image to display. - * - * @param delay The time between updates, in milliseconds. Defaults - * to: DISPLAY_DEFAULT_SCROLL_SPEED. - * - * @param stride The number of pixels to shift by in each update. Defaults to DISPLAY_DEFAULT_SCROLL_STRIDE. - * - * @return DEVICE_OK, DEVICE_BUSY if the display is already in use, or DEVICE_INVALID_PARAMETER. - * - * @code - * Image i("1,1,1,1,1\n1,1,1,1,1\n"); - * display.scrollAsync(i,100,1); - * @endcode - */ - int scrollAsync(Image image, int delay = DISPLAY_DEFAULT_SCROLL_SPEED, int stride = DISPLAY_DEFAULT_SCROLL_STRIDE); - - /** - * Scrolls the given string across the display, from right to left. - * Blocks the calling thread until all text has been displayed. - * - * @param s The string to display. - * - * @param delay The time to delay between characters, in milliseconds. Defaults - * to: DISPLAY_DEFAULT_SCROLL_SPEED. - * - * @return DEVICE_OK, DEVICE_CANCELLED or DEVICE_INVALID_PARAMETER. - * - * @code - * display.scroll("abc123",100); - * @endcode - */ - int scroll(ManagedString s, int delay = DISPLAY_DEFAULT_SCROLL_SPEED); - - /** - * Scrolls the given image across the display, from right to left. - * Blocks the calling thread until all the text has been displayed. - * - * @param image The image to display. - * - * @param delay The time between updates, in milliseconds. Defaults - * to: DISPLAY_DEFAULT_SCROLL_SPEED. - * - * @param stride The number of pixels to shift by in each update. Defaults to DISPLAY_DEFAULT_SCROLL_STRIDE. - * - * @return DEVICE_OK, DEVICE_CANCELLED or DEVICE_INVALID_PARAMETER. - * - * @code - * Image i("1,1,1,1,1\n1,1,1,1,1\n"); - * display.scroll(i,100,1); - * @endcode - */ - int scroll(Image image, int delay = DISPLAY_DEFAULT_SCROLL_SPEED, int stride = DISPLAY_DEFAULT_SCROLL_STRIDE); - - /** - * "Animates" the current image across the display with a given stride, finishing on the last frame of the animation. - * Returns immediately. - * - * @param image The image to display. - * - * @param delay The time to delay between each update of the display, in milliseconds. - * - * @param stride The number of pixels to shift by in each update. - * - * @param startingPosition the starting position on the display for the animation - * to begin at. Defaults to DISPLAY_ANIMATE_DEFAULT_POS. - * - * @param autoClear defines whether or not the display is automatically cleared once the animation is complete. By default, the display is cleared. Set this parameter to zero to disable the autoClear operation. - * - * @return DEVICE_OK, DEVICE_BUSY if the screen is in use, or DEVICE_INVALID_PARAMETER. - * - * @code - * const int heart_w = 10; - * const int heart_h = 5; - * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; - * - * Image i(heart_w,heart_h,heart); - * display.animateAsync(i,100,5); - * @endcode - */ - int animateAsync(Image image, int delay, int stride, int startingPosition = DISPLAY_ANIMATE_DEFAULT_POS, int autoClear = DISPLAY_DEFAULT_AUTOCLEAR); - - /** - * "Animates" the current image across the display with a given stride, finishing on the last frame of the animation. - * Blocks the calling thread until the animation is complete. - * - * - * @param delay The time to delay between each update of the display, in milliseconds. - * - * @param stride The number of pixels to shift by in each update. - * - * @param startingPosition the starting position on the display for the animation - * to begin at. Defaults to DISPLAY_ANIMATE_DEFAULT_POS. - * - * @param autoClear defines whether or not the display is automatically cleared once the animation is complete. By default, the display is cleared. Set this parameter to zero to disable the autoClear operation. - * - * @return DEVICE_OK, DEVICE_CANCELLED or DEVICE_INVALID_PARAMETER. - * - * @code - * const int heart_w = 10; - * const int heart_h = 5; - * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; - * - * Image i(heart_w,heart_h,heart); - * display.animate(i,100,5); - * @endcode - */ - int animate(Image image, int delay, int stride, int startingPosition = DISPLAY_ANIMATE_DEFAULT_POS, int autoClear = DISPLAY_DEFAULT_AUTOCLEAR); - - /** - * Destructor for AnimatedDisplay, where we deregister this instance from the array of system components. - */ - ~AnimatedDisplay(); - - }; -} + ~AnimatedDisplay(); +}; +} // namespace codal #endif diff --git a/inc/drivers/AsciiKeyMap.h b/inc/drivers/AsciiKeyMap.h index 7dd1dbe7..94c7a2e3 100644 --- a/inc/drivers/AsciiKeyMap.h +++ b/inc/drivers/AsciiKeyMap.h @@ -1,22 +1,16 @@ -#include "KeyMap.h" #include "ErrorNo.h" +#include "KeyMap.h" -namespace codal -{ - class AsciiKeyMap : public KeyMap - { - public: - - AsciiKeyMap(const KeySequence* seq, uint32_t len) : KeyMap(seq, len) - { - } +namespace codal { +class AsciiKeyMap : public KeyMap { + public: + AsciiKeyMap(const KeySequence* seq, uint32_t len) : KeyMap(seq, len) {} - virtual const KeySequence* mapCharacter(uint16_t c) - { - if(c >= length) - return NULL; + virtual const KeySequence* mapCharacter(uint16_t c) + { + if (c >= length) return NULL; - return &map[c]; - } - }; -} + return &map[c]; + } +}; +} // namespace codal diff --git a/inc/drivers/Button.h b/inc/drivers/Button.h index 7be13bf0..5f9da556 100644 --- a/inc/drivers/Button.h +++ b/inc/drivers/Button.h @@ -26,133 +26,129 @@ DEALINGS IN THE SOFTWARE. #define CODAL_BUTTON_H #include "AbstractButton.h" -#include "CodalConfig.h" #include "CodalComponent.h" +#include "CodalConfig.h" #include "Event.h" #include "Pin.h" -namespace codal -{ +namespace codal { +/** + * Class definition for Device Button. + * + * Represents a single, generic button on the device. + */ +class Button : public AbstractButton, public PinPeripheral { + unsigned long downStartTime; // used to store the current system clock when a button down event occurs + uint8_t + sigma; // integration of samples over time. We use this for debouncing, and noise tolerance for touch sensing + ButtonEventConfiguration + eventConfiguration; // Do we want to generate high level event (clicks), or defer this to another service. + ButtonPolarity polarity; // Determines if the button is active HIGH or LOW. + + public: + Pin& _pin; // The pin this button is connected to. + PullMode pullMode; // Determines if pull up or pull down resistors should be applied. + + /** + * Constructor. + * + * Create a software representation of a button. + * + * @param pin the physical pin on the device connected to this button. + * + * @param id the ID of the new Button object. + * + * @param eventConfiguration Configures the events that will be generated by this Button instance. + * Defaults to DEVICE_BUTTON_ALL_EVENTS. + * + * @param mode the configuration of internal pullups/pulldowns, as defined in the mbed PullMode class. PullNone by + * default. + * + * @code + * buttonA(DEVICE_PIN_BUTTON_A, DEVICE_ID_BUTTON_A); + * @endcode + */ + Button(Pin& pin, uint16_t id, ButtonEventConfiguration eventConfiguration = DEVICE_BUTTON_ALL_EVENTS, + ButtonPolarity polarity = ACTIVE_LOW, PullMode mode = PullMode::None); + + /** + * Tests if this Button is currently pressed. + * + * @code + * if(buttonA.isPressed()) + * display.scroll("Pressed!"); + * @endcode + * + * @return 1 if this button is pressed, 0 otherwise. + */ + virtual int isPressed(); + + /** + * Changes the event configuration used by this button to the given ButtonEventConfiguration. + * + * All subsequent events generated by this button will then be informed by this configuraiton. + * + * @param config The new configuration for this button. Legal values are DEVICE_BUTTON_ALL_EVENTS or + * DEVICE_BUTTON_SIMPLE_EVENTS. + * + * Example: + * @code + * // Configure a button to generate all possible events. + * buttonA.setEventConfiguration(DEVICE_BUTTON_ALL_EVENTS); + * + * // Configure a button to suppress DEVICE_BUTTON_EVT_CLICK and DEVICE_BUTTON_EVT_LONG_CLICK events. + * buttonA.setEventConfiguration(DEVICE_BUTTON_SIMPLE_EVENTS); + * @endcode + */ + void setEventConfiguration(ButtonEventConfiguration config); + + /** + * periodic callback from Device system timer. + * + * Check for state change for this button, and fires various events on a state change. + */ + void periodicCallback(); + + /** + * Sets whether the button should trigger power manager wake-up. + * + * @param wake The action of the button - either 1 to trigger wake-up or 0 for no wake-up + */ + void wakeOnActive(int wake) { _pin.wakeOnActive(wake); } + + /** + * Deternine if the button should trigger power manager wake-up. + * + * @param wake The action of the button - either 1 to trigger wake up or 0 for no + */ + int isWakeOnActive() { return _pin.isWakeOnActive(); } + + /** + * Method to release the given pin from a peripheral, if already bound. + * Device drivers should override this method to disconnect themselves from the give pin + * to allow it to be used by a different peripheral. + * + * @param pin the Pin to be released + */ + virtual int releasePin(Pin& pin) override; + + /** + * Destructor for Button, where we deregister this instance from the array of fiber components. + */ + ~Button(); + + protected: + /** + * Determines if this button is instantenously active (i.e. pressed). + * Internal method, use before debouncing. + */ + virtual int buttonActive(); + /** - * Class definition for Device Button. - * - * Represents a single, generic button on the device. - */ - class Button : public AbstractButton, public PinPeripheral - { - unsigned long downStartTime; // used to store the current system clock when a button down event occurs - uint8_t sigma; // integration of samples over time. We use this for debouncing, and noise tolerance for touch sensing - ButtonEventConfiguration eventConfiguration; // Do we want to generate high level event (clicks), or defer this to another service. - ButtonPolarity polarity; // Determines if the button is active HIGH or LOW. - - public: - Pin &_pin; // The pin this button is connected to. - PullMode pullMode; // Determines if pull up or pull down resistors should be applied. - - /** - * Constructor. - * - * Create a software representation of a button. - * - * @param pin the physical pin on the device connected to this button. - * - * @param id the ID of the new Button object. - * - * @param eventConfiguration Configures the events that will be generated by this Button instance. - * Defaults to DEVICE_BUTTON_ALL_EVENTS. - * - * @param mode the configuration of internal pullups/pulldowns, as defined in the mbed PullMode class. PullNone by default. - * - * @code - * buttonA(DEVICE_PIN_BUTTON_A, DEVICE_ID_BUTTON_A); - * @endcode - */ - Button(Pin &pin, uint16_t id, ButtonEventConfiguration eventConfiguration = DEVICE_BUTTON_ALL_EVENTS, ButtonPolarity polarity = ACTIVE_LOW, PullMode mode = PullMode::None); - - /** - * Tests if this Button is currently pressed. - * - * @code - * if(buttonA.isPressed()) - * display.scroll("Pressed!"); - * @endcode - * - * @return 1 if this button is pressed, 0 otherwise. - */ - virtual int isPressed(); - - /** - * Changes the event configuration used by this button to the given ButtonEventConfiguration. - * - * All subsequent events generated by this button will then be informed by this configuraiton. - * - * @param config The new configuration for this button. Legal values are DEVICE_BUTTON_ALL_EVENTS or DEVICE_BUTTON_SIMPLE_EVENTS. - * - * Example: - * @code - * // Configure a button to generate all possible events. - * buttonA.setEventConfiguration(DEVICE_BUTTON_ALL_EVENTS); - * - * // Configure a button to suppress DEVICE_BUTTON_EVT_CLICK and DEVICE_BUTTON_EVT_LONG_CLICK events. - * buttonA.setEventConfiguration(DEVICE_BUTTON_SIMPLE_EVENTS); - * @endcode - */ - void setEventConfiguration(ButtonEventConfiguration config); - - /** - * periodic callback from Device system timer. - * - * Check for state change for this button, and fires various events on a state change. - */ - void periodicCallback(); - - /** - * Sets whether the button should trigger power manager wake-up. - * - * @param wake The action of the button - either 1 to trigger wake-up or 0 for no wake-up - */ - void wakeOnActive(int wake) - { - _pin.wakeOnActive( wake); - } - - /** - * Deternine if the button should trigger power manager wake-up. - * - * @param wake The action of the button - either 1 to trigger wake up or 0 for no - */ - int isWakeOnActive() - { - return _pin.isWakeOnActive(); - } - - /** - * Method to release the given pin from a peripheral, if already bound. - * Device drivers should override this method to disconnect themselves from the give pin - * to allow it to be used by a different peripheral. - * - * @param pin the Pin to be released - */ - virtual int releasePin(Pin &pin) override; - - /** - * Destructor for Button, where we deregister this instance from the array of fiber components. - */ - ~Button(); - - protected: - /** - * Determines if this button is instantenously active (i.e. pressed). - * Internal method, use before debouncing. - */ - virtual int buttonActive(); - - /** - * Puts the component in (or out of) sleep (low power) mode. - */ - virtual int setSleep(bool doSleep) override; - - }; -} + * Puts the component in (or out of) sleep (low power) mode. + */ + virtual int setSleep(bool doSleep) override; +}; +} // namespace codal #endif diff --git a/inc/drivers/FAT.h b/inc/drivers/FAT.h index 1da32dbd..acabc615 100644 --- a/inc/drivers/FAT.h +++ b/inc/drivers/FAT.h @@ -27,21 +27,18 @@ DEALINGS IN THE SOFTWARE. #include -namespace codal -{ +namespace codal { -#define FAT_RESERVED_SECTORS 1 -#define FAT_ROOT_DIR_SECTORS 4 +#define FAT_RESERVED_SECTORS 1 +#define FAT_ROOT_DIR_SECTORS 4 #define FAT_SECTORS_PER_FAT(numBl) ((unsigned)(((numBl)*2 + 511) / 512)) -#define FAT_START_FAT0(numBl) FAT_RESERVED_SECTORS -#define FAT_START_FAT1(numBl) (FAT_RESERVED_SECTORS + FAT_SECTORS_PER_FAT(numBl)) -#define FAT_START_ROOTDIR(numBl) (FAT_RESERVED_SECTORS + 2 * FAT_SECTORS_PER_FAT(numBl)) -#define FAT_START_CLUSTERS(numBl) \ - (FAT_RESERVED_SECTORS + 2 * FAT_SECTORS_PER_FAT(numBl) + FAT_ROOT_DIR_SECTORS) +#define FAT_START_FAT0(numBl) FAT_RESERVED_SECTORS +#define FAT_START_FAT1(numBl) (FAT_RESERVED_SECTORS + FAT_SECTORS_PER_FAT(numBl)) +#define FAT_START_ROOTDIR(numBl) (FAT_RESERVED_SECTORS + 2 * FAT_SECTORS_PER_FAT(numBl)) +#define FAT_START_CLUSTERS(numBl) (FAT_RESERVED_SECTORS + 2 * FAT_SECTORS_PER_FAT(numBl) + FAT_ROOT_DIR_SECTORS) -typedef struct -{ +typedef struct { uint8_t JumpInstruction[3]; uint8_t OEMInfo[8]; uint16_t SectorSize; @@ -64,8 +61,7 @@ typedef struct uint8_t FilesystemIdentifier[8]; } __attribute__((packed)) FAT_BootBlock; -typedef struct -{ +typedef struct { char name[8]; char ext[3]; uint8_t attrs; @@ -81,8 +77,7 @@ typedef struct uint32_t size; } __attribute__((packed)) DirEntry; -typedef struct -{ +typedef struct { uint8_t seqno; uint16_t name0[5]; uint8_t attrs; @@ -92,6 +87,6 @@ typedef struct uint16_t startCluster; uint16_t name2[2]; } __attribute__((packed)) VFatEntry; -} +} // namespace codal #endif diff --git a/inc/drivers/FXOS8700.h b/inc/drivers/FXOS8700.h index 4b5be172..459f9d2f 100644 --- a/inc/drivers/FXOS8700.h +++ b/inc/drivers/FXOS8700.h @@ -25,229 +25,224 @@ DEALINGS IN THE SOFTWARE. #ifndef FXOS8700_H #define FXOS8700_H -#include "CodalConfig.h" +#include "Accelerometer.h" #include "CodalComponent.h" -#include "Pin.h" -#include "I2C.h" -#include "CoordinateSystem.h" +#include "CodalConfig.h" #include "CodalUtil.h" -#include "Accelerometer.h" #include "Compass.h" +#include "CoordinateSystem.h" +#include "I2C.h" +#include "Pin.h" /** - * I2C constants - */ -#define FXOS8700_DEFAULT_ADDR 0x3C + * I2C constants + */ +#define FXOS8700_DEFAULT_ADDR 0x3C /** - * FXOS8700 Register map - */ -#define FXOS8700_STATUS_REG 0x00 -#define FXOS8700_OUT_X_MSB 0x01 -#define FXOS8700_OUT_X_LSB 0x02 -#define FXOS8700_OUT_Y_MSB 0x03 -#define FXOS8700_OUT_Y_LSB 0x04 -#define FXOS8700_OUT_Z_MSB 0x05 -#define FXOS8700_OUT_Z_LSB 0x06 -#define FXOS8700_F_SETUP 0x09 -#define FXOS8700_TRIG_CFG 0x0A -#define FXOS8700_SYSMOD 0x0B -#define FXOS8700_INT_SOURCE 0x0C -#define FXOS8700_WHO_AM_I 0x0D -#define FXOS8700_XYZ_DATA_CFG 0x0E -#define FXOS8700_HP_FILTER_CUTOFF 0x0F -#define FXOS8700_PL_STATUS 0x10 -#define FXOS8700_PL_CFG 0x11 -#define FXOS8700_PL_COUNT 0x12 -#define FXOS8700_PL_BF_ZCOMP 0x13 -#define FXOS8700_PL_THS_REG 0x14 -#define FXOS8700_A_FFMT_CFG 0x15 -#define FXOS8700_A_FFMT_SRC 0x16 -#define FXOS8700_A_FFMT_THS 0x17 -#define FXOS8700_A_FFMT_COUNT 0x18 -#define FXOS8700_TRANSIENT_CFG 0x1D -#define FXOS8700_TRANSIENT_SRC 0x1E -#define FXOS8700_TRANSIENT_THS 0x1F -#define FXOS8700_TRANSIENT_COUNT 0x20 -#define FXOS8700_PULSE_CFG 0x21 -#define FXOS8700_PULSE_SRC 0x22 -#define FXOS8700_PULSE_THSX 0x23 -#define FXOS8700_PULSE_THSY 0x24 -#define FXOS8700_PULSE_THSZ 0x25 -#define FXOS8700_PULSE_TMLT 0x26 -#define FXOS8700_PULSE_LTCY 0x27 -#define FXOS8700_PULSE_WIND 0x28 -#define FXOS8700_ASLP_COUNT 0x29 -#define FXOS8700_CTRL_REG1 0x2A -#define FXOS8700_CTRL_REG2 0x2B -#define FXOS8700_CTRL_REG3 0x2C -#define FXOS8700_CTRL_REG4 0x2D -#define FXOS8700_CTRL_REG5 0x2E -#define FXOS8700_OFF_X 0x2F -#define FXOS8700_OFF_Y 0x30 -#define FXOS8700_OFF_Z 0x31 -#define FXOS8700_M_DR_STATUS 0x32 -#define FXOS8700_M_OUT_X_MSB 0x33 -#define FXOS8700_M_OUT_X_LSB 0x34 -#define FXOS8700_M_OUT_Y_MSB 0x35 -#define FXOS8700_M_OUT_Y_LSB 0x36 -#define FXOS8700_M_OUT_Z_MSB 0x37 -#define FXOS8700_M_OUT_Z_LSB 0x38 -#define FXOS8700_CMP_X_MSB 0x39 -#define FXOS8700_CMP_X_LSB 0x3A -#define FXOS8700_CMP_Y_MSB 0x3B -#define FXOS8700_CMP_Y_LSB 0x3C -#define FXOS8700_CMP_Z_MSB 0x3D -#define FXOS8700_CMP_Z_LSB 0x3E -#define FXOS8700_M_OFF_X_MSB 0x3F -#define FXOS8700_M_OFF_X_LSB 0x40 -#define FXOS8700_M_OFF_Y_MSB 0x41 -#define FXOS8700_M_OFF_Y_LSB 0x42 -#define FXOS8700_M_OFF_Z_MSB 0x43 -#define FXOS8700_M_OFF_Z_LSB 0x44 -#define FXOS8700_MAX_X_MSB 0x45 -#define FXOS8700_MAX_X_LSB 0x46 -#define FXOS8700_MAX_Y_MSB 0x47 -#define FXOS8700_MAX_Y_LSB 0x48 -#define FXOS8700_MAX_Z_MSB 0x49 -#define FXOS8700_MAX_Z_LSB 0x4A -#define FXOS8700_MIN_X_MSB 0x4B -#define FXOS8700_MIN_X_LSB 0x4C -#define FXOS8700_MIN_Y_MSB 0x4D -#define FXOS8700_MIN_Y_LSB 0x4E -#define FXOS8700_MIN_Z_MSB 0x4F -#define FXOS8700_MIN_Z_LSB 0x50 -#define FXOS8700_TEMP 0x51 -#define FXOS8700_M_THS_CFG 0x52 -#define FXOS8700_M_THS_SRC 0x53 -#define FXOS8700_M_THS_X_MSB 0x54 -#define FXOS8700_M_THS_X_LSB 0x55 -#define FXOS8700_M_THS_Y_MSB 0x56 -#define FXOS8700_M_THS_Y_LSB 0x57 -#define FXOS8700_M_THS_Z_MSB 0x58 -#define FXOS8700_M_THS_Z_LSB 0x59 -#define FXOS8700_M_THS_COUNT 0x5A -#define FXOS8700_M_CTRL_REG1 0x5B -#define FXOS8700_M_CTRL_REG2 0x5C -#define FXOS8700_M_CTRL_REG3 0x5D -#define FXOS8700_M_INT_SRC 0x5E -#define FXOS8700_A_VECM_CFG 0x5F -#define FXOS8700_A_VECM_THS_MSB 0x60 -#define FXOS8700_A_VECM_THS_LSB 0x61 -#define FXOS8700_A_VECM_CNT 0x62 -#define FXOS8700_A_VECM_INITX_MSB 0x63 -#define FXOS8700_A_VECM_INITX_LSB 0x64 -#define FXOS8700_A_VECM_INITY_MSB 0x65 -#define FXOS8700_A_VECM_INITY_LSB 0x66 -#define FXOS8700_A_VECM_INITZ_MSB 0x67 -#define FXOS8700_A_VECM_INITZ_LSB 0x68 -#define FXOS8700_M_VECM_CFG 0x69 -#define FXOS8700_M_VECM_THS_MSB 0x6A -#define FXOS8700_M_VECM_THS_LSB 0x6B -#define FXOS8700_M_VECM_CNT 0x6C -#define FXOS8700_M_VECM_INITX_MSB 0x6D -#define FXOS8700_M_VECM_INITX_LSB 0x6E -#define FXOS8700_M_VECM_INITY_MSB 0x6F -#define FXOS8700_M_VECM_INITY_LSB 0x70 -#define FXOS8700_M_VECM_INITZ_MSB 0x71 -#define FXOS8700_M_VECM_INITZ_LSB 0x72 -#define FXOS8700_A_FFMT_THS_X_MSB 0x73 -#define FXOS8700_A_FFMT_THS_X_LSB 0x74 -#define FXOS8700_A_FFMT_THS_Y_MSB 0x75 -#define FXOS8700_A_FFMT_THS_Y_LSB 0x76 -#define FXOS8700_A_FFMT_THS_Z_MSB 0x77 -#define FXOS8700_A_FFMT_THS_Z_LSB 0x78 - -// Constants -#define FXOS8700_STATUS_DATA_READY 0x07 -#define FXOS8700_WHOAMI_VAL 0xC7 + * FXOS8700 Register map + */ +#define FXOS8700_STATUS_REG 0x00 +#define FXOS8700_OUT_X_MSB 0x01 +#define FXOS8700_OUT_X_LSB 0x02 +#define FXOS8700_OUT_Y_MSB 0x03 +#define FXOS8700_OUT_Y_LSB 0x04 +#define FXOS8700_OUT_Z_MSB 0x05 +#define FXOS8700_OUT_Z_LSB 0x06 +#define FXOS8700_F_SETUP 0x09 +#define FXOS8700_TRIG_CFG 0x0A +#define FXOS8700_SYSMOD 0x0B +#define FXOS8700_INT_SOURCE 0x0C +#define FXOS8700_WHO_AM_I 0x0D +#define FXOS8700_XYZ_DATA_CFG 0x0E +#define FXOS8700_HP_FILTER_CUTOFF 0x0F +#define FXOS8700_PL_STATUS 0x10 +#define FXOS8700_PL_CFG 0x11 +#define FXOS8700_PL_COUNT 0x12 +#define FXOS8700_PL_BF_ZCOMP 0x13 +#define FXOS8700_PL_THS_REG 0x14 +#define FXOS8700_A_FFMT_CFG 0x15 +#define FXOS8700_A_FFMT_SRC 0x16 +#define FXOS8700_A_FFMT_THS 0x17 +#define FXOS8700_A_FFMT_COUNT 0x18 +#define FXOS8700_TRANSIENT_CFG 0x1D +#define FXOS8700_TRANSIENT_SRC 0x1E +#define FXOS8700_TRANSIENT_THS 0x1F +#define FXOS8700_TRANSIENT_COUNT 0x20 +#define FXOS8700_PULSE_CFG 0x21 +#define FXOS8700_PULSE_SRC 0x22 +#define FXOS8700_PULSE_THSX 0x23 +#define FXOS8700_PULSE_THSY 0x24 +#define FXOS8700_PULSE_THSZ 0x25 +#define FXOS8700_PULSE_TMLT 0x26 +#define FXOS8700_PULSE_LTCY 0x27 +#define FXOS8700_PULSE_WIND 0x28 +#define FXOS8700_ASLP_COUNT 0x29 +#define FXOS8700_CTRL_REG1 0x2A +#define FXOS8700_CTRL_REG2 0x2B +#define FXOS8700_CTRL_REG3 0x2C +#define FXOS8700_CTRL_REG4 0x2D +#define FXOS8700_CTRL_REG5 0x2E +#define FXOS8700_OFF_X 0x2F +#define FXOS8700_OFF_Y 0x30 +#define FXOS8700_OFF_Z 0x31 +#define FXOS8700_M_DR_STATUS 0x32 +#define FXOS8700_M_OUT_X_MSB 0x33 +#define FXOS8700_M_OUT_X_LSB 0x34 +#define FXOS8700_M_OUT_Y_MSB 0x35 +#define FXOS8700_M_OUT_Y_LSB 0x36 +#define FXOS8700_M_OUT_Z_MSB 0x37 +#define FXOS8700_M_OUT_Z_LSB 0x38 +#define FXOS8700_CMP_X_MSB 0x39 +#define FXOS8700_CMP_X_LSB 0x3A +#define FXOS8700_CMP_Y_MSB 0x3B +#define FXOS8700_CMP_Y_LSB 0x3C +#define FXOS8700_CMP_Z_MSB 0x3D +#define FXOS8700_CMP_Z_LSB 0x3E +#define FXOS8700_M_OFF_X_MSB 0x3F +#define FXOS8700_M_OFF_X_LSB 0x40 +#define FXOS8700_M_OFF_Y_MSB 0x41 +#define FXOS8700_M_OFF_Y_LSB 0x42 +#define FXOS8700_M_OFF_Z_MSB 0x43 +#define FXOS8700_M_OFF_Z_LSB 0x44 +#define FXOS8700_MAX_X_MSB 0x45 +#define FXOS8700_MAX_X_LSB 0x46 +#define FXOS8700_MAX_Y_MSB 0x47 +#define FXOS8700_MAX_Y_LSB 0x48 +#define FXOS8700_MAX_Z_MSB 0x49 +#define FXOS8700_MAX_Z_LSB 0x4A +#define FXOS8700_MIN_X_MSB 0x4B +#define FXOS8700_MIN_X_LSB 0x4C +#define FXOS8700_MIN_Y_MSB 0x4D +#define FXOS8700_MIN_Y_LSB 0x4E +#define FXOS8700_MIN_Z_MSB 0x4F +#define FXOS8700_MIN_Z_LSB 0x50 +#define FXOS8700_TEMP 0x51 +#define FXOS8700_M_THS_CFG 0x52 +#define FXOS8700_M_THS_SRC 0x53 +#define FXOS8700_M_THS_X_MSB 0x54 +#define FXOS8700_M_THS_X_LSB 0x55 +#define FXOS8700_M_THS_Y_MSB 0x56 +#define FXOS8700_M_THS_Y_LSB 0x57 +#define FXOS8700_M_THS_Z_MSB 0x58 +#define FXOS8700_M_THS_Z_LSB 0x59 +#define FXOS8700_M_THS_COUNT 0x5A +#define FXOS8700_M_CTRL_REG1 0x5B +#define FXOS8700_M_CTRL_REG2 0x5C +#define FXOS8700_M_CTRL_REG3 0x5D +#define FXOS8700_M_INT_SRC 0x5E +#define FXOS8700_A_VECM_CFG 0x5F +#define FXOS8700_A_VECM_THS_MSB 0x60 +#define FXOS8700_A_VECM_THS_LSB 0x61 +#define FXOS8700_A_VECM_CNT 0x62 +#define FXOS8700_A_VECM_INITX_MSB 0x63 +#define FXOS8700_A_VECM_INITX_LSB 0x64 +#define FXOS8700_A_VECM_INITY_MSB 0x65 +#define FXOS8700_A_VECM_INITY_LSB 0x66 +#define FXOS8700_A_VECM_INITZ_MSB 0x67 +#define FXOS8700_A_VECM_INITZ_LSB 0x68 +#define FXOS8700_M_VECM_CFG 0x69 +#define FXOS8700_M_VECM_THS_MSB 0x6A +#define FXOS8700_M_VECM_THS_LSB 0x6B +#define FXOS8700_M_VECM_CNT 0x6C +#define FXOS8700_M_VECM_INITX_MSB 0x6D +#define FXOS8700_M_VECM_INITX_LSB 0x6E +#define FXOS8700_M_VECM_INITY_MSB 0x6F +#define FXOS8700_M_VECM_INITY_LSB 0x70 +#define FXOS8700_M_VECM_INITZ_MSB 0x71 +#define FXOS8700_M_VECM_INITZ_LSB 0x72 +#define FXOS8700_A_FFMT_THS_X_MSB 0x73 +#define FXOS8700_A_FFMT_THS_X_LSB 0x74 +#define FXOS8700_A_FFMT_THS_Y_MSB 0x75 +#define FXOS8700_A_FFMT_THS_Y_LSB 0x76 +#define FXOS8700_A_FFMT_THS_Z_MSB 0x77 +#define FXOS8700_A_FFMT_THS_Z_LSB 0x78 + +// Constants +#define FXOS8700_STATUS_DATA_READY 0x07 +#define FXOS8700_WHOAMI_VAL 0xC7 /** - * Term to convert sample data into SI units. - */ + * Term to convert sample data into SI units. + */ #define FXOS8700_NORMALIZE_SAMPLE(x) (100 * (int)(x)) - -namespace codal -{ - struct FXOSRawSample - { - int16_t ax; - int16_t ay; - int16_t az; - int16_t cx; - int16_t cy; - int16_t cz; - }; - +namespace codal { +struct FXOSRawSample { + int16_t ax; + int16_t ay; + int16_t az; + int16_t cx; + int16_t cy; + int16_t cz; +}; /** * Class definition for an FXSO8700 hybrid Accelerometer/Magnetometer */ -class FXOS8700 : public Accelerometer, public Compass -{ - I2C& i2c; // The I2C interface to use. - Pin &int1; // Data ready interrupt. - uint16_t address; // I2C address of this accelerometer. - - public: - /** - * Constructor. - * Create a software abstraction of an FXOS8700 sensor. - * - * @param _i2c an instance of I2C used to communicate with the onboard accelerometer. - * @param _int1 a pin connected to the INT1 interrupt source of the sensor. - * @param coordinateSpace The orientation of the sensor. Defaults to: SIMPLE_CARTESIAN. - * @param address the default I2C address of the accelerometer. Defaults to: FXOS8700_DEFAULT_ADDR. - * - */ - FXOS8700(I2C &_i2c, Pin &_int1, CoordinateSpace &coordinateSpace, uint16_t address = FXOS8700_DEFAULT_ADDR, uint16_t aid = DEVICE_ID_ACCELEROMETER, uint16_t cid = DEVICE_ID_COMPASS); - - /** - * Configures the accelerometer for G range and sample rate defined - * in this object. The nearest values are chosen to those defined - * that are supported by the hardware. The instance variables are then - * updated to reflect reality. - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the accelerometer could not be configured. - */ - virtual int configure() override; - - /** - * Reads the acceleration data from the accelerometer, and stores it in our buffer. - * This only happens if the accelerometer indicates that it has new data via int1. - * - * On first use, this member function will attempt to add this component to the - * list of fiber components in order to constantly update the values stored - * by this object. - * - * This technique is called lazy instantiation, and it means that we do not - * obtain the overhead from non-chalantly adding this component to fiber components. - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the read request fails. - */ - virtual int requestUpdate() override; - - /** - * A periodic callback invoked by the fiber scheduler idle thread. - * - * Internally calls updateSample(). - */ - virtual void idleCallback() override; - - /** - * Attempts to read the 8 bit WHO_AM_I value from the accelerometer - * - * @return true if the WHO_AM_I value is succesfully read. false otherwise. - */ - static int isDetected(I2C &i2c, uint16_t address = FXOS8700_DEFAULT_ADDR); - - /** - * Destructor. - */ - ~FXOS8700(); - - }; -} +class FXOS8700 : public Accelerometer, public Compass { + I2C& i2c; // The I2C interface to use. + Pin& int1; // Data ready interrupt. + uint16_t address; // I2C address of this accelerometer. + + public: + /** + * Constructor. + * Create a software abstraction of an FXOS8700 sensor. + * + * @param _i2c an instance of I2C used to communicate with the onboard accelerometer. + * @param _int1 a pin connected to the INT1 interrupt source of the sensor. + * @param coordinateSpace The orientation of the sensor. Defaults to: SIMPLE_CARTESIAN. + * @param address the default I2C address of the accelerometer. Defaults to: FXOS8700_DEFAULT_ADDR. + * + */ + FXOS8700(I2C& _i2c, Pin& _int1, CoordinateSpace& coordinateSpace, uint16_t address = FXOS8700_DEFAULT_ADDR, + uint16_t aid = DEVICE_ID_ACCELEROMETER, uint16_t cid = DEVICE_ID_COMPASS); + + /** + * Configures the accelerometer for G range and sample rate defined + * in this object. The nearest values are chosen to those defined + * that are supported by the hardware. The instance variables are then + * updated to reflect reality. + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the accelerometer could not be configured. + */ + virtual int configure() override; + + /** + * Reads the acceleration data from the accelerometer, and stores it in our buffer. + * This only happens if the accelerometer indicates that it has new data via int1. + * + * On first use, this member function will attempt to add this component to the + * list of fiber components in order to constantly update the values stored + * by this object. + * + * This technique is called lazy instantiation, and it means that we do not + * obtain the overhead from non-chalantly adding this component to fiber components. + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the read request fails. + */ + virtual int requestUpdate() override; + + /** + * A periodic callback invoked by the fiber scheduler idle thread. + * + * Internally calls updateSample(). + */ + virtual void idleCallback() override; + + /** + * Attempts to read the 8 bit WHO_AM_I value from the accelerometer + * + * @return true if the WHO_AM_I value is succesfully read. false otherwise. + */ + static int isDetected(I2C& i2c, uint16_t address = FXOS8700_DEFAULT_ADDR); + + /** + * Destructor. + */ + ~FXOS8700(); +}; +} // namespace codal #endif diff --git a/inc/drivers/GhostFAT.h b/inc/drivers/GhostFAT.h index 5b68cf1c..89fc2834 100644 --- a/inc/drivers/GhostFAT.h +++ b/inc/drivers/GhostFAT.h @@ -29,19 +29,17 @@ DEALINGS IN THE SOFTWARE. #if CONFIG_ENABLED(DEVICE_USB) -namespace codal -{ +namespace codal { struct GFATEntry; -typedef void (*GFATReadCallback)(GFATEntry *ent, unsigned blockAddr, char *dst); +typedef void (*GFATReadCallback)(GFATEntry* ent, unsigned blockAddr, char* dst); -struct GFATEntry -{ - GFATEntry *next; +struct GFATEntry { + GFATEntry* next; uint32_t size; GFATReadCallback read; - void *userdata; + void* userdata; uint16_t startCluster; uint8_t attrs; uint8_t flags; @@ -51,34 +49,32 @@ struct GFATEntry // the name VirtualFAT would be more fitting, but it's unfortunately already taken. -class GhostFAT : public USBMSC -{ - void buildBlock(uint32_t block_no, uint8_t *data); - void readDirData(uint8_t *dest, int blkno, uint8_t dirid); +class GhostFAT : public USBMSC { + void buildBlock(uint32_t block_no, uint8_t* data); + void readDirData(uint8_t* dest, int blkno, uint8_t dirid); -protected: - GFATEntry *files; + protected: + GFATEntry* files; void finalizeFiles(); -public: + public: GhostFAT(); virtual uint32_t getCapacity(); virtual void readBlocks(int blockAddr, int numBlocks); virtual void writeBlocks(int blockAddr, int numBlocks); - GFATEntry *addFile(GFATReadCallback read, void *userdata, const char *filename, uint32_t size, - uint8_t dirid = 0); - GFATEntry *addStringFile(const char *data, const char *filename, uint8_t dirid = 0); - void addDirectory(uint8_t id, const char *dirname); + GFATEntry* addFile(GFATReadCallback read, void* userdata, const char* filename, uint32_t size, uint8_t dirid = 0); + GFATEntry* addStringFile(const char* data, const char* filename, uint8_t dirid = 0); + void addDirectory(uint8_t id, const char* dirname); bool filesFinalized(); // these are typically overridden in a derived class virtual void addFiles(); - virtual uint32_t internalFlashSize() { return 256 * 1024; } // for current.uf2 - virtual const char *volumeLabel() { return "CODAL"; } + virtual uint32_t internalFlashSize() { return 256 * 1024; } // for current.uf2 + virtual const char* volumeLabel() { return "CODAL"; } }; -} +} // namespace codal #endif diff --git a/inc/drivers/HID.h b/inc/drivers/HID.h index 8f71f240..e98bee3a 100644 --- a/inc/drivers/HID.h +++ b/inc/drivers/HID.h @@ -29,36 +29,33 @@ DEALINGS IN THE SOFTWARE. #if CONFIG_ENABLED(DEVICE_USB) -#define HID_REQUEST_GET_REPORT 0x01 -#define HID_REQUEST_GET_IDLE 0x02 +#define HID_REQUEST_GET_REPORT 0x01 +#define HID_REQUEST_GET_IDLE 0x02 #define HID_REQUEST_GET_PROTOCOL 0x03 -#define HID_REQUEST_SET_REPORT 0x09 -#define HID_REQUEST_SET_IDLE 0x0A +#define HID_REQUEST_SET_REPORT 0x09 +#define HID_REQUEST_SET_IDLE 0x0A #define HID_REQUEST_SET_PROTOCOL 0x0B -namespace codal -{ - typedef struct { - uint8_t len; - uint8_t type; // 0x21 - uint16_t hidBCD; // 0x100 - uint8_t countryCode; - uint8_t numDesc; - uint8_t reportDescType; // 0x22 - uint16_t sizeOfReport; - } __attribute__((packed)) HIDReportDescriptor; - - class USBHID : public CodalUSBInterface - { - public: - USBHID(); - - virtual int classRequest(UsbEndpointIn &ctrl, USBSetup& setup); - virtual int stdRequest(UsbEndpointIn &ctrl, USBSetup& setup); - virtual const InterfaceInfo *getInterfaceInfo(); - }; -} - +namespace codal { +typedef struct { + uint8_t len; + uint8_t type; // 0x21 + uint16_t hidBCD; // 0x100 + uint8_t countryCode; + uint8_t numDesc; + uint8_t reportDescType; // 0x22 + uint16_t sizeOfReport; +} __attribute__((packed)) HIDReportDescriptor; + +class USBHID : public CodalUSBInterface { + public: + USBHID(); + + virtual int classRequest(UsbEndpointIn& ctrl, USBSetup& setup); + virtual int stdRequest(UsbEndpointIn& ctrl, USBSetup& setup); + virtual const InterfaceInfo* getInterfaceInfo(); +}; +} // namespace codal #endif diff --git a/inc/drivers/HIDJoystick.h b/inc/drivers/HIDJoystick.h index 1083eaaa..944f1332 100644 --- a/inc/drivers/HIDJoystick.h +++ b/inc/drivers/HIDJoystick.h @@ -29,42 +29,38 @@ DEALINGS IN THE SOFTWARE. #if CONFIG_ENABLED(DEVICE_USB) -namespace codal -{ - typedef struct { - int8_t throttle0; - int8_t throttle1; +namespace codal { +typedef struct { + int8_t throttle0; + int8_t throttle1; - int8_t x0; - int8_t y0; + int8_t x0; + int8_t y0; - int8_t x1; - int8_t y1; + int8_t x1; + int8_t y1; - uint16_t buttons; - } __attribute__((packed)) HIDJoystickState; + uint16_t buttons; +} __attribute__((packed)) HIDJoystickState; - class USBHIDJoystick : public USBHID - { +class USBHIDJoystick : public USBHID { + public: + USBHIDJoystick(); -public: - USBHIDJoystick(); + virtual int stdRequest(UsbEndpointIn& ctrl, USBSetup& setup); + virtual const InterfaceInfo* getInterfaceInfo(); - virtual int stdRequest(UsbEndpointIn &ctrl, USBSetup& setup); - virtual const InterfaceInfo *getInterfaceInfo(); + int buttonDown(uint8_t b); + int buttonUp(uint8_t b); - int buttonDown(uint8_t b); - int buttonUp(uint8_t b); + int move(int8_t num, int8_t x, int8_t y); - int move(int8_t num, int8_t x, int8_t y); - - int setThrottle(uint8_t num, uint8_t val); - -private: - int sendReport(); - }; -} + int setThrottle(uint8_t num, uint8_t val); + private: + int sendReport(); +}; +} // namespace codal #endif diff --git a/inc/drivers/HIDKeyboard.h b/inc/drivers/HIDKeyboard.h index 0aca1c17..b4ca4ffd 100644 --- a/inc/drivers/HIDKeyboard.h +++ b/inc/drivers/HIDKeyboard.h @@ -31,250 +31,242 @@ DEALINGS IN THE SOFTWARE. #if CONFIG_ENABLED(DEVICE_USB) -//report 0 is empty +// report 0 is empty #define HID_KEYBOARD_NUM_REPORTS 3 -#define HID_KEYBOARD_REPORT_GENERIC 0x01 -#define HID_KEYBOARD_REPORT_CONSUMER 0x02 -#define HID_KEYBOARD_KEYSTATE_SIZE_GENERIC 0x08 +#define HID_KEYBOARD_REPORT_GENERIC 0x01 +#define HID_KEYBOARD_REPORT_CONSUMER 0x02 +#define HID_KEYBOARD_KEYSTATE_SIZE_GENERIC 0x08 #define HID_KEYBOARD_KEYSTATE_SIZE_CONSUMER 0x02 -#define HID_KEYBOARD_MODIFIER_OFFSET 2 +#define HID_KEYBOARD_MODIFIER_OFFSET 2 #define HID_KEYBOARD_DELAY_DEFAULT 10 -namespace codal -{ - enum KeyActionType - { - PressKey, - ReleaseKey - }; - - typedef struct { - uint8_t reportID; - uint8_t *keyState; - uint8_t reportSize; - uint8_t keyPressedCount; - } HIDKeyboardReport; - - class USBHIDKeyboard : public USBHID - { - uint8_t keyStateGeneric[HID_KEYBOARD_KEYSTATE_SIZE_GENERIC]; - uint8_t keyStateConsumer[HID_KEYBOARD_KEYSTATE_SIZE_CONSUMER]; - - /** - * Writes the given report out over USB. - * - * @param report A pointer to the report to copy to USB - */ - int updateReport(HIDKeyboardReport* report); - - /** - * sets the media key buffer to the given Key, without affecting the state of other media keys. - * - * @param k a valid media key - * - * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if an incorrect key is passed. - */ - int mediaKeyPress(Key k, KeyActionType action); - - /** - * sets the keyboard modifier buffer to the given Key, without affecting the state of other keys. - * - * @param k a valid modifier key - * - * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if an incorrect key is passed. - */ - int modifierKeyPress(Key k, KeyActionType action); - - /** - * sets one keyboard key buffer slot to the given Key. - * - * @param k a valid modifier key - * - * @return DEVICE_OK on success - */ - int standardKeyPress(Key k, KeyActionType action); - - /** - * initialises the report arrays for this USBHID instance. - */ - void initReports(); - - public: - - /** - * Default constructor for a USBHIDKeyboard instance, sets the KeyMap to an ASCII default . - */ - USBHIDKeyboard(); - - /** - * Constructor for a USBHIDKeyboard instance, sets the KeyMap to the given keymap. - * - * @param k The KeyMap to use. - */ - USBHIDKeyboard(KeyMap& k); - - /** - * Sets the KeyMap for this USBHIDKeyboard instance - * - * @param map The KeyMap to use. - * - * @return DEVICE_OK on success. - */ - int setKeyMap(KeyMap& map); - - /** - * Releases the given Key. - * - * @param k A valid Key - * - * @return DEVICE_OK on success. - */ - int keyUp(Key k); - - /** - * Releases the given Key. - * - * @param k A valid MediaKey - * - * @return DEVICE_OK on success. - */ - int keyUp(MediaKey k); - - /** - * Releases the given Key. - * - * @param k A valid FunctionKey - * - * @return DEVICE_OK on success. - */ - int keyUp(FunctionKey k); - - /** - * Release the key corresponding to the given character. - * - * @param c A valid character - * - * @return DEVICE_OK on success. - */ - int keyUp(uint16_t c); - - /** - * Press the given Key. - * - * @param k A valid Key - * - * @return DEVICE_OK on success. - */ - int keyDown(Key k); - - /** - * Press the given Key. - * - * @param k A valid MediaKey - * - * @return DEVICE_OK on success. - */ - int keyDown(MediaKey k); - - /** - * Press the given Key. - * - * @param k A valid FunctionKey - * - * @return DEVICE_OK on success. - */ - int keyDown(FunctionKey k); - - /** - * Press the key corresponding to the given character. - * - * @param c A valid character - * - * @return DEVICE_OK on success. - */ - int keyDown(uint16_t c); - - /** - * Presses and releases the given Key. - * - * @param k A valid Key - * - * @return DEVICE_OK on success. - */ - int press(Key k); - - /** - * Press and releases the given Key. - * - * @param k A valid MediaKey - * - * @return DEVICE_OK on success. - */ - int press(MediaKey k); - - /** - * Press and releases the given Key. - * - * @param k A valid FunctionKey - * - * @return DEVICE_OK on success. - */ - int press(FunctionKey k); - - /** - * Press and releases the Key corresponding to the given character. - * - * @param k A valid character - * - * @return DEVICE_OK on success. - */ - int press(uint16_t c); - - /** - * Releases ALL keys on the keyboard (including Media keys) - * - * @return DEVICE_OK on success. - */ - int flush(); - - /** - * Type a sequence of keys - * - * @param seq A valid pointer to a KeySequence containing multiple keys. See ASCIIKeyMap.cpp for example usage. - * - * @return DEVICE_OK on success. - */ - int type(const KeySequence *seq); - - /** - * Type a sequence of characters - * - * @param s A valid pointer to a char array - * - * @param len The length of s. - * - * @return DEVICE_OK on success. - */ - int type(const char* s, uint32_t len); - - /** - * Type a sequence of characters - * - * @param s A ManagedString instance containing the characters to type. - * - * @return DEVICE_OK on success. - */ - int type(ManagedString s); - - HIDKeyboardReport reports[HID_KEYBOARD_NUM_REPORTS]; - - virtual int stdRequest(UsbEndpointIn &ctrl, USBSetup& setup); - virtual const InterfaceInfo *getInterfaceInfo(); - }; -} - +namespace codal { +enum KeyActionType { PressKey, ReleaseKey }; + +typedef struct { + uint8_t reportID; + uint8_t* keyState; + uint8_t reportSize; + uint8_t keyPressedCount; +} HIDKeyboardReport; + +class USBHIDKeyboard : public USBHID { + uint8_t keyStateGeneric[HID_KEYBOARD_KEYSTATE_SIZE_GENERIC]; + uint8_t keyStateConsumer[HID_KEYBOARD_KEYSTATE_SIZE_CONSUMER]; + + /** + * Writes the given report out over USB. + * + * @param report A pointer to the report to copy to USB + */ + int updateReport(HIDKeyboardReport* report); + + /** + * sets the media key buffer to the given Key, without affecting the state of other media keys. + * + * @param k a valid media key + * + * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if an incorrect key is passed. + */ + int mediaKeyPress(Key k, KeyActionType action); + + /** + * sets the keyboard modifier buffer to the given Key, without affecting the state of other keys. + * + * @param k a valid modifier key + * + * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if an incorrect key is passed. + */ + int modifierKeyPress(Key k, KeyActionType action); + + /** + * sets one keyboard key buffer slot to the given Key. + * + * @param k a valid modifier key + * + * @return DEVICE_OK on success + */ + int standardKeyPress(Key k, KeyActionType action); + + /** + * initialises the report arrays for this USBHID instance. + */ + void initReports(); + + public: + /** + * Default constructor for a USBHIDKeyboard instance, sets the KeyMap to an ASCII default . + */ + USBHIDKeyboard(); + + /** + * Constructor for a USBHIDKeyboard instance, sets the KeyMap to the given keymap. + * + * @param k The KeyMap to use. + */ + USBHIDKeyboard(KeyMap& k); + + /** + * Sets the KeyMap for this USBHIDKeyboard instance + * + * @param map The KeyMap to use. + * + * @return DEVICE_OK on success. + */ + int setKeyMap(KeyMap& map); + + /** + * Releases the given Key. + * + * @param k A valid Key + * + * @return DEVICE_OK on success. + */ + int keyUp(Key k); + + /** + * Releases the given Key. + * + * @param k A valid MediaKey + * + * @return DEVICE_OK on success. + */ + int keyUp(MediaKey k); + + /** + * Releases the given Key. + * + * @param k A valid FunctionKey + * + * @return DEVICE_OK on success. + */ + int keyUp(FunctionKey k); + + /** + * Release the key corresponding to the given character. + * + * @param c A valid character + * + * @return DEVICE_OK on success. + */ + int keyUp(uint16_t c); + + /** + * Press the given Key. + * + * @param k A valid Key + * + * @return DEVICE_OK on success. + */ + int keyDown(Key k); + + /** + * Press the given Key. + * + * @param k A valid MediaKey + * + * @return DEVICE_OK on success. + */ + int keyDown(MediaKey k); + + /** + * Press the given Key. + * + * @param k A valid FunctionKey + * + * @return DEVICE_OK on success. + */ + int keyDown(FunctionKey k); + + /** + * Press the key corresponding to the given character. + * + * @param c A valid character + * + * @return DEVICE_OK on success. + */ + int keyDown(uint16_t c); + + /** + * Presses and releases the given Key. + * + * @param k A valid Key + * + * @return DEVICE_OK on success. + */ + int press(Key k); + + /** + * Press and releases the given Key. + * + * @param k A valid MediaKey + * + * @return DEVICE_OK on success. + */ + int press(MediaKey k); + + /** + * Press and releases the given Key. + * + * @param k A valid FunctionKey + * + * @return DEVICE_OK on success. + */ + int press(FunctionKey k); + + /** + * Press and releases the Key corresponding to the given character. + * + * @param k A valid character + * + * @return DEVICE_OK on success. + */ + int press(uint16_t c); + + /** + * Releases ALL keys on the keyboard (including Media keys) + * + * @return DEVICE_OK on success. + */ + int flush(); + + /** + * Type a sequence of keys + * + * @param seq A valid pointer to a KeySequence containing multiple keys. See ASCIIKeyMap.cpp for example usage. + * + * @return DEVICE_OK on success. + */ + int type(const KeySequence* seq); + + /** + * Type a sequence of characters + * + * @param s A valid pointer to a char array + * + * @param len The length of s. + * + * @return DEVICE_OK on success. + */ + int type(const char* s, uint32_t len); + + /** + * Type a sequence of characters + * + * @param s A ManagedString instance containing the characters to type. + * + * @return DEVICE_OK on success. + */ + int type(ManagedString s); + + HIDKeyboardReport reports[HID_KEYBOARD_NUM_REPORTS]; + + virtual int stdRequest(UsbEndpointIn& ctrl, USBSetup& setup); + virtual const InterfaceInfo* getInterfaceInfo(); +}; +} // namespace codal #endif diff --git a/inc/drivers/HIDMouse.h b/inc/drivers/HIDMouse.h index 9a263aee..a69a63a9 100644 --- a/inc/drivers/HIDMouse.h +++ b/inc/drivers/HIDMouse.h @@ -29,53 +29,49 @@ DEALINGS IN THE SOFTWARE. #if CONFIG_ENABLED(DEVICE_USB) -namespace codal -{ - typedef enum { - HID_MOUSE_LEFT = 0x01, - HID_MOUSE_RIGHT = 0x02, - HID_MOUSE_MIDDLE = 0x04, - } USBHIDMouseButton; - - typedef union { - struct { - bool rightButton:1; - bool middleButton:1; - bool leftButton:1; - uint8_t reserved:5; - } bit; - uint8_t reg; - } HIDMouseButtons; - - typedef struct { - HIDMouseButtons buttons; - - int8_t xMovement; - int8_t yMovement; - int8_t wheelMovement; - - } __attribute__((packed)) HIDMouseState; - - class USBHIDMouse : public USBHID - { - -public: - USBHIDMouse(); - - virtual int stdRequest(UsbEndpointIn &ctrl, USBSetup& setup); - virtual const InterfaceInfo *getInterfaceInfo(); - - int buttonDown(USBHIDMouseButton b); - int buttonUp(USBHIDMouseButton b); - - int move(int8_t x, int8_t y); - int moveWheel(int8_t w); - -private: - int sendReport(); - }; -} - +namespace codal { +typedef enum { + HID_MOUSE_LEFT = 0x01, + HID_MOUSE_RIGHT = 0x02, + HID_MOUSE_MIDDLE = 0x04, +} USBHIDMouseButton; + +typedef union { + struct { + bool rightButton : 1; + bool middleButton : 1; + bool leftButton : 1; + uint8_t reserved : 5; + } bit; + uint8_t reg; +} HIDMouseButtons; + +typedef struct { + HIDMouseButtons buttons; + + int8_t xMovement; + int8_t yMovement; + int8_t wheelMovement; + +} __attribute__((packed)) HIDMouseState; + +class USBHIDMouse : public USBHID { + public: + USBHIDMouse(); + + virtual int stdRequest(UsbEndpointIn& ctrl, USBSetup& setup); + virtual const InterfaceInfo* getInterfaceInfo(); + + int buttonDown(USBHIDMouseButton b); + int buttonUp(USBHIDMouseButton b); + + int move(int8_t x, int8_t y); + int moveWheel(int8_t w); + + private: + int sendReport(); +}; +} // namespace codal #endif diff --git a/inc/drivers/ILI9341.h b/inc/drivers/ILI9341.h index a1f1983d..60cf2327 100644 --- a/inc/drivers/ILI9341.h +++ b/inc/drivers/ILI9341.h @@ -27,16 +27,14 @@ DEALINGS IN THE SOFTWARE. #include "ST7735.h" -namespace codal -{ +namespace codal { -class ILI9341 : public ST7735 -{ -public: - ILI9341(ScreenIO &io, Pin &cs, Pin &dc); +class ILI9341 : public ST7735 { + public: + ILI9341(ScreenIO& io, Pin& cs, Pin& dc); int init(); }; -} +} // namespace codal #endif \ No newline at end of file diff --git a/inc/drivers/KeyMap.h b/inc/drivers/KeyMap.h index ee9d31f5..4f3faf54 100644 --- a/inc/drivers/KeyMap.h +++ b/inc/drivers/KeyMap.h @@ -2,147 +2,140 @@ #define DEVICE_KEYMAP_H #include + #include -#define KEYMAP_ALL_KEYS_UP_Val 1 -#define KEYMAP_ALL_KEYS_UP_POS 28 -#define KEYMAP_ALL_KEYS_UP_MASK(x) ((uint32_t)x << KEYMAP_ALL_KEYS_UP_POS) -#define KEYMAP_ALL_KEYS_UP KEYMAP_ALL_KEYS_UP_MASK(KEYMAP_ALL_KEYS_UP_Val) - -#define KEYMAP_NORMAL_KEY_Val 0 -#define KEYMAP_MODIFIER_KEY_Val 1 -#define KEYMAP_MODIFIER_POS 29 -#define KEYMAP_MODIFIER_MASK(x) ((uint32_t)x << KEYMAP_MODIFIER_POS) -#define KEYMAP_MODIFIER_KEY KEYMAP_MODIFIER_MASK(KEYMAP_MODIFIER_KEY_Val) - -#define KEYMAP_MEDIA_KEY_Val 1 -#define KEYMAP_MEDIA_POS 30 -#define KEYMAP_MEDIA_MASK(x) ((uint32_t)x << KEYMAP_MEDIA_POS) -#define KEYMAP_MEDIA_KEY KEYMAP_MEDIA_MASK(KEYMAP_MEDIA_KEY_Val) - -#define KEYMAP_KEY_UP_Val 0 -#define KEYMAP_KEY_DOWN_Val 1 -#define KEYMAP_KEY_DOWN_POS 31 -#define KEYMAP_KEY_DOWN_MASK(x) ((uint32_t)x << KEYMAP_KEY_DOWN_POS) -#define KEYMAP_KEY_DOWN KEYMAP_KEY_DOWN_MASK(KEYMAP_KEY_DOWN_Val) -#define KEYMAP_KEY_UP KEYMAP_KEY_DOWN_MASK(KEYMAP_KEY_UP_Val) - -#define KEYMAP_REGISTER(x) { .seq = x, .length = sizeof(x)/sizeof(Key) } - -namespace codal -{ - typedef enum - { - Mute, - VolumeUp, - VolumeDown, - PlayPause, - Stop, - PreviousTrack, - NextTrack, - Mail, - Calculator, - WebSearch, - WebHome, - WebFavourites, - WebRefresh, - WebStop, - WebForward, - WebBack - } MediaKey; - - typedef enum - { - F1Key = 0x3a, /* F1 key */ - F2Key, /* F2 key */ - F3Key, /* F3 key */ - F4Key, /* F4 key */ - F5Key, /* F5 key */ - F6Key, /* F6 key */ - F7Key, /* F7 key */ - F8Key, /* F8 key */ - F9Key, /* F9 key */ - F10Key, /* F10 key */ - F11Key, /* F11 key */ - F12Key, /* F12 key */ - - PrintScreen = 0x46, /* Print Screen key */ - ScrollLock, /* Scroll lock */ - Pause, /* pause key */ - Insert, /* Insert key */ - Home, /* Home key */ - PageUp, /* Page Up key */ - DeleteForward, /* Delete Forward */ - End, /* End */ - PageDown, /* Page Down key */ - - RightArrow = 0x4F, /* Right arrow */ - LeftArrow, /* Left arrow */ - DownArrow, /* Down arrow */ - UpArrow, /* Up arrow */ - } FunctionKey; - - typedef union +#define KEYMAP_ALL_KEYS_UP_Val 1 +#define KEYMAP_ALL_KEYS_UP_POS 28 +#define KEYMAP_ALL_KEYS_UP_MASK(x) ((uint32_t)x << KEYMAP_ALL_KEYS_UP_POS) +#define KEYMAP_ALL_KEYS_UP KEYMAP_ALL_KEYS_UP_MASK(KEYMAP_ALL_KEYS_UP_Val) + +#define KEYMAP_NORMAL_KEY_Val 0 +#define KEYMAP_MODIFIER_KEY_Val 1 +#define KEYMAP_MODIFIER_POS 29 +#define KEYMAP_MODIFIER_MASK(x) ((uint32_t)x << KEYMAP_MODIFIER_POS) +#define KEYMAP_MODIFIER_KEY KEYMAP_MODIFIER_MASK(KEYMAP_MODIFIER_KEY_Val) + +#define KEYMAP_MEDIA_KEY_Val 1 +#define KEYMAP_MEDIA_POS 30 +#define KEYMAP_MEDIA_MASK(x) ((uint32_t)x << KEYMAP_MEDIA_POS) +#define KEYMAP_MEDIA_KEY KEYMAP_MEDIA_MASK(KEYMAP_MEDIA_KEY_Val) + +#define KEYMAP_KEY_UP_Val 0 +#define KEYMAP_KEY_DOWN_Val 1 +#define KEYMAP_KEY_DOWN_POS 31 +#define KEYMAP_KEY_DOWN_MASK(x) ((uint32_t)x << KEYMAP_KEY_DOWN_POS) +#define KEYMAP_KEY_DOWN KEYMAP_KEY_DOWN_MASK(KEYMAP_KEY_DOWN_Val) +#define KEYMAP_KEY_UP KEYMAP_KEY_DOWN_MASK(KEYMAP_KEY_UP_Val) + +#define KEYMAP_REGISTER(x) \ + { \ + .seq = x, .length = sizeof(x) / sizeof(Key) \ + } + +namespace codal { +typedef enum { + Mute, + VolumeUp, + VolumeDown, + PlayPause, + Stop, + PreviousTrack, + NextTrack, + Mail, + Calculator, + WebSearch, + WebHome, + WebFavourites, + WebRefresh, + WebStop, + WebForward, + WebBack +} MediaKey; + +typedef enum { + F1Key = 0x3a, /* F1 key */ + F2Key, /* F2 key */ + F3Key, /* F3 key */ + F4Key, /* F4 key */ + F5Key, /* F5 key */ + F6Key, /* F6 key */ + F7Key, /* F7 key */ + F8Key, /* F8 key */ + F9Key, /* F9 key */ + F10Key, /* F10 key */ + F11Key, /* F11 key */ + F12Key, /* F12 key */ + + PrintScreen = 0x46, /* Print Screen key */ + ScrollLock, /* Scroll lock */ + Pause, /* pause key */ + Insert, /* Insert key */ + Home, /* Home key */ + PageUp, /* Page Up key */ + DeleteForward, /* Delete Forward */ + End, /* End */ + PageDown, /* Page Down key */ + + RightArrow = 0x4F, /* Right arrow */ + LeftArrow, /* Left arrow */ + DownArrow, /* Down arrow */ + UpArrow, /* Up arrow */ +} FunctionKey; + +typedef union { + struct { + uint16_t code : 16; + uint16_t reserved : 12; + bool allKeysUp : 1; + bool isModifier : 1; + bool isMedia : 1; + bool isKeyDown : 1; + } bit; + uint32_t reg; +} Key; + +typedef struct { + const Key* seq; + uint8_t length; +} KeySequence; + +class KeyMap { + protected: + const KeySequence* map; + + public: + uint32_t length; + + KeyMap() { length = 0; } + + KeyMap(const KeySequence* seq, uint32_t len) { - struct { - uint16_t code:16; - uint16_t reserved:12; - bool allKeysUp:1; - bool isModifier:1; - bool isMedia:1; - bool isKeyDown:1; - } bit; - uint32_t reg; - } Key; - - typedef struct{ - const Key* seq; - uint8_t length; - } KeySequence; - - class KeyMap - { - protected: - const KeySequence* map; - - public: - uint32_t length; - - KeyMap() - { - length = 0; - } - - KeyMap(const KeySequence* seq, uint32_t len) - { - map = seq; - length = len; - }; + map = seq; + length = len; + }; - Key getMediaKey(MediaKey t) - { - Key k; + Key getMediaKey(MediaKey t) + { + Key k; - // shift t by 8 (network byte order) - k.reg = KEYMAP_KEY_DOWN | KEYMAP_MEDIA_KEY | (1 << t); + // shift t by 8 (network byte order) + k.reg = KEYMAP_KEY_DOWN | KEYMAP_MEDIA_KEY | (1 << t); - return k; - } + return k; + } - Key getFunctionKey(FunctionKey t) - { - Key k; + Key getFunctionKey(FunctionKey t) + { + Key k; - k.reg = KEYMAP_KEY_DOWN | t; + k.reg = KEYMAP_KEY_DOWN | t; - return k; - } + return k; + } - virtual const KeySequence* mapCharacter(uint16_t c) - { - return NULL; - }; - }; -} + virtual const KeySequence* mapCharacter(uint16_t c) { return NULL; }; +}; +} // namespace codal #endif \ No newline at end of file diff --git a/inc/drivers/KeyValueStorage.h b/inc/drivers/KeyValueStorage.h index fb67c7d8..b0094e6a 100644 --- a/inc/drivers/KeyValueStorage.h +++ b/inc/drivers/KeyValueStorage.h @@ -27,204 +27,194 @@ DEALINGS IN THE SOFTWARE. #define KEY_VALUE_STORAGE_H #include "CodalConfig.h" -#include "ManagedString.h" #include "ErrorNo.h" +#include "ManagedString.h" #include "NVMController.h" #ifndef DEVICE_KEY_VALUE_STORE_OFFSET -#define DEVICE_KEY_VALUE_STORE_OFFSET -4 +#define DEVICE_KEY_VALUE_STORE_OFFSET -4 #endif -#define KEY_VALUE_STORAGE_MAGIC 0xC0DA1 - -#define KEY_VALUE_STORAGE_BLOCK_SIZE 48 -#define KEY_VALUE_STORAGE_KEY_SIZE 16 -#define KEY_VALUE_STORAGE_VALUE_SIZE KEY_VALUE_STORAGE_BLOCK_SIZE - KEY_VALUE_STORAGE_KEY_SIZE - -#define KEY_VALUE_STORAGE_SCRATCH_WORD_SIZE 64 - -#define KEY_VALUE_STORAGE_MAX_PAIRS 5 - -namespace codal -{ - struct KeyValuePair - { - uint8_t key[KEY_VALUE_STORAGE_KEY_SIZE]; - uint8_t value[KEY_VALUE_STORAGE_VALUE_SIZE]; - }; - - struct KeyValueStore - { - uint32_t magic; - uint32_t size; - - KeyValueStore(uint32_t magic, uint32_t size) - { - this->magic = magic; - this->size = size; - } - - KeyValueStore() - { - this->magic = 0; - this->size = 0; - } - }; - - - /** - * Class definition for the KeyValueStorage class. - * This allows reading and writing of small blocks of data to FLASH memory. - * - * This class operates as a key value store, it allows the retrieval, addition - * and deletion of KeyValuePairs. - * - * The first 8 bytes are reserved for the KeyValueStore struct which gives core - * information such as the number of KeyValuePairs in the store, and whether the - * store has been initialised. - * - * After the KeyValueStore struct, KeyValuePairs are arranged contiguously until - * the end of the block used as persistent storage. - * - * |-------8-------|--------48-------|-----|---------48--------| - * | KeyValueStore | KeyValuePair[0] | ... | KeyValuePair[N-1] | - * |---------------|-----------------|-----|-------------------| - */ - class KeyValueStorage - { - uint32_t flashPagePtr; - NVMController& controller; - uint32_t *scratch; - - public: - - /** - * Constructor. - * - * Creates an instance of KeyValueStorage which acts like a KeyValueStore - * that allows the retrieval, addition and deletion of KeyValuePairs. - * - * @param controller The non-volatile storage controller to use - * @param pageNumber The logical page number for this KeyValueStorage. - * Optionally use negative number to count from end of address space. - */ - KeyValueStorage(NVMController& controller, int pageNumber = DEVICE_KEY_VALUE_STORE_OFFSET); - - /** - * Places a given key, and it's corresponding value into flash at the earliest - * available point. - * - * @param key the unique name that should be used as an identifier for the given data. - * The key is presumed to be null terminated. - * - * @param data a pointer to the beginning of the data to be persisted. - * - * @param dataSize the size of the data to be persisted - * - * @return KEY_VALUE_OK on success, KEY_VALUE_INVALID_PARAMETER if the key or size is too large, - * KEY_VALUE_NO_RESOURCES if the storage page is full - */ - int put(const char* key, uint8_t* data, int dataSize); - - - /** - * Places a given key, and it's corresponding value into flash at the earliest - * available point. - * - * @param key the unique name that should be used as an identifier for the given data. - * - * @param data a pointer to the beginning of the data to be persisted. - * - * @param dataSize the size of the data to be persisted - * - * @return KEY_VALUE_OK on success, KEY_VALUE_INVALID_PARAMETER if the key or size is too large, - * KEY_VALUE_NO_RESOURCES if the storage page is full - */ - int put(ManagedString key, uint8_t* data, int dataSize); - - /** - * Retreives a KeyValuePair identified by a given key. - * - * @param key the unique name used to identify a KeyValuePair in flash. - * - * @return a pointer to a heap allocated KeyValuePair struct, this pointer will be - * NULL if the key was not found in storage. - * - * @note it is up to the user to free memory after use. - */ - KeyValuePair* get(const char* key); - - /** - * Retreives a KeyValuePair identified by a given key. - * - * @param key the unique name used to identify a KeyValuePair in flash. - * - * @return a pointer to a heap allocated KeyValuePair struct, this pointer will be - * NULL if the key was not found in storage. - * - * @note it is up to the user to free memory after use. - */ - KeyValuePair* get(ManagedString key); - - /** - * Removes a KeyValuePair identified by a given key. - * - * @param key the unique name used to identify a KeyValuePair in flash. - * - * @return KEY_VALUE_OK on success, or KEY_VALUE_NO_DATA if the given key - * was not found in flash. - */ - int remove(const char* key); - - /** - * Removes a KeyValuePair identified by a given key. - * - * @param key the unique name used to identify a KeyValuePair in flash. - * - * @return KEY_VALUE_OK on success, or KEY_VALUE_NO_DATA if the given key - * was not found in flash. - */ - int remove(ManagedString key); - - /** - * The size of the flash based KeyValueStore. - * - * @return the number of entries in the key value store - */ - int size(); - - /** - * Erase all contents of this KeyValue store - */ - int wipe(); - - private: - - /** - * Function to lazily instatiate a scratch buffer - */ - void scratchReset(); - - /** - * Function for populating the scratch page with a KeyValueStore. - * - * @param store the KeyValueStore struct to write to the scratch page. - */ - void scratchKeyValueStore(KeyValueStore store); - - /** - * Function for populating the scratch page with a KeyValuePair. - * - * @param pair the KeyValuePair struct to write to the scratch page. - * - * @param flashPointer the pointer in flash where this KeyValuePair resides. This pointer - * is used to determine the offset into the scratch page, where the KeyValuePair should - * be written. - */ - void scratchKeyValuePair(KeyValuePair pair, int scratchOffset); - - - }; -} +#define KEY_VALUE_STORAGE_MAGIC 0xC0DA1 + +#define KEY_VALUE_STORAGE_BLOCK_SIZE 48 +#define KEY_VALUE_STORAGE_KEY_SIZE 16 +#define KEY_VALUE_STORAGE_VALUE_SIZE KEY_VALUE_STORAGE_BLOCK_SIZE - KEY_VALUE_STORAGE_KEY_SIZE + +#define KEY_VALUE_STORAGE_SCRATCH_WORD_SIZE 64 + +#define KEY_VALUE_STORAGE_MAX_PAIRS 5 + +namespace codal { +struct KeyValuePair { + uint8_t key[KEY_VALUE_STORAGE_KEY_SIZE]; + uint8_t value[KEY_VALUE_STORAGE_VALUE_SIZE]; +}; + +struct KeyValueStore { + uint32_t magic; + uint32_t size; + + KeyValueStore(uint32_t magic, uint32_t size) + { + this->magic = magic; + this->size = size; + } + + KeyValueStore() + { + this->magic = 0; + this->size = 0; + } +}; + +/** + * Class definition for the KeyValueStorage class. + * This allows reading and writing of small blocks of data to FLASH memory. + * + * This class operates as a key value store, it allows the retrieval, addition + * and deletion of KeyValuePairs. + * + * The first 8 bytes are reserved for the KeyValueStore struct which gives core + * information such as the number of KeyValuePairs in the store, and whether the + * store has been initialised. + * + * After the KeyValueStore struct, KeyValuePairs are arranged contiguously until + * the end of the block used as persistent storage. + * + * |-------8-------|--------48-------|-----|---------48--------| + * | KeyValueStore | KeyValuePair[0] | ... | KeyValuePair[N-1] | + * |---------------|-----------------|-----|-------------------| + */ +class KeyValueStorage { + uint32_t flashPagePtr; + NVMController& controller; + uint32_t* scratch; + + public: + /** + * Constructor. + * + * Creates an instance of KeyValueStorage which acts like a KeyValueStore + * that allows the retrieval, addition and deletion of KeyValuePairs. + * + * @param controller The non-volatile storage controller to use + * @param pageNumber The logical page number for this KeyValueStorage. + * Optionally use negative number to count from end of address space. + */ + KeyValueStorage(NVMController& controller, int pageNumber = DEVICE_KEY_VALUE_STORE_OFFSET); + + /** + * Places a given key, and it's corresponding value into flash at the earliest + * available point. + * + * @param key the unique name that should be used as an identifier for the given data. + * The key is presumed to be null terminated. + * + * @param data a pointer to the beginning of the data to be persisted. + * + * @param dataSize the size of the data to be persisted + * + * @return KEY_VALUE_OK on success, KEY_VALUE_INVALID_PARAMETER if the key or size is too large, + * KEY_VALUE_NO_RESOURCES if the storage page is full + */ + int put(const char* key, uint8_t* data, int dataSize); + + /** + * Places a given key, and it's corresponding value into flash at the earliest + * available point. + * + * @param key the unique name that should be used as an identifier for the given data. + * + * @param data a pointer to the beginning of the data to be persisted. + * + * @param dataSize the size of the data to be persisted + * + * @return KEY_VALUE_OK on success, KEY_VALUE_INVALID_PARAMETER if the key or size is too large, + * KEY_VALUE_NO_RESOURCES if the storage page is full + */ + int put(ManagedString key, uint8_t* data, int dataSize); + + /** + * Retreives a KeyValuePair identified by a given key. + * + * @param key the unique name used to identify a KeyValuePair in flash. + * + * @return a pointer to a heap allocated KeyValuePair struct, this pointer will be + * NULL if the key was not found in storage. + * + * @note it is up to the user to free memory after use. + */ + KeyValuePair* get(const char* key); + + /** + * Retreives a KeyValuePair identified by a given key. + * + * @param key the unique name used to identify a KeyValuePair in flash. + * + * @return a pointer to a heap allocated KeyValuePair struct, this pointer will be + * NULL if the key was not found in storage. + * + * @note it is up to the user to free memory after use. + */ + KeyValuePair* get(ManagedString key); + + /** + * Removes a KeyValuePair identified by a given key. + * + * @param key the unique name used to identify a KeyValuePair in flash. + * + * @return KEY_VALUE_OK on success, or KEY_VALUE_NO_DATA if the given key + * was not found in flash. + */ + int remove(const char* key); + + /** + * Removes a KeyValuePair identified by a given key. + * + * @param key the unique name used to identify a KeyValuePair in flash. + * + * @return KEY_VALUE_OK on success, or KEY_VALUE_NO_DATA if the given key + * was not found in flash. + */ + int remove(ManagedString key); + + /** + * The size of the flash based KeyValueStore. + * + * @return the number of entries in the key value store + */ + int size(); + + /** + * Erase all contents of this KeyValue store + */ + int wipe(); + + private: + /** + * Function to lazily instatiate a scratch buffer + */ + void scratchReset(); + + /** + * Function for populating the scratch page with a KeyValueStore. + * + * @param store the KeyValueStore struct to write to the scratch page. + */ + void scratchKeyValueStore(KeyValueStore store); + + /** + * Function for populating the scratch page with a KeyValuePair. + * + * @param pair the KeyValuePair struct to write to the scratch page. + * + * @param flashPointer the pointer in flash where this KeyValuePair resides. This pointer + * is used to determine the offset into the scratch page, where the KeyValuePair should + * be written. + */ + void scratchKeyValuePair(KeyValuePair pair, int scratchOffset); +}; +} // namespace codal #endif \ No newline at end of file diff --git a/inc/drivers/LEDMatrix.h b/inc/drivers/LEDMatrix.h index a823329b..30fa80a0 100644 --- a/inc/drivers/LEDMatrix.h +++ b/inc/drivers/LEDMatrix.h @@ -25,24 +25,24 @@ DEALINGS IN THE SOFTWARE. #ifndef LED_MATRIX_H #define LED_MATRIX_H -#include "CodalConfig.h" -#include "ManagedString.h" #include "CodalComponent.h" +#include "CodalConfig.h" #include "Display.h" #include "Image.h" +#include "ManagedString.h" #include "Pin.h" #include "Timer.h" // // Internal constants // -#define LED_MATRIX_GREYSCALE_BIT_DEPTH 8 +#define LED_MATRIX_GREYSCALE_BIT_DEPTH 8 // // Event codes raised by an LEDMatrix // -#define LED_MATRIX_EVT_LIGHT_SENSE 2 -#define LED_MATRIX_EVT_FRAME_TIMEOUT 3 +#define LED_MATRIX_EVT_LIGHT_SENSE 2 +#define LED_MATRIX_EVT_FRAME_TIMEOUT 3 // // Compile Time Configuration Options @@ -51,226 +51,220 @@ DEALINGS IN THE SOFTWARE. // Selects the minimum permissable brightness level for the device // in the region of 0 (off) to 255 (full brightness) #ifndef LED_MATRIX_MINIMUM_BRIGHTNESS -#define LED_MATRIX_MINIMUM_BRIGHTNESS 1 +#define LED_MATRIX_MINIMUM_BRIGHTNESS 1 #endif // Selects the maximum permissable brightness level for the device // in the region of 0 (off) to 255 (full brightness) #ifndef LED_MATRIX_MAXIMUM_BRIGHTNESS -#define LED_MATRIX_MAXIMUM_BRIGHTNESS 255 +#define LED_MATRIX_MAXIMUM_BRIGHTNESS 255 #endif // Selects the default brightness for the display // in the region of zero (off) to 255 (full brightness) #ifndef LED_MATRIX_DEFAULT_BRIGHTNESS -#define LED_MATRIX_DEFAULT_BRIGHTNESS LED_MATRIX_MAXIMUM_BRIGHTNESS +#define LED_MATRIX_DEFAULT_BRIGHTNESS LED_MATRIX_MAXIMUM_BRIGHTNESS #endif -namespace codal -{ - // - // The different modes that this driver can operate in - // - enum DisplayMode { - DISPLAY_MODE_BLACK_AND_WHITE, - DISPLAY_MODE_GREYSCALE, - DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE, - DISPLAY_MODE_GREYSCALE_LIGHT_SENSE - }; +namespace codal { +// +// The different modes that this driver can operate in +// +enum DisplayMode { + DISPLAY_MODE_BLACK_AND_WHITE, + DISPLAY_MODE_GREYSCALE, + DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE, + DISPLAY_MODE_GREYSCALE_LIGHT_SENSE +}; + +// +// Valid rotation settings. +// +enum DisplayRotation { + MATRIX_DISPLAY_ROTATION_0, + MATRIX_DISPLAY_ROTATION_90, + MATRIX_DISPLAY_ROTATION_180, + MATRIX_DISPLAY_ROTATION_270 +}; + +/** + * Provides the mapping from Matrix ROW/COL to a linear X/Y buffer. + * Arranged such that matrixMap[col, row] provides the [x,y] screen co-ordinate. + */ + +struct MatrixPoint { + uint8_t x; + uint8_t y; +}; +#define NO_CONN 0 + +/** + * This struct presumes rows and columns are arranged contiguously... + */ +struct MatrixMap { + int width; // The physical width of the LED matrix, in pixels. + int height; // The physical height of the LED matrix, in pixels. + int rows; // The number of drive pins connected to LEDs. + int columns; // The number of sink pins connected to the LEDs. + + Pin** rowPins; // Array of pointers containing an ordered list of pins to drive. + Pin** columnPins; // Array of pointers containing an ordered list of pins to sink. + + const MatrixPoint* map; // Table mapping logical LED positions to physical positions. +}; + +/** + * Class definition for LEDMatrix. + * + * Represents an LED matrix array. + */ +class LEDMatrix : public Display { + uint8_t strobeRow; + uint8_t rotation; + uint8_t mode; + uint8_t greyscaleBitMsk; + uint8_t timingCount; + int frameTimeout; // - // Valid rotation settings. + // State used by all animation routines. // - enum DisplayRotation { - MATRIX_DISPLAY_ROTATION_0, - MATRIX_DISPLAY_ROTATION_90, - MATRIX_DISPLAY_ROTATION_180, - MATRIX_DISPLAY_ROTATION_270 - }; + + const MatrixMap& matrixMap; + + // Internal methods to handle animation. /** - * Provides the mapping from Matrix ROW/COL to a linear X/Y buffer. - * Arranged such that matrixMap[col, row] provides the [x,y] screen co-ordinate. + * Called by the display in an interval determined by the brightness of the display, to give an impression + * of brightness. */ + void renderFinish(); - struct MatrixPoint - { - uint8_t x; - uint8_t y; - }; -#define NO_CONN 0 + /** + * Event handler, called when a requested time has elapsed (used for brightness control). + */ + void onTimeoutEvent(Event); + + /** + * Translates a bit mask to a bit mask suitable for the nrf PORT0 and PORT1. + * Brightness has two levels on, or off. + */ + void render(); + + /** + * Renders the current image, and drops the fourth frame to allow for + * sensors that require the display to operate. + */ + void renderWithLightSense(); + + /** + * Translates a bit mask into a timer interrupt that gives the appearence of greyscale. + */ + void renderGreyscale(); + + /** + * Enables or disables the display entirely, and releases the pins for other uses. + * + * @param enableDisplay true to enabled the display, or false to disable it. + */ + void setEnable(bool enableDisplay); + + public: + /** + * Constructor. + * + * Create a software representation of a LED matrix. + * The display is initially blank. + * + * @param map The mapping information that relates pin inputs/outputs to physical screen coordinates. + * @param id The id the display should use when sending events on the MessageBus. Defaults to DEVICE_ID_DISPLAY. + * + */ + LEDMatrix(const MatrixMap& map, uint16_t id = DEVICE_ID_DISPLAY); + + /** + * Frame update method, invoked periodically to strobe the display. + */ + virtual void periodicCallback(); + + /** + * Configures the mode of the display. + * + * @param mode The mode to swap the display into. One of: DISPLAY_MODE_GREYSCALE, + * DISPLAY_MODE_BLACK_AND_WHITE, DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE + * + * @code + * display.setDisplayMode(DISPLAY_MODE_GREYSCALE); //per pixel brightness + * @endcode + */ + void setDisplayMode(DisplayMode mode); + + /** + * Retrieves the mode of the display. + * + * @return the current mode of the display + */ + int getDisplayMode(); + + /** + * Rotates the display to the given position. + * + * Axis aligned values only. + * + * @code + * display.rotateTo(DISPLAY_ROTATION_180); //rotates 180 degrees from original orientation + * @endcode + */ + void rotateTo(DisplayRotation position); /** - * This struct presumes rows and columns are arranged contiguously... + * Enables the display, should only be called if the display is disabled. + * + * @code + * display.enable(); //Enables the display mechanics + * @endcode + * + * @note Only enables the display if the display is currently disabled. */ - struct MatrixMap - { - int width; // The physical width of the LED matrix, in pixels. - int height; // The physical height of the LED matrix, in pixels. - int rows; // The number of drive pins connected to LEDs. - int columns; // The number of sink pins connected to the LEDs. + virtual void enable(); - Pin **rowPins; // Array of pointers containing an ordered list of pins to drive. - Pin **columnPins; // Array of pointers containing an ordered list of pins to sink. + /** + * Disables the display, which releases control of the GPIO pins used by the display, + * which are exposed on the edge connector. + * + * @code + * display.disable(); //disables the display + * @endcode + * + * @note Only disables the display if the display is currently enabled. + */ + virtual void disable(); - const MatrixPoint *map; // Table mapping logical LED positions to physical positions. - }; + /** + * Clears the display of any remaining pixels. + * + * `display.image.clear()` can also be used! + * + * @code + * display.clear(); //clears the display + * @endcode + */ + void clear(); /** - * Class definition for LEDMatrix. + * Configures the brightness of the display. * - * Represents an LED matrix array. + * @param b The brightness to set the brightness to, in the range 0 - 255. + * + * @return DEVICE_OK, or DEVICE_INVALID_PARAMETER + */ + virtual int setBrightness(int b); + + /** + * Destructor for CodalDisplay, where we deregister this instance from the array of system components. */ - class LEDMatrix : public Display - { - uint8_t strobeRow; - uint8_t rotation; - uint8_t mode; - uint8_t greyscaleBitMsk; - uint8_t timingCount; - int frameTimeout; - - // - // State used by all animation routines. - // - - const MatrixMap &matrixMap; - - // Internal methods to handle animation. - - /** - * Called by the display in an interval determined by the brightness of the display, to give an impression - * of brightness. - */ - void renderFinish(); - - /** - * Event handler, called when a requested time has elapsed (used for brightness control). - */ - void onTimeoutEvent(Event); - - /** - * Translates a bit mask to a bit mask suitable for the nrf PORT0 and PORT1. - * Brightness has two levels on, or off. - */ - void render(); - - /** - * Renders the current image, and drops the fourth frame to allow for - * sensors that require the display to operate. - */ - void renderWithLightSense(); - - /** - * Translates a bit mask into a timer interrupt that gives the appearence of greyscale. - */ - void renderGreyscale(); - - /** - * Enables or disables the display entirely, and releases the pins for other uses. - * - * @param enableDisplay true to enabled the display, or false to disable it. - */ - void setEnable(bool enableDisplay); - - public: - - /** - * Constructor. - * - * Create a software representation of a LED matrix. - * The display is initially blank. - * - * @param map The mapping information that relates pin inputs/outputs to physical screen coordinates. - * @param id The id the display should use when sending events on the MessageBus. Defaults to DEVICE_ID_DISPLAY. - * - */ - LEDMatrix(const MatrixMap &map, uint16_t id = DEVICE_ID_DISPLAY); - - /** - * Frame update method, invoked periodically to strobe the display. - */ - virtual void periodicCallback(); - - /** - * Configures the mode of the display. - * - * @param mode The mode to swap the display into. One of: DISPLAY_MODE_GREYSCALE, - * DISPLAY_MODE_BLACK_AND_WHITE, DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE - * - * @code - * display.setDisplayMode(DISPLAY_MODE_GREYSCALE); //per pixel brightness - * @endcode - */ - void setDisplayMode(DisplayMode mode); - - /** - * Retrieves the mode of the display. - * - * @return the current mode of the display - */ - int getDisplayMode(); - - /** - * Rotates the display to the given position. - * - * Axis aligned values only. - * - * @code - * display.rotateTo(DISPLAY_ROTATION_180); //rotates 180 degrees from original orientation - * @endcode - */ - void rotateTo(DisplayRotation position); - - /** - * Enables the display, should only be called if the display is disabled. - * - * @code - * display.enable(); //Enables the display mechanics - * @endcode - * - * @note Only enables the display if the display is currently disabled. - */ - virtual void enable(); - - /** - * Disables the display, which releases control of the GPIO pins used by the display, - * which are exposed on the edge connector. - * - * @code - * display.disable(); //disables the display - * @endcode - * - * @note Only disables the display if the display is currently enabled. - */ - virtual void disable(); - - /** - * Clears the display of any remaining pixels. - * - * `display.image.clear()` can also be used! - * - * @code - * display.clear(); //clears the display - * @endcode - */ - void clear(); - - /** - * Configures the brightness of the display. - * - * @param b The brightness to set the brightness to, in the range 0 - 255. - * - * @return DEVICE_OK, or DEVICE_INVALID_PARAMETER - */ - virtual int setBrightness(int b); - - - /** - * Destructor for CodalDisplay, where we deregister this instance from the array of system components. - */ - ~LEDMatrix(); - }; -} + ~LEDMatrix(); +}; +} // namespace codal #endif \ No newline at end of file diff --git a/inc/drivers/LIS3DH.h b/inc/drivers/LIS3DH.h index bf4270ae..39981a9b 100644 --- a/inc/drivers/LIS3DH.h +++ b/inc/drivers/LIS3DH.h @@ -25,145 +25,143 @@ DEALINGS IN THE SOFTWARE. #ifndef LIS3DH_H #define LIS3DH_H -#include "CodalConfig.h" +#include "Accelerometer.h" #include "CodalComponent.h" +#include "CodalConfig.h" #include "CodalUtil.h" #include "CoordinateSystem.h" -#include "Pin.h" #include "I2C.h" -#include "Accelerometer.h" +#include "Pin.h" + +/** + * Status flags + */ +#define ACCELEROMETER_IMU_DATA_VALID 0x02 /** - * Status flags - */ -#define ACCELEROMETER_IMU_DATA_VALID 0x02 + * I2C constants + */ +#define LIS3DH_DEFAULT_ADDR 0x32 /** - * I2C constants - */ -#define LIS3DH_DEFAULT_ADDR 0x32 + * LIS3DH Register map (partial) + */ +#define LIS3DH_STATUS_REG 0x27 +#define LIS3DH_STATUS_REG_AUX 0x07 +#define LIS3DH_OUT_X_L 0x28 +#define LIS3DH_OUT_X_H 0x29 +#define LIS3DH_OUT_Y_L 0x2A +#define LIS3DH_OUT_Y_H 0x2B +#define LIS3DH_OUT_Z_L 0x2C +#define LIS3DH_OUT_Z_H 0x2D +#define LIS3DH_WHOAMI 0x0F +#define LIS3DH_CTRL_REG0 0x1E +#define LIS3DH_CTRL_REG1 0x20 +#define LIS3DH_CTRL_REG2 0x21 +#define LIS3DH_CTRL_REG3 0x22 +#define LIS3DH_CTRL_REG4 0x23 +#define LIS3DH_CTRL_REG5 0x24 +#define LIS3DH_CTRL_REG6 0x25 + +#define LIS3DH_FIFO_CTRL_REG 0x2E +#define LIS3DH_FIFO_SRC_REG 0x2F +#define LIS3DH_INT1_CFG 0x30 +#define LIS3DH_INT1_SRC 0x31 +#define LIS3DH_INT1_THS 0x32 +#define LIS3DH_INT1_DURATION 0x33 +#define LIS3DH_INT2_CFG 0x34 +#define LIS3DH_INT2_SRC 0x35 +#define LIS3DH_INT2_THS 0x36 +#define LIS3DH_INT2_DURATION 0x37 /** - * LIS3DH Register map (partial) - */ -#define LIS3DH_STATUS_REG 0x27 -#define LIS3DH_STATUS_REG_AUX 0x07 -#define LIS3DH_OUT_X_L 0x28 -#define LIS3DH_OUT_X_H 0x29 -#define LIS3DH_OUT_Y_L 0x2A -#define LIS3DH_OUT_Y_H 0x2B -#define LIS3DH_OUT_Z_L 0x2C -#define LIS3DH_OUT_Z_H 0x2D -#define LIS3DH_WHOAMI 0x0F -#define LIS3DH_CTRL_REG0 0x1E -#define LIS3DH_CTRL_REG1 0x20 -#define LIS3DH_CTRL_REG2 0x21 -#define LIS3DH_CTRL_REG3 0x22 -#define LIS3DH_CTRL_REG4 0x23 -#define LIS3DH_CTRL_REG5 0x24 -#define LIS3DH_CTRL_REG6 0x25 - -#define LIS3DH_FIFO_CTRL_REG 0x2E -#define LIS3DH_FIFO_SRC_REG 0x2F -#define LIS3DH_INT1_CFG 0x30 -#define LIS3DH_INT1_SRC 0x31 -#define LIS3DH_INT1_THS 0x32 -#define LIS3DH_INT1_DURATION 0x33 -#define LIS3DH_INT2_CFG 0x34 -#define LIS3DH_INT2_SRC 0x35 -#define LIS3DH_INT2_THS 0x36 -#define LIS3DH_INT2_DURATION 0x37 + * MMA8653 constants + */ +#define LIS3DH_WHOAMI_VAL 0x33 +namespace codal { /** - * MMA8653 constants - */ -#define LIS3DH_WHOAMI_VAL 0x33 + * Class definition for Accelerometer. + * + * Represents an implementation of the Freescale MMA8653 3 axis accelerometer + * Also includes basic data caching and on demand activation. + */ +class LIS3DH : public Accelerometer { + I2C& i2c; // The I2C interface to use. + Pin& int1; // Data ready interrupt. + uint16_t address; // I2C address of this accelerometer. + + public: + /** + * Constructor. + * Create a software abstraction of an accelerometer. + * + * @param _i2c an instance of I2C used to communicate with the onboard accelerometer. + * + * @param address the default I2C address of the accelerometer. Defaults to: MMA8653_DEFAULT_ADDR. + * + * @param id the unique EventModel id of this component. Defaults to: DEVICE_ID_ACCELEROMETER + * + * @param coordinateSystem the orientation of the sensor. Defaults to: SIMPLE_CARTESIAN + * + * @code + * I2C i2c = I2C(I2C_SDA0, I2C_SCL0); + * + * Accelerometer accelerometer = Accelerometer(i2c); + * @endcode + */ + LIS3DH(I2C& _i2c, Pin& _int1, CoordinateSpace& coordinateSpace, uint16_t address = LIS3DH_DEFAULT_ADDR, + uint16_t id = DEVICE_ID_ACCELEROMETER); + + /** + * Attempts to read the 8 bit ID from the accelerometer, this can be used for + * validation purposes. + * + * @return the 8 bit ID returned by the accelerometer, or DEVICE_I2C_ERROR if the request fails. + * + * @code + * accelerometer.whoAmI(); + * @endcode + */ + int whoAmI(); -namespace codal -{ /** - * Class definition for Accelerometer. + * A periodic callback invoked by the fiber scheduler idle thread. * - * Represents an implementation of the Freescale MMA8653 3 axis accelerometer - * Also includes basic data caching and on demand activation. + * Internally calls updateSample(). */ - class LIS3DH : public Accelerometer - { - I2C& i2c; // The I2C interface to use. - Pin &int1; // Data ready interrupt. - uint16_t address; // I2C address of this accelerometer. - - public: - - /** - * Constructor. - * Create a software abstraction of an accelerometer. - * - * @param _i2c an instance of I2C used to communicate with the onboard accelerometer. - * - * @param address the default I2C address of the accelerometer. Defaults to: MMA8653_DEFAULT_ADDR. - * - * @param id the unique EventModel id of this component. Defaults to: DEVICE_ID_ACCELEROMETER - * - * @param coordinateSystem the orientation of the sensor. Defaults to: SIMPLE_CARTESIAN - * - * @code - * I2C i2c = I2C(I2C_SDA0, I2C_SCL0); - * - * Accelerometer accelerometer = Accelerometer(i2c); - * @endcode - */ - LIS3DH(I2C &_i2c, Pin &_int1, CoordinateSpace &coordinateSpace, uint16_t address = LIS3DH_DEFAULT_ADDR, uint16_t id = DEVICE_ID_ACCELEROMETER); - - /** - * Attempts to read the 8 bit ID from the accelerometer, this can be used for - * validation purposes. - * - * @return the 8 bit ID returned by the accelerometer, or DEVICE_I2C_ERROR if the request fails. - * - * @code - * accelerometer.whoAmI(); - * @endcode - */ - int whoAmI(); - - /** - * A periodic callback invoked by the fiber scheduler idle thread. - * - * Internally calls updateSample(). - */ - virtual void idleCallback() override; - - /** - * Configures the accelerometer for G range and sample rate defined - * in this object. The nearest values are chosen to those defined - * that are supported by the hardware. The instance variables are then - * updated to reflect reality. - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the accelerometer could not be configured. - */ - virtual int configure() override; - - /** - * Poll to see if new data is available from the hardware. If so, update it. - * n.b. it is not necessary to explicitly call this function to update data - * (it normally happens in the background when the scheduler is idle), but a check is performed - * if the user explicitly requests up to date data. - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the update fails. - * - * @note This method should be overidden by the hardware driver to implement the requested - * changes in hardware. - */ - virtual int requestUpdate() override; - - /** - * Destructor. - */ - ~LIS3DH(); - - virtual int setSleep(bool sleepMode); - }; -} + virtual void idleCallback() override; + + /** + * Configures the accelerometer for G range and sample rate defined + * in this object. The nearest values are chosen to those defined + * that are supported by the hardware. The instance variables are then + * updated to reflect reality. + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the accelerometer could not be configured. + */ + virtual int configure() override; + + /** + * Poll to see if new data is available from the hardware. If so, update it. + * n.b. it is not necessary to explicitly call this function to update data + * (it normally happens in the background when the scheduler is idle), but a check is performed + * if the user explicitly requests up to date data. + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the update fails. + * + * @note This method should be overidden by the hardware driver to implement the requested + * changes in hardware. + */ + virtual int requestUpdate() override; + + /** + * Destructor. + */ + ~LIS3DH(); + + virtual int setSleep(bool sleepMode); +}; +} // namespace codal #endif diff --git a/inc/drivers/LSM303Accelerometer.h b/inc/drivers/LSM303Accelerometer.h index 2f17822c..bdcf46ae 100644 --- a/inc/drivers/LSM303Accelerometer.h +++ b/inc/drivers/LSM303Accelerometer.h @@ -25,89 +25,86 @@ DEALINGS IN THE SOFTWARE. #ifndef LSM303_A_H #define LSM303_A_H -#include "CodalConfig.h" +#include "Accelerometer.h" #include "CodalComponent.h" +#include "CodalConfig.h" #include "CodalUtil.h" #include "CoordinateSystem.h" -#include "Pin.h" #include "I2C.h" -#include "Accelerometer.h" - +#include "Pin.h" /** - * I2C constants - */ -#define LSM303_A_DEFAULT_ADDR 0x32 + * I2C constants + */ +#define LSM303_A_DEFAULT_ADDR 0x32 /** - * LSM303 Register map (partial) - */ - -#define LSM303_STATUS_REG_AUX_A 0x07 -#define LSM303_OUT_TEMP_L_A 0x0C -#define LSM303_OUT_TEMP_H_A 0x0D -#define LSM303_INT_COUNTER_REG_A 0x0E -#define LSM303_WHO_AM_I_A 0x0F -#define LSM303_TEMP_CFG_REG_A 0x1F -#define LSM303_CTRL_REG1_A 0x20 -#define LSM303_CTRL_REG2_A 0x21 -#define LSM303_CTRL_REG3_A 0x22 -#define LSM303_CTRL_REG4_A 0x23 -#define LSM303_CTRL_REG5_A 0x24 -#define LSM303_CTRL_REG6_A 0x25 -#define LSM303_DATACAPTURE_A 0x26 -#define LSM303_STATUS_REG_A 0x27 -#define LSM303_OUT_X_L_A 0x28 -#define LSM303_OUT_X_H_A 0x29 -#define LSM303_OUT_Y_L_A 0x2A -#define LSM303_OUT_Y_H_A 0x2B -#define LSM303_OUT_Z_L_A 0x2C -#define LSM303_OUT_Z_H_A 0x2D -#define LSM303_FIFO_CTRL_REG_A 0x2E -#define LSM303_FIFO_SRC_REG_A 0x2F -#define LSM303_INT1_CFG_A 0x30 -#define LSM303_INT1_SRC_A 0x31 -#define LSM303_INT1_THS_A 0x32 -#define LSM303_INT1_DURATION_A 0x33 -#define LSM303_INT2_CFG_A 0x34 -#define LSM303_INT2_SRC_A 0x35 -#define LSM303_INT2_THS_A 0x36 -#define LSM303_INT2_DURATION_A 0x37 -#define LSM303_CLICK_CFG_A 0x38 -#define LSM303_CLICK_SRC_A 0x39 -#define LSM303_CLICK_THS_A 0x3A -#define LSM303_TIME_LIMIT_A 0x3B -#define LSM303_TIME_LATENCY_A 0x3C -#define LSM303_TIME_WINDOW_A 0x3D -#define LSM303_ACT_THS_A 0x3E -#define LSM303_ACT_DUR_A 0x3F + * LSM303 Register map (partial) + */ + +#define LSM303_STATUS_REG_AUX_A 0x07 +#define LSM303_OUT_TEMP_L_A 0x0C +#define LSM303_OUT_TEMP_H_A 0x0D +#define LSM303_INT_COUNTER_REG_A 0x0E +#define LSM303_WHO_AM_I_A 0x0F +#define LSM303_TEMP_CFG_REG_A 0x1F +#define LSM303_CTRL_REG1_A 0x20 +#define LSM303_CTRL_REG2_A 0x21 +#define LSM303_CTRL_REG3_A 0x22 +#define LSM303_CTRL_REG4_A 0x23 +#define LSM303_CTRL_REG5_A 0x24 +#define LSM303_CTRL_REG6_A 0x25 +#define LSM303_DATACAPTURE_A 0x26 +#define LSM303_STATUS_REG_A 0x27 +#define LSM303_OUT_X_L_A 0x28 +#define LSM303_OUT_X_H_A 0x29 +#define LSM303_OUT_Y_L_A 0x2A +#define LSM303_OUT_Y_H_A 0x2B +#define LSM303_OUT_Z_L_A 0x2C +#define LSM303_OUT_Z_H_A 0x2D +#define LSM303_FIFO_CTRL_REG_A 0x2E +#define LSM303_FIFO_SRC_REG_A 0x2F +#define LSM303_INT1_CFG_A 0x30 +#define LSM303_INT1_SRC_A 0x31 +#define LSM303_INT1_THS_A 0x32 +#define LSM303_INT1_DURATION_A 0x33 +#define LSM303_INT2_CFG_A 0x34 +#define LSM303_INT2_SRC_A 0x35 +#define LSM303_INT2_THS_A 0x36 +#define LSM303_INT2_DURATION_A 0x37 +#define LSM303_CLICK_CFG_A 0x38 +#define LSM303_CLICK_SRC_A 0x39 +#define LSM303_CLICK_THS_A 0x3A +#define LSM303_TIME_LIMIT_A 0x3B +#define LSM303_TIME_LATENCY_A 0x3C +#define LSM303_TIME_WINDOW_A 0x3D +#define LSM303_ACT_THS_A 0x3E +#define LSM303_ACT_DUR_A 0x3F /** - * LSM303_A constants - */ -#define LSM303_A_WHOAMI_VAL 0x33 -#define LSM303_A_STATUS_DATA_READY 0x08 + * LSM303_A constants + */ +#define LSM303_A_WHOAMI_VAL 0x33 +#define LSM303_A_STATUS_DATA_READY 0x08 /** * LSM303 Status flags */ -#define LSM303_A_STATUS_ENABLED 0x0100 -#define LSM303_A_STATUS_SLEEPING 0x0200 - -namespace codal -{ - /** - * Class definition for LSM303Accelerometer. - * This class provides a simple wrapper between the hybrid FXOS8700 accelerometer and higher level accelerometer funcitonality. - */ - class LSM303Accelerometer : public Accelerometer - { - I2C& i2c; // The I2C interface to use. - Pin& int1; // Data ready interrupt. - uint16_t address; // I2C address of this accelerometer. - - public: +#define LSM303_A_STATUS_ENABLED 0x0100 +#define LSM303_A_STATUS_SLEEPING 0x0200 + +namespace codal { +/** + * Class definition for LSM303Accelerometer. + * This class provides a simple wrapper between the hybrid FXOS8700 accelerometer and higher level accelerometer + * funcitonality. + */ +class LSM303Accelerometer : public Accelerometer { + I2C& i2c; // The I2C interface to use. + Pin& int1; // Data ready interrupt. + uint16_t address; // I2C address of this accelerometer. + public: /** * Constructor. * Create a software abstraction of an accelerometer. @@ -116,7 +113,8 @@ namespace codal * @param id The unique EventModel id of this component. Defaults to: DEVICE_ID_ACCELEROMETER * */ - LSM303Accelerometer(I2C& _i2c, Pin &_int1, CoordinateSpace &coordinateSpace, uint16_t address = LSM303_A_DEFAULT_ADDR, uint16_t id = DEVICE_ID_ACCELEROMETER); + LSM303Accelerometer(I2C& _i2c, Pin& _int1, CoordinateSpace& coordinateSpace, + uint16_t address = LSM303_A_DEFAULT_ADDR, uint16_t id = DEVICE_ID_ACCELEROMETER); /** * Configures the accelerometer for G range and sample rate defined @@ -155,20 +153,18 @@ namespace codal * Puts the component in (or out of) sleep (low power) mode. */ virtual int setSleep(bool doSleep) override; - /** * Attempts to read the 8 bit WHO_AM_I value from the accelerometer * * @return true if the WHO_AM_I value is succesfully read. false otherwise. */ - static int isDetected(I2C &i2c, uint16_t address = LSM303_A_DEFAULT_ADDR); + static int isDetected(I2C& i2c, uint16_t address = LSM303_A_DEFAULT_ADDR); /** - * Destructor. - */ + * Destructor. + */ ~LSM303Accelerometer(); - }; -} +}; +} // namespace codal #endif - diff --git a/inc/drivers/LSM303Magnetometer.h b/inc/drivers/LSM303Magnetometer.h index 4142f2a0..e5eeace8 100644 --- a/inc/drivers/LSM303Magnetometer.h +++ b/inc/drivers/LSM303Magnetometer.h @@ -25,66 +25,65 @@ DEALINGS IN THE SOFTWARE. #ifndef LSM303_M_H #define LSM303_M_H -#include "CodalConfig.h" #include "CodalComponent.h" +#include "CodalConfig.h" #include "CodalUtil.h" +#include "Compass.h" #include "CoordinateSystem.h" -#include "Pin.h" #include "I2C.h" -#include "Compass.h" - +#include "Pin.h" /** - * Term to convert sample data into SI units. - */ + * Term to convert sample data into SI units. + */ #define LSM303_M_NORMALIZE_SAMPLE(x) (150 * (int)(x)) /** - * LSM303_M MAGIC ID value - * Returned from the MAG_WHO_AM_I register for ID purposes. - */ -#define LSM303_M_WHOAMI_VAL 0x40 + * LSM303_M MAGIC ID value + * Returned from the MAG_WHO_AM_I register for ID purposes. + */ +#define LSM303_M_WHOAMI_VAL 0x40 /** - * I2C constants - */ -#define LSM303_M_DEFAULT_ADDR 0x3C + * I2C constants + */ +#define LSM303_M_DEFAULT_ADDR 0x3C /** - * LSM303_M Register map - */ -#define LSM303_OFFSET_X_REG_L_M 0x45 -#define LSM303_OFFSET_X_REG_H_M 0x46 -#define LSM303_OFFSET_Y_REG_L_M 0x47 -#define LSM303_OFFSET_Y_REG_H_M 0x48 -#define LSM303_OFFSET_Z_REG_L_M 0x49 -#define LSM303_OFFSET_Z_REG_H_M 0x4A -#define LSM303_WHO_AM_I_M 0x4F -#define LSM303_CFG_REG_A_M 0x60 -#define LSM303_CFG_REG_B_M 0x61 -#define LSM303_CFG_REG_C_M 0x62 -#define LSM303_INT_CRTL_REG_M 0x63 -#define LSM303_INT_SOURCE_REG_M 0x64 -#define LSM303_INT_THS_L_REG_M 0x65 -#define LSM303_INT_THS_H_REG_M 0x66 -#define LSM303_STATUS_REG_M 0x67 -#define LSM303_OUTX_L_REG_M 0x68 -#define LSM303_OUTX_H_REG_M 0x69 -#define LSM303_OUTY_L_REG_M 0x6A -#define LSM303_OUTY_H_REG_M 0x6B -#define LSM303_OUTZ_L_REG_M 0x6C -#define LSM303_OUTZ_H_REG_M 0x6D + * LSM303_M Register map + */ +#define LSM303_OFFSET_X_REG_L_M 0x45 +#define LSM303_OFFSET_X_REG_H_M 0x46 +#define LSM303_OFFSET_Y_REG_L_M 0x47 +#define LSM303_OFFSET_Y_REG_H_M 0x48 +#define LSM303_OFFSET_Z_REG_L_M 0x49 +#define LSM303_OFFSET_Z_REG_H_M 0x4A +#define LSM303_WHO_AM_I_M 0x4F +#define LSM303_CFG_REG_A_M 0x60 +#define LSM303_CFG_REG_B_M 0x61 +#define LSM303_CFG_REG_C_M 0x62 +#define LSM303_INT_CRTL_REG_M 0x63 +#define LSM303_INT_SOURCE_REG_M 0x64 +#define LSM303_INT_THS_L_REG_M 0x65 +#define LSM303_INT_THS_H_REG_M 0x66 +#define LSM303_STATUS_REG_M 0x67 +#define LSM303_OUTX_L_REG_M 0x68 +#define LSM303_OUTX_H_REG_M 0x69 +#define LSM303_OUTY_L_REG_M 0x6A +#define LSM303_OUTY_H_REG_M 0x6B +#define LSM303_OUTZ_L_REG_M 0x6C +#define LSM303_OUTZ_H_REG_M 0x6D /** - * LSM303_M constants - */ -#define LSM303_M_STATUS_DATA_READY 0x08 + * LSM303_M constants + */ +#define LSM303_M_STATUS_DATA_READY 0x08 /** * LSM303 Status flags */ -#define LSM303_M_STATUS_ENABLED 0x0100 -#define LSM303_M_STATUS_SLEEPING 0x0200 +#define LSM303_M_STATUS_ENABLED 0x0100 +#define LSM303_M_STATUS_SLEEPING 0x0200 /** * Class definition for LSM303_M. @@ -92,77 +91,73 @@ DEALINGS IN THE SOFTWARE. * This class provides the low level driver implementation for the LSM303_M Magnetometer * */ -namespace codal -{ - class LSM303Magnetometer : public Compass - { - I2C& i2c; // The I2C interface to use. - Pin& int1; // Data ready interrupt. - uint16_t address; // I2C address of this compass. - - public: - - /** - * Constructor. - * Create a software abstraction of an compass. - * - * @param coordinateSpace The orientation of the sensor. Defaults to: SIMPLE_CARTESIAN - * @param id The unique EventModel id of this component. Defaults to: DEVICE_ID_ACCELEROMETER - * - */ - LSM303Magnetometer(I2C& _i2c, Pin &_int1, CoordinateSpace &coordinateSpace, uint16_t address = LSM303_M_DEFAULT_ADDR, uint16_t id = DEVICE_ID_COMPASS); - - /** - * Configures the magnetometer for the sample rate defined - * in this object. The nearest values are chosen to those defined - * that are supported by the hardware. The instance variables are then - * updated to reflect reality. - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the magnetometer could not be configured. - * - * @note This method should be overidden by the hardware driver to implement the requested - * changes in hardware. - */ - virtual int configure() override; - - /** - * Poll to see if new data is available from the hardware. If so, update it. - * n.b. it is not necessary to explicitly call this function to update data - * (it normally happens in the background when the scheduler is idle), but a check is performed - * if the user explicitly requests up to date data. - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the update fails. - * - * @note This method should be overidden by the hardware driver to implement the requested - * changes in hardware. - */ - virtual int requestUpdate() override; - - /** - * A periodic callback invoked by the fiber scheduler idle thread. - * - * Internally calls updateSample(). - */ - virtual void idleCallback() override; - - /** - * Puts the component in (or out of) sleep (low power) mode. - */ - virtual int setSleep(bool doSleep) override; - - /** - * Attempts to read the 8 bit WHO_AM_I value from the accelerometer - * - * @return true if the WHO_AM_I value is succesfully read. false otherwise. - */ - static int isDetected(I2C &i2c, uint16_t address = LSM303_M_DEFAULT_ADDR); - - /** - * Destructor. - */ - ~LSM303Magnetometer(); - - }; -} +namespace codal { +class LSM303Magnetometer : public Compass { + I2C& i2c; // The I2C interface to use. + Pin& int1; // Data ready interrupt. + uint16_t address; // I2C address of this compass. + + public: + /** + * Constructor. + * Create a software abstraction of an compass. + * + * @param coordinateSpace The orientation of the sensor. Defaults to: SIMPLE_CARTESIAN + * @param id The unique EventModel id of this component. Defaults to: DEVICE_ID_ACCELEROMETER + * + */ + LSM303Magnetometer(I2C& _i2c, Pin& _int1, CoordinateSpace& coordinateSpace, + uint16_t address = LSM303_M_DEFAULT_ADDR, uint16_t id = DEVICE_ID_COMPASS); + + /** + * Configures the magnetometer for the sample rate defined + * in this object. The nearest values are chosen to those defined + * that are supported by the hardware. The instance variables are then + * updated to reflect reality. + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the magnetometer could not be configured. + * + * @note This method should be overidden by the hardware driver to implement the requested + * changes in hardware. + */ + virtual int configure() override; + + /** + * Poll to see if new data is available from the hardware. If so, update it. + * n.b. it is not necessary to explicitly call this function to update data + * (it normally happens in the background when the scheduler is idle), but a check is performed + * if the user explicitly requests up to date data. + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the update fails. + * + * @note This method should be overidden by the hardware driver to implement the requested + * changes in hardware. + */ + virtual int requestUpdate() override; + + /** + * A periodic callback invoked by the fiber scheduler idle thread. + * + * Internally calls updateSample(). + */ + virtual void idleCallback() override; + + /** + * Puts the component in (or out of) sleep (low power) mode. + */ + virtual int setSleep(bool doSleep) override; + + /** + * Attempts to read the 8 bit WHO_AM_I value from the accelerometer + * + * @return true if the WHO_AM_I value is succesfully read. false otherwise. + */ + static int isDetected(I2C& i2c, uint16_t address = LSM303_M_DEFAULT_ADDR); + + /** + * Destructor. + */ + ~LSM303Magnetometer(); +}; +} // namespace codal #endif - diff --git a/inc/drivers/LinearAnalogSensor.h b/inc/drivers/LinearAnalogSensor.h index 9672d4d4..37e86eb3 100644 --- a/inc/drivers/LinearAnalogSensor.h +++ b/inc/drivers/LinearAnalogSensor.h @@ -25,49 +25,45 @@ DEALINGS IN THE SOFTWARE. #ifndef LINEAR_ANALOG_SENSOR_H #define LINEAR_ANALOG_SENSOR_H -#include "CodalConfig.h" #include "AnalogSensor.h" +#include "CodalConfig.h" +namespace codal { +/** + * Class definition for a normalised, linear analog sensor, that takes the general form of a linear response between + * sensed value and result. Given an input range and an output range, automatically scales sampled data into the given + * output range. + */ +class LinearAnalogSensor : public AnalogSensor { + private: + uint16_t inputFloor; // The minimum level in the input range. + float outputFloor; // The minimum level in the output range. + float conversionFactor; // no of output units per input unit. -namespace codal -{ + public: /** - * Class definition for a normalised, linear analog sensor, that takes the general form of a linear response between sensed value and result. - * Given an input range and an output range, automatically scales sampled data into the given output range. + * Constructor. + * + * Creates a LinearAnalogSensor. + * + * @param pin The pin on which to sense + * @param id The ID of this compoenent e.g. DEVICE_ID_THERMOMETER + * @param inputFloor The minimum level in the input range. + * @param inputCeiling The maximum level in the input range. + * @param outputFloor The minimum level in the output range. Default: 0. + * @param outputCeiling The maximum level in the output range. Default: 1023. + * */ - class LinearAnalogSensor : public AnalogSensor - { - private: - - uint16_t inputFloor; // The minimum level in the input range. - float outputFloor; // The minimum level in the output range. - float conversionFactor; // no of output units per input unit. - - public: - - /** - * Constructor. - * - * Creates a LinearAnalogSensor. - * - * @param pin The pin on which to sense - * @param id The ID of this compoenent e.g. DEVICE_ID_THERMOMETER - * @param inputFloor The minimum level in the input range. - * @param inputCeiling The maximum level in the input range. - * @param outputFloor The minimum level in the output range. Default: 0. - * @param outputCeiling The maximum level in the output range. Default: 1023. - * - */ - LinearAnalogSensor(Pin &pin, uint16_t id, uint16_t sampleFloor, uint16_t sampleCeiling, float valueFloor = 0.0f, float valueCeiling = 1023.0f); + LinearAnalogSensor(Pin& pin, uint16_t id, uint16_t sampleFloor, uint16_t sampleCeiling, float valueFloor = 0.0f, + float valueCeiling = 1023.0f); - /** - * Updates the internal reading of the sensor. Typically called periodicaly. - * - * @return DEVICE_OK on success. - */ - virtual void updateSample(); - - }; -} + /** + * Updates the internal reading of the sensor. Typically called periodicaly. + * + * @return DEVICE_OK on success. + */ + virtual void updateSample(); +}; +} // namespace codal #endif diff --git a/inc/drivers/MAG3110.h b/inc/drivers/MAG3110.h index e5861b3d..c60e0d84 100644 --- a/inc/drivers/MAG3110.h +++ b/inc/drivers/MAG3110.h @@ -26,19 +26,19 @@ DEALINGS IN THE SOFTWARE. #ifndef CODAL_MAG3110_H #define CODAL_MAG3110_H +#include "Accelerometer.h" #include "CodalConfig.h" -#include "I2C.h" #include "Compass.h" -#include "Accelerometer.h" +#include "I2C.h" /** - * I2C constants - */ -#define MAG3110_DEFAULT_ADDR 0x1D + * I2C constants + */ +#define MAG3110_DEFAULT_ADDR 0x1D /** - * MAG3110 Register map - */ + * MAG3110 Register map + */ #define MAG_DR_STATUS 0x00 #define MAG_OUT_X_MSB 0x01 #define MAG_OUT_X_LSB 0x02 @@ -59,62 +59,58 @@ DEALINGS IN THE SOFTWARE. #define MAG_CTRL_REG2 0x11 /** - * Configuration options - */ -struct MAG3110SampleRateConfig -{ - uint32_t sample_period; - uint8_t ctrl_reg1; + * Configuration options + */ +struct MAG3110SampleRateConfig { + uint32_t sample_period; + uint8_t ctrl_reg1; }; extern const MAG3110SampleRateConfig MAG3110SampleRate[]; -#define MAG3110_SAMPLE_RATES 11 +#define MAG3110_SAMPLE_RATES 11 /** - * Term to convert sample data into SI units - */ -#define MAG3110_NORMALIZE_SAMPLE(x) (100*x) + * Term to convert sample data into SI units + */ +#define MAG3110_NORMALIZE_SAMPLE(x) (100 * x) /** - * MAG3110 MAGIC ID value - * Returned from the MAG_WHO_AM_I register for ID purposes. - */ + * MAG3110 MAGIC ID value + * Returned from the MAG_WHO_AM_I register for ID purposes. + */ #define MAG3110_WHOAMI_VAL 0xC4 -namespace codal -{ - /** - * Class definition for a MAG3110 Compass. - * - * Represents an implementation of the Freescale MAG3110 I2C Magnetmometer. - */ - class MAG3110 : public Compass - { - uint16_t address; // I2C address of the magnetmometer. - Pin& int1; // Data ready interrupt. - I2C& i2c; // The I2C interface the sensor is connected to. - - public: - - MAG3110(I2C& _i2c, Pin& int1, Accelerometer& _accelerometer, CoordinateSpace &coordinateSpace, uint16_t address = MAG3110_DEFAULT_ADDR, uint16_t id = DEVICE_ID_COMPASS); - - int whoAmI(); - - /** - * Configures the compass for the sample rate defined in this object. - * The nearest values are chosen to those defined that are supported by the hardware. - * The instance variables are then updated to reflect reality. - * - * @return DEVICE_OK or DEVICE_I2C_ERROR if the magnetometer could not be configured. - */ - virtual int configure() override; - - virtual int requestUpdate() override; - - virtual void idleCallback() override; - }; -} - +namespace codal { +/** + * Class definition for a MAG3110 Compass. + * + * Represents an implementation of the Freescale MAG3110 I2C Magnetmometer. + */ +class MAG3110 : public Compass { + uint16_t address; // I2C address of the magnetmometer. + Pin& int1; // Data ready interrupt. + I2C& i2c; // The I2C interface the sensor is connected to. + + public: + MAG3110(I2C& _i2c, Pin& int1, Accelerometer& _accelerometer, CoordinateSpace& coordinateSpace, + uint16_t address = MAG3110_DEFAULT_ADDR, uint16_t id = DEVICE_ID_COMPASS); + + int whoAmI(); + + /** + * Configures the compass for the sample rate defined in this object. + * The nearest values are chosen to those defined that are supported by the hardware. + * The instance variables are then updated to reflect reality. + * + * @return DEVICE_OK or DEVICE_I2C_ERROR if the magnetometer could not be configured. + */ + virtual int configure() override; + + virtual int requestUpdate() override; + + virtual void idleCallback() override; +}; +} // namespace codal #endif diff --git a/inc/drivers/MMA8453.h b/inc/drivers/MMA8453.h index efef6fc7..49d9534b 100644 --- a/inc/drivers/MMA8453.h +++ b/inc/drivers/MMA8453.h @@ -30,38 +30,38 @@ DEALINGS IN THE SOFTWARE. // It's almost like 8653, except for address -#define MMA8453_DEFAULT_ADDR 0x38 -#define MMA8453_WHOAMI_VAL 0x3A +#define MMA8453_DEFAULT_ADDR 0x38 +#define MMA8453_WHOAMI_VAL 0x3A -namespace codal -{ +namespace codal { +/** + * Class definition for MMA8453 Accelerometer. + * + * Represents an implementation of the Freescale MMA8453 3 axis accelerometer + * Also includes basic data caching and on demand activation. + */ +class MMA8453 : public MMA8653 { + public: /** - * Class definition for MMA8453 Accelerometer. + * Constructor. + * Create a software abstraction of an accelerometer. * - * Represents an implementation of the Freescale MMA8453 3 axis accelerometer - * Also includes basic data caching and on demand activation. + * @param _i2c an instance of a codal::I2C device used to communicate with the onboard accelerometer. + * + * @param address the default I2C address of the accelerometer. Defaults to: MMA8453_DEFAULT_ADDR. + * + * @param id the unique EventModel id of this component. Defaults to: DEVICE_ID_ACCELEROMETER + * + * @code + * MMA8453 accelerometer = MMA8453(i2c); + * @endcode */ - class MMA8453 : public MMA8653 + MMA8453(I2C& _i2c, Pin& int1, CoordinateSpace& cspace, uint16_t address = MMA8453_DEFAULT_ADDR, + uint16_t id = DEVICE_ID_ACCELEROMETER) + : MMA8653(_i2c, int1, cspace, address, id) { - public: - - /** - * Constructor. - * Create a software abstraction of an accelerometer. - * - * @param _i2c an instance of a codal::I2C device used to communicate with the onboard accelerometer. - * - * @param address the default I2C address of the accelerometer. Defaults to: MMA8453_DEFAULT_ADDR. - * - * @param id the unique EventModel id of this component. Defaults to: DEVICE_ID_ACCELEROMETER - * - * @code - * MMA8453 accelerometer = MMA8453(i2c); - * @endcode - */ - MMA8453(I2C &_i2c, Pin& int1, CoordinateSpace& cspace, uint16_t address = MMA8453_DEFAULT_ADDR, uint16_t id = DEVICE_ID_ACCELEROMETER) : - MMA8653(_i2c, int1, cspace, address, id) {} - }; -} + } +}; +} // namespace codal #endif diff --git a/inc/drivers/MMA8653.h b/inc/drivers/MMA8653.h index 26b819e1..01e47882 100644 --- a/inc/drivers/MMA8653.h +++ b/inc/drivers/MMA8653.h @@ -26,127 +26,118 @@ DEALINGS IN THE SOFTWARE. #ifndef CODAL_MMA8635_H #define CODAL_MMA8635_H -#include "CodalConfig.h" +#include "Accelerometer.h" #include "CodalComponent.h" +#include "CodalConfig.h" #include "CoordinateSystem.h" #include "I2C.h" -#include "Accelerometer.h" +/** + * I2C constants + */ +#define MMA8653_DEFAULT_ADDR 0x3A /** - * I2C constants - */ -#define MMA8653_DEFAULT_ADDR 0x3A + * MMA8653 Register map (partial) + */ +#define MMA8653_STATUS 0x00 +#define MMA8653_OUT_X_MSB 0x01 +#define MMA8653_WHOAMI 0x0D +#define MMA8653_XYZ_DATA_CFG 0x0E +#define MMA8653_CTRL_REG1 0x2A +#define MMA8653_CTRL_REG2 0x2B +#define MMA8653_CTRL_REG3 0x2C +#define MMA8653_CTRL_REG4 0x2D +#define MMA8653_CTRL_REG5 0x2E /** - * MMA8653 Register map (partial) - */ -#define MMA8653_STATUS 0x00 -#define MMA8653_OUT_X_MSB 0x01 -#define MMA8653_WHOAMI 0x0D -#define MMA8653_XYZ_DATA_CFG 0x0E -#define MMA8653_CTRL_REG1 0x2A -#define MMA8653_CTRL_REG2 0x2B -#define MMA8653_CTRL_REG3 0x2C -#define MMA8653_CTRL_REG4 0x2D -#define MMA8653_CTRL_REG5 0x2E + * MMA8653 constants + */ +#define MMA8653_WHOAMI_VAL 0x5A +#define MMA8653_SAMPLE_RANGES 3 +#define MMA8653_SAMPLE_RATES 8 -/** - * MMA8653 constants - */ -#define MMA8653_WHOAMI_VAL 0x5A - -#define MMA8653_SAMPLE_RANGES 3 -#define MMA8653_SAMPLE_RATES 8 - -struct MMA8653Sample -{ - int16_t x; - int16_t y; - int16_t z; +struct MMA8653Sample { + int16_t x; + int16_t y; + int16_t z; }; -struct MMA8653SampleRateConfig -{ - uint32_t sample_period; - uint8_t ctrl_reg1; +struct MMA8653SampleRateConfig { + uint32_t sample_period; + uint8_t ctrl_reg1; }; -struct MMA8653SampleRangeConfig -{ - uint8_t sample_range; - uint8_t xyz_data_cfg; +struct MMA8653SampleRangeConfig { + uint8_t sample_range; + uint8_t xyz_data_cfg; }; - extern const MMA8653SampleRangeConfig MMA8653SampleRange[]; extern const MMA8653SampleRateConfig MMA8653SampleRate[]; +namespace codal { +/** + * Class definition for MMA8563 Accelerometer. + * + * Represents an implementation of the Freescale MMA8653 3 axis accelerometer + * Also includes basic data caching and on demand activation. + */ +class MMA8653 : public Accelerometer { + uint16_t address; // I2C address of this accelerometer. + Pin& int1; // Data ready interrupt. + I2C& i2c; // The I2C interface to use. + + public: + /** + * Constructor. + * Create a software abstraction of an accelerometer. + * + * @param _i2c an instance of a codal::I2C device used to communicate with the onboard accelerometer. + * + * @param address the default I2C address of the accelerometer. Defaults to: MMA8653_DEFAULT_ADDR. + * + * @param id the unique EventModel id of this component. Defaults to: DEVICE_ID_ACCELEROMETER + * + * @code + * MMA8653 accelerometer = MMA8653(i2c); + * @endcode + */ + MMA8653(I2C& _i2c, Pin& int1, CoordinateSpace& cspace, uint16_t address = MMA8653_DEFAULT_ADDR, + uint16_t id = DEVICE_ID_ACCELEROMETER); + + /** + * Configures the accelerometer for G range and sample rate defined + * in this object. The nearest values are chosen to those defined + * that are supported by the hardware. The instance variables are then + * updated to reflect reality. + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the accelerometer could not be configured. + */ + virtual int configure() override; -namespace codal -{ /** - * Class definition for MMA8563 Accelerometer. + * Reads the acceleration data from the accelerometer, and stores it in our buffer. + * This only happens if the accelerometer indicates that it has new data via int1. * - * Represents an implementation of the Freescale MMA8653 3 axis accelerometer - * Also includes basic data caching and on demand activation. + * On first use, this member function will attempt to add this component to the + * list of fiber components in order to constantly update the values stored + * by this object. + * + * This technique is called lazy instantiation, and it means that we do not + * obtain the overhead from non-chalantly adding this component to fiber components. + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the read request fails. */ - class MMA8653 : public Accelerometer - { - uint16_t address; // I2C address of this accelerometer. - Pin& int1; // Data ready interrupt. - I2C& i2c; // The I2C interface to use. - - public: - - /** - * Constructor. - * Create a software abstraction of an accelerometer. - * - * @param _i2c an instance of a codal::I2C device used to communicate with the onboard accelerometer. - * - * @param address the default I2C address of the accelerometer. Defaults to: MMA8653_DEFAULT_ADDR. - * - * @param id the unique EventModel id of this component. Defaults to: DEVICE_ID_ACCELEROMETER - * - * @code - * MMA8653 accelerometer = MMA8653(i2c); - * @endcode - */ - MMA8653(I2C &_i2c, Pin& int1, CoordinateSpace& cspace, uint16_t address = MMA8653_DEFAULT_ADDR, uint16_t id = DEVICE_ID_ACCELEROMETER); - - /** - * Configures the accelerometer for G range and sample rate defined - * in this object. The nearest values are chosen to those defined - * that are supported by the hardware. The instance variables are then - * updated to reflect reality. - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the accelerometer could not be configured. - */ - virtual int configure() override; - - /** - * Reads the acceleration data from the accelerometer, and stores it in our buffer. - * This only happens if the accelerometer indicates that it has new data via int1. - * - * On first use, this member function will attempt to add this component to the - * list of fiber components in order to constantly update the values stored - * by this object. - * - * This technique is called lazy instantiation, and it means that we do not - * obtain the overhead from non-chalantly adding this component to fiber components. - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the read request fails. - */ - virtual int requestUpdate() override; - - int whoAmI(); - - virtual void idleCallback() override; - - virtual int setSleep(bool sleepMode); - }; -} + virtual int requestUpdate() override; + + int whoAmI(); + + virtual void idleCallback() override; + + virtual int setSleep(bool sleepMode); +}; +} // namespace codal #endif diff --git a/inc/drivers/MPU6050.h b/inc/drivers/MPU6050.h index f59fe4f0..cde620e2 100644 --- a/inc/drivers/MPU6050.h +++ b/inc/drivers/MPU6050.h @@ -1,77 +1,76 @@ #ifndef CODAL_MPU6050_H #define CODAL_MPU6050_H -#include "CodalConfig.h" +#include "Accelerometer.h" #include "CodalComponent.h" +#include "CodalConfig.h" #include "CoordinateSystem.h" -#include "I2C.h" -#include "Accelerometer.h" #include "Gyroscope.h" +#include "I2C.h" -#define MPU6050_DEFAULT_ADDR 0x68 -#define MPU6050_WHOAMI 0x75 - -#define MPU6050_WHOAMI_VAL 0x34 +#define MPU6050_DEFAULT_ADDR 0x68 +#define MPU6050_WHOAMI 0x75 -namespace codal{ +#define MPU6050_WHOAMI_VAL 0x34 - class MPU6050 : public Accelerometer - { - I2C& i2c; - Pin &int1; // Data ready interrupt. - uint16_t address; // I2C address of this accelerometer. - int16_t temp; - Sample3D gyro; // The gyro value +namespace codal { - public: +class MPU6050 : public Accelerometer { + I2C& i2c; + Pin& int1; // Data ready interrupt. + uint16_t address; // I2C address of this accelerometer. + int16_t temp; + Sample3D gyro; // The gyro value - MPU6050(I2C &_i2c, Pin &_int1, CoordinateSpace &coordinateSpace, uint16_t address = MPU6050_DEFAULT_ADDR, uint16_t id = DEVICE_ID_ACCELEROMETER); + public: + MPU6050(I2C& _i2c, Pin& _int1, CoordinateSpace& coordinateSpace, uint16_t address = MPU6050_DEFAULT_ADDR, + uint16_t id = DEVICE_ID_ACCELEROMETER); - /** - * Attempts to read the 8 bit ID from the accelerometer, this can be used for - * validation purposes. - * - * @return the 8 bit ID returned by the accelerometer, or DEVICE_I2C_ERROR if the request fails. - * - * @code - * accelerometer.whoAmI(); - * @endcode - */ - int whoAmI(); + /** + * Attempts to read the 8 bit ID from the accelerometer, this can be used for + * validation purposes. + * + * @return the 8 bit ID returned by the accelerometer, or DEVICE_I2C_ERROR if the request fails. + * + * @code + * accelerometer.whoAmI(); + * @endcode + */ + int whoAmI(); - /** - * A periodic callback invoked by the fiber scheduler idle thread. - * - * Internally calls updateSample(). - */ - virtual void idleCallback() override; + /** + * A periodic callback invoked by the fiber scheduler idle thread. + * + * Internally calls updateSample(). + */ + virtual void idleCallback() override; - /** - * Configures the accelerometer for G range and sample rate defined - * in this object. The nearest values are chosen to those defined - * that are supported by the hardware. The instance variables are then - * updated to reflect reality. - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the accelerometer could not be configured. - */ - virtual int configure() override; + /** + * Configures the accelerometer for G range and sample rate defined + * in this object. The nearest values are chosen to those defined + * that are supported by the hardware. The instance variables are then + * updated to reflect reality. + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the accelerometer could not be configured. + */ + virtual int configure() override; - /** - * Poll to see if new data is available from the hardware. If so, update it. - * n.b. it is not necessary to explicitly call this function to update data - * (it normally happens in the background when the scheduler is idle), but a check is performed - * if the user explicitly requests up to date data. - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the update fails. - * - * @note This method should be overidden by the hardware driver to implement the requested - * changes in hardware. - */ - virtual int requestUpdate() override; + /** + * Poll to see if new data is available from the hardware. If so, update it. + * n.b. it is not necessary to explicitly call this function to update data + * (it normally happens in the background when the scheduler is idle), but a check is performed + * if the user explicitly requests up to date data. + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the update fails. + * + * @note This method should be overidden by the hardware driver to implement the requested + * changes in hardware. + */ + virtual int requestUpdate() override; - virtual int setSleep(bool sleepMode); - }; + virtual int setSleep(bool sleepMode); +}; -} +} // namespace codal #endif \ No newline at end of file diff --git a/inc/drivers/MessageBus.h b/inc/drivers/MessageBus.h index 0f316331..4258a2fe 100644 --- a/inc/drivers/MessageBus.h +++ b/inc/drivers/MessageBus.h @@ -25,166 +25,161 @@ DEALINGS IN THE SOFTWARE. #ifndef DEVICE_MESSAGE_BUS_H #define DEVICE_MESSAGE_BUS_H -#include "CodalConfig.h" #include "CodalComponent.h" -#include "Event.h" +#include "CodalConfig.h" #include "CodalListener.h" +#include "Event.h" #include "EventModel.h" +namespace codal { +/** + * Class definition for the MessageBus. + * + * The MessageBus is the common mechanism to deliver asynchronous events on the + * Device platform. It serves a number of purposes: + * + * 1) It provides an eventing abstraction that is independent of the underlying substrate. + * + * 2) It provides a mechanism to decouple user code from trusted system code + * i.e. the basis of a message passing nano kernel. + * + * 3) It allows a common high level eventing abstraction across a range of hardware types.e.g. buttons, BLE... + * + * 4) It provides a mechanim for extensibility - new devices added via I/O pins can have OO based + * drivers and communicate via the message bus with minima impact on user level languages. + * + * 5) It allows for the possiblility of event / data aggregation, which in turn can save energy. + * + * It has the following design principles: + * + * 1) Maintain a low RAM footprint where possible + * + * 2) Make few assumptions about the underlying platform, but allow optimizations where possible. + */ +class MessageBus : public EventModel, public CodalComponent { + uint16_t userNotifyId; + + public: + /** + * Default constructor. + * + * Adds itself as a fiber component, and also configures itself to be the + * default EventModel if defaultEventBus is NULL. + */ + MessageBus(); + + /** + * Queues the given event to be sent to all registered recipients. + * + * @param evt The event to send. + * + * @code + * MessageBus bus; + * + * // Creates and sends the Event using bus. + * Event evt(DEVICE_ID_BUTTON_A, DEVICE_BUTTON_EVT_CLICK); + * + * // Creates the Event, but delays the sending of that event. + * Event evt1(DEVICE_ID_BUTTON_A, DEVICE_BUTTON_EVT_CLICK, CREATE_ONLY); + * + * bus.send(evt1); + * + * // This has the same effect! + * evt1.fire() + * @endcode + */ + virtual int send(Event evt); + + /** + * Internal function, used to deliver the given event to all relevant recipients. + * Normally, this is called once an event has been removed from the event queue. + * + * @param evt The event to send. + * + * @param urgent The type of listeners to process (optional). If set to true, only listeners defined as urgent and + * non-blocking will be processed otherwise, all other (standard) listeners will be processed. Defaults to false. + * + * @return 1 if all matching listeners were processed, 0 if further processing is required. + * + * @note It is recommended that all external code uses the send() function instead of this function, + * or the constructors provided by Event. + */ + int process(Event& evt, bool urgent = false); + + /** + * Returns the Listener with the given position in our list. + * + * @param n The position in the list to return. + * + * @return the Listener at postion n in the list, or NULL if the position is invalid. + */ + virtual Listener* elementAt(int n); + + /** + * Destructor for MessageBus, where we deregister this instance from the array of fiber components. + */ + ~MessageBus(); + + /** + * Add the given Listener to the list of event handlers, unconditionally. + * + * @param listener The Listener to add. + * + * @return DEVICE_OK if the listener is valid, DEVICE_INVALID_PARAMETER otherwise. + */ + virtual int add(Listener* newListener); + + /** + * Remove the given Listener from the list of event handlers. + * + * @param listener The Listener to remove. + * + * @return DEVICE_OK if the listener is valid, DEVICE_INVALID_PARAMETER otherwise. + */ + virtual int remove(Listener* newListener); + + private: + Listener* listeners; // Chain of active listeners. + EventQueueItem* evt_queue_head; // Head of queued events to be processed. + EventQueueItem* evt_queue_tail; // Tail of queued events to be processed. + uint16_t nonce_val; // The last nonce issued. + uint16_t queueLength; // The number of events currently waiting to be processed. + + /** + * Cleanup any Listeners marked for deletion from the list. + * + * @return The number of listeners removed from the list. + */ + int deleteMarkedListeners(); -namespace codal -{ /** - * Class definition for the MessageBus. - * - * The MessageBus is the common mechanism to deliver asynchronous events on the - * Device platform. It serves a number of purposes: - * - * 1) It provides an eventing abstraction that is independent of the underlying substrate. - * - * 2) It provides a mechanism to decouple user code from trusted system code - * i.e. the basis of a message passing nano kernel. - * - * 3) It allows a common high level eventing abstraction across a range of hardware types.e.g. buttons, BLE... - * - * 4) It provides a mechanim for extensibility - new devices added via I/O pins can have OO based - * drivers and communicate via the message bus with minima impact on user level languages. - * - * 5) It allows for the possiblility of event / data aggregation, which in turn can save energy. - * - * It has the following design principles: - * - * 1) Maintain a low RAM footprint where possible - * - * 2) Make few assumptions about the underlying platform, but allow optimizations where possible. - */ - class MessageBus : public EventModel, public CodalComponent - { - uint16_t userNotifyId; - - public: - - /** - * Default constructor. - * - * Adds itself as a fiber component, and also configures itself to be the - * default EventModel if defaultEventBus is NULL. - */ - MessageBus(); - - /** - * Queues the given event to be sent to all registered recipients. - * - * @param evt The event to send. - * - * @code - * MessageBus bus; - * - * // Creates and sends the Event using bus. - * Event evt(DEVICE_ID_BUTTON_A, DEVICE_BUTTON_EVT_CLICK); - * - * // Creates the Event, but delays the sending of that event. - * Event evt1(DEVICE_ID_BUTTON_A, DEVICE_BUTTON_EVT_CLICK, CREATE_ONLY); - * - * bus.send(evt1); - * - * // This has the same effect! - * evt1.fire() - * @endcode - */ - virtual int send(Event evt); - - /** - * Internal function, used to deliver the given event to all relevant recipients. - * Normally, this is called once an event has been removed from the event queue. - * - * @param evt The event to send. - * - * @param urgent The type of listeners to process (optional). If set to true, only listeners defined as urgent and non-blocking will be processed - * otherwise, all other (standard) listeners will be processed. Defaults to false. - * - * @return 1 if all matching listeners were processed, 0 if further processing is required. - * - * @note It is recommended that all external code uses the send() function instead of this function, - * or the constructors provided by Event. - */ - int process(Event &evt, bool urgent = false); - - /** - * Returns the Listener with the given position in our list. - * - * @param n The position in the list to return. - * - * @return the Listener at postion n in the list, or NULL if the position is invalid. - */ - virtual Listener *elementAt(int n); - - /** - * Destructor for MessageBus, where we deregister this instance from the array of fiber components. - */ - ~MessageBus(); - - /** - * Add the given Listener to the list of event handlers, unconditionally. - * - * @param listener The Listener to add. - * - * @return DEVICE_OK if the listener is valid, DEVICE_INVALID_PARAMETER otherwise. - */ - virtual int add(Listener *newListener); - - /** - * Remove the given Listener from the list of event handlers. - * - * @param listener The Listener to remove. - * - * @return DEVICE_OK if the listener is valid, DEVICE_INVALID_PARAMETER otherwise. - */ - virtual int remove(Listener *newListener); - - private: - - Listener *listeners; // Chain of active listeners. - EventQueueItem *evt_queue_head; // Head of queued events to be processed. - EventQueueItem *evt_queue_tail; // Tail of queued events to be processed. - uint16_t nonce_val; // The last nonce issued. - uint16_t queueLength; // The number of events currently waiting to be processed. - - /** - * Cleanup any Listeners marked for deletion from the list. - * - * @return The number of listeners removed from the list. - */ - int deleteMarkedListeners(); - - /** - * Queue the given event for processing at a later time. - * Add the given event at the tail of our queue. - * - * @param The event to queue. - */ - void queueEvent(Event &evt); - - /** - * Extract the next event from the front of the event queue (if present). - * - * @return a pointer to the EventQueueItem that is at the head of the list. - */ - EventQueueItem* dequeueEvent(); - - /** - * Periodic callback from Device. - * - * Process at least one event from the event queue, if it is not empty. - * We then continue processing events until something appears on the runqueue. - */ - void idle(Event); - }; + * Queue the given event for processing at a later time. + * Add the given event at the tail of our queue. + * + * @param The event to queue. + */ + void queueEvent(Event& evt); + + /** + * Extract the next event from the front of the event queue (if present). + * + * @return a pointer to the EventQueueItem that is at the head of the list. + */ + EventQueueItem* dequeueEvent(); /** - * Allocate a NOTIFY event code dynamicaly, for generally purpose condition synchronisation. + * Periodic callback from Device. + * + * Process at least one event from the event queue, if it is not empty. + * We then continue processing events until something appears on the runqueue. */ - uint16_t allocateNotifyEvent(); -} + void idle(Event); +}; + +/** + * Allocate a NOTIFY event code dynamicaly, for generally purpose condition synchronisation. + */ +uint16_t allocateNotifyEvent(); +} // namespace codal #endif diff --git a/inc/drivers/MultiButton.h b/inc/drivers/MultiButton.h index 5cbb6eb5..7bdee93c 100644 --- a/inc/drivers/MultiButton.h +++ b/inc/drivers/MultiButton.h @@ -25,153 +25,151 @@ DEALINGS IN THE SOFTWARE. #ifndef MULTI_BUTTON_H #define MULTI_BUTTON_H -#include "CodalConfig.h" #include "Button.h" +#include "CodalConfig.h" #include "EventModel.h" -#define MULTI_BUTTON_STATE_1 0x01 -#define MULTI_BUTTON_STATE_2 0x02 -#define MULTI_BUTTON_HOLD_TRIGGERED_1 0x04 -#define MULTI_BUTTON_HOLD_TRIGGERED_2 0x08 -#define MULTI_BUTTON_SUPRESSED_1 0X10 -#define MULTI_BUTTON_SUPRESSED_2 0x20 -#define MULTI_BUTTON_ATTACHED 0x40 +#define MULTI_BUTTON_STATE_1 0x01 +#define MULTI_BUTTON_STATE_2 0x02 +#define MULTI_BUTTON_HOLD_TRIGGERED_1 0x04 +#define MULTI_BUTTON_HOLD_TRIGGERED_2 0x08 +#define MULTI_BUTTON_SUPRESSED_1 0X10 +#define MULTI_BUTTON_SUPRESSED_2 0x20 +#define MULTI_BUTTON_ATTACHED 0x40 /** - * Class definition for a MultiButton. - * - * Represents a virtual button, capable of reacting to simultaneous presses of two - * other buttons. - */ -namespace codal -{ - class MultiButton : public AbstractButton - { - uint16_t button1; // ID of the first button we're monitoring - uint16_t button2; // ID of the second button we're monitoring - ButtonEventConfiguration eventConfiguration; // Do we want to generate high level event (clicks), or defer this to another service. - - /** - * Retrieves the button id for the alternate button id given. - * - * @param b the id of the button whose state we would like to retrieve. - * - * @return the other sub button id. - */ - uint16_t otherSubButton(uint16_t b); - - /** - * Determines if the given button id is marked as pressed. - * - * @param button the id of the button whose state we would like to retrieve. - * - * @return 1 if pressed, 0 if not. - */ - int isSubButtonPressed(uint16_t button); - - /** - * Determines if the given button id is marked as held. - * - * @param button the id of the button whose state we would like to retrieve. - * - * @return 1 if held, 0 if not. - */ - int isSubButtonHeld(uint16_t button); - - /** - * Determines if the given button id is marked as supressed. - * - * @param button the id of the button whose state we would like to retrieve. - * - * @return 1 if supressed, 0 if not. - */ - int isSubButtonSupressed(uint16_t button); - - /** - * Configures the button pressed state for the given button id. - * - * @param button the id of the button whose state requires updating. - * - * @param value the value to set for this buttons state. (Transformed into a logical 0 or 1). - */ - void setButtonState(uint16_t button, int value); - - /** - * Configures the button held state for the given button id. - * - * @param button the id of the button whose state requires updating. - * - * @param value the value to set for this buttons state. (Transformed into a logical 0 or 1). - */ - void setHoldState(uint16_t button, int value); - - /** - * Configures the button suppressed state for the given button id. - * - * @param button the id of the button whose state requires updating. - * - * @param value the value to set for this buttons state. (Transformed into a logical 0 or 1). - */ - void setSupressedState(uint16_t button, int value); - - public: - - /** - * Constructor. - * - * Create a representation of a virtual button, that generates events based upon the combination - * of two given buttons. - * - * @param button1 the unique ID of the first button to watch. - * - * @param button2 the unique ID of the second button to watch. - * - * @param id the unique EventModel id of this MultiButton instance. - * - * @code - * multiButton(DEVICE_ID_BUTTON_A, DEVICE_ID_BUTTON_B, DEVICE_ID_BUTTON_AB); - * @endcode - */ - MultiButton(uint16_t button1, uint16_t button2, uint16_t id); - - /** - * Tests if this MultiButton instance is virtually pressed. - * - * @return 1 if both physical buttons are pressed simultaneously. - * - * @code - * if(buttonAB.isPressed()) - * display.scroll("Pressed!"); - * @endcode - */ - virtual int isPressed(); - - /** - * Changes the event configuration of this button to the given ButtonEventConfiguration. - * All subsequent events generated by this button will then be informed by this configuration. - * - * @param config The new configuration for this button. Legal values are DEVICE_BUTTON_ALL_EVENTS or DEVICE_BUTTON_SIMPLE_EVENTS. - * - * @code - * // Configure a button to generate all possible events. - * buttonAB.setEventConfiguration(DEVICE_BUTTON_ALL_EVENTS); - * - * // Configure a button to suppress DEVICE_BUTTON_EVT_CLICK and DEVICE_BUTTON_EVT_LONG_CLICK events. - * buttonAB.setEventConfiguration(DEVICE_BUTTON_SIMPLE_EVENTS); - * @endcode - */ - void setEventConfiguration(ButtonEventConfiguration config); - - private: - - /** - * A member function that is invoked when any event is detected from the two - * button IDs this MultiButton instance was constructed with. - * - * @param evt the event received from the default EventModel. - */ - void onButtonEvent(Event evt); - }; -} + * Class definition for a MultiButton. + * + * Represents a virtual button, capable of reacting to simultaneous presses of two + * other buttons. + */ +namespace codal { +class MultiButton : public AbstractButton { + uint16_t button1; // ID of the first button we're monitoring + uint16_t button2; // ID of the second button we're monitoring + ButtonEventConfiguration + eventConfiguration; // Do we want to generate high level event (clicks), or defer this to another service. + + /** + * Retrieves the button id for the alternate button id given. + * + * @param b the id of the button whose state we would like to retrieve. + * + * @return the other sub button id. + */ + uint16_t otherSubButton(uint16_t b); + + /** + * Determines if the given button id is marked as pressed. + * + * @param button the id of the button whose state we would like to retrieve. + * + * @return 1 if pressed, 0 if not. + */ + int isSubButtonPressed(uint16_t button); + + /** + * Determines if the given button id is marked as held. + * + * @param button the id of the button whose state we would like to retrieve. + * + * @return 1 if held, 0 if not. + */ + int isSubButtonHeld(uint16_t button); + + /** + * Determines if the given button id is marked as supressed. + * + * @param button the id of the button whose state we would like to retrieve. + * + * @return 1 if supressed, 0 if not. + */ + int isSubButtonSupressed(uint16_t button); + + /** + * Configures the button pressed state for the given button id. + * + * @param button the id of the button whose state requires updating. + * + * @param value the value to set for this buttons state. (Transformed into a logical 0 or 1). + */ + void setButtonState(uint16_t button, int value); + + /** + * Configures the button held state for the given button id. + * + * @param button the id of the button whose state requires updating. + * + * @param value the value to set for this buttons state. (Transformed into a logical 0 or 1). + */ + void setHoldState(uint16_t button, int value); + + /** + * Configures the button suppressed state for the given button id. + * + * @param button the id of the button whose state requires updating. + * + * @param value the value to set for this buttons state. (Transformed into a logical 0 or 1). + */ + void setSupressedState(uint16_t button, int value); + + public: + /** + * Constructor. + * + * Create a representation of a virtual button, that generates events based upon the combination + * of two given buttons. + * + * @param button1 the unique ID of the first button to watch. + * + * @param button2 the unique ID of the second button to watch. + * + * @param id the unique EventModel id of this MultiButton instance. + * + * @code + * multiButton(DEVICE_ID_BUTTON_A, DEVICE_ID_BUTTON_B, DEVICE_ID_BUTTON_AB); + * @endcode + */ + MultiButton(uint16_t button1, uint16_t button2, uint16_t id); + + /** + * Tests if this MultiButton instance is virtually pressed. + * + * @return 1 if both physical buttons are pressed simultaneously. + * + * @code + * if(buttonAB.isPressed()) + * display.scroll("Pressed!"); + * @endcode + */ + virtual int isPressed(); + + /** + * Changes the event configuration of this button to the given ButtonEventConfiguration. + * All subsequent events generated by this button will then be informed by this configuration. + * + * @param config The new configuration for this button. Legal values are DEVICE_BUTTON_ALL_EVENTS or + * DEVICE_BUTTON_SIMPLE_EVENTS. + * + * @code + * // Configure a button to generate all possible events. + * buttonAB.setEventConfiguration(DEVICE_BUTTON_ALL_EVENTS); + * + * // Configure a button to suppress DEVICE_BUTTON_EVT_CLICK and DEVICE_BUTTON_EVT_LONG_CLICK events. + * buttonAB.setEventConfiguration(DEVICE_BUTTON_SIMPLE_EVENTS); + * @endcode + */ + void setEventConfiguration(ButtonEventConfiguration config); + + private: + /** + * A member function that is invoked when any event is detected from the two + * button IDs this MultiButton instance was constructed with. + * + * @param evt the event received from the default EventModel. + */ + void onButtonEvent(Event evt); +}; +} // namespace codal #endif diff --git a/inc/drivers/NonLinearAnalogSensor.h b/inc/drivers/NonLinearAnalogSensor.h index b65dfd05..5c281d84 100644 --- a/inc/drivers/NonLinearAnalogSensor.h +++ b/inc/drivers/NonLinearAnalogSensor.h @@ -25,49 +25,48 @@ DEALINGS IN THE SOFTWARE. #ifndef NONLINEAR_ANALOG_SENSOR_H #define NONLINEAR_ANALOG_SENSOR_H -#include "CodalConfig.h" #include "AnalogSensor.h" +#include "CodalConfig.h" -namespace codal -{ +namespace codal { +/** + * Class definition for a normalised, non-linear analog sensor, that takes the general form of a logarithmic response to + * a sensed value, in a potential divider. Implements a base class for such a sensor, using the Steinhart-Hart equation + * to delineate a result. + */ +class NonLinearAnalogSensor : public AnalogSensor { + float nominalValue; // The value (in SI units) of a nominal position. + float nominalReading; // The reading (in sensed level) at that nominal position. + float beta; // The Steinhart B parameter. + float seriesResistor; // the resitance (in ohms) of the associated series resistor. + float zeroOffset; // A user defined "zero" point (negative asymptote). + + public: /** - * Class definition for a normalised, non-linear analog sensor, that takes the general form of a logarithmic response to a sensed value, in a potential divider. - * Implements a base class for such a sensor, using the Steinhart-Hart equation to delineate a result. + * Constructor. + * + * Creates a generic AnalogSensor. + * + * @param pin The pin on which to sense + * @param id The ID of this compoenent e.g. DEVICE_ID_THERMOMETER + * @param nominalValue The value (in SI units) of a nominal position. + * @param nominalReading The raw reading from the sensor at the nominal position. + * @param beta The Steinhart-Hart Beta constant for the device + * @param seriesResistor The value (in ohms) of the resistor in series with the sensor. + * @param zeroOffset Optional zero offset applied to all SI units (e.g. 273.15 for temperature sensing in C vs + * Kelvin). + * */ - class NonLinearAnalogSensor : public AnalogSensor - { - float nominalValue; // The value (in SI units) of a nominal position. - float nominalReading; // The reading (in sensed level) at that nominal position. - float beta; // The Steinhart B parameter. - float seriesResistor; // the resitance (in ohms) of the associated series resistor. - float zeroOffset; // A user defined "zero" point (negative asymptote). - - public: + NonLinearAnalogSensor(Pin& pin, uint16_t id, float nominalValue, float nominalReading, float beta, + float seriesResistor, float zeroOffset = 0.0f); - /** - * Constructor. - * - * Creates a generic AnalogSensor. - * - * @param pin The pin on which to sense - * @param id The ID of this compoenent e.g. DEVICE_ID_THERMOMETER - * @param nominalValue The value (in SI units) of a nominal position. - * @param nominalReading The raw reading from the sensor at the nominal position. - * @param beta The Steinhart-Hart Beta constant for the device - * @param seriesResistor The value (in ohms) of the resistor in series with the sensor. - * @param zeroOffset Optional zero offset applied to all SI units (e.g. 273.15 for temperature sensing in C vs Kelvin). - * - */ - NonLinearAnalogSensor(Pin &pin, uint16_t id, float nominalValue, float nominalReading, float beta, float seriesResistor, float zeroOffset = 0.0f); - - /** - * Updates the internal reading of the sensor. Typically called periodicaly. - * - * @return DEVICE_OK on success. - */ - virtual void updateSample(); - - }; -} + /** + * Updates the internal reading of the sensor. Typically called periodicaly. + * + * @return DEVICE_OK on success. + */ + virtual void updateSample(); +}; +} // namespace codal #endif diff --git a/inc/drivers/PearsonHash.h b/inc/drivers/PearsonHash.h index 6b13a152..93184a03 100644 --- a/inc/drivers/PearsonHash.h +++ b/inc/drivers/PearsonHash.h @@ -4,21 +4,19 @@ #include "CodalConfig.h" #include "ManagedString.h" -namespace codal -{ - /** - * PearsonHashing is a simple way to turn a string into a number. - * Unfortunately, uniqueness guarantees are not too high, and scales with the bit depth. - **/ - class PearsonHash - { - static uint32_t hashN(ManagedString s, uint8_t byteCount); +namespace codal { +/** + * PearsonHashing is a simple way to turn a string into a number. + * Unfortunately, uniqueness guarantees are not too high, and scales with the bit depth. + **/ +class PearsonHash { + static uint32_t hashN(ManagedString s, uint8_t byteCount); - public: - static uint8_t hash8(ManagedString s); - static uint16_t hash16(ManagedString s); - static uint32_t hash32(ManagedString s); - }; -} + public: + static uint8_t hash8(ManagedString s); + static uint16_t hash16(ManagedString s); + static uint32_t hash32(ManagedString s); +}; +} // namespace codal #endif \ No newline at end of file diff --git a/inc/drivers/PulseIn.h b/inc/drivers/PulseIn.h index 58554880..d3b5df56 100644 --- a/inc/drivers/PulseIn.h +++ b/inc/drivers/PulseIn.h @@ -22,41 +22,39 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include "CodalFiber.h" #include "Event.h" #include "Pin.h" -#include "CodalFiber.h" #ifndef CODAL_PULSE_IN_H #define CODAL_PULSE_IN_H -#define DEVICE_EVT_PULSE_IN_TIMEOUT 10000 +#define DEVICE_EVT_PULSE_IN_TIMEOUT 10000 -namespace codal -{ +namespace codal { -class PulseIn : public PinPeripheral -{ - Pin &pin; - uint32_t lastPeriod; - FiberLock lock; - CODAL_TIMESTAMP timeout; - static bool timeoutGeneratorStarted; - bool enabled; +class PulseIn : public PinPeripheral { + Pin& pin; + uint32_t lastPeriod; + FiberLock lock; + CODAL_TIMESTAMP timeout; + static bool timeoutGeneratorStarted; + bool enabled; + + public: + uint32_t lastEdge; - public: - uint32_t lastEdge; - /** * Creates a new instance of a synchronous pulse detector ont he given pin. - * + * * @param pin The pin to observe for pulse events * @return the period of the next pulse in microseconds, or XXX if the given timeout expires. */ - PulseIn(Pin &pin); + PulseIn(Pin& pin); /** * Synchronously await a pulse, and return the period of the pulse. - * + * * @param timeout The maximum amount of time to wait for a pulse, in microseconds. Set to zero to wait indefinitely. * @return The period of the next pulse, in microseconds, or DEVICE_CANCELLED if the timeout passes. */ @@ -65,32 +63,30 @@ class PulseIn : public PinPeripheral /** * Event handler called when a pulse is detected. */ - void - onPulse(Event e); + void onPulse(Event e); /** * Event handler called when a timeout event is generated. */ - void - onTimeout(Event e); + void onTimeout(Event e); /** - * Method to release the given pin from a peripheral, if already bound. - * Device drivers should override this method to disconnect themselves from the give pin - * to allow it to be used by a different peripheral. - * - * @param pin the Pin to be released - */ - virtual int releasePin(Pin &pin) override; + * Method to release the given pin from a peripheral, if already bound. + * Device drivers should override this method to disconnect themselves from the give pin + * to allow it to be used by a different peripheral. + * + * @param pin the Pin to be released + */ + virtual int releasePin(Pin& pin) override; /** * Destructor */ virtual ~PulseIn(); - private: + private: void disable(); }; -} +} // namespace codal #endif diff --git a/inc/drivers/SPIScreenIO.h b/inc/drivers/SPIScreenIO.h index 1d96a34b..14641320 100644 --- a/inc/drivers/SPIScreenIO.h +++ b/inc/drivers/SPIScreenIO.h @@ -29,19 +29,16 @@ DEALINGS IN THE SOFTWARE. #include "SPI.h" #include "ScreenIO.h" -namespace codal -{ - -class SPIScreenIO : public ScreenIO -{ -public: - SPI &spi; - SPIScreenIO(SPI &spi); - virtual void send(const void *txBuffer, uint32_t txSize); - virtual void startSend(const void *txBuffer, uint32_t txSize, PVoidCallback doneHandler, - void *handlerArg); +namespace codal { + +class SPIScreenIO : public ScreenIO { + public: + SPI& spi; + SPIScreenIO(SPI& spi); + virtual void send(const void* txBuffer, uint32_t txSize); + virtual void startSend(const void* txBuffer, uint32_t txSize, PVoidCallback doneHandler, void* handlerArg); }; -} // namespace codal +} // namespace codal #endif \ No newline at end of file diff --git a/inc/drivers/ST7735.h b/inc/drivers/ST7735.h index 7b1020f0..8dc4d84b 100644 --- a/inc/drivers/ST7735.h +++ b/inc/drivers/ST7735.h @@ -25,32 +25,30 @@ DEALINGS IN THE SOFTWARE. #ifndef DEVICE_ST7735_H #define DEVICE_ST7735_H +#include "Event.h" #include "Pin.h" #include "SPI.h" -#include "Event.h" #include "ScreenIO.h" -namespace codal -{ +namespace codal { struct ST7735WorkBuffer; -#define MADCTL_MY 0x80 -#define MADCTL_MX 0x40 -#define MADCTL_MV 0x20 -#define MADCTL_ML 0x10 +#define MADCTL_MY 0x80 +#define MADCTL_MX 0x40 +#define MADCTL_MV 0x20 +#define MADCTL_ML 0x10 #define MADCTL_RGB 0x00 #define MADCTL_BGR 0x08 -#define MADCTL_MH 0x04 - -class ST7735 : public CodalComponent -{ -protected: - ScreenIO &io; - Pin *cs; - Pin *dc; +#define MADCTL_MH 0x04 + +class ST7735 : public CodalComponent { + protected: + ScreenIO& io; + Pin* cs; + Pin* dc; uint8_t cmdBuf[20]; - ST7735WorkBuffer *work; + ST7735WorkBuffer* work; bool inSleepMode; // if true, every pixel will be plotted as 4 pixels and 16 bit color mode @@ -58,23 +56,29 @@ class ST7735 : public CodalComponent // and doesn't support 12 bit color bool double16; - void beginCS() { if (cs) cs->setDigitalValue(0); } - void endCS() { if (cs) cs->setDigitalValue(1); } + void beginCS() + { + if (cs) cs->setDigitalValue(0); + } + void endCS() + { + if (cs) cs->setDigitalValue(1); + } void setCommand() { dc->setDigitalValue(0); } void setData() { dc->setDigitalValue(1); } - void sendCmd(uint8_t *buf, int len); - void sendCmdSeq(const uint8_t *buf); + void sendCmd(uint8_t* buf, int len); + void sendCmdSeq(const uint8_t* buf); void sendDone(Event); void sendWords(unsigned numBytes); void startTransfer(unsigned size); void sendBytes(unsigned num); void startRAMWR(int cmd = 0); - static void sendColorsStep(ST7735 *st); + static void sendColorsStep(ST7735* st); -public: - ST7735(ScreenIO &io, Pin &cs, Pin &dc); + public: + ST7735(ScreenIO& io, Pin& cs, Pin& dc); virtual int init(); /** @@ -93,7 +97,7 @@ class ST7735 : public CodalComponent * Send 4 bit indexed color image, little endian, column-major, using specified palette (use * NULL if unchanged). */ - int sendIndexedImage(const uint8_t *src, unsigned width, unsigned height, uint32_t *palette); + int sendIndexedImage(const uint8_t* src, unsigned width, unsigned height, uint32_t* palette); /** * Waits for the previous sendIndexedImage() operation to complete (it normally executes in * background). @@ -106,6 +110,6 @@ class ST7735 : public CodalComponent virtual int setSleep(bool sleepMode); }; -} // namespace codal +} // namespace codal #endif \ No newline at end of file diff --git a/inc/drivers/StandardSPIFlash.h b/inc/drivers/StandardSPIFlash.h index 12d0274b..91d647d9 100644 --- a/inc/drivers/StandardSPIFlash.h +++ b/inc/drivers/StandardSPIFlash.h @@ -25,35 +25,33 @@ DEALINGS IN THE SOFTWARE. #ifndef CODAL_STD_SPIFLASH_H #define CODAL_STD_SPIFLASH_H -#include "SPIFlash.h" #include "SPI.h" +#include "SPIFlash.h" -namespace codal -{ -class StandardSPIFlash : public SPIFlash -{ -protected: +namespace codal { +class StandardSPIFlash : public SPIFlash { + protected: uint32_t _numPages; - SPI &spi; - Pin &ssel; + SPI& spi; + Pin& ssel; uint8_t cmdBuf[4]; uint8_t status; void setCommand(uint8_t command, int addr); - int sendCommand(uint8_t command, int addr = -1, void *resp = 0, int respSize = 0); + int sendCommand(uint8_t command, int addr = -1, void* resp = 0, int respSize = 0); int eraseCore(uint8_t cmd, uint32_t addr); int waitBusy(int waitMS); void writeEnable(); -public: - StandardSPIFlash(SPI &spi, Pin &ssel, int numPages); + public: + StandardSPIFlash(SPI& spi, Pin& ssel, int numPages); virtual int numPages(); - virtual int readBytes(uint32_t addr, void *buffer, uint32_t len); - virtual int writeBytes(uint32_t addr, const void *buffer, uint32_t len); + virtual int readBytes(uint32_t addr, void* buffer, uint32_t len); + virtual int writeBytes(uint32_t addr, const void* buffer, uint32_t len); virtual int eraseSmallRow(uint32_t addr); virtual int eraseBigRow(uint32_t addr); virtual int eraseChip(); }; -} +} // namespace codal #endif diff --git a/inc/drivers/TouchButton.h b/inc/drivers/TouchButton.h index 2dc44a20..2e19760b 100644 --- a/inc/drivers/TouchButton.h +++ b/inc/drivers/TouchButton.h @@ -25,129 +25,126 @@ DEALINGS IN THE SOFTWARE. #ifndef TOUCH_BUTTON_H #define TOUCH_BUTTON_H -#include "CodalConfig.h" #include "Button.h" #include "CodalComponent.h" +#include "CodalConfig.h" #include "Event.h" #include "Pin.h" #include "TouchSensor.h" // Constants associated with TouchButton -#define TOUCH_BUTTON_CALIBRATION_LINEAR_OFFSET 2 // Constant value added to sensed baseline to determine threshold. -#define TOUCH_BUTTON_CALIBRATION_PERCENTAGE_OFFSET 5 // Proportion (percentage) of baseline reading added to sensed baseline to determine threshold. +#define TOUCH_BUTTON_CALIBRATION_LINEAR_OFFSET 2 // Constant value added to sensed baseline to determine threshold. +#define TOUCH_BUTTON_CALIBRATION_PERCENTAGE_OFFSET \ + 5 // Proportion (percentage) of baseline reading added to sensed baseline to determine threshold. // Configure default TouchButton sensitivity. Defined as a percentage above the current threshold. // Samples above this value are classified as ACTIVE. #ifndef TOUCH_BUTTON_SENSITIVITY -#define TOUCH_BUTTON_SENSITIVITY 10 +#define TOUCH_BUTTON_SENSITIVITY 10 #endif -// Configure default TouchButton calibration period. -//Defined as number of samples to aggregate. +// Configure default TouchButton calibration period. +// Defined as number of samples to aggregate. #ifndef TOUCH_BUTTON_CALIBRATION_PERIOD -#define TOUCH_BUTTON_CALIBRATION_PERIOD 10 +#define TOUCH_BUTTON_CALIBRATION_PERIOD 10 #endif // Status flags associated with a touch sensor -#define TOUCH_BUTTON_CALIBRATING 0x10 -#define TOUCH_BUTTON_RUNNING 0x20 +#define TOUCH_BUTTON_CALIBRATING 0x10 +#define TOUCH_BUTTON_RUNNING 0x20 + +namespace codal { +class TouchSensor; + +/** + * Class definition for a TouchButtonButton. + * + * Represents a single, software controlled capacitative touch button on the device. + */ +class TouchButton : public Button { + public: + TouchSensor& touchSensor; // The TouchSensor driving this button + int threshold; // The calibration threshold of this button + int reading; // The last sample taken of this button. + bool active; // true if this button is currnelty being sensed, false otherwise. + + /** + * Constructor. + * + * Enables software controlled capacitative touch sensing on the given pin. + * + * @param pin The physical pin on the device to sense. + * @param sensor The touch sensor driver for this touch sensitive pin. + * @param threshold The calibration threshold to use for this button. If undefined, auto calibration will be + * performed. + */ + TouchButton(Pin& pin, TouchSensor& sensor, int threshold = -1); + + /** + * Estimate and apply a threshold based on the current reading of the device. + */ + void calibrate(); + + /** + * Manually define the threshold use to detect a touch event. Any sensed value equal to or greater than this value + * will be interpreted as a touch. See getValue(). + * + * @param threshold The threshold value to use for this touchButton. + */ + void setThreshold(int threshold); + + /** + * Determine the threshold currently in use by the TouchButton + * + * @return the current threshold value + */ + int getThreshold(); -namespace codal -{ - class TouchSensor; + /** + * Determine the last reading taken from this button. + * + * @return the last reading taken. + */ + int getValue(); + + /** + * Updates the record of the last reading from this button. + */ + void setValue(int reading); + + /** + * Determines if this button is instantenously active (i.e. pressed). + * Internal method, use before debouncing. + */ + int buttonActive(); /** - * Class definition for a TouchButtonButton. - * - * Represents a single, software controlled capacitative touch button on the device. - */ - class TouchButton : public Button - { - public: - - TouchSensor &touchSensor; // The TouchSensor driving this button - int threshold; // The calibration threshold of this button - int reading; // The last sample taken of this button. - bool active; // true if this button is currnelty being sensed, false otherwise. - - - /** - * Constructor. - * - * Enables software controlled capacitative touch sensing on the given pin. - * - * @param pin The physical pin on the device to sense. - * @param sensor The touch sensor driver for this touch sensitive pin. - * @param threshold The calibration threshold to use for this button. If undefined, auto calibration will be performed. - */ - TouchButton(Pin &pin, TouchSensor &sensor, int threshold = -1); - - /** - * Estimate and apply a threshold based on the current reading of the device. - */ - void calibrate(); - - /** - * Manually define the threshold use to detect a touch event. Any sensed value equal to or greater than this value will - * be interpreted as a touch. See getValue(). - * - * @param threshold The threshold value to use for this touchButton. - */ - void setThreshold(int threshold); - - /** - * Determine the threshold currently in use by the TouchButton - * - * @return the current threshold value - */ - int getThreshold(); - - /** - * Determine the last reading taken from this button. - * - * @return the last reading taken. - */ - int getValue(); - - /** - * Updates the record of the last reading from this button. - */ - void setValue(int reading); - - /** - * Determines if this button is instantenously active (i.e. pressed). - * Internal method, use before debouncing. - */ - int buttonActive(); - - /** - * Determines the instantneous digital value of the pin associated with this TouchButton - * - * @return true if a digital read of the attached pin is a logic 1, false otherwise. - */ - int getPinValue(); - - /** - * Drives a given digital value to the pin associated with this TouchButton - * - * @param v the digital value to write to the pin associated with this TouchButton. - */ - void setPinValue(int v); - - /** - * Method to release the given pin from a peripheral, if already bound. - * Device drivers should override this method to disconnect themselves from the give pin - * to allow it to be used by a different peripheral. - * - * @param pin the Pin to be released - */ - virtual int releasePin(Pin &pin) override; - /** - * Destructor for Button, where we deregister this instance from the array of fiber components. - */ - ~TouchButton(); - - }; -} + * Determines the instantneous digital value of the pin associated with this TouchButton + * + * @return true if a digital read of the attached pin is a logic 1, false otherwise. + */ + int getPinValue(); + + /** + * Drives a given digital value to the pin associated with this TouchButton + * + * @param v the digital value to write to the pin associated with this TouchButton. + */ + void setPinValue(int v); + + /** + * Method to release the given pin from a peripheral, if already bound. + * Device drivers should override this method to disconnect themselves from the give pin + * to allow it to be used by a different peripheral. + * + * @param pin the Pin to be released + */ + virtual int releasePin(Pin& pin) override; + /** + * Destructor for Button, where we deregister this instance from the array of fiber components. + */ + ~TouchButton(); +}; +} // namespace codal #endif diff --git a/inc/drivers/TouchSensor.h b/inc/drivers/TouchSensor.h index a78f5cd4..0b3b0b64 100644 --- a/inc/drivers/TouchSensor.h +++ b/inc/drivers/TouchSensor.h @@ -25,79 +25,75 @@ DEALINGS IN THE SOFTWARE. #ifndef TOUCH_SENSOR_H #define TOUCH_SENSOR_H -#include "CodalConfig.h" #include "CodalComponent.h" +#include "CodalConfig.h" #include "Event.h" #include "Pin.h" #include "TouchButton.h" // Constants -#define TOUCH_SENSOR_MAX_BUTTONS 10 -#define TOUCH_SENSOR_SAMPLE_PERIOD 50 -#define TOUCH_SENSE_SAMPLE_MAX 1000 +#define TOUCH_SENSOR_MAX_BUTTONS 10 +#define TOUCH_SENSOR_SAMPLE_PERIOD 50 +#define TOUCH_SENSE_SAMPLE_MAX 1000 // Event codes associate with this touch sensor. -#define TOUCH_SENSOR_UPDATE_NEEDED 1 +#define TOUCH_SENSOR_UPDATE_NEEDED 1 + +namespace codal { +class TouchButton; + +/** + * Class definition for a TouchSensor + * + * Drives a number of TouchButtons ona device. + */ +class TouchSensor : public CodalComponent { + protected: + TouchButton* buttons[TOUCH_SENSOR_MAX_BUTTONS]; + Pin& drivePin; + int numberOfButtons; + + public: + /** + * Constructor. + * + * Enables software controlled capacitative touch sensing on a set of pins. + * + * @param pin The physical pin on the device that drives the capacitative sensing. + * @id The ID of this component, defaults to DEVICE_ID_TOUCH_SENSOR + */ + TouchSensor(Pin& pin, uint16_t id = DEVICE_ID_TOUCH_SENSOR); + + /** + * Default Constructor. + * + * Enables software controlled capacitative touch sensing on a set of pins. + * Use this default constructor when using TouchSensor as a base class. + * + * @id The ID of this component, defaults to DEVICE_ID_TOUCH_SENSOR + */ + TouchSensor(uint16_t id); -namespace codal -{ - class TouchButton; + /** + * Begin touch sensing on the given button + */ + virtual int addTouchButton(TouchButton* button); + + /** + * Stop touch sensing on the given button + */ + virtual int removeTouchButton(TouchButton* button); + + /** + * Initiate a scan of the sensors. + */ + virtual void onSampleEvent(Event); /** - * Class definition for a TouchSensor - * - * Drives a number of TouchButtons ona device. - */ - class TouchSensor : public CodalComponent - { - protected: - - TouchButton* buttons[TOUCH_SENSOR_MAX_BUTTONS]; - Pin &drivePin; - int numberOfButtons; - - public: - - /** - * Constructor. - * - * Enables software controlled capacitative touch sensing on a set of pins. - * - * @param pin The physical pin on the device that drives the capacitative sensing. - * @id The ID of this component, defaults to DEVICE_ID_TOUCH_SENSOR - */ - TouchSensor(Pin &pin, uint16_t id = DEVICE_ID_TOUCH_SENSOR); - - /** - * Default Constructor. - * - * Enables software controlled capacitative touch sensing on a set of pins. - * Use this default constructor when using TouchSensor as a base class. - * - * @id The ID of this component, defaults to DEVICE_ID_TOUCH_SENSOR - */ - TouchSensor(uint16_t id); - - /** - * Begin touch sensing on the given button - */ - virtual int addTouchButton(TouchButton *button); - - /** - * Stop touch sensing on the given button - */ - virtual int removeTouchButton(TouchButton *button); - - /** - * Initiate a scan of the sensors. - */ - virtual void onSampleEvent(Event); - - /** - * Destructor. - */ - ~TouchSensor(); - }; -} + * Destructor. + */ + ~TouchSensor(); +}; +} // namespace codal #endif diff --git a/inc/drivers/USBMSC.h b/inc/drivers/USBMSC.h index dceed24b..76989ab6 100644 --- a/inc/drivers/USBMSC.h +++ b/inc/drivers/USBMSC.h @@ -30,21 +30,19 @@ DEALINGS IN THE SOFTWARE. #if CONFIG_ENABLED(DEVICE_USB) -namespace codal -{ +namespace codal { struct MSCState; -class USBMSC : public CodalUSBInterface -{ - struct MSCState *state; +class USBMSC : public CodalUSBInterface { + struct MSCState* state; uint32_t blockAddr; uint16_t blockCount; bool failed; bool listen; bool disableIRQ; - bool writePadded(const void *ptr, int dataSize, int allocSize = -1); + bool writePadded(const void* ptr, int dataSize, int allocSize = -1); void writeHandler(Event); void readHandler(Event); @@ -60,27 +58,27 @@ class USBMSC : public CodalUSBInterface bool cmdModeSense(bool is10); bool cmdReadFormatCapacity(); -public: + public: USBMSC(); virtual int endpointRequest(); - virtual int classRequest(UsbEndpointIn &ctrl, USBSetup &setup); - virtual const InterfaceInfo *getInterfaceInfo(); + virtual int classRequest(UsbEndpointIn& ctrl, USBSetup& setup); + virtual const InterfaceInfo* getInterfaceInfo(); virtual int totalLUNs() { return 1; } virtual bool storageOK() { return true; } virtual bool isReadOnly() { return false; } - virtual uint32_t getCapacity() { return 8 * 1024 * 2; } // 8M + virtual uint32_t getCapacity() { return 8 * 1024 * 2; } // 8M - void writeBulk(const void *ptr, int dataSize); - void readBulk(void *ptr, int dataSize); + void writeBulk(const void* ptr, int dataSize); + void readBulk(void* ptr, int dataSize); void finishReadWrite(); int currLUN(); uint32_t cbwTag(); - virtual void readBlocks(int blockAddr, int numBlocks) = 0; + virtual void readBlocks(int blockAddr, int numBlocks) = 0; virtual void writeBlocks(int blockAddr, int numBlocks) = 0; }; -} +} // namespace codal #endif diff --git a/inc/drivers/USBMassStorageClass.h b/inc/drivers/USBMassStorageClass.h index f34d198a..86f397f3 100644 --- a/inc/drivers/USBMassStorageClass.h +++ b/inc/drivers/USBMassStorageClass.h @@ -52,315 +52,310 @@ #define ATTR_PACKED __attribute__((packed)) - /* Includes: */ +/* Includes: */ - /* Enable C linkage for C++ Compilers: */ - #if defined(__cplusplus) - extern "C" { - #endif +/* Enable C linkage for C++ Compilers: */ +#if defined(__cplusplus) +extern "C" { +#endif + +/* Macros: */ +/** Magic signature for a Command Block Wrapper used in the Mass Storage Bulk-Only transport protocol. */ +#define MS_CBW_SIGNATURE 0x43425355UL + +/** Magic signature for a Command Status Wrapper used in the Mass Storage Bulk-Only transport protocol. */ +#define MS_CSW_SIGNATURE 0x53425355UL - /* Macros: */ - /** Magic signature for a Command Block Wrapper used in the Mass Storage Bulk-Only transport protocol. */ - #define MS_CBW_SIGNATURE 0x43425355UL +/** Mask for a Command Block Wrapper's flags attribute to specify a command with data sent from host-to-device. */ +#define MS_COMMAND_DIR_DATA_OUT (0 << 7) - /** Magic signature for a Command Status Wrapper used in the Mass Storage Bulk-Only transport protocol. */ - #define MS_CSW_SIGNATURE 0x53425355UL +/** Mask for a Command Block Wrapper's flags attribute to specify a command with data sent from device-to-host. */ +#define MS_COMMAND_DIR_DATA_IN (1 << 7) - /** Mask for a Command Block Wrapper's flags attribute to specify a command with data sent from host-to-device. */ - #define MS_COMMAND_DIR_DATA_OUT (0 << 7) +/** \name SCSI Commands*/ +//@{ +/** SCSI Command Code for an INQUIRY command. */ +#define SCSI_CMD_INQUIRY 0x12 - /** Mask for a Command Block Wrapper's flags attribute to specify a command with data sent from device-to-host. */ - #define MS_COMMAND_DIR_DATA_IN (1 << 7) +/** SCSI Command Code for a REQUEST SENSE command. */ +#define SCSI_CMD_REQUEST_SENSE 0x03 - /** \name SCSI Commands*/ - //@{ - /** SCSI Command Code for an INQUIRY command. */ - #define SCSI_CMD_INQUIRY 0x12 +/** SCSI Command Code for a TEST UNIT READY command. */ +#define SCSI_CMD_TEST_UNIT_READY 0x00 - /** SCSI Command Code for a REQUEST SENSE command. */ - #define SCSI_CMD_REQUEST_SENSE 0x03 +/** SCSI Command Code for a READ CAPACITY (10) command. */ +#define SCSI_CMD_READ_CAPACITY_10 0x25 - /** SCSI Command Code for a TEST UNIT READY command. */ - #define SCSI_CMD_TEST_UNIT_READY 0x00 +/** SCSI Command Code for a START STOP UNIT command. */ +#define SCSI_CMD_START_STOP_UNIT 0x1B - /** SCSI Command Code for a READ CAPACITY (10) command. */ - #define SCSI_CMD_READ_CAPACITY_10 0x25 +/** SCSI Command Code for a SEND DIAGNOSTIC command. */ +#define SCSI_CMD_SEND_DIAGNOSTIC 0x1D - /** SCSI Command Code for a START STOP UNIT command. */ - #define SCSI_CMD_START_STOP_UNIT 0x1B +/** SCSI Command Code for a PREVENT ALLOW MEDIUM REMOVAL command. */ +#define SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E - /** SCSI Command Code for a SEND DIAGNOSTIC command. */ - #define SCSI_CMD_SEND_DIAGNOSTIC 0x1D +/** SCSI Command Code for a WRITE (10) command. */ +#define SCSI_CMD_WRITE_10 0x2A - /** SCSI Command Code for a PREVENT ALLOW MEDIUM REMOVAL command. */ - #define SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E +/** SCSI Command Code for a READ (10) command. */ +#define SCSI_CMD_READ_10 0x28 - /** SCSI Command Code for a WRITE (10) command. */ - #define SCSI_CMD_WRITE_10 0x2A +/** SCSI Command Code for a WRITE (6) command. */ +#define SCSI_CMD_WRITE_6 0x0A - /** SCSI Command Code for a READ (10) command. */ - #define SCSI_CMD_READ_10 0x28 +/** SCSI Command Code for a READ (6) command. */ +#define SCSI_CMD_READ_6 0x08 - /** SCSI Command Code for a WRITE (6) command. */ - #define SCSI_CMD_WRITE_6 0x0A +/** SCSI Command Code for a VERIFY (10) command. */ +#define SCSI_CMD_VERIFY_10 0x2F - /** SCSI Command Code for a READ (6) command. */ - #define SCSI_CMD_READ_6 0x08 +/** SCSI Command Code for a MODE SENSE (6) command. */ +#define SCSI_CMD_MODE_SENSE_6 0x1A - /** SCSI Command Code for a VERIFY (10) command. */ - #define SCSI_CMD_VERIFY_10 0x2F +/** SCSI Command Code for a MODE SENSE (10) command. */ +#define SCSI_CMD_MODE_SENSE_10 0x5A +//@} - /** SCSI Command Code for a MODE SENSE (6) command. */ - #define SCSI_CMD_MODE_SENSE_6 0x1A +#define SCSI_CMD_READ_FORMAT_CAPACITY 0x23 - /** SCSI Command Code for a MODE SENSE (10) command. */ - #define SCSI_CMD_MODE_SENSE_10 0x5A - //@} +/** \name SCSI Sense Key Values */ +//@{ +/** SCSI Sense Code to indicate no error has occurred. */ +#define SCSI_SENSE_KEY_GOOD 0x00 - #define SCSI_CMD_READ_FORMAT_CAPACITY 0x23 +/** SCSI Sense Code to indicate that the device has recovered from an error. */ +#define SCSI_SENSE_KEY_RECOVERED_ERROR 0x01 - /** \name SCSI Sense Key Values */ - //@{ - /** SCSI Sense Code to indicate no error has occurred. */ - #define SCSI_SENSE_KEY_GOOD 0x00 +/** SCSI Sense Code to indicate that the device is not ready for a new command. */ +#define SCSI_SENSE_KEY_NOT_READY 0x02 - /** SCSI Sense Code to indicate that the device has recovered from an error. */ - #define SCSI_SENSE_KEY_RECOVERED_ERROR 0x01 +/** SCSI Sense Code to indicate an error whilst accessing the medium. */ +#define SCSI_SENSE_KEY_MEDIUM_ERROR 0x03 - /** SCSI Sense Code to indicate that the device is not ready for a new command. */ - #define SCSI_SENSE_KEY_NOT_READY 0x02 +/** SCSI Sense Code to indicate a hardware error has occurred. */ +#define SCSI_SENSE_KEY_HARDWARE_ERROR 0x04 - /** SCSI Sense Code to indicate an error whilst accessing the medium. */ - #define SCSI_SENSE_KEY_MEDIUM_ERROR 0x03 +/** SCSI Sense Code to indicate that an illegal request has been issued. */ +#define SCSI_SENSE_KEY_ILLEGAL_REQUEST 0x05 + +/** SCSI Sense Code to indicate that the unit requires attention from the host to indicate + * a reset event, medium removal or other condition. + */ +#define SCSI_SENSE_KEY_UNIT_ATTENTION 0x06 - /** SCSI Sense Code to indicate a hardware error has occurred. */ - #define SCSI_SENSE_KEY_HARDWARE_ERROR 0x04 +/** SCSI Sense Code to indicate that a write attempt on a protected block has been made. */ +#define SCSI_SENSE_KEY_DATA_PROTECT 0x07 - /** SCSI Sense Code to indicate that an illegal request has been issued. */ - #define SCSI_SENSE_KEY_ILLEGAL_REQUEST 0x05 +/** SCSI Sense Code to indicate an error while trying to write to a write-once medium. */ +#define SCSI_SENSE_KEY_BLANK_CHECK 0x08 - /** SCSI Sense Code to indicate that the unit requires attention from the host to indicate - * a reset event, medium removal or other condition. - */ - #define SCSI_SENSE_KEY_UNIT_ATTENTION 0x06 +/** SCSI Sense Code to indicate a vendor specific error has occurred. */ +#define SCSI_SENSE_KEY_VENDOR_SPECIFIC 0x09 - /** SCSI Sense Code to indicate that a write attempt on a protected block has been made. */ - #define SCSI_SENSE_KEY_DATA_PROTECT 0x07 +/** SCSI Sense Code to indicate that an EXTENDED COPY command has aborted due to an error. */ +#define SCSI_SENSE_KEY_COPY_ABORTED 0x0A - /** SCSI Sense Code to indicate an error while trying to write to a write-once medium. */ - #define SCSI_SENSE_KEY_BLANK_CHECK 0x08 +/** SCSI Sense Code to indicate that the device has aborted the issued command. */ +#define SCSI_SENSE_KEY_ABORTED_COMMAND 0x0B - /** SCSI Sense Code to indicate a vendor specific error has occurred. */ - #define SCSI_SENSE_KEY_VENDOR_SPECIFIC 0x09 +/** SCSI Sense Code to indicate an attempt to write past the end of a partition has been made. */ +#define SCSI_SENSE_KEY_VOLUME_OVERFLOW 0x0D - /** SCSI Sense Code to indicate that an EXTENDED COPY command has aborted due to an error. */ - #define SCSI_SENSE_KEY_COPY_ABORTED 0x0A +/** SCSI Sense Code to indicate that the source data did not match the data read from the medium. */ +#define SCSI_SENSE_KEY_MISCOMPARE 0x0E +//@} - /** SCSI Sense Code to indicate that the device has aborted the issued command. */ - #define SCSI_SENSE_KEY_ABORTED_COMMAND 0x0B +/** \name SCSI Additional Sense Codes */ +//@{ +/** SCSI Additional Sense Code to indicate no additional sense information is available. */ +#define SCSI_ASENSE_NO_ADDITIONAL_INFORMATION 0x00 + +/** SCSI Additional Sense Code to indicate that the logical unit (LUN) addressed is not ready. */ +#define SCSI_ASENSE_LOGICAL_UNIT_NOT_READY 0x04 + +/** SCSI Additional Sense Code to indicate an invalid field was encountered while processing the issued command. */ +#define SCSI_ASENSE_INVALID_FIELD_IN_CDB 0x24 + +/** SCSI Additional Sense Code to indicate that a medium that was previously indicated as not ready has now + * become ready for use. + */ +#define SCSI_ASENSE_NOT_READY_TO_READY_CHANGE 0x28 - /** SCSI Sense Code to indicate an attempt to write past the end of a partition has been made. */ - #define SCSI_SENSE_KEY_VOLUME_OVERFLOW 0x0D - - /** SCSI Sense Code to indicate that the source data did not match the data read from the medium. */ - #define SCSI_SENSE_KEY_MISCOMPARE 0x0E - //@} - - /** \name SCSI Additional Sense Codes */ - //@{ - /** SCSI Additional Sense Code to indicate no additional sense information is available. */ - #define SCSI_ASENSE_NO_ADDITIONAL_INFORMATION 0x00 - - /** SCSI Additional Sense Code to indicate that the logical unit (LUN) addressed is not ready. */ - #define SCSI_ASENSE_LOGICAL_UNIT_NOT_READY 0x04 - - /** SCSI Additional Sense Code to indicate an invalid field was encountered while processing the issued command. */ - #define SCSI_ASENSE_INVALID_FIELD_IN_CDB 0x24 - - /** SCSI Additional Sense Code to indicate that a medium that was previously indicated as not ready has now - * become ready for use. - */ - #define SCSI_ASENSE_NOT_READY_TO_READY_CHANGE 0x28 - - /** SCSI Additional Sense Code to indicate that an attempt to write to a protected area was made. */ - #define SCSI_ASENSE_WRITE_PROTECTED 0x27 - - /** SCSI Additional Sense Code to indicate an error whilst formatting the device medium. */ - #define SCSI_ASENSE_FORMAT_ERROR 0x31 - - /** SCSI Additional Sense Code to indicate an invalid command was issued. */ - #define SCSI_ASENSE_INVALID_COMMAND 0x20 - - /** SCSI Additional Sense Code to indicate a write to a block out outside of the medium's range was issued. */ - #define SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x21 - - /** SCSI Additional Sense Code to indicate that no removable medium is inserted into the device. */ - #define SCSI_ASENSE_MEDIUM_NOT_PRESENT 0x3A - //@} - - /** \name SCSI Additional Sense Key Code Qualifiers */ - //@{ - /** SCSI Additional Sense Qualifier Code to indicate no additional sense qualifier information is available. */ - #define SCSI_ASENSEQ_NO_QUALIFIER 0x00 - - /** SCSI Additional Sense Qualifier Code to indicate that a medium format command failed to complete. */ - #define SCSI_ASENSEQ_FORMAT_COMMAND_FAILED 0x01 - - /** SCSI Additional Sense Qualifier Code to indicate that an initializing command must be issued before the issued - * command can be executed. - */ - #define SCSI_ASENSEQ_INITIALIZING_COMMAND_REQUIRED 0x02 - - /** SCSI Additional Sense Qualifier Code to indicate that an operation is currently in progress. */ - #define SCSI_ASENSEQ_OPERATION_IN_PROGRESS 0x07 - //@} - - /* Enums: */ - /** Enum for possible Class, Subclass and Protocol values of device and interface descriptors relating to the Mass - * Storage device class. - */ - enum MS_Descriptor_ClassSubclassProtocol_t - { - MS_CSCP_MassStorageClass = 0x08, /**< Descriptor Class value indicating that the device or interface - * belongs to the Mass Storage class. - */ - MS_CSCP_SCSITransparentSubclass = 0x06, /**< Descriptor Subclass value indicating that the device or interface - * belongs to the SCSI Transparent Command Set subclass of the Mass - * storage class. - */ - MS_CSCP_BulkOnlyTransportProtocol = 0x50, /**< Descriptor Protocol value indicating that the device or interface - * belongs to the Bulk Only Transport protocol of the Mass Storage class. - */ - }; - - /** Enum for the Mass Storage class specific control requests that can be issued by the USB bus host. */ - enum MS_ClassRequests_t - { - MS_REQ_GetMaxLUN = 0xFE, /**< Mass Storage class-specific request to retrieve the total number of Logical - * Units (drives) in the SCSI device. - */ - MS_REQ_MassStorageReset = 0xFF, /**< Mass Storage class-specific request to reset the Mass Storage interface, - * ready for the next command. - */ - }; - - /** Enum for the possible command status wrapper return status codes. */ - enum MS_CommandStatusCodes_t - { - MS_SCSI_COMMAND_Pass = 0, /**< Command completed with no error */ - MS_SCSI_COMMAND_Fail = 1, /**< Command failed to complete - host may check the exact error via a - * SCSI REQUEST SENSE command. - */ - MS_SCSI_COMMAND_PhaseError = 2, /**< Command failed due to being invalid in the current phase. */ - }; - - /* Type Defines: */ - /** \brief Mass Storage Class Command Block Wrapper. - * - * Type define for a Command Block Wrapper, used in the Mass Storage Bulk-Only Transport protocol. - * - * \note Regardless of CPU architecture, these values should be stored as little endian. - */ - typedef struct - { - uint32_t Signature; /**< Command block signature, must be \ref MS_CBW_SIGNATURE to indicate a valid Command Block. */ - uint32_t Tag; /**< Unique command ID value, to associate a command block wrapper with its command status wrapper. */ - uint32_t DataTransferLength; /**< Length of the optional data portion of the issued command, in bytes. */ - uint8_t Flags; /**< Command block flags, indicating command data direction. */ - uint8_t LUN; /**< Logical Unit number this command is issued to. */ - uint8_t SCSICommandLength; /**< Length of the issued SCSI command within the SCSI command data array. */ - uint8_t SCSICommandData[16]; /**< Issued SCSI command in the Command Block. */ - } ATTR_PACKED MS_CommandBlockWrapper_t; - - /** \brief Mass Storage Class Command Status Wrapper. - * - * Type define for a Command Status Wrapper, used in the Mass Storage Bulk-Only Transport protocol. - * - * \note Regardless of CPU architecture, these values should be stored as little endian. - */ - typedef struct - { - uint32_t Signature; /**< Status block signature, must be \ref MS_CSW_SIGNATURE to indicate a valid Command Status. */ - uint32_t Tag; /**< Unique command ID value, to associate a command block wrapper with its command status wrapper. */ - uint32_t DataTransferResidue; /**< Number of bytes of data not processed in the SCSI command. */ - uint8_t Status; /**< Status code of the issued command - a value from the \ref MS_CommandStatusCodes_t enum. */ - } ATTR_PACKED MS_CommandStatusWrapper_t; - - /** \brief Mass Storage Class SCSI Sense Structure - * - * Type define for a SCSI Sense structure. Structures of this type are filled out by the - * device via the \ref MS_Host_RequestSense() function, indicating the current sense data of the - * device (giving explicit error codes for the last issued command). For details of the - * structure contents, refer to the SCSI specifications. - */ - typedef struct - { - uint8_t ResponseCode; - - uint8_t SegmentNumber; - - unsigned SenseKey : 4; - unsigned Reserved : 1; - unsigned ILI : 1; - unsigned EOM : 1; - unsigned FileMark : 1; - - uint8_t Information[4]; - uint8_t AdditionalLength; - uint8_t CmdSpecificInformation[4]; - uint8_t AdditionalSenseCode; - uint8_t AdditionalSenseQualifier; - uint8_t FieldReplaceableUnitCode; - uint8_t SenseKeySpecific[3]; - } ATTR_PACKED SCSI_Request_Sense_Response_t; - - /** \brief Mass Storage Class SCSI Inquiry Structure. - * - * Type define for a SCSI Inquiry structure. Structures of this type are filled out by the - * device via the \ref MS_Host_GetInquiryData() function, retrieving the attached device's - * information. - * - * For details of the structure contents, refer to the SCSI specifications. - */ - typedef struct - { - unsigned DeviceType : 5; - unsigned PeripheralQualifier : 3; - - unsigned Reserved : 7; - unsigned Removable : 1; - - uint8_t Version; - - unsigned ResponseDataFormat : 4; - unsigned Reserved2 : 1; - unsigned NormACA : 1; - unsigned TrmTsk : 1; - unsigned AERC : 1; - - uint8_t AdditionalLength; - uint8_t Reserved3[2]; - - unsigned SoftReset : 1; - unsigned CmdQue : 1; - unsigned Reserved4 : 1; - unsigned Linked : 1; - unsigned Sync : 1; - unsigned WideBus16Bit : 1; - unsigned WideBus32Bit : 1; - unsigned RelAddr : 1; - - uint8_t VendorID[8]; - uint8_t ProductID[16]; - uint8_t RevisionID[4]; - } ATTR_PACKED SCSI_Inquiry_Response_t; - - /* Disable C linkage for C++ Compilers: */ - #if defined(__cplusplus) - } - #endif +/** SCSI Additional Sense Code to indicate that an attempt to write to a protected area was made. */ +#define SCSI_ASENSE_WRITE_PROTECTED 0x27 + +/** SCSI Additional Sense Code to indicate an error whilst formatting the device medium. */ +#define SCSI_ASENSE_FORMAT_ERROR 0x31 + +/** SCSI Additional Sense Code to indicate an invalid command was issued. */ +#define SCSI_ASENSE_INVALID_COMMAND 0x20 + +/** SCSI Additional Sense Code to indicate a write to a block out outside of the medium's range was issued. */ +#define SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x21 + +/** SCSI Additional Sense Code to indicate that no removable medium is inserted into the device. */ +#define SCSI_ASENSE_MEDIUM_NOT_PRESENT 0x3A +//@} + +/** \name SCSI Additional Sense Key Code Qualifiers */ +//@{ +/** SCSI Additional Sense Qualifier Code to indicate no additional sense qualifier information is available. */ +#define SCSI_ASENSEQ_NO_QUALIFIER 0x00 + +/** SCSI Additional Sense Qualifier Code to indicate that a medium format command failed to complete. */ +#define SCSI_ASENSEQ_FORMAT_COMMAND_FAILED 0x01 + +/** SCSI Additional Sense Qualifier Code to indicate that an initializing command must be issued before the issued + * command can be executed. + */ +#define SCSI_ASENSEQ_INITIALIZING_COMMAND_REQUIRED 0x02 +/** SCSI Additional Sense Qualifier Code to indicate that an operation is currently in progress. */ +#define SCSI_ASENSEQ_OPERATION_IN_PROGRESS 0x07 +//@} + +/* Enums: */ +/** Enum for possible Class, Subclass and Protocol values of device and interface descriptors relating to the Mass + * Storage device class. + */ +enum MS_Descriptor_ClassSubclassProtocol_t { + MS_CSCP_MassStorageClass = 0x08, /**< Descriptor Class value indicating that the device or interface + * belongs to the Mass Storage class. + */ + MS_CSCP_SCSITransparentSubclass = 0x06, /**< Descriptor Subclass value indicating that the device or interface + * belongs to the SCSI Transparent Command Set subclass of the Mass + * storage class. + */ + MS_CSCP_BulkOnlyTransportProtocol = + 0x50, /**< Descriptor Protocol value indicating that the device or interface + * belongs to the Bulk Only Transport protocol of the Mass Storage class. + */ +}; + +/** Enum for the Mass Storage class specific control requests that can be issued by the USB bus host. */ +enum MS_ClassRequests_t { + MS_REQ_GetMaxLUN = 0xFE, /**< Mass Storage class-specific request to retrieve the total number of Logical + * Units (drives) in the SCSI device. + */ + MS_REQ_MassStorageReset = 0xFF, /**< Mass Storage class-specific request to reset the Mass Storage interface, + * ready for the next command. + */ +}; + +/** Enum for the possible command status wrapper return status codes. */ +enum MS_CommandStatusCodes_t { + MS_SCSI_COMMAND_Pass = 0, /**< Command completed with no error */ + MS_SCSI_COMMAND_Fail = 1, /**< Command failed to complete - host may check the exact error via a + * SCSI REQUEST SENSE command. + */ + MS_SCSI_COMMAND_PhaseError = 2, /**< Command failed due to being invalid in the current phase. */ +}; + +/* Type Defines: */ +/** \brief Mass Storage Class Command Block Wrapper. + * + * Type define for a Command Block Wrapper, used in the Mass Storage Bulk-Only Transport protocol. + * + * \note Regardless of CPU architecture, these values should be stored as little endian. + */ +typedef struct { + uint32_t + Signature; /**< Command block signature, must be \ref MS_CBW_SIGNATURE to indicate a valid Command Block. */ + uint32_t Tag; /**< Unique command ID value, to associate a command block wrapper with its command status wrapper. */ + uint32_t DataTransferLength; /**< Length of the optional data portion of the issued command, in bytes. */ + uint8_t Flags; /**< Command block flags, indicating command data direction. */ + uint8_t LUN; /**< Logical Unit number this command is issued to. */ + uint8_t SCSICommandLength; /**< Length of the issued SCSI command within the SCSI command data array. */ + uint8_t SCSICommandData[16]; /**< Issued SCSI command in the Command Block. */ +} ATTR_PACKED MS_CommandBlockWrapper_t; + +/** \brief Mass Storage Class Command Status Wrapper. + * + * Type define for a Command Status Wrapper, used in the Mass Storage Bulk-Only Transport protocol. + * + * \note Regardless of CPU architecture, these values should be stored as little endian. + */ +typedef struct { + uint32_t + Signature; /**< Status block signature, must be \ref MS_CSW_SIGNATURE to indicate a valid Command Status. */ + uint32_t Tag; /**< Unique command ID value, to associate a command block wrapper with its command status wrapper. */ + uint32_t DataTransferResidue; /**< Number of bytes of data not processed in the SCSI command. */ + uint8_t Status; /**< Status code of the issued command - a value from the \ref MS_CommandStatusCodes_t enum. */ +} ATTR_PACKED MS_CommandStatusWrapper_t; + +/** \brief Mass Storage Class SCSI Sense Structure + * + * Type define for a SCSI Sense structure. Structures of this type are filled out by the + * device via the \ref MS_Host_RequestSense() function, indicating the current sense data of the + * device (giving explicit error codes for the last issued command). For details of the + * structure contents, refer to the SCSI specifications. + */ +typedef struct { + uint8_t ResponseCode; + + uint8_t SegmentNumber; + + unsigned SenseKey : 4; + unsigned Reserved : 1; + unsigned ILI : 1; + unsigned EOM : 1; + unsigned FileMark : 1; + + uint8_t Information[4]; + uint8_t AdditionalLength; + uint8_t CmdSpecificInformation[4]; + uint8_t AdditionalSenseCode; + uint8_t AdditionalSenseQualifier; + uint8_t FieldReplaceableUnitCode; + uint8_t SenseKeySpecific[3]; +} ATTR_PACKED SCSI_Request_Sense_Response_t; + +/** \brief Mass Storage Class SCSI Inquiry Structure. + * + * Type define for a SCSI Inquiry structure. Structures of this type are filled out by the + * device via the \ref MS_Host_GetInquiryData() function, retrieving the attached device's + * information. + * + * For details of the structure contents, refer to the SCSI specifications. + */ +typedef struct { + unsigned DeviceType : 5; + unsigned PeripheralQualifier : 3; + + unsigned Reserved : 7; + unsigned Removable : 1; + + uint8_t Version; + + unsigned ResponseDataFormat : 4; + unsigned Reserved2 : 1; + unsigned NormACA : 1; + unsigned TrmTsk : 1; + unsigned AERC : 1; + + uint8_t AdditionalLength; + uint8_t Reserved3[2]; + + unsigned SoftReset : 1; + unsigned CmdQue : 1; + unsigned Reserved4 : 1; + unsigned Linked : 1; + unsigned Sync : 1; + unsigned WideBus16Bit : 1; + unsigned WideBus32Bit : 1; + unsigned RelAddr : 1; + + uint8_t VendorID[8]; + uint8_t ProductID[16]; + uint8_t RevisionID[4]; +} ATTR_PACKED SCSI_Inquiry_Response_t; + +/* Disable C linkage for C++ Compilers: */ +#if defined(__cplusplus) +} #endif -/** @} */ +#endif +/** @} */ diff --git a/inc/drivers/USB_HID_Keys.h b/inc/drivers/USB_HID_Keys.h index 3b92a99f..30711627 100644 --- a/inc/drivers/USB_HID_Keys.h +++ b/inc/drivers/USB_HID_Keys.h @@ -33,163 +33,163 @@ * KEY_ERR_OVF in all slots to indicate this condition. */ -#define KEY_NONE 0x00 // No key pressed -#define KEY_ERR_OVF 0x01 // Keyboard Error Roll Over - used for all slots if too many keys are pressed ("Phantom key") +#define KEY_NONE 0x00 // No key pressed +#define KEY_ERR_OVF 0x01 // Keyboard Error Roll Over - used for all slots if too many keys are pressed ("Phantom key") // 0x02 // Keyboard POST Fail // 0x03 // Keyboard Error Undefined -#define KEY_A 0x04 // Keyboard a and A -#define KEY_B 0x05 // Keyboard b and B -#define KEY_C 0x06 // Keyboard c and C -#define KEY_D 0x07 // Keyboard d and D -#define KEY_E 0x08 // Keyboard e and E -#define KEY_F 0x09 // Keyboard f and F -#define KEY_G 0x0a // Keyboard g and G -#define KEY_H 0x0b // Keyboard h and H -#define KEY_I 0x0c // Keyboard i and I -#define KEY_J 0x0d // Keyboard j and J -#define KEY_K 0x0e // Keyboard k and K -#define KEY_L 0x0f // Keyboard l and L -#define KEY_M 0x10 // Keyboard m and M -#define KEY_N 0x11 // Keyboard n and N -#define KEY_O 0x12 // Keyboard o and O -#define KEY_P 0x13 // Keyboard p and P -#define KEY_Q 0x14 // Keyboard q and Q -#define KEY_R 0x15 // Keyboard r and R -#define KEY_S 0x16 // Keyboard s and S -#define KEY_T 0x17 // Keyboard t and T -#define KEY_U 0x18 // Keyboard u and U -#define KEY_V 0x19 // Keyboard v and V -#define KEY_W 0x1a // Keyboard w and W -#define KEY_X 0x1b // Keyboard x and X -#define KEY_Y 0x1c // Keyboard y and Y -#define KEY_Z 0x1d // Keyboard z and Z +#define KEY_A 0x04 // Keyboard a and A +#define KEY_B 0x05 // Keyboard b and B +#define KEY_C 0x06 // Keyboard c and C +#define KEY_D 0x07 // Keyboard d and D +#define KEY_E 0x08 // Keyboard e and E +#define KEY_F 0x09 // Keyboard f and F +#define KEY_G 0x0a // Keyboard g and G +#define KEY_H 0x0b // Keyboard h and H +#define KEY_I 0x0c // Keyboard i and I +#define KEY_J 0x0d // Keyboard j and J +#define KEY_K 0x0e // Keyboard k and K +#define KEY_L 0x0f // Keyboard l and L +#define KEY_M 0x10 // Keyboard m and M +#define KEY_N 0x11 // Keyboard n and N +#define KEY_O 0x12 // Keyboard o and O +#define KEY_P 0x13 // Keyboard p and P +#define KEY_Q 0x14 // Keyboard q and Q +#define KEY_R 0x15 // Keyboard r and R +#define KEY_S 0x16 // Keyboard s and S +#define KEY_T 0x17 // Keyboard t and T +#define KEY_U 0x18 // Keyboard u and U +#define KEY_V 0x19 // Keyboard v and V +#define KEY_W 0x1a // Keyboard w and W +#define KEY_X 0x1b // Keyboard x and X +#define KEY_Y 0x1c // Keyboard y and Y +#define KEY_Z 0x1d // Keyboard z and Z -#define KEY_1 0x1e // Keyboard 1 and ! -#define KEY_2 0x1f // Keyboard 2 and @ -#define KEY_3 0x20 // Keyboard 3 and # -#define KEY_4 0x21 // Keyboard 4 and $ -#define KEY_5 0x22 // Keyboard 5 and % -#define KEY_6 0x23 // Keyboard 6 and ^ -#define KEY_7 0x24 // Keyboard 7 and & -#define KEY_8 0x25 // Keyboard 8 and * -#define KEY_9 0x26 // Keyboard 9 and ( -#define KEY_0 0x27 // Keyboard 0 and ) +#define KEY_1 0x1e // Keyboard 1 and ! +#define KEY_2 0x1f // Keyboard 2 and @ +#define KEY_3 0x20 // Keyboard 3 and # +#define KEY_4 0x21 // Keyboard 4 and $ +#define KEY_5 0x22 // Keyboard 5 and % +#define KEY_6 0x23 // Keyboard 6 and ^ +#define KEY_7 0x24 // Keyboard 7 and & +#define KEY_8 0x25 // Keyboard 8 and * +#define KEY_9 0x26 // Keyboard 9 and ( +#define KEY_0 0x27 // Keyboard 0 and ) -#define KEY_ENTER 0x28 // Keyboard Return (ENTER) -#define KEY_ESC 0x29 // Keyboard ESCAPE -#define KEY_BACKSPACE 0x2a // Keyboard DELETE (Backspace) -#define KEY_TAB 0x2b // Keyboard Tab -#define KEY_SPACE 0x2c // Keyboard Spacebar -#define KEY_MINUS 0x2d // Keyboard - and _ -#define KEY_EQUAL 0x2e // Keyboard = and + -#define KEY_LEFTBRACE 0x2f // Keyboard [ and { -#define KEY_RIGHTBRACE 0x30 // Keyboard ] and } -#define KEY_BACKSLASH 0x31 // Keyboard \ and | -#define KEY_HASHTILDE 0x32 // Keyboard Non-US # and ~ -#define KEY_SEMICOLON 0x33 // Keyboard ; and : -#define KEY_APOSTROPHE 0x34 // Keyboard ' and " -#define KEY_GRAVE 0x35 // Keyboard ` and ~ -#define KEY_COMMA 0x36 // Keyboard , and < -#define KEY_DOT 0x37 // Keyboard . and > -#define KEY_SLASH 0x38 // Keyboard / and ? -#define KEY_CAPSLOCK 0x39 // Keyboard Caps Lock +#define KEY_ENTER 0x28 // Keyboard Return (ENTER) +#define KEY_ESC 0x29 // Keyboard ESCAPE +#define KEY_BACKSPACE 0x2a // Keyboard DELETE (Backspace) +#define KEY_TAB 0x2b // Keyboard Tab +#define KEY_SPACE 0x2c // Keyboard Spacebar +#define KEY_MINUS 0x2d // Keyboard - and _ +#define KEY_EQUAL 0x2e // Keyboard = and + +#define KEY_LEFTBRACE 0x2f // Keyboard [ and { +#define KEY_RIGHTBRACE 0x30 // Keyboard ] and } +#define KEY_BACKSLASH 0x31 // Keyboard \ and | +#define KEY_HASHTILDE 0x32 // Keyboard Non-US # and ~ +#define KEY_SEMICOLON 0x33 // Keyboard ; and : +#define KEY_APOSTROPHE 0x34 // Keyboard ' and " +#define KEY_GRAVE 0x35 // Keyboard ` and ~ +#define KEY_COMMA 0x36 // Keyboard , and < +#define KEY_DOT 0x37 // Keyboard . and > +#define KEY_SLASH 0x38 // Keyboard / and ? +#define KEY_CAPSLOCK 0x39 // Keyboard Caps Lock -#define KEY_F1 0x3a // Keyboard F1 -#define KEY_F2 0x3b // Keyboard F2 -#define KEY_F3 0x3c // Keyboard F3 -#define KEY_F4 0x3d // Keyboard F4 -#define KEY_F5 0x3e // Keyboard F5 -#define KEY_F6 0x3f // Keyboard F6 -#define KEY_F7 0x40 // Keyboard F7 -#define KEY_F8 0x41 // Keyboard F8 -#define KEY_F9 0x42 // Keyboard F9 -#define KEY_F10 0x43 // Keyboard F10 -#define KEY_F11 0x44 // Keyboard F11 -#define KEY_F12 0x45 // Keyboard F12 +#define KEY_F1 0x3a // Keyboard F1 +#define KEY_F2 0x3b // Keyboard F2 +#define KEY_F3 0x3c // Keyboard F3 +#define KEY_F4 0x3d // Keyboard F4 +#define KEY_F5 0x3e // Keyboard F5 +#define KEY_F6 0x3f // Keyboard F6 +#define KEY_F7 0x40 // Keyboard F7 +#define KEY_F8 0x41 // Keyboard F8 +#define KEY_F9 0x42 // Keyboard F9 +#define KEY_F10 0x43 // Keyboard F10 +#define KEY_F11 0x44 // Keyboard F11 +#define KEY_F12 0x45 // Keyboard F12 -#define KEY_SYSRQ 0x46 // Keyboard Print Screen -#define KEY_SCROLLLOCK 0x47 // Keyboard Scroll Lock -#define KEY_PAUSE 0x48 // Keyboard Pause -#define KEY_INSERT 0x49 // Keyboard Insert -#define KEY_HOME 0x4a // Keyboard Home -#define KEY_PAGEUP 0x4b // Keyboard Page Up -#define KEY_DELETE 0x4c // Keyboard Delete Forward -#define KEY_END 0x4d // Keyboard End -#define KEY_PAGEDOWN 0x4e // Keyboard Page Down -#define KEY_RIGHT 0x4f // Keyboard Right Arrow -#define KEY_LEFT 0x50 // Keyboard Left Arrow -#define KEY_DOWN 0x51 // Keyboard Down Arrow -#define KEY_UP 0x52 // Keyboard Up Arrow +#define KEY_SYSRQ 0x46 // Keyboard Print Screen +#define KEY_SCROLLLOCK 0x47 // Keyboard Scroll Lock +#define KEY_PAUSE 0x48 // Keyboard Pause +#define KEY_INSERT 0x49 // Keyboard Insert +#define KEY_HOME 0x4a // Keyboard Home +#define KEY_PAGEUP 0x4b // Keyboard Page Up +#define KEY_DELETE 0x4c // Keyboard Delete Forward +#define KEY_END 0x4d // Keyboard End +#define KEY_PAGEDOWN 0x4e // Keyboard Page Down +#define KEY_RIGHT 0x4f // Keyboard Right Arrow +#define KEY_LEFT 0x50 // Keyboard Left Arrow +#define KEY_DOWN 0x51 // Keyboard Down Arrow +#define KEY_UP 0x52 // Keyboard Up Arrow -#define KEY_NUMLOCK 0x53 // Keyboard Num Lock and Clear -#define KEY_KPSLASH 0x54 // Keypad / -#define KEY_KPASTERISK 0x55 // Keypad * -#define KEY_KPMINUS 0x56 // Keypad - -#define KEY_KPPLUS 0x57 // Keypad + -#define KEY_KPENTER 0x58 // Keypad ENTER -#define KEY_KP1 0x59 // Keypad 1 and End -#define KEY_KP2 0x5a // Keypad 2 and Down Arrow -#define KEY_KP3 0x5b // Keypad 3 and PageDn -#define KEY_KP4 0x5c // Keypad 4 and Left Arrow -#define KEY_KP5 0x5d // Keypad 5 -#define KEY_KP6 0x5e // Keypad 6 and Right Arrow -#define KEY_KP7 0x5f // Keypad 7 and Home -#define KEY_KP8 0x60 // Keypad 8 and Up Arrow -#define KEY_KP9 0x61 // Keypad 9 and Page Up -#define KEY_KP0 0x62 // Keypad 0 and Insert -#define KEY_KPDOT 0x63 // Keypad . and Delete +#define KEY_NUMLOCK 0x53 // Keyboard Num Lock and Clear +#define KEY_KPSLASH 0x54 // Keypad / +#define KEY_KPASTERISK 0x55 // Keypad * +#define KEY_KPMINUS 0x56 // Keypad - +#define KEY_KPPLUS 0x57 // Keypad + +#define KEY_KPENTER 0x58 // Keypad ENTER +#define KEY_KP1 0x59 // Keypad 1 and End +#define KEY_KP2 0x5a // Keypad 2 and Down Arrow +#define KEY_KP3 0x5b // Keypad 3 and PageDn +#define KEY_KP4 0x5c // Keypad 4 and Left Arrow +#define KEY_KP5 0x5d // Keypad 5 +#define KEY_KP6 0x5e // Keypad 6 and Right Arrow +#define KEY_KP7 0x5f // Keypad 7 and Home +#define KEY_KP8 0x60 // Keypad 8 and Up Arrow +#define KEY_KP9 0x61 // Keypad 9 and Page Up +#define KEY_KP0 0x62 // Keypad 0 and Insert +#define KEY_KPDOT 0x63 // Keypad . and Delete -#define KEY_102ND 0x64 // Keyboard Non-US \ and | -#define KEY_COMPOSE 0x65 // Keyboard Application -#define KEY_POWER 0x66 // Keyboard Power -#define KEY_KPEQUAL 0x67 // Keypad = +#define KEY_102ND 0x64 // Keyboard Non-US \ and | +#define KEY_COMPOSE 0x65 // Keyboard Application +#define KEY_POWER 0x66 // Keyboard Power +#define KEY_KPEQUAL 0x67 // Keypad = -#define KEY_F13 0x68 // Keyboard F13 -#define KEY_F14 0x69 // Keyboard F14 -#define KEY_F15 0x6a // Keyboard F15 -#define KEY_F16 0x6b // Keyboard F16 -#define KEY_F17 0x6c // Keyboard F17 -#define KEY_F18 0x6d // Keyboard F18 -#define KEY_F19 0x6e // Keyboard F19 -#define KEY_F20 0x6f // Keyboard F20 -#define KEY_F21 0x70 // Keyboard F21 -#define KEY_F22 0x71 // Keyboard F22 -#define KEY_F23 0x72 // Keyboard F23 -#define KEY_F24 0x73 // Keyboard F24 +#define KEY_F13 0x68 // Keyboard F13 +#define KEY_F14 0x69 // Keyboard F14 +#define KEY_F15 0x6a // Keyboard F15 +#define KEY_F16 0x6b // Keyboard F16 +#define KEY_F17 0x6c // Keyboard F17 +#define KEY_F18 0x6d // Keyboard F18 +#define KEY_F19 0x6e // Keyboard F19 +#define KEY_F20 0x6f // Keyboard F20 +#define KEY_F21 0x70 // Keyboard F21 +#define KEY_F22 0x71 // Keyboard F22 +#define KEY_F23 0x72 // Keyboard F23 +#define KEY_F24 0x73 // Keyboard F24 -#define KEY_OPEN 0x74 // Keyboard Execute -#define KEY_HELP 0x75 // Keyboard Help -#define KEY_PROPS 0x76 // Keyboard Menu -#define KEY_FRONT 0x77 // Keyboard Select -#define KEY_STOP 0x78 // Keyboard Stop -#define KEY_AGAIN 0x79 // Keyboard Again -#define KEY_UNDO 0x7a // Keyboard Undo -#define KEY_CUT 0x7b // Keyboard Cut -#define KEY_COPY 0x7c // Keyboard Copy -#define KEY_PASTE 0x7d // Keyboard Paste -#define KEY_FIND 0x7e // Keyboard Find -#define KEY_MUTE 0x7f // Keyboard Mute -#define KEY_VOLUMEUP 0x80 // Keyboard Volume Up -#define KEY_VOLUMEDOWN 0x81 // Keyboard Volume Down +#define KEY_OPEN 0x74 // Keyboard Execute +#define KEY_HELP 0x75 // Keyboard Help +#define KEY_PROPS 0x76 // Keyboard Menu +#define KEY_FRONT 0x77 // Keyboard Select +#define KEY_STOP 0x78 // Keyboard Stop +#define KEY_AGAIN 0x79 // Keyboard Again +#define KEY_UNDO 0x7a // Keyboard Undo +#define KEY_CUT 0x7b // Keyboard Cut +#define KEY_COPY 0x7c // Keyboard Copy +#define KEY_PASTE 0x7d // Keyboard Paste +#define KEY_FIND 0x7e // Keyboard Find +#define KEY_MUTE 0x7f // Keyboard Mute +#define KEY_VOLUMEUP 0x80 // Keyboard Volume Up +#define KEY_VOLUMEDOWN 0x81 // Keyboard Volume Down // 0x82 Keyboard Locking Caps Lock // 0x83 Keyboard Locking Num Lock // 0x84 Keyboard Locking Scroll Lock -#define KEY_KPCOMMA 0x85 // Keypad Comma +#define KEY_KPCOMMA 0x85 // Keypad Comma // 0x86 Keypad Equal Sign -#define KEY_RO 0x87 // Keyboard International1 -#define KEY_KATAKANAHIRAGANA 0x88 // Keyboard International2 -#define KEY_YEN 0x89 // Keyboard International3 -#define KEY_HENKAN 0x8a // Keyboard International4 -#define KEY_MUHENKAN 0x8b // Keyboard International5 -#define KEY_KPJPCOMMA 0x8c // Keyboard International6 +#define KEY_RO 0x87 // Keyboard International1 +#define KEY_KATAKANAHIRAGANA 0x88 // Keyboard International2 +#define KEY_YEN 0x89 // Keyboard International3 +#define KEY_HENKAN 0x8a // Keyboard International4 +#define KEY_MUHENKAN 0x8b // Keyboard International5 +#define KEY_KPJPCOMMA 0x8c // Keyboard International6 // 0x8d Keyboard International7 // 0x8e Keyboard International8 // 0x8f Keyboard International9 -#define KEY_HANGEUL 0x90 // Keyboard LANG1 -#define KEY_HANJA 0x91 // Keyboard LANG2 -#define KEY_KATAKANA 0x92 // Keyboard LANG3 -#define KEY_HIRAGANA 0x93 // Keyboard LANG4 -#define KEY_ZENKAKUHANKAKU 0x94 // Keyboard LANG5 +#define KEY_HANGEUL 0x90 // Keyboard LANG1 +#define KEY_HANJA 0x91 // Keyboard LANG2 +#define KEY_KATAKANA 0x92 // Keyboard LANG3 +#define KEY_HIRAGANA 0x93 // Keyboard LANG4 +#define KEY_ZENKAKUHANKAKU 0x94 // Keyboard LANG5 // 0x95 Keyboard LANG6 // 0x96 Keyboard LANG7 // 0x97 Keyboard LANG8 @@ -213,8 +213,8 @@ // 0xb3 Decimal Separator // 0xb4 Currency Unit // 0xb5 Currency Sub-unit -#define KEY_KPLEFTPAREN 0xb6 // Keypad ( -#define KEY_KPRIGHTPAREN 0xb7 // Keypad ) +#define KEY_KPLEFTPAREN 0xb6 // Keypad ( +#define KEY_KPRIGHTPAREN 0xb7 // Keypad ) // 0xb8 Keypad { // 0xb9 Keypad } // 0xba Keypad Tab @@ -254,34 +254,34 @@ // 0xdc Keypad Decimal // 0xdd Keypad Hexadecimal -#define KEY_LEFTCTRL 0xe0 // Keyboard Left Control -#define KEY_LEFTSHIFT 0xe1 // Keyboard Left Shift -#define KEY_LEFTALT 0xe2 // Keyboard Left Alt -#define KEY_LEFTMETA 0xe3 // Keyboard Left GUI -#define KEY_RIGHTCTRL 0xe4 // Keyboard Right Control -#define KEY_RIGHTSHIFT 0xe5 // Keyboard Right Shift -#define KEY_RIGHTALT 0xe6 // Keyboard Right Alt -#define KEY_RIGHTMETA 0xe7 // Keyboard Right GUI +#define KEY_LEFTCTRL 0xe0 // Keyboard Left Control +#define KEY_LEFTSHIFT 0xe1 // Keyboard Left Shift +#define KEY_LEFTALT 0xe2 // Keyboard Left Alt +#define KEY_LEFTMETA 0xe3 // Keyboard Left GUI +#define KEY_RIGHTCTRL 0xe4 // Keyboard Right Control +#define KEY_RIGHTSHIFT 0xe5 // Keyboard Right Shift +#define KEY_RIGHTALT 0xe6 // Keyboard Right Alt +#define KEY_RIGHTMETA 0xe7 // Keyboard Right GUI -#define KEY_MEDIA_PLAYPAUSE 0xe8 -#define KEY_MEDIA_STOPCD 0xe9 +#define KEY_MEDIA_PLAYPAUSE 0xe8 +#define KEY_MEDIA_STOPCD 0xe9 #define KEY_MEDIA_PREVIOUSSONG 0xea -#define KEY_MEDIA_NEXTSONG 0xeb -#define KEY_MEDIA_EJECTCD 0xec -#define KEY_MEDIA_VOLUMEUP 0xed -#define KEY_MEDIA_VOLUMEDOWN 0xee -#define KEY_MEDIA_MUTE 0xef -#define KEY_MEDIA_WWW 0xf0 -#define KEY_MEDIA_BACK 0xf1 -#define KEY_MEDIA_FORWARD 0xf2 -#define KEY_MEDIA_STOP 0xf3 -#define KEY_MEDIA_FIND 0xf4 -#define KEY_MEDIA_SCROLLUP 0xf5 -#define KEY_MEDIA_SCROLLDOWN 0xf6 -#define KEY_MEDIA_EDIT 0xf7 -#define KEY_MEDIA_SLEEP 0xf8 -#define KEY_MEDIA_COFFEE 0xf9 -#define KEY_MEDIA_REFRESH 0xfa -#define KEY_MEDIA_CALC 0xfb +#define KEY_MEDIA_NEXTSONG 0xeb +#define KEY_MEDIA_EJECTCD 0xec +#define KEY_MEDIA_VOLUMEUP 0xed +#define KEY_MEDIA_VOLUMEDOWN 0xee +#define KEY_MEDIA_MUTE 0xef +#define KEY_MEDIA_WWW 0xf0 +#define KEY_MEDIA_BACK 0xf1 +#define KEY_MEDIA_FORWARD 0xf2 +#define KEY_MEDIA_STOP 0xf3 +#define KEY_MEDIA_FIND 0xf4 +#define KEY_MEDIA_SCROLLUP 0xf5 +#define KEY_MEDIA_SCROLLDOWN 0xf6 +#define KEY_MEDIA_EDIT 0xf7 +#define KEY_MEDIA_SLEEP 0xf8 +#define KEY_MEDIA_COFFEE 0xf9 +#define KEY_MEDIA_REFRESH 0xfa +#define KEY_MEDIA_CALC 0xfb -#endif // USB_HID_KEYS \ No newline at end of file +#endif // USB_HID_KEYS \ No newline at end of file diff --git a/inc/drivers/uf2format.h b/inc/drivers/uf2format.h index 5722acf8..13511190 100644 --- a/inc/drivers/uf2format.h +++ b/inc/drivers/uf2format.h @@ -1,23 +1,22 @@ #ifndef UF2FORMAT_H #define UF2FORMAT_H 1 -#include #include +#include // All entries are little endian. // if you increase that, you will also need to update the linker script file #define APP_START_ADDRESS 0x00002000 -#define UF2_MAGIC_START0 0x0A324655UL // "UF2\n" -#define UF2_MAGIC_START1 0x9E5D5157UL // Randomly selected -#define UF2_MAGIC_END 0x0AB16F30UL // Ditto +#define UF2_MAGIC_START0 0x0A324655UL // "UF2\n" +#define UF2_MAGIC_START1 0x9E5D5157UL // Randomly selected +#define UF2_MAGIC_END 0x0AB16F30UL // Ditto // If set, the block is "comment" and should not be flashed to the device #define UF2_FLAG_NOFLASH 0x00000001 -typedef struct -{ +typedef struct { // 32 byte header uint32_t magicStart0; uint32_t magicStart1; @@ -35,82 +34,73 @@ typedef struct uint32_t magicEnd; } UF2_Block; -typedef struct -{ +typedef struct { uint8_t version; uint8_t ep_in; uint8_t ep_out; uint8_t reserved0; uint32_t cbw_tag; uint32_t blocks_remaining; - uint8_t *buffer; + uint8_t* buffer; } UF2_HandoverArgs; -typedef void (*UF2_MSC_Handover_Handler)(UF2_HandoverArgs *handover); +typedef void (*UF2_MSC_Handover_Handler)(UF2_HandoverArgs* handover); typedef void (*UF2_HID_Handover_Handler)(int ep); // this is required to be exactly 16 bytes long by the linker script -typedef struct -{ - void *reserved0; +typedef struct { + void* reserved0; UF2_HID_Handover_Handler handoverHID; UF2_MSC_Handover_Handler handoverMSC; - const char *info_uf2; + const char* info_uf2; } UF2_BInfo; -static inline bool is_uf2_block(void *data) +static inline bool is_uf2_block(void* data) { - UF2_Block *bl = (UF2_Block *)data; - return bl->magicStart0 == UF2_MAGIC_START0 && bl->magicStart1 == UF2_MAGIC_START1 && - bl->magicEnd == UF2_MAGIC_END; + UF2_Block* bl = (UF2_Block*)data; + return bl->magicStart0 == UF2_MAGIC_START0 && bl->magicStart1 == UF2_MAGIC_START1 && bl->magicEnd == UF2_MAGIC_END; } #ifdef BOOTLOADER_START_ADDR -#define UF2_BINFO ((UF2_BInfo *)(BOOTLOADER_END_ADDR - sizeof(UF2_BInfo))) +#define UF2_BINFO ((UF2_BInfo*)(BOOTLOADER_END_ADDR - sizeof(UF2_BInfo))) #ifndef UF2_INFO_ADDR #define UF2_INFO_ADDR UF2_BINFO->info_uf2 #endif -static inline bool in_uf2_bootloader_space(const void *addr) +static inline bool in_uf2_bootloader_space(const void* addr) { return (BOOTLOADER_START_ADDR + 0xb0) <= (uint32_t)addr && (uint32_t)addr < BOOTLOADER_END_ADDR; } -static inline const char *uf2_info(void) +static inline const char* uf2_info(void) { - if (in_uf2_bootloader_space(UF2_INFO_ADDR)) - return UF2_INFO_ADDR; + if (in_uf2_bootloader_space(UF2_INFO_ADDR)) return UF2_INFO_ADDR; return "N/A"; } #ifdef UF2_DEFINE_HANDOVER static inline void hf2_handover(uint8_t ep) { - const char *board_info = UF2_INFO_ADDR; + const char* board_info = UF2_INFO_ADDR; UF2_HID_Handover_Handler fn = UF2_BINFO->handoverHID; - if (in_uf2_bootloader_space(board_info) && in_uf2_bootloader_space((const void *)fn) && - ((uint32_t)fn & 1)) - { + if (in_uf2_bootloader_space(board_info) && in_uf2_bootloader_space((const void*)fn) && ((uint32_t)fn & 1)) { // Pass control to bootloader; never returns fn(ep & 0xf); } } -static inline void check_uf2_handover(uint8_t *buffer, uint32_t blocks_remaining, uint8_t ep_in, - uint8_t ep_out, uint32_t cbw_tag) +static inline void check_uf2_handover(uint8_t* buffer, uint32_t blocks_remaining, uint8_t ep_in, uint8_t ep_out, + uint32_t cbw_tag) { - if (!is_uf2_block(buffer)) - return; + if (!is_uf2_block(buffer)) return; - const char *board_info = UF2_BINFO->info_uf2; + const char* board_info = UF2_BINFO->info_uf2; UF2_MSC_Handover_Handler fn = UF2_BINFO->handoverMSC; - if (in_uf2_bootloader_space(board_info) && in_uf2_bootloader_space((const void *)fn) && - ((uint32_t)fn & 1)) - { + if (in_uf2_bootloader_space(board_info) && in_uf2_bootloader_space((const void*)fn) && ((uint32_t)fn & 1)) { UF2_HandoverArgs hand = { 1, ep_in, ep_out, 0, cbw_tag, blocks_remaining, buffer, }; @@ -118,8 +108,8 @@ static inline void check_uf2_handover(uint8_t *buffer, uint32_t blocks_remaining fn(&hand); } } -#endif // UF2_DEFINE_HANDOVER +#endif // UF2_DEFINE_HANDOVER -#endif // BOOTLOADER_START_ADDR +#endif // BOOTLOADER_START_ADDR #endif diff --git a/inc/streams/DataStream.h b/inc/streams/DataStream.h index dc69e5f6..7e4583a9 100644 --- a/inc/streams/DataStream.h +++ b/inc/streams/DataStream.h @@ -25,199 +25,195 @@ DEALINGS IN THE SOFTWARE. #ifndef CODAL_DATA_STREAM_H #define CODAL_DATA_STREAM_H +#include "CodalConfig.h" #include "ManagedBuffer.h" #include "MessageBus.h" -#include "CodalConfig.h" -#define DATASTREAM_MAXIMUM_BUFFERS 1 +#define DATASTREAM_MAXIMUM_BUFFERS 1 // Define valid data representation formats supplied by a DataSource. // n.b. MUST remain in strict monotically increasing order of sample size. -#define DATASTREAM_FORMAT_UNKNOWN 0 -#define DATASTREAM_FORMAT_8BIT_UNSIGNED 1 -#define DATASTREAM_FORMAT_8BIT_SIGNED 2 -#define DATASTREAM_FORMAT_16BIT_UNSIGNED 3 -#define DATASTREAM_FORMAT_16BIT_SIGNED 4 -#define DATASTREAM_FORMAT_24BIT_UNSIGNED 5 -#define DATASTREAM_FORMAT_24BIT_SIGNED 6 -#define DATASTREAM_FORMAT_32BIT_UNSIGNED 7 -#define DATASTREAM_FORMAT_32BIT_SIGNED 8 - -#define DATASTREAM_FORMAT_BYTES_PER_SAMPLE(x) ((x+1)/2) - -#define DATASTREAM_SAMPLE_RATE_UNKNOWN 0.0f - -namespace codal -{ - /** - * Interface definition for a DataSource. - */ - class DataSink - { - public: - - virtual int pullRequest(); - }; - - /** - * Interface definition for a DataSource. - */ - class DataSource - { - public: - virtual ManagedBuffer pull(); - virtual void connect(DataSink &sink); - virtual bool isConnected() { return false; } - virtual void disconnect(); - virtual int getFormat(); - virtual int setFormat(int format); - virtual float getSampleRate(); - virtual float requestSampleRate(float sampleRate); - }; - - /** - * Class definition for DataStream. - * A Datastream holds a number of ManagedBuffer references, provides basic flow control through a push/pull mechanism - * and byte level access to the datastream, even if it spans different buffers. - */ - class DataStream : public DataSource, public DataSink - { - uint16_t pullRequestEventCode; - uint16_t flowEventCode; - ManagedBuffer nextBuffer; - bool hasPending; - bool isBlocking; - unsigned int missedBuffers; - int downstreamReturn; - - DataSink *downStream; - DataSource *upStream; - - public: - - /** - * Default Constructor. - * Creates an empty DataStream. - * - * @param upstream the component that will normally feed this datastream with data. - */ - DataStream(DataSource &upstream); - - /** - * Destructor. - * Removes all resources held by the instance. - */ - ~DataStream(); - - /** - * Controls if this component should emit flow state events. - * - * @warning Should not be called mutliple times with `id == 0`, as it will spuriously reallocate event IDs - * - * @param id If zero, this will auto-allocate a new event ID - * @return uint16_t The new event ID for this DataStream - */ - uint16_t emitFlowEvents( uint16_t id = 0 ); - - /** - * Determines if any of the data currently flowing through this stream is held in non-volatile (FLASH) memory. - * @return true if one or more of the ManagedBuffers in this stream reside in FLASH memory, false otherwise. - */ - bool isReadOnly(); - - /** - * Attempts to determine if another component downstream of this one is _actually_ pulling data, and thus, data - * is flowing. - * - * @return true If there is a count-match between `pullRequest` and `pull` calls. - * @return false If `pullRequest` calls are not currently being matched by `pull` calls. - */ - bool isFlowing(); - - /** - * Define a downstream component for data stream. - * - * @sink The component that data will be delivered to, when it is available - */ - virtual void connect(DataSink &sink) override; - - /** - * Determines if this source is connected to a downstream component - * - * @return true If a downstream is connected - * @return false If a downstream is not connected - */ - virtual bool isConnected(); - - /** - * Define a downstream component for data stream. - * - * @sink The component that data will be delivered to, when it is available - */ - virtual void disconnect() override; - - /** - * Determine the data format of the buffers streamed out of this component. - */ - virtual int getFormat() override; - - /** - * Determines if this stream acts in a synchronous, blocking mode or asynchronous mode. In blocking mode, writes to a full buffer - * will result int he calling fiber being blocked until space is available. Downstream DataSinks will also attempt to process data - * immediately as it becomes available. In non-blocking asynchronpus mode, writes to a full buffer are dropped and downstream Datasinks will - * be processed in a new fiber. - */ - void setBlocking(bool isBlocking); - - /** - * Determines if a buffer of the given size can be added to the buffer. - * - * @param size The number of bytes to add to the buffer. - * @return true if there is space for "size" bytes in the buffer. false otherwise. - */ - bool canPull(int size = 0); - - /** - * Provide the next available ManagedBuffer to our downstream caller, if available. - */ - virtual ManagedBuffer pull(); - - /** - * Deliver the next available ManagedBuffer to our downstream caller. - */ - virtual int pullRequest(); - - /** - * Query the stream for its current sample rate. - * - * If the current object is unable to determine this itself, it will pass the call upstream until it reaches a component can respond. - * - * @warning The sample rate for a stream may change during its lifetime. If a component is sensitive to this, it should periodically check. - * - * @return float The current sample rate for this stream, or `DATASTREAM_SAMPLE_RATE_UNKNOWN` if none is found. - */ - virtual float getSampleRate() override; - - /** - * Request a new sample rate on this stream. - * - * Most components will simply forward this call upstream, and upon reaching a data source, if possible the source should change - * the sample rate to accomodate the request. - * - * @warning Not all sample rates will be possible for all devices, so if the caller needs to know the _actual_ rate, they should check the returned value here - * - * @param sampleRate The requested sample rate, to be handled by the nearest component capable of doing so. - * @return float The actual sample rate this stream will now run at, may differ from the requested sample rate. - */ - virtual float requestSampleRate(float sampleRate) override; - - private: - /** - * Issue a deferred pull request to our downstream component, if one has been registered. - */ - void onDeferredPullRequest(Event); - - }; -} +#define DATASTREAM_FORMAT_UNKNOWN 0 +#define DATASTREAM_FORMAT_8BIT_UNSIGNED 1 +#define DATASTREAM_FORMAT_8BIT_SIGNED 2 +#define DATASTREAM_FORMAT_16BIT_UNSIGNED 3 +#define DATASTREAM_FORMAT_16BIT_SIGNED 4 +#define DATASTREAM_FORMAT_24BIT_UNSIGNED 5 +#define DATASTREAM_FORMAT_24BIT_SIGNED 6 +#define DATASTREAM_FORMAT_32BIT_UNSIGNED 7 +#define DATASTREAM_FORMAT_32BIT_SIGNED 8 + +#define DATASTREAM_FORMAT_BYTES_PER_SAMPLE(x) ((x + 1) / 2) + +#define DATASTREAM_SAMPLE_RATE_UNKNOWN 0.0f + +namespace codal { +/** + * Interface definition for a DataSource. + */ +class DataSink { + public: + virtual int pullRequest(); +}; + +/** + * Interface definition for a DataSource. + */ +class DataSource { + public: + virtual ManagedBuffer pull(); + virtual void connect(DataSink& sink); + virtual bool isConnected() { return false; } + virtual void disconnect(); + virtual int getFormat(); + virtual int setFormat(int format); + virtual float getSampleRate(); + virtual float requestSampleRate(float sampleRate); +}; + +/** + * Class definition for DataStream. + * A Datastream holds a number of ManagedBuffer references, provides basic flow control through a push/pull mechanism + * and byte level access to the datastream, even if it spans different buffers. + */ +class DataStream : public DataSource, public DataSink { + uint16_t pullRequestEventCode; + uint16_t flowEventCode; + ManagedBuffer nextBuffer; + bool hasPending; + bool isBlocking; + unsigned int missedBuffers; + int downstreamReturn; + + DataSink* downStream; + DataSource* upStream; + + public: + /** + * Default Constructor. + * Creates an empty DataStream. + * + * @param upstream the component that will normally feed this datastream with data. + */ + DataStream(DataSource& upstream); + + /** + * Destructor. + * Removes all resources held by the instance. + */ + ~DataStream(); + + /** + * Controls if this component should emit flow state events. + * + * @warning Should not be called mutliple times with `id == 0`, as it will spuriously reallocate event IDs + * + * @param id If zero, this will auto-allocate a new event ID + * @return uint16_t The new event ID for this DataStream + */ + uint16_t emitFlowEvents(uint16_t id = 0); + + /** + * Determines if any of the data currently flowing through this stream is held in non-volatile (FLASH) memory. + * @return true if one or more of the ManagedBuffers in this stream reside in FLASH memory, false otherwise. + */ + bool isReadOnly(); + + /** + * Attempts to determine if another component downstream of this one is _actually_ pulling data, and thus, data + * is flowing. + * + * @return true If there is a count-match between `pullRequest` and `pull` calls. + * @return false If `pullRequest` calls are not currently being matched by `pull` calls. + */ + bool isFlowing(); + + /** + * Define a downstream component for data stream. + * + * @sink The component that data will be delivered to, when it is available + */ + virtual void connect(DataSink& sink) override; + + /** + * Determines if this source is connected to a downstream component + * + * @return true If a downstream is connected + * @return false If a downstream is not connected + */ + virtual bool isConnected(); + + /** + * Define a downstream component for data stream. + * + * @sink The component that data will be delivered to, when it is available + */ + virtual void disconnect() override; + + /** + * Determine the data format of the buffers streamed out of this component. + */ + virtual int getFormat() override; + + /** + * Determines if this stream acts in a synchronous, blocking mode or asynchronous mode. In blocking mode, writes to + * a full buffer will result int he calling fiber being blocked until space is available. Downstream DataSinks will + * also attempt to process data immediately as it becomes available. In non-blocking asynchronpus mode, writes to a + * full buffer are dropped and downstream Datasinks will be processed in a new fiber. + */ + void setBlocking(bool isBlocking); + + /** + * Determines if a buffer of the given size can be added to the buffer. + * + * @param size The number of bytes to add to the buffer. + * @return true if there is space for "size" bytes in the buffer. false otherwise. + */ + bool canPull(int size = 0); + + /** + * Provide the next available ManagedBuffer to our downstream caller, if available. + */ + virtual ManagedBuffer pull(); + + /** + * Deliver the next available ManagedBuffer to our downstream caller. + */ + virtual int pullRequest(); + + /** + * Query the stream for its current sample rate. + * + * If the current object is unable to determine this itself, it will pass the call upstream until it reaches a + * component can respond. + * + * @warning The sample rate for a stream may change during its lifetime. If a component is sensitive to this, it + * should periodically check. + * + * @return float The current sample rate for this stream, or `DATASTREAM_SAMPLE_RATE_UNKNOWN` if none is found. + */ + virtual float getSampleRate() override; + + /** + * Request a new sample rate on this stream. + * + * Most components will simply forward this call upstream, and upon reaching a data source, if possible the source + * should change the sample rate to accomodate the request. + * + * @warning Not all sample rates will be possible for all devices, so if the caller needs to know the _actual_ rate, + * they should check the returned value here + * + * @param sampleRate The requested sample rate, to be handled by the nearest component capable of doing so. + * @return float The actual sample rate this stream will now run at, may differ from the requested sample rate. + */ + virtual float requestSampleRate(float sampleRate) override; + + private: + /** + * Issue a deferred pull request to our downstream component, if one has been registered. + */ + void onDeferredPullRequest(Event); +}; +} // namespace codal #endif diff --git a/inc/streams/EffectFilter.h b/inc/streams/EffectFilter.h index f2de3834..7f1a544e 100644 --- a/inc/streams/EffectFilter.h +++ b/inc/streams/EffectFilter.h @@ -1,52 +1,51 @@ -#include "ManagedBuffer.h" #include "DataStream.h" +#include "ManagedBuffer.h" #include "StreamNormalizer.h" #ifndef EFFECT_FILTER_H #define EFFECT_FILTER_H -namespace codal -{ - class EffectFilter : public DataSource, public DataSink - { - protected: - - DataSink *downStream; - DataSource &upStream; - bool deepCopy; - - public: - - EffectFilter(DataSource &source, bool deepCopy = true); - ~EffectFilter(); - - virtual ManagedBuffer pull(); - virtual int pullRequest(); - virtual void connect( DataSink &sink ); - bool isConnected(); - virtual void disconnect(); - virtual int getFormat(); - virtual int setFormat( int format ); - - virtual float getSampleRate(); - virtual float requestSampleRate(float sampleRate); - - /** - * Defines if this filter should perform a deep copy of incoming data, or update data in place. - * - * @param deepCopy Set to true to copy incoming data into a freshly allocated buffer, or false to change data in place. - */ - void setDeepCopy(bool deepCopy); - - /** - * Default effect - a simple pass through filter. Override this method in subclasses to create specialist effects/filters. - * - * @param inputBuffer the buffer containing data to process. - * @param outputBuffer the buffer in which to store the filtered data. n.b. MAY be the same memory as the input buffer. - * @param format the format of the data (word size and signed/unsigned representation) - */ - virtual void applyEffect(ManagedBuffer inputBuffer, ManagedBuffer outputBuffer, int format); - }; -} +namespace codal { +class EffectFilter : public DataSource, public DataSink { + protected: + DataSink* downStream; + DataSource& upStream; + bool deepCopy; + + public: + EffectFilter(DataSource& source, bool deepCopy = true); + ~EffectFilter(); + + virtual ManagedBuffer pull(); + virtual int pullRequest(); + virtual void connect(DataSink& sink); + bool isConnected(); + virtual void disconnect(); + virtual int getFormat(); + virtual int setFormat(int format); + + virtual float getSampleRate(); + virtual float requestSampleRate(float sampleRate); + + /** + * Defines if this filter should perform a deep copy of incoming data, or update data in place. + * + * @param deepCopy Set to true to copy incoming data into a freshly allocated buffer, or false to change data in + * place. + */ + void setDeepCopy(bool deepCopy); + + /** + * Default effect - a simple pass through filter. Override this method in subclasses to create specialist + * effects/filters. + * + * @param inputBuffer the buffer containing data to process. + * @param outputBuffer the buffer in which to store the filtered data. n.b. MAY be the same memory as the input + * buffer. + * @param format the format of the data (word size and signed/unsigned representation) + */ + virtual void applyEffect(ManagedBuffer inputBuffer, ManagedBuffer outputBuffer, int format); +}; +} // namespace codal #endif \ No newline at end of file diff --git a/inc/streams/FIFOStream.h b/inc/streams/FIFOStream.h index a16503b2..0d589d1a 100644 --- a/inc/streams/FIFOStream.h +++ b/inc/streams/FIFOStream.h @@ -1,52 +1,46 @@ #ifndef FIFO_STREAM_H #define FIFO_STREAM_H -#include "ManagedBuffer.h" #include "DataStream.h" - +#include "ManagedBuffer.h" #define FIFO_MAXIMUM_BUFFERS 256 namespace codal { - class FIFOStream : public DataSource, public DataSink - { - private: - - ManagedBuffer buffer[FIFO_MAXIMUM_BUFFERS]; - int bufferCount; - int bufferLength; - - bool allowInput; - bool allowOutput; - - DataSink *downStream; - DataSource &upStream; - - public: +class FIFOStream : public DataSource, public DataSink { + private: + ManagedBuffer buffer[FIFO_MAXIMUM_BUFFERS]; + int bufferCount; + int bufferLength; - FIFOStream( DataSource &source ); - ~FIFOStream(); + bool allowInput; + bool allowOutput; - virtual ManagedBuffer pull(); - virtual int pullRequest(); - virtual void connect( DataSink &sink ); - bool isConnected(); - virtual void disconnect(); - virtual int getFormat(); - virtual int setFormat( int format ); - int length(); - void dumpState(); + DataSink* downStream; + DataSource& upStream; - bool canPull(); - bool isFull(); + public: + FIFOStream(DataSource& source); + ~FIFOStream(); - void setInputEnable( bool state ); - void setOutputEnable( bool state ); + virtual ManagedBuffer pull(); + virtual int pullRequest(); + virtual void connect(DataSink& sink); + bool isConnected(); + virtual void disconnect(); + virtual int getFormat(); + virtual int setFormat(int format); + int length(); + void dumpState(); + bool canPull(); + bool isFull(); - }; + void setInputEnable(bool state); + void setOutputEnable(bool state); +}; -} +} // namespace codal #endif \ No newline at end of file diff --git a/inc/streams/LevelDetector.h b/inc/streams/LevelDetector.h index ca66f9d9..657284e0 100644 --- a/inc/streams/LevelDetector.h +++ b/inc/streams/LevelDetector.h @@ -28,129 +28,125 @@ DEALINGS IN THE SOFTWARE. #ifndef LEVEL_DETECTOR_H #define LEVEL_DETECTOR_H - /** - * Sensor events - */ -#define LEVEL_THRESHOLD_LOW 1 -#define LEVEL_THRESHOLD_HIGH 2 + * Sensor events + */ +#define LEVEL_THRESHOLD_LOW 1 +#define LEVEL_THRESHOLD_HIGH 2 /** * Status values */ -#define LEVEL_DETECTOR_INITIALISED 0x01 -#define LEVEL_DETECTOR_HIGH_THRESHOLD_PASSED 0x02 -#define LEVEL_DETECTOR_LOW_THRESHOLD_PASSED 0x04 +#define LEVEL_DETECTOR_INITIALISED 0x01 +#define LEVEL_DETECTOR_HIGH_THRESHOLD_PASSED 0x02 +#define LEVEL_DETECTOR_LOW_THRESHOLD_PASSED 0x04 /** * Default configuration values */ -#define LEVEL_DETECTOR_DEFAULT_WINDOW_SIZE 128 - -namespace codal{ - class LevelDetector : public CodalComponent, public DataSink - { - public: - - // The stream component that is serving our data - DataSource &upstream; // The component producing data to process - int highThreshold; // threshold at which a HIGH event is generated - int lowThreshold; // threshold at which a LOW event is generated - int windowSize; // The number of samples the make up a level detection window. - int windowPosition; // The number of samples used so far in the calculation of a window. - int level; // The current, instantaneous level. - int sigma; // Running total of the samples in the current window. - bool activated; // Has this component been connected yet. - uint64_t timeout; // The timestamp at which this component will cease actively sampling the data stream - - - /** - * Creates a component capable of measuring and thresholding stream data - * - * @param source a DataSource to measure the level of. - * @param highThreshold the HIGH threshold at which a LEVEL_THRESHOLD_HIGH event will be generated - * @param lowThreshold the HIGH threshold at which a LEVEL_THRESHOLD_LOW event will be generated - * @param id The id to use for the message bus when transmitting events. - * @param connectImmediately Should this component connect to upstream splitter when started - */ - LevelDetector(DataSource &source, int highThreshold, int lowThreshold, uint16_t id = DEVICE_ID_SYSTEM_LEVEL_DETECTOR, bool connectImmediately = true); - - /** - * Callback provided when data is ready. - */ - virtual int pullRequest(); - - /* - * Determines the instantaneous value of the sensor, in SI units, and returns it. - * - * @return The current value of the sensor. - */ - int getValue(); - - /** - * Enable (or disable) this component constantly listening for events. - * - * This will supporess the sampling timeout mechanisms. - * - * @param state If true, keep the component consuming buffers and emitting events. - */ - void activateForEvents( bool state ); - - /** - * Set the LOW threshold to the given value. Events will be generated when these thresholds are crossed. - * - * If the provided value is higher than the HIGH threshold, the HIGH threshold will be - * increased to one unit above this value. - * - * @param value the LOW threshold at which a LEVEL_THRESHOLD_LOW will be generated. - * - * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if the request fails. - */ - int setLowThreshold(int value); - - /** - * Set the HIGH threshold to the given value. Events will be generated when these thresholds are crossed. - * - * If the provided value is lower than the LOW threshold, the LOW threshold will be - * reduced to one unit below this value. - * - * @param value the HIGH threshold at which a LEVEL_THRESHOLD_HIGH will be generated. - * - * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if the request fails. - */ - int setHighThreshold(int value); - - /** - * Determines the currently defined low threshold. - * - * @return The current low threshold. DEVICE_INVALID_PARAMETER if no threshold has been defined. - */ - int getLowThreshold(); - - /** - * Determines the currently defined high threshold. - * - * @return The current high threshold. DEVICE_INVALID_PARAMETER if no threshold has been defined. - */ - int getHighThreshold(); - - /** - * Set the window size to the given value. The window size defines the number of samples used to determine a sound level. - * The higher the value, the more accurate the result will be. The lower the value, the more responsive the result will be. - * Adjust this value to suit the requirements of your applicaiton. - * - * @param size The size of the window to use (number of samples). - * - * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if the request fails. - */ - int setWindowSize(int size); - - /** - * Destructor. - */ - ~LevelDetector(); - - }; -} +#define LEVEL_DETECTOR_DEFAULT_WINDOW_SIZE 128 + +namespace codal { +class LevelDetector : public CodalComponent, public DataSink { + public: + // The stream component that is serving our data + DataSource& upstream; // The component producing data to process + int highThreshold; // threshold at which a HIGH event is generated + int lowThreshold; // threshold at which a LOW event is generated + int windowSize; // The number of samples the make up a level detection window. + int windowPosition; // The number of samples used so far in the calculation of a window. + int level; // The current, instantaneous level. + int sigma; // Running total of the samples in the current window. + bool activated; // Has this component been connected yet. + uint64_t timeout; // The timestamp at which this component will cease actively sampling the data stream + + /** + * Creates a component capable of measuring and thresholding stream data + * + * @param source a DataSource to measure the level of. + * @param highThreshold the HIGH threshold at which a LEVEL_THRESHOLD_HIGH event will be generated + * @param lowThreshold the HIGH threshold at which a LEVEL_THRESHOLD_LOW event will be generated + * @param id The id to use for the message bus when transmitting events. + * @param connectImmediately Should this component connect to upstream splitter when started + */ + LevelDetector(DataSource& source, int highThreshold, int lowThreshold, + uint16_t id = DEVICE_ID_SYSTEM_LEVEL_DETECTOR, bool connectImmediately = true); + + /** + * Callback provided when data is ready. + */ + virtual int pullRequest(); + + /* + * Determines the instantaneous value of the sensor, in SI units, and returns it. + * + * @return The current value of the sensor. + */ + int getValue(); + + /** + * Enable (or disable) this component constantly listening for events. + * + * This will supporess the sampling timeout mechanisms. + * + * @param state If true, keep the component consuming buffers and emitting events. + */ + void activateForEvents(bool state); + + /** + * Set the LOW threshold to the given value. Events will be generated when these thresholds are crossed. + * + * If the provided value is higher than the HIGH threshold, the HIGH threshold will be + * increased to one unit above this value. + * + * @param value the LOW threshold at which a LEVEL_THRESHOLD_LOW will be generated. + * + * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if the request fails. + */ + int setLowThreshold(int value); + + /** + * Set the HIGH threshold to the given value. Events will be generated when these thresholds are crossed. + * + * If the provided value is lower than the LOW threshold, the LOW threshold will be + * reduced to one unit below this value. + * + * @param value the HIGH threshold at which a LEVEL_THRESHOLD_HIGH will be generated. + * + * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if the request fails. + */ + int setHighThreshold(int value); + + /** + * Determines the currently defined low threshold. + * + * @return The current low threshold. DEVICE_INVALID_PARAMETER if no threshold has been defined. + */ + int getLowThreshold(); + + /** + * Determines the currently defined high threshold. + * + * @return The current high threshold. DEVICE_INVALID_PARAMETER if no threshold has been defined. + */ + int getHighThreshold(); + + /** + * Set the window size to the given value. The window size defines the number of samples used to determine a sound + * level. The higher the value, the more accurate the result will be. The lower the value, the more responsive the + * result will be. Adjust this value to suit the requirements of your applicaiton. + * + * @param size The size of the window to use (number of samples). + * + * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if the request fails. + */ + int setWindowSize(int size); + + /** + * Destructor. + */ + ~LevelDetector(); +}; +} // namespace codal #endif diff --git a/inc/streams/LevelDetectorSPL.h b/inc/streams/LevelDetectorSPL.h index f016cfcc..1e95fe23 100644 --- a/inc/streams/LevelDetectorSPL.h +++ b/inc/streams/LevelDetectorSPL.h @@ -23,8 +23,8 @@ DEALINGS IN THE SOFTWARE. */ #include "CodalConfig.h" -#include "DataStream.h" #include "CodalFiber.h" +#include "DataStream.h" #ifndef LEVEL_DETECTOR_SPL_H #define LEVEL_DETECTOR_SPL_H @@ -32,24 +32,23 @@ DEALINGS IN THE SOFTWARE. /** * Status values */ -#define LEVEL_DETECTOR_SPL_INITIALISED 0x01 -#define LEVEL_DETECTOR_SPL_HIGH_THRESHOLD_PASSED 0x02 -#define LEVEL_DETECTOR_SPL_LOW_THRESHOLD_PASSED 0x04 -#define LEVEL_DETECTOR_SPL_CLAP 0x08 - +#define LEVEL_DETECTOR_SPL_INITIALISED 0x01 +#define LEVEL_DETECTOR_SPL_HIGH_THRESHOLD_PASSED 0x02 +#define LEVEL_DETECTOR_SPL_LOW_THRESHOLD_PASSED 0x04 +#define LEVEL_DETECTOR_SPL_CLAP 0x08 /** * Default configuration values */ -#define LEVEL_DETECTOR_SPL_DEFAULT_WINDOW_SIZE 128 +#define LEVEL_DETECTOR_SPL_DEFAULT_WINDOW_SIZE 128 #ifndef LEVEL_DETECTOR_SPL_NORMALIZE -#define LEVEL_DETECTOR_SPL_NORMALIZE 1 +#define LEVEL_DETECTOR_SPL_NORMALIZE 1 #endif // The number of buffers to use to settle the room ambient SPL before reporting events and values. #ifndef LEVEL_DETECTOR_SPL_MIN_BUFFERS -#define LEVEL_DETECTOR_SPL_MIN_BUFFERS 2 +#define LEVEL_DETECTOR_SPL_MIN_BUFFERS 2 #endif /** @@ -58,172 +57,170 @@ DEALINGS IN THE SOFTWARE. // The level (in dB) that corresponds to an 8bit value of 0. #ifndef LEVEL_DETECTOR_SPL_8BIT_000_POINT -#define LEVEL_DETECTOR_SPL_8BIT_000_POINT 35.0f +#define LEVEL_DETECTOR_SPL_8BIT_000_POINT 35.0f #endif // The level (in dB) that corresponds to an 8bit value of 255. #ifndef LEVEL_DETECTOR_SPL_8BIT_255_POINT -#define LEVEL_DETECTOR_SPL_8BIT_255_POINT 100.0f +#define LEVEL_DETECTOR_SPL_8BIT_255_POINT 100.0f #endif -#define LEVEL_DETECTOR_SPL_8BIT_CONVERSION (255.0f/(LEVEL_DETECTOR_SPL_8BIT_255_POINT-LEVEL_DETECTOR_SPL_8BIT_000_POINT)) +#define LEVEL_DETECTOR_SPL_8BIT_CONVERSION \ + (255.0f / (LEVEL_DETECTOR_SPL_8BIT_255_POINT - LEVEL_DETECTOR_SPL_8BIT_000_POINT)) /** * Level detetor unit enumeration. */ -#define LEVEL_DETECTOR_SPL_DB 1 -#define LEVEL_DETECTOR_SPL_8BIT 2 +#define LEVEL_DETECTOR_SPL_DB 1 +#define LEVEL_DETECTOR_SPL_8BIT 2 // Clap detection constants -#define LEVEL_DETECTOR_SPL_BEGIN_POSS_CLAP_RMS 200 // threshold to start considering clap - rms value -#define LEVEL_DETECTOR_SPL_MIN_IN_CLAP_RMS 300 // minimum amount to be within a clap once considering -#define LEVEL_DETECTOR_SPL_CLAP_OVER_RMS 100 // threshold once in clap to consider noise over -#define LEVEL_DETECTOR_SPL_CLAP_MAX_LOUD_BLOCKS 13 // ensure noise not too long to be a clap -#define LEVEL_DETECTOR_SPL_CLAP_MIN_LOUD_BLOCKS 2 // ensure noise not too short to be a clap -#define LEVEL_DETECTOR_SPL_CLAP_MIN_QUIET_BLOCKS 20 // prevent very fast taps being registered as clap - - -namespace codal{ - class LevelDetectorSPL : public CodalComponent, public DataSink - { - public: - - // The stream component that is serving our data - DataSource &upstream; // The component producing data to process - float highThreshold; // threshold at which a HIGH event is generated - float lowThreshold; // threshold at which a LOW event is generated - int windowSize; // The number of samples the make up a level detection window. - float level; // The current, instantaneous level. - int sigma; // Running total of the samples in the current window. - float gain; - float minValue; - bool activated; // Has this component been connected yet - bool enabled; // Is the component currently running - int unit; // The units to be returned from this level detector (e.g. dB or linear 8bit) - int quietBlockCount; // number of quiet blocks consecutively - used for clap detection - int noisyBlockCount; // number of noisy blocks consecutively - used for clap detection - bool inNoisyBlock; // if had noisy and waiting to lower beyond lower threshold - float maxRms; // maximum rms within a noisy block - - private: - uint64_t timeout; // The timestamp at which this component will cease actively sampling the data stream - uint8_t bufferCount; // Used to track that enough buffers have been seen since activation to output a valid value/event - FiberLock resourceLock; - public: - - /** - * Creates a component capable of measuring and thresholding stream data - * - * @param source a DataSource to measure the level of. - * @param highThreshold the HIGH threshold at which a SPL_LEVEL_THRESHOLD_HIGH event will be generated - * @param lowThreshold the HIGH threshold at which a SPL_LEVEL_THRESHOLD_LOW event will be generated - * @param id The id to use for the message bus when transmitting events. - * @param activateImmediately Should this component start emitting events immediately - */ - LevelDetectorSPL(DataSource &source, float highThreshold, float lowThreshold, float gain, - float minValue = 52, - uint16_t id = DEVICE_ID_SYSTEM_LEVEL_DETECTOR_SPL, - bool activateImmediately = true); - - /** - * Callback provided when data is ready. - */ - virtual int pullRequest(); - - /* - * Determines the instantaneous value of the sensor, in SI units, and returns it. - * - * @param scale either LEVEL_DETECTOR_SPL_DB or LEVEL_DETECTOR_SPL_8BIT to select the scale for this call. If not supplied it will default to the current system setting. - * @return The current value of the sensor. - */ - float getValue( int scale = -1 ); - - /** - * Keep this component active and processing buffers so that events can be produced - * - * @param state If set to true, this component will connect (if required) and start consuming buffers - */ - void activateForEvents( bool state ); - - /** - * Disable component - */ - void disable(); - - /** - * Set the LOW threshold to the given value. Events will be generated when these thresholds are crossed. - * - * If the provided value is higher than the HIGH threshold, the HIGH threshold will be - * increased to one dB above this value. - * - * The unit used for the input value will be the unit configured via setUnit(). - * - * @param value The LOW threshold at which a LEVEL_THRESHOLD_LOW will be generated. - * - * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if the request fails. - */ - int setLowThreshold(float value); - - /** - * Set the HIGH threshold to the given value. Events will be generated when these thresholds are crossed. - * - * If the provided value is lower than the LOW threshold, the LOW threshold will be - * reduced to one dB below this value. - * - * The unit used for the input value will be the unit configured via setUnit(). - * - * @param value The HIGH threshold at which a LEVEL_THRESHOLD_HIGH will be generated. - * - * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if the request fails. - */ - int setHighThreshold(float value); - - /** - * Determines the currently defined low threshold. - * - * @return The current low threshold. DEVICE_INVALID_PARAMETER if no threshold has been defined. - * The returned value unit can be configured via setUnit(). - */ - float getLowThreshold(); - - /** - * Determines the currently defined high threshold. - * - * @return The current high threshold. DEVICE_INVALID_PARAMETER if no threshold has been defined. - * The returned value unit can be configured via setUnit(). - */ - float getHighThreshold(); - - /** - * Set the window size to the given value. The window size defines the number of samples used to determine a sound level. - * The higher the value, the more accurate the result will be. The lower the value, the more responsive the result will be. - * Adjust this value to suit the requirements of your applicaiton. - * - * @param size The size of the window to use (number of samples). - * - * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if the request fails. - */ - int setWindowSize(int size); - - int setGain(float gain); - - /** - * Defines the units that will be returned by the getValue() function. - * - * @param unit Either LEVEL_DETECTOR_SPL_DB or LEVEL_DETECTOR_SPL_8BIT. - * @return DEVICE_OK or DEVICE_INVALID_PARAMETER. - */ - int setUnit(int unit); - - /** - * Destructor. - */ - ~LevelDetectorSPL(); - - private: - float splToUnit(float f, int queryUnit = -1); - float unitToSpl(float f, int queryUnit = -1); - }; -} +#define LEVEL_DETECTOR_SPL_BEGIN_POSS_CLAP_RMS 200 // threshold to start considering clap - rms value +#define LEVEL_DETECTOR_SPL_MIN_IN_CLAP_RMS 300 // minimum amount to be within a clap once considering +#define LEVEL_DETECTOR_SPL_CLAP_OVER_RMS 100 // threshold once in clap to consider noise over +#define LEVEL_DETECTOR_SPL_CLAP_MAX_LOUD_BLOCKS 13 // ensure noise not too long to be a clap +#define LEVEL_DETECTOR_SPL_CLAP_MIN_LOUD_BLOCKS 2 // ensure noise not too short to be a clap +#define LEVEL_DETECTOR_SPL_CLAP_MIN_QUIET_BLOCKS 20 // prevent very fast taps being registered as clap + +namespace codal { +class LevelDetectorSPL : public CodalComponent, public DataSink { + public: + // The stream component that is serving our data + DataSource& upstream; // The component producing data to process + float highThreshold; // threshold at which a HIGH event is generated + float lowThreshold; // threshold at which a LOW event is generated + int windowSize; // The number of samples the make up a level detection window. + float level; // The current, instantaneous level. + int sigma; // Running total of the samples in the current window. + float gain; + float minValue; + bool activated; // Has this component been connected yet + bool enabled; // Is the component currently running + int unit; // The units to be returned from this level detector (e.g. dB or linear 8bit) + int quietBlockCount; // number of quiet blocks consecutively - used for clap detection + int noisyBlockCount; // number of noisy blocks consecutively - used for clap detection + bool inNoisyBlock; // if had noisy and waiting to lower beyond lower threshold + float maxRms; // maximum rms within a noisy block + + private: + uint64_t timeout; // The timestamp at which this component will cease actively sampling the data stream + uint8_t + bufferCount; // Used to track that enough buffers have been seen since activation to output a valid value/event + FiberLock resourceLock; + + public: + /** + * Creates a component capable of measuring and thresholding stream data + * + * @param source a DataSource to measure the level of. + * @param highThreshold the HIGH threshold at which a SPL_LEVEL_THRESHOLD_HIGH event will be generated + * @param lowThreshold the HIGH threshold at which a SPL_LEVEL_THRESHOLD_LOW event will be generated + * @param id The id to use for the message bus when transmitting events. + * @param activateImmediately Should this component start emitting events immediately + */ + LevelDetectorSPL(DataSource& source, float highThreshold, float lowThreshold, float gain, float minValue = 52, + uint16_t id = DEVICE_ID_SYSTEM_LEVEL_DETECTOR_SPL, bool activateImmediately = true); + + /** + * Callback provided when data is ready. + */ + virtual int pullRequest(); + + /* + * Determines the instantaneous value of the sensor, in SI units, and returns it. + * + * @param scale either LEVEL_DETECTOR_SPL_DB or LEVEL_DETECTOR_SPL_8BIT to select the scale for this call. If not + * supplied it will default to the current system setting. + * @return The current value of the sensor. + */ + float getValue(int scale = -1); + + /** + * Keep this component active and processing buffers so that events can be produced + * + * @param state If set to true, this component will connect (if required) and start consuming buffers + */ + void activateForEvents(bool state); + + /** + * Disable component + */ + void disable(); + + /** + * Set the LOW threshold to the given value. Events will be generated when these thresholds are crossed. + * + * If the provided value is higher than the HIGH threshold, the HIGH threshold will be + * increased to one dB above this value. + * + * The unit used for the input value will be the unit configured via setUnit(). + * + * @param value The LOW threshold at which a LEVEL_THRESHOLD_LOW will be generated. + * + * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if the request fails. + */ + int setLowThreshold(float value); + + /** + * Set the HIGH threshold to the given value. Events will be generated when these thresholds are crossed. + * + * If the provided value is lower than the LOW threshold, the LOW threshold will be + * reduced to one dB below this value. + * + * The unit used for the input value will be the unit configured via setUnit(). + * + * @param value The HIGH threshold at which a LEVEL_THRESHOLD_HIGH will be generated. + * + * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if the request fails. + */ + int setHighThreshold(float value); + + /** + * Determines the currently defined low threshold. + * + * @return The current low threshold. DEVICE_INVALID_PARAMETER if no threshold has been defined. + * The returned value unit can be configured via setUnit(). + */ + float getLowThreshold(); + + /** + * Determines the currently defined high threshold. + * + * @return The current high threshold. DEVICE_INVALID_PARAMETER if no threshold has been defined. + * The returned value unit can be configured via setUnit(). + */ + float getHighThreshold(); + + /** + * Set the window size to the given value. The window size defines the number of samples used to determine a sound + * level. The higher the value, the more accurate the result will be. The lower the value, the more responsive the + * result will be. Adjust this value to suit the requirements of your applicaiton. + * + * @param size The size of the window to use (number of samples). + * + * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if the request fails. + */ + int setWindowSize(int size); + + int setGain(float gain); + + /** + * Defines the units that will be returned by the getValue() function. + * + * @param unit Either LEVEL_DETECTOR_SPL_DB or LEVEL_DETECTOR_SPL_8BIT. + * @return DEVICE_OK or DEVICE_INVALID_PARAMETER. + */ + int setUnit(int unit); + + /** + * Destructor. + */ + ~LevelDetectorSPL(); + + private: + float splToUnit(float f, int queryUnit = -1); + float unitToSpl(float f, int queryUnit = -1); +}; +} // namespace codal #endif diff --git a/inc/streams/LowPassFilter.h b/inc/streams/LowPassFilter.h index 4eabc439..622e5d62 100644 --- a/inc/streams/LowPassFilter.h +++ b/inc/streams/LowPassFilter.h @@ -1,36 +1,33 @@ -#include "ManagedBuffer.h" #include "DataStream.h" #include "EffectFilter.h" +#include "ManagedBuffer.h" #ifndef LOW_PASS_FILTER_H #define LOW_PASS_FILTER_H -namespace codal -{ - class LowPassFilter : public EffectFilter - { - private: - - float lpf_value; - float lpf_beta; - - public: - - LowPassFilter( DataSource &source, float beta = 0.003f, bool deepCopy = true); - ~LowPassFilter(); - - /** - * Apply a simple low pass filter on the give buffer of data. - * Y(n) = (1-ß)*Y(n-1) + (ß*X(n))) = Y(n-1) - (ß*(Y(n-1)-X(n))); - * - * @param inputBuffer the buffer containing data to process. - * @param outputBuffer the buffer in which to store the filtered data. n.b. MAY be the same memory as the input buffer. - * @param format the format of the data (word size and signed/unsigned representation) - */ - virtual void applyEffect(ManagedBuffer inputBuffer, ManagedBuffer outputBuffer, int format) override; - - void setBeta( float beta ); - }; -} +namespace codal { +class LowPassFilter : public EffectFilter { + private: + float lpf_value; + float lpf_beta; + + public: + LowPassFilter(DataSource& source, float beta = 0.003f, bool deepCopy = true); + ~LowPassFilter(); + + /** + * Apply a simple low pass filter on the give buffer of data. + * Y(n) = (1-ß)*Y(n-1) + (ß*X(n))) = Y(n-1) - (ß*(Y(n-1)-X(n))); + * + * @param inputBuffer the buffer containing data to process. + * @param outputBuffer the buffer in which to store the filtered data. n.b. MAY be the same memory as the input + * buffer. + * @param format the format of the data (word size and signed/unsigned representation) + */ + virtual void applyEffect(ManagedBuffer inputBuffer, ManagedBuffer outputBuffer, int format) override; + + void setBeta(float beta); +}; +} // namespace codal #endif \ No newline at end of file diff --git a/inc/streams/MemorySource.h b/inc/streams/MemorySource.h index 5203ac95..cf26d5dd 100644 --- a/inc/streams/MemorySource.h +++ b/inc/streams/MemorySource.h @@ -28,122 +28,122 @@ DEALINGS IN THE SOFTWARE. #ifndef MEMORY_SOURCE_H #define MEMORY_SOURCE_H -#define MEMORY_SOURCE_DEFAULT_MAX_BUFFER 256 +#define MEMORY_SOURCE_DEFAULT_MAX_BUFFER 256 /** * A simple buffer class for streaming bytes from memory across the Stream APIs. */ -namespace codal -{ - class MemorySource : public DataSource - { - private: - int outputFormat; // The format to output in. By default, this is the same as the input. - int outputBufferSize; // The maximum size of an output buffer. - ManagedBuffer buffer; // The output buffer being filled - - uint8_t *data; // The input data being played (immutable) - uint8_t *in; // The input data being played (mutable) - int length; // The lenght of the input buffer (immutable) - int bytesToSend; // The lenght of the input buffer (mutable) - int count; // The number of times left to repeat - - DataSink *downstream; // Pointer to our downstream component - bool blockingPlayout; // Set to true if a blocking playout has been requested - FiberLock lock; // used to synchronise blocking play calls. - - public: - DataSource &output; // DEPRECATED: backward compatilbity only - - /** - * Default Constructor. - */ - MemorySource(); - - /** - * Provide the next available ManagedBuffer to our downstream caller, if available. - */ - virtual ManagedBuffer pull(); - - /** - * Determine the data format of the buffers streamed out of this component. - */ - virtual int getFormat(); - - /** - * Defines the data format of the buffers streamed out of this component. - * @param format valid values include: - * - * DATASTREAM_FORMAT_8BIT_UNSIGNED - * DATASTREAM_FORMAT_8BIT_SIGNED - * DATASTREAM_FORMAT_16BIT_UNSIGNED - * DATASTREAM_FORMAT_16BIT_SIGNED - * DATASTREAM_FORMAT_24BIT_UNSIGNED - * DATASTREAM_FORMAT_24BIT_SIGNED - * DATASTREAM_FORMAT_32BIT_UNSIGNED - * DATASTREAM_FORMAT_32BIT_SIGNED - */ - virtual int setFormat(int format); - - /* - * Allow out downstream component to register itself with us - */ - virtual void connect(DataSink &sink); - - /** - * Determines if this source is connected to a downstream component - * - * @return true If a downstream is connected - * @return false If a downstream is not connected - */ - bool isConnected(); - - - /** - * Determine the maximum size of the buffers streamed out of this component. - * @return The maximum size of this component's output buffers, in bytes. - */ - int getBufferSize(); - - /** - * Defines the maximum size of the buffers streamed out of this component. - * @param size the size of this component's output buffers, in bytes. - */ - int setBufferSize(int size); - - /** - * Perform a blocking playout of the data buffer. Returns when all the data has been queued. - * @param data pointer to memory location to playout - * @param length number of samples in the buffer. Assumes a sample size as defined by setFormat(). - * @param count if set, playback the buffer the given number of times. Defaults to 1. Set to a negative number to loop forever. - */ - void play(const void *data, int length, int count = 1); - - /** - * Perform a blocking playout of the data buffer. Returns when all the data has been queued. - * @param b the buffer to playout - * @param count if set, playback the buffer the given number of times. Defaults to 1. Set to a negative number to loop forever. - */ - void play(ManagedBuffer b, int count = 1); - - /** - * Perform a blocking playout of the data buffer. Returns when all the data has been queued. - * @param data pointer to memory location to playout - * @param length number of samples in the buffer. Assumes a sample size as defined by setFormat(). - * @param count if set, playback the buffer the given number of times. Defaults to 1. Set to a negative number to loop forever. - */ - void playAsync(const void *data, int length, int count = 1); - - /** - * Perform a blocking playout of the data buffer. Returns when all the data has been queued. - * @param b the buffer to playout - * @param count if set, playback the buffer the given number of times. Defaults to 1. Set to a negative number to loop forever. - */ - void playAsync(ManagedBuffer b, int count = 1); - - - private: - void _play(const void *data, int length, int count, bool mode); - }; -} +namespace codal { +class MemorySource : public DataSource { + private: + int outputFormat; // The format to output in. By default, this is the same as the input. + int outputBufferSize; // The maximum size of an output buffer. + ManagedBuffer buffer; // The output buffer being filled + + uint8_t* data; // The input data being played (immutable) + uint8_t* in; // The input data being played (mutable) + int length; // The lenght of the input buffer (immutable) + int bytesToSend; // The lenght of the input buffer (mutable) + int count; // The number of times left to repeat + + DataSink* downstream; // Pointer to our downstream component + bool blockingPlayout; // Set to true if a blocking playout has been requested + FiberLock lock; // used to synchronise blocking play calls. + + public: + DataSource& output; // DEPRECATED: backward compatilbity only + + /** + * Default Constructor. + */ + MemorySource(); + + /** + * Provide the next available ManagedBuffer to our downstream caller, if available. + */ + virtual ManagedBuffer pull(); + + /** + * Determine the data format of the buffers streamed out of this component. + */ + virtual int getFormat(); + + /** + * Defines the data format of the buffers streamed out of this component. + * @param format valid values include: + * + * DATASTREAM_FORMAT_8BIT_UNSIGNED + * DATASTREAM_FORMAT_8BIT_SIGNED + * DATASTREAM_FORMAT_16BIT_UNSIGNED + * DATASTREAM_FORMAT_16BIT_SIGNED + * DATASTREAM_FORMAT_24BIT_UNSIGNED + * DATASTREAM_FORMAT_24BIT_SIGNED + * DATASTREAM_FORMAT_32BIT_UNSIGNED + * DATASTREAM_FORMAT_32BIT_SIGNED + */ + virtual int setFormat(int format); + + /* + * Allow out downstream component to register itself with us + */ + virtual void connect(DataSink& sink); + + /** + * Determines if this source is connected to a downstream component + * + * @return true If a downstream is connected + * @return false If a downstream is not connected + */ + bool isConnected(); + + /** + * Determine the maximum size of the buffers streamed out of this component. + * @return The maximum size of this component's output buffers, in bytes. + */ + int getBufferSize(); + + /** + * Defines the maximum size of the buffers streamed out of this component. + * @param size the size of this component's output buffers, in bytes. + */ + int setBufferSize(int size); + + /** + * Perform a blocking playout of the data buffer. Returns when all the data has been queued. + * @param data pointer to memory location to playout + * @param length number of samples in the buffer. Assumes a sample size as defined by setFormat(). + * @param count if set, playback the buffer the given number of times. Defaults to 1. Set to a negative number to + * loop forever. + */ + void play(const void* data, int length, int count = 1); + + /** + * Perform a blocking playout of the data buffer. Returns when all the data has been queued. + * @param b the buffer to playout + * @param count if set, playback the buffer the given number of times. Defaults to 1. Set to a negative number to + * loop forever. + */ + void play(ManagedBuffer b, int count = 1); + + /** + * Perform a blocking playout of the data buffer. Returns when all the data has been queued. + * @param data pointer to memory location to playout + * @param length number of samples in the buffer. Assumes a sample size as defined by setFormat(). + * @param count if set, playback the buffer the given number of times. Defaults to 1. Set to a negative number to + * loop forever. + */ + void playAsync(const void* data, int length, int count = 1); + + /** + * Perform a blocking playout of the data buffer. Returns when all the data has been queued. + * @param b the buffer to playout + * @param count if set, playback the buffer the given number of times. Defaults to 1. Set to a negative number to + * loop forever. + */ + void playAsync(ManagedBuffer b, int count = 1); + + private: + void _play(const void* data, int length, int count, bool mode); +}; +} // namespace codal #endif \ No newline at end of file diff --git a/inc/streams/Mixer.h b/inc/streams/Mixer.h index 696f1d05..45ac28cd 100644 --- a/inc/streams/Mixer.h +++ b/inc/streams/Mixer.h @@ -27,27 +27,24 @@ DEALINGS IN THE SOFTWARE. #include "DataStream.h" -namespace codal -{ - -class MixerChannel -{ -private: - MixerChannel *next; - DataStream *stream; +namespace codal { + +class MixerChannel { + private: + MixerChannel* next; + DataStream* stream; friend class Mixer; -public: + public: uint16_t volume; bool isSigned; }; -class Mixer : public DataSource, public DataSink -{ - MixerChannel *channels; - DataSink *downStream; +class Mixer : public DataSource, public DataSink { + MixerChannel* channels; + DataSink* downStream; -public: + public: /** * Default Constructor. * Creates an empty Mixer. @@ -60,7 +57,7 @@ class Mixer : public DataSource, public DataSink */ ~Mixer(); - MixerChannel *addChannel(DataStream &stream); + MixerChannel* addChannel(DataStream& stream); /** * Provide the next available ManagedBuffer to our downstream caller, if available. @@ -77,17 +74,17 @@ class Mixer : public DataSource, public DataSink * * @sink The component that data will be delivered to, when it is available */ - virtual void connect(DataSink &sink); + virtual void connect(DataSink& sink); /** * Determines if this source is connected to a downstream component - * + * * @return true If a downstream is connected * @return false If a downstream is not connected */ bool isConnected(); }; -} // namespace codal +} // namespace codal #endif diff --git a/inc/streams/StreamFlowTrigger.h b/inc/streams/StreamFlowTrigger.h index f13c81f3..85366e58 100644 --- a/inc/streams/StreamFlowTrigger.h +++ b/inc/streams/StreamFlowTrigger.h @@ -1,5 +1,5 @@ -#include "ManagedBuffer.h" #include "DataStream.h" +#include "ManagedBuffer.h" #ifndef STREAM_FLOW_TRIGGER_H #define STREAM_FLOW_TRIGGER_H @@ -9,29 +9,27 @@ namespace codal { - class StreamFlowTrigger : public DataSource, public DataSink { - private: - - DataSink *downStream; - DataSource &upStream; - - void (*eventHandler)(int); +class StreamFlowTrigger : public DataSource, public DataSink { + private: + DataSink* downStream; + DataSource& upStream; - public: + void (*eventHandler)(int); - StreamFlowTrigger( DataSource &source ); - ~StreamFlowTrigger(); + public: + StreamFlowTrigger(DataSource& source); + ~StreamFlowTrigger(); - void setDataHandler( void (*handler)(int) ); + void setDataHandler(void (*handler)(int)); - virtual ManagedBuffer pull(); - virtual int pullRequest(); - virtual void connect( DataSink &sink ); - bool isConnected(); - virtual void disconnect(); - virtual int getFormat(); - virtual int setFormat( int format ); - }; -} + virtual ManagedBuffer pull(); + virtual int pullRequest(); + virtual void connect(DataSink& sink); + bool isConnected(); + virtual void disconnect(); + virtual int getFormat(); + virtual int setFormat(int format); +}; +} // namespace codal #endif \ No newline at end of file diff --git a/inc/streams/StreamNormalizer.h b/inc/streams/StreamNormalizer.h index 00d353a6..a67d16d8 100644 --- a/inc/streams/StreamNormalizer.h +++ b/inc/streams/StreamNormalizer.h @@ -31,130 +31,129 @@ DEALINGS IN THE SOFTWARE. /** * Sample read/write functions for 8, 16, 24, 32 bit signed/unsigned data. */ -typedef int (*SampleReadFn)(uint8_t *); -typedef void (*SampleWriteFn)(uint8_t *, int); - +typedef int (*SampleReadFn)(uint8_t*); +typedef void (*SampleWriteFn)(uint8_t*, int); /** * Default configuration values */ -namespace codal{ - - class StreamNormalizer : public DataSink, public DataSource - { - public: - int outputFormat; // The format to output in. By default, this is the sme as the input. - int stabilisation; // The % stability of the zero-offset calculation required to begin operation. - float gain; // Gain to apply. - float zeroOffset; // Best estimate of the zero point of the data source. - uint32_t orMask; // post processing step - or'd with each sample. - bool normalize; // If set, will recalculate a zero offset. - bool zeroOffsetValid; // Set to true after the first buffer has been processed. - bool outputEnabled; // When set any bxuffer processed will be forwarded downstream. - DataSource &upstream; // The upstream component of this StreamNormalizer. - DataStream output; // The downstream output stream of this StreamNormalizer. - //ManagedBuffer buffer; // The buffer being processed. - - static SampleReadFn readSample[9]; - static SampleWriteFn writeSample[9]; - - /** - * Creates a component capable of translating one data representation format into another - * - * @param source a DataSource to receive data from - * @param gain The gain to apply to each sample (default: 1.0) - * @param normalize Derive a zero offset for the input stream, and subtract from each sample (default: false) - * @param format The format to convert the input stream into - * @param stabilisation the maximum change of zero-offset permitted between subsequent buffers before output is initiated. Set to zero to disable (default) - */ - StreamNormalizer(DataSource &source, float gain = 1.0f, bool normalize = false, int format = DATASTREAM_FORMAT_UNKNOWN, int stabilisation = 0); - - /** - * Callback provided when data is ready. - */ - virtual int pullRequest(); - - /** - * Provide the next available ManagedBuffer to our downstream caller, if available. - */ - virtual ManagedBuffer pull(); - - /** - * Defines whether this input stream will be normalized based on its mean average value. - * - * @param normalize The state to apply - set to true to apply normlization, false otherwise. - * @return DEVICE_OK on success. - */ - int setNormalize(bool normalize); - - /** - * Determines whether normalization is being applied . - * @return true if normlization is being performed, false otherwise. - */ - bool getNormalize(); - - /** - * Determine the data format of the buffers streamed out of this component. - */ - virtual int getFormat(); - - /** - * Defines the data format of the buffers streamed out of this component. - * @param format valid values include: - * - * DATASTREAM_FORMAT_8BIT_UNSIGNED - * DATASTREAM_FORMAT_8BIT_SIGNED - * DATASTREAM_FORMAT_16BIT_UNSIGNED - * DATASTREAM_FORMAT_16BIT_SIGNED - * DATASTREAM_FORMAT_24BIT_UNSIGNED - * DATASTREAM_FORMAT_24BIT_SIGNED - * DATASTREAM_FORMAT_32BIT_UNSIGNED - * DATASTREAM_FORMAT_32BIT_SIGNED - */ - virtual int setFormat(int format); - - /** - * Defines an optional gain to apply to the input, as a floating point multiple. - * - * @param gain The gain to apply to this input stream. - * @return DEVICE_OK on success. - */ - int setGain(float gain); - - /** - * Determines the gain being applied to the input, as a floating point multiple. - * @return the gain applied. - */ - float getGain(); - - /** - * Defines an optional bit mask to logical OR with each sample. - * Useful if the downstream component encodes control data within its samples. - * - * @param mask The bitmask to to apply to each sample. - * @return DEVICE_OK on success. - */ - int setOrMask(uint32_t mask); - - float getSampleRate(); - - float requestSampleRate(float sampleRate); - - /** - * Determines if this source is connected to a downstream component - * - * @return true If a downstream is connected - * @return false If a downstream is not connected - */ - bool isConnected(); - - /** - * Destructor. - */ - ~StreamNormalizer(); - - }; -} +namespace codal { + +class StreamNormalizer : public DataSink, public DataSource { + public: + int outputFormat; // The format to output in. By default, this is the sme as the input. + int stabilisation; // The % stability of the zero-offset calculation required to begin operation. + float gain; // Gain to apply. + float zeroOffset; // Best estimate of the zero point of the data source. + uint32_t orMask; // post processing step - or'd with each sample. + bool normalize; // If set, will recalculate a zero offset. + bool zeroOffsetValid; // Set to true after the first buffer has been processed. + bool outputEnabled; // When set any bxuffer processed will be forwarded downstream. + DataSource& upstream; // The upstream component of this StreamNormalizer. + DataStream output; // The downstream output stream of this StreamNormalizer. + // ManagedBuffer buffer; // The buffer being processed. + + static SampleReadFn readSample[9]; + static SampleWriteFn writeSample[9]; + + /** + * Creates a component capable of translating one data representation format into another + * + * @param source a DataSource to receive data from + * @param gain The gain to apply to each sample (default: 1.0) + * @param normalize Derive a zero offset for the input stream, and subtract from each sample (default: false) + * @param format The format to convert the input stream into + * @param stabilisation the maximum change of zero-offset permitted between subsequent buffers before output is + * initiated. Set to zero to disable (default) + */ + StreamNormalizer(DataSource& source, float gain = 1.0f, bool normalize = false, + int format = DATASTREAM_FORMAT_UNKNOWN, int stabilisation = 0); + + /** + * Callback provided when data is ready. + */ + virtual int pullRequest(); + + /** + * Provide the next available ManagedBuffer to our downstream caller, if available. + */ + virtual ManagedBuffer pull(); + + /** + * Defines whether this input stream will be normalized based on its mean average value. + * + * @param normalize The state to apply - set to true to apply normlization, false otherwise. + * @return DEVICE_OK on success. + */ + int setNormalize(bool normalize); + + /** + * Determines whether normalization is being applied . + * @return true if normlization is being performed, false otherwise. + */ + bool getNormalize(); + + /** + * Determine the data format of the buffers streamed out of this component. + */ + virtual int getFormat(); + + /** + * Defines the data format of the buffers streamed out of this component. + * @param format valid values include: + * + * DATASTREAM_FORMAT_8BIT_UNSIGNED + * DATASTREAM_FORMAT_8BIT_SIGNED + * DATASTREAM_FORMAT_16BIT_UNSIGNED + * DATASTREAM_FORMAT_16BIT_SIGNED + * DATASTREAM_FORMAT_24BIT_UNSIGNED + * DATASTREAM_FORMAT_24BIT_SIGNED + * DATASTREAM_FORMAT_32BIT_UNSIGNED + * DATASTREAM_FORMAT_32BIT_SIGNED + */ + virtual int setFormat(int format); + + /** + * Defines an optional gain to apply to the input, as a floating point multiple. + * + * @param gain The gain to apply to this input stream. + * @return DEVICE_OK on success. + */ + int setGain(float gain); + + /** + * Determines the gain being applied to the input, as a floating point multiple. + * @return the gain applied. + */ + float getGain(); + + /** + * Defines an optional bit mask to logical OR with each sample. + * Useful if the downstream component encodes control data within its samples. + * + * @param mask The bitmask to to apply to each sample. + * @return DEVICE_OK on success. + */ + int setOrMask(uint32_t mask); + + float getSampleRate(); + + float requestSampleRate(float sampleRate); + + /** + * Determines if this source is connected to a downstream component + * + * @return true If a downstream is connected + * @return false If a downstream is not connected + */ + bool isConnected(); + + /** + * Destructor. + */ + ~StreamNormalizer(); +}; +} // namespace codal #endif diff --git a/inc/streams/StreamRecording.h b/inc/streams/StreamRecording.h index 4db351df..8e48eb91 100644 --- a/inc/streams/StreamRecording.h +++ b/inc/streams/StreamRecording.h @@ -1,191 +1,192 @@ #ifndef RECORDING_STREAM_H #define RECORDING_STREAM_H -#include "ManagedBuffer.h" #include "DataStream.h" +#include "ManagedBuffer.h" // Pretty much the largest sensible number we can have on a Micro:bit v2 #ifndef CODAL_DEFAULT_STREAM_RECORDING_MAX_LENGTH - #define CODAL_DEFAULT_STREAM_RECORDING_MAX_LENGTH 50000 // 50k, in bytes +#define CODAL_DEFAULT_STREAM_RECORDING_MAX_LENGTH 50000 // 50k, in bytes #endif #define REC_STATE_STOPPED 0 #define REC_STATE_PLAYING 1 #define REC_STATE_RECORDING 2 -namespace codal -{ - - class StreamRecording_Buffer { - public: - ManagedBuffer buffer; - StreamRecording_Buffer * next; +namespace codal { - StreamRecording_Buffer( ManagedBuffer data ) { - this->buffer = data; - this->next = NULL; - } - }; +class StreamRecording_Buffer { + public: + ManagedBuffer buffer; + StreamRecording_Buffer* next; - class StreamRecording : public DataSource, public DataSink + StreamRecording_Buffer(ManagedBuffer data) { - private: - - //ManagedBuffer buffer[REC_MAX_BUFFERS]; - //StreamRecording_Buffer_t * bufferChain; - StreamRecording_Buffer * lastBuffer; - StreamRecording_Buffer * readHead; - uint32_t maxBufferLenth; - uint32_t totalBufferLength; - int state; - float lastUpstreamRate; - - DataSink *downStream; - DataSource &upStream; - - public: - - StreamRecording_Buffer * bufferChain; - - /** - * @brief Construct a new Stream Recording object - * - * @param source An upstream DataSource to connect to - * @param length The maximum amount of memory (RAM) in bytes to allow this recording object to use. Defaults to CODAL_DEFAULT_STREAM_RECORDING_MAX_LENGTH. - */ - StreamRecording( DataSource &source, uint32_t length = CODAL_DEFAULT_STREAM_RECORDING_MAX_LENGTH ); - - /** - * @brief Destroy the Stream Recording object - */ - ~StreamRecording(); - - virtual ManagedBuffer pull(); - virtual int pullRequest(); - virtual void connect( DataSink &sink ); - bool isConnected(); - virtual void disconnect(); - virtual int getFormat(); - virtual int setFormat( int format ); - - void printChain(); - - /** - * @brief Calculate and return the length in bytes that this StreamRecording represents - * - * @return int The length, in bytes. - */ - int length(); - - /** - * @brief Calculate the recorded duration for this StreamRecording. - * - * As this cannot be known by this class (as the sample rate may change during playback or recording) the expected rate must be supplied. - * - * @param sampleRate The sample rate to calculate the duration for, in samples per second. - * @return long The total duration of this StreamRecording, based on the supplied sample rate, in seconds. - */ - float duration( unsigned int sampleRate ); - - /** - * @brief Downstream classes should use this to determing if there is data to pull from this StreamRecording object. - * - * @return true If data is available - * @return false If the object is completely empty - */ - bool canPull(); - - /** - * @brief Checks if this object can store any further ManagedBuffers from the upstream components. - * - * @note This does not mean that RAM is completely full, but simply that there is now more internal storage for ManagedBuffer references. - * - * @return true If there are no more slots available to track more ManagedBuffers. - * @return false If there is remaining internal storage capacity for more data - */ - bool isFull(); - - /** - * @brief Begin recording data from the connected upstream - * - * The StreamRecording object will, if already playing; stop playback, erase its buffer, and start recording. - * - * Non-blocking, will return immediately. - * - * @return Returns true if the object state actually changed (ie. we weren't already recording) - */ - bool recordAsync(); - - /** - * @brief Begin recording data from the connected upstream - * - * The StreamRecording object will, if already playing; stop playback, erase its buffer, and start recording. - * - * Blocking call, will repeatedly deschedule the current fiber until the recording completes. - */ - void record(); - - /** - * @brief Begin playing data from the connected upstream - * - * The StreamRecording object will, if already recording; stop recording, rewind to the start of its buffer, and start playing. - * - * Non-blocking, will return immediately. - * - * @return Returns true if the object state actually changed (ie. we weren't already recording) - */ - bool playAsync(); - - /** - * @brief Begin playing data from the connected upstream - * - * The StreamRecording object will, if already recording; stop recording, rewind to the start of its buffer, and start playing. - * - * Blocking call, will repeatedly deschedule the current fiber until the playback completes. - */ - void play(); - - /** - * @brief Stop recording or playing the data stored in this StreamRecording object. - * - * Repeated calls to this will do nothing if the object is not in a recording or playback state. - * - * @return Do not use this value, return semantics are changing. - */ - bool stop(); - - /** - * @brief Erase the internal buffer. - * - * Will also stop playback or recording, if either are active. - */ - void erase(); - - /** - * @brief Checks if the object is playing back recorded data. - * - * @return True if playing back, else false if stopped or recording. - */ - bool isPlaying(); - - /** - * @brief Checks if the object is recording new data. - * - * @return True if recording, else false if stopped or playing back. - */ - bool isRecording(); - - /** - * @brief Checks if the object is stopped - * - * @return True if stopped, else false if recording or playing back. - */ - bool isStopped(); - - virtual float getSampleRate(); - - }; - -} + this->buffer = data; + this->next = NULL; + } +}; + +class StreamRecording : public DataSource, public DataSink { + private: + // ManagedBuffer buffer[REC_MAX_BUFFERS]; + // StreamRecording_Buffer_t * bufferChain; + StreamRecording_Buffer* lastBuffer; + StreamRecording_Buffer* readHead; + uint32_t maxBufferLenth; + uint32_t totalBufferLength; + int state; + float lastUpstreamRate; + + DataSink* downStream; + DataSource& upStream; + + public: + StreamRecording_Buffer* bufferChain; + + /** + * @brief Construct a new Stream Recording object + * + * @param source An upstream DataSource to connect to + * @param length The maximum amount of memory (RAM) in bytes to allow this recording object to use. Defaults to + * CODAL_DEFAULT_STREAM_RECORDING_MAX_LENGTH. + */ + StreamRecording(DataSource& source, uint32_t length = CODAL_DEFAULT_STREAM_RECORDING_MAX_LENGTH); + + /** + * @brief Destroy the Stream Recording object + */ + ~StreamRecording(); + + virtual ManagedBuffer pull(); + virtual int pullRequest(); + virtual void connect(DataSink& sink); + bool isConnected(); + virtual void disconnect(); + virtual int getFormat(); + virtual int setFormat(int format); + + void printChain(); + + /** + * @brief Calculate and return the length in bytes that this StreamRecording represents + * + * @return int The length, in bytes. + */ + int length(); + + /** + * @brief Calculate the recorded duration for this StreamRecording. + * + * As this cannot be known by this class (as the sample rate may change during playback or recording) the + * expected rate must be supplied. + * + * @param sampleRate The sample rate to calculate the duration for, in samples per second. + * @return long The total duration of this StreamRecording, based on the supplied sample rate, in seconds. + */ + float duration(unsigned int sampleRate); + + /** + * @brief Downstream classes should use this to determing if there is data to pull from this StreamRecording object. + * + * @return true If data is available + * @return false If the object is completely empty + */ + bool canPull(); + + /** + * @brief Checks if this object can store any further ManagedBuffers from the upstream components. + * + * @note This does not mean that RAM is completely full, but simply that there is now more internal storage + * for ManagedBuffer references. + * + * @return true If there are no more slots available to track more ManagedBuffers. + * @return false If there is remaining internal storage capacity for more data + */ + bool isFull(); + + /** + * @brief Begin recording data from the connected upstream + * + * The StreamRecording object will, if already playing; stop playback, erase its buffer, and start recording. + * + * Non-blocking, will return immediately. + * + * @return Returns true if the object state actually changed (ie. we weren't already recording) + */ + bool recordAsync(); + + /** + * @brief Begin recording data from the connected upstream + * + * The StreamRecording object will, if already playing; stop playback, erase its buffer, and start recording. + * + * Blocking call, will repeatedly deschedule the current fiber until the recording completes. + */ + void record(); + + /** + * @brief Begin playing data from the connected upstream + * + * The StreamRecording object will, if already recording; stop recording, rewind to the start of its buffer, and + * start playing. + * + * Non-blocking, will return immediately. + * + * @return Returns true if the object state actually changed (ie. we weren't already recording) + */ + bool playAsync(); + + /** + * @brief Begin playing data from the connected upstream + * + * The StreamRecording object will, if already recording; stop recording, rewind to the start of its buffer, and + * start playing. + * + * Blocking call, will repeatedly deschedule the current fiber until the playback completes. + */ + void play(); + + /** + * @brief Stop recording or playing the data stored in this StreamRecording object. + * + * Repeated calls to this will do nothing if the object is not in a recording or playback state. + * + * @return Do not use this value, return semantics are changing. + */ + bool stop(); + + /** + * @brief Erase the internal buffer. + * + * Will also stop playback or recording, if either are active. + */ + void erase(); + + /** + * @brief Checks if the object is playing back recorded data. + * + * @return True if playing back, else false if stopped or recording. + */ + bool isPlaying(); + + /** + * @brief Checks if the object is recording new data. + * + * @return True if recording, else false if stopped or playing back. + */ + bool isRecording(); + + /** + * @brief Checks if the object is stopped + * + * @return True if stopped, else false if recording or playing back. + */ + bool isStopped(); + + virtual float getSampleRate(); +}; + +} // namespace codal #endif diff --git a/inc/streams/StreamSplitter.h b/inc/streams/StreamSplitter.h index 976caff2..16ee6a38 100644 --- a/inc/streams/StreamSplitter.h +++ b/inc/streams/StreamSplitter.h @@ -38,98 +38,95 @@ DEALINGS IN THE SOFTWARE. #endif /** - * Splitter events - */ -#define SPLITTER_CHANNEL_CONNECT 1 -#define SPLITTER_CHANNEL_DISCONNECT 2 -#define SPLITTER_ACTIVATE 3 -#define SPLITTER_DEACTIVATE 4 -#define SPLITTER_TICK 10 - + * Splitter events + */ +#define SPLITTER_CHANNEL_CONNECT 1 +#define SPLITTER_CHANNEL_DISCONNECT 2 +#define SPLITTER_ACTIVATE 3 +#define SPLITTER_DEACTIVATE 4 +#define SPLITTER_TICK 10 /** * Default configuration values */ -namespace codal{ - - class StreamSplitter; - - class SplitterChannel : public DataSource, public DataSink { - private: - StreamSplitter * parent; - float sampleRate; - unsigned int inUnderflow; - - ManagedBuffer resample( ManagedBuffer _in, uint8_t * buffer = NULL, int length = -1 ); - - public: - int pullAttempts; // Number of failed pull request attempts - uint32_t sentBuffers; - DataSink * output; - - /** - * @brief Construct a new Splitter Channel object. - * - * This should not normally be done manually; StreamSplitter objects will create these - * on-demand via createChannel() - * - * @param parent The StreamSplitter this channel is part of - * @param output An output DataSink to send data to. Can be NULL for a disconnected channel. - */ - SplitterChannel( StreamSplitter *parent, DataSink *output ); - virtual ~SplitterChannel(); - - virtual int pullRequest(); - uint8_t * pullInto( uint8_t * rawBuffer, int length ); - virtual ManagedBuffer pull(); - virtual void connect(DataSink &sink); - bool isConnected(); - virtual void disconnect(); - virtual int getFormat(); - virtual int setFormat(int format); - virtual float getSampleRate(); - virtual float requestSampleRate(float sampleRate); - }; - - class StreamSplitter : public DataSink, public CodalComponent - { - private: - ManagedBuffer lastBuffer; // Buffer being processed - uint64_t __cycle; - - public: - bool isActive; // Track if we need to emit activate/deactivate messages - int channels; // Current number of channels Splitter is serving - volatile int activeChannels; // Current number of /active/ channels this Splitter is serving - DataSource &upstream; // The upstream component of this Splitter - SplitterChannel * outputChannels[CONFIG_MAX_CHANNELS]; // Array of SplitterChannels the Splitter is serving - - /** - * Creates a component that distributes a single upstream datasource to many downstream datasinks - * - * @param source a DataSource to receive data from - */ - StreamSplitter(DataSource &source, uint16_t id = CodalComponent::generateDynamicID()); - - /** - * Callback provided when data is ready. - */ - virtual int pullRequest(); - - virtual ManagedBuffer getBuffer(); - virtual SplitterChannel * createChannel(); - virtual bool destroyChannel( SplitterChannel * channel ); - virtual SplitterChannel * getChannel( DataSink * output ); - - /** - * Destructor. - */ - virtual ~StreamSplitter(); - - friend SplitterChannel; - - }; -} +namespace codal { + +class StreamSplitter; + +class SplitterChannel : public DataSource, public DataSink { + private: + StreamSplitter* parent; + float sampleRate; + unsigned int inUnderflow; + + ManagedBuffer resample(ManagedBuffer _in, uint8_t* buffer = NULL, int length = -1); + + public: + int pullAttempts; // Number of failed pull request attempts + uint32_t sentBuffers; + DataSink* output; + + /** + * @brief Construct a new Splitter Channel object. + * + * This should not normally be done manually; StreamSplitter objects will create these + * on-demand via createChannel() + * + * @param parent The StreamSplitter this channel is part of + * @param output An output DataSink to send data to. Can be NULL for a disconnected channel. + */ + SplitterChannel(StreamSplitter* parent, DataSink* output); + virtual ~SplitterChannel(); + + virtual int pullRequest(); + uint8_t* pullInto(uint8_t* rawBuffer, int length); + virtual ManagedBuffer pull(); + virtual void connect(DataSink& sink); + bool isConnected(); + virtual void disconnect(); + virtual int getFormat(); + virtual int setFormat(int format); + virtual float getSampleRate(); + virtual float requestSampleRate(float sampleRate); +}; + +class StreamSplitter : public DataSink, public CodalComponent { + private: + ManagedBuffer lastBuffer; // Buffer being processed + uint64_t __cycle; + + public: + bool isActive; // Track if we need to emit activate/deactivate messages + int channels; // Current number of channels Splitter is serving + volatile int activeChannels; // Current number of /active/ channels this Splitter is serving + DataSource& upstream; // The upstream component of this Splitter + SplitterChannel* outputChannels[CONFIG_MAX_CHANNELS]; // Array of SplitterChannels the Splitter is serving + + /** + * Creates a component that distributes a single upstream datasource to many downstream datasinks + * + * @param source a DataSource to receive data from + */ + StreamSplitter(DataSource& source, uint16_t id = CodalComponent::generateDynamicID()); + + /** + * Callback provided when data is ready. + */ + virtual int pullRequest(); + + virtual ManagedBuffer getBuffer(); + virtual SplitterChannel* createChannel(); + virtual bool destroyChannel(SplitterChannel* channel); + virtual SplitterChannel* getChannel(DataSink* output); + + /** + * Destructor. + */ + virtual ~StreamSplitter(); + + friend SplitterChannel; +}; +} // namespace codal #endif \ No newline at end of file diff --git a/inc/streams/Synthesizer.h b/inc/streams/Synthesizer.h index f17dc97d..bbc694f0 100644 --- a/inc/streams/Synthesizer.h +++ b/inc/streams/Synthesizer.h @@ -27,140 +27,136 @@ DEALINGS IN THE SOFTWARE. #include "DataStream.h" -#define SYNTHESIZER_SAMPLE_RATE 44100 -#define TONE_WIDTH 1024 - -namespace codal -{ - typedef uint16_t (*SynthesizerGetSample)(void *arg, int position); - - class Synthesizer : public DataSource, public CodalComponent - { - int samplePeriodNs; // The length of a single sample, in nanoseconds. - int bufferSize; // The number of samples to create in a single buffer before scheduling it for playback - - int newPeriodNs; // new period of waveform, if change has been requested. - int amplitude; // The maximum amplitude of the wave to generate (the volume of the output) - bool active; // Determines if background playback of audio is currently active. - bool synchronous; // Determines if a synchronous mode of operation has been requested. - bool isSigned; // If true, samples use int16_t otherwise uint16_t. - - ManagedBuffer buffer; // Playout buffer. - int bytesWritten; // Number of bytes written to the output buffer. - void* tonePrintArg; - SynthesizerGetSample tonePrint; // The tone currently selected playout tone (always unsigned). - int position; // Position within the tonePrint - - public: - - DataStream output; - - static uint16_t SineTone(void *arg, int position); - static uint16_t SawtoothTone(void *arg, int position); - static uint16_t TriangleTone(void *arg, int position); - static uint16_t SquareWaveTone(void *arg, int position); - static uint16_t SquareWaveToneExt(void *arg, int position); - static uint16_t NoiseTone(void *arg, int position); - static uint16_t CustomTone(void *arg, int position); - - /** - * Default Constructor. - * Creates an empty DataStream. - * - * @param sampleRate The sample rate at which this synthesizer will produce data. - */ - Synthesizer(int sampleRate = SYNTHESIZER_SAMPLE_RATE, bool isSigned = false); - - /** - * Destructor. - * Removes all resources held by the instance. - */ - ~Synthesizer(); - - /** - * Define the central frequency of this synthesizer. Takes effect at the start of the next waveform period. - * @param frequency The frequency, in Hz to generate. - */ - int setFrequency(float frequency); - - /** - * Define the central frequency of this synthesizer. Takes effect at the start of the next waveform period. - * @param frequency The frequency, in Hz to generate. - * @param period The period, in ms, to play the frequency. - * @param envelopeStart Starting amplitude (multiplied by general volume of this synth) - * @param envelopeEnd Final amplitude (multiplied by general volume of this synth) - */ - int setFrequency(float frequency, int period, int envelopeStart = 1024, int envelopeEnd = 1024); - - /** - * Define the volume of the wave to generate. - * @param volume The new output volume, in the range 0..1023 - * @return DEVICE_OK on success, or DEVICE_INVALID_PARAMETER - */ - int setVolume(int volume); - - /** - * Define the size of the audio buffer to hold. The larger the buffer, the lower the CPU overhead, but the longer the delay. - * @param size The new bufer size to use. - * @return DEVICE_OK on success, or DEVICE_INVALID_PARAMETER - */ - int setBufferSize(int size); - - /** - * Determine the sample rate currently in use by this Synthesizer. - * @return the current sample rate, in Hz. - */ - float getSampleRate(); - - /** - * Change the sample rate used by this Synthesizer, - * @param sampleRate The new sample rate, in Hz. - * @return DEVICE_OK on success. - */ - int setSampleRate(int sampleRate); - - /** - * Provide the next available ManagedBuffer to our downstream caller, if available. - */ - virtual ManagedBuffer pull(); - - /** - * Implement this function to receive a callback when the device is idling. - */ - virtual void idleCallback(); - - /** - * Creates the next audio buffer, and attmepts to queue this on the output stream. - */ - void generate(int playoutTimeUs, int envelopeStart = 1024, int envelopeEnd = 1024); - - /** - * Defines the tone to generate. - * @param the tone print to use with this synthesizer. - * Examples include: - * - * Synthesizer::SineTone - * Synthesizer::SawtoothTone - * Synthesizer::TriangleTone - * Synthesizer::SquareWaveTone - * Synthesizer::SquareWaveToneExt (with argument which is duty cycle 0-1023) - */ - void setTone(SynthesizerGetSample tonePrint, void *arg = NULL); - // legacy - void setTone(const uint16_t *tonePrint) { setTone(CustomTone, (void*)tonePrint); } - - private: - - /** - * Determine the number of samples required for the given playout time. - * - * @param playoutTimeUs The playout time (in microseconds) - * @return The number if samples required to play for the given amount fo time - * (at the currently defined sample rate) - */ - int determineSampleCount(int playoutTimeUs); - - }; -} +#define SYNTHESIZER_SAMPLE_RATE 44100 +#define TONE_WIDTH 1024 + +namespace codal { +typedef uint16_t (*SynthesizerGetSample)(void* arg, int position); + +class Synthesizer : public DataSource, public CodalComponent { + int samplePeriodNs; // The length of a single sample, in nanoseconds. + int bufferSize; // The number of samples to create in a single buffer before scheduling it for playback + + int newPeriodNs; // new period of waveform, if change has been requested. + int amplitude; // The maximum amplitude of the wave to generate (the volume of the output) + bool active; // Determines if background playback of audio is currently active. + bool synchronous; // Determines if a synchronous mode of operation has been requested. + bool isSigned; // If true, samples use int16_t otherwise uint16_t. + + ManagedBuffer buffer; // Playout buffer. + int bytesWritten; // Number of bytes written to the output buffer. + void* tonePrintArg; + SynthesizerGetSample tonePrint; // The tone currently selected playout tone (always unsigned). + int position; // Position within the tonePrint + + public: + DataStream output; + + static uint16_t SineTone(void* arg, int position); + static uint16_t SawtoothTone(void* arg, int position); + static uint16_t TriangleTone(void* arg, int position); + static uint16_t SquareWaveTone(void* arg, int position); + static uint16_t SquareWaveToneExt(void* arg, int position); + static uint16_t NoiseTone(void* arg, int position); + static uint16_t CustomTone(void* arg, int position); + + /** + * Default Constructor. + * Creates an empty DataStream. + * + * @param sampleRate The sample rate at which this synthesizer will produce data. + */ + Synthesizer(int sampleRate = SYNTHESIZER_SAMPLE_RATE, bool isSigned = false); + + /** + * Destructor. + * Removes all resources held by the instance. + */ + ~Synthesizer(); + + /** + * Define the central frequency of this synthesizer. Takes effect at the start of the next waveform period. + * @param frequency The frequency, in Hz to generate. + */ + int setFrequency(float frequency); + + /** + * Define the central frequency of this synthesizer. Takes effect at the start of the next waveform period. + * @param frequency The frequency, in Hz to generate. + * @param period The period, in ms, to play the frequency. + * @param envelopeStart Starting amplitude (multiplied by general volume of this synth) + * @param envelopeEnd Final amplitude (multiplied by general volume of this synth) + */ + int setFrequency(float frequency, int period, int envelopeStart = 1024, int envelopeEnd = 1024); + + /** + * Define the volume of the wave to generate. + * @param volume The new output volume, in the range 0..1023 + * @return DEVICE_OK on success, or DEVICE_INVALID_PARAMETER + */ + int setVolume(int volume); + + /** + * Define the size of the audio buffer to hold. The larger the buffer, the lower the CPU overhead, but the longer + * the delay. + * @param size The new bufer size to use. + * @return DEVICE_OK on success, or DEVICE_INVALID_PARAMETER + */ + int setBufferSize(int size); + + /** + * Determine the sample rate currently in use by this Synthesizer. + * @return the current sample rate, in Hz. + */ + float getSampleRate(); + + /** + * Change the sample rate used by this Synthesizer, + * @param sampleRate The new sample rate, in Hz. + * @return DEVICE_OK on success. + */ + int setSampleRate(int sampleRate); + + /** + * Provide the next available ManagedBuffer to our downstream caller, if available. + */ + virtual ManagedBuffer pull(); + + /** + * Implement this function to receive a callback when the device is idling. + */ + virtual void idleCallback(); + + /** + * Creates the next audio buffer, and attmepts to queue this on the output stream. + */ + void generate(int playoutTimeUs, int envelopeStart = 1024, int envelopeEnd = 1024); + + /** + * Defines the tone to generate. + * @param the tone print to use with this synthesizer. + * Examples include: + * + * Synthesizer::SineTone + * Synthesizer::SawtoothTone + * Synthesizer::TriangleTone + * Synthesizer::SquareWaveTone + * Synthesizer::SquareWaveToneExt (with argument which is duty cycle 0-1023) + */ + void setTone(SynthesizerGetSample tonePrint, void* arg = NULL); + // legacy + void setTone(const uint16_t* tonePrint) { setTone(CustomTone, (void*)tonePrint); } + + private: + /** + * Determine the number of samples required for the given playout time. + * + * @param playoutTimeUs The playout time (in microseconds) + * @return The number if samples required to play for the given amount fo time + * (at the currently defined sample rate) + */ + int determineSampleCount(int playoutTimeUs); +}; +} // namespace codal #endif diff --git a/inc/types/BitmapFont.h b/inc/types/BitmapFont.h index b778d62b..9b31471a 100644 --- a/inc/types/BitmapFont.h +++ b/inc/types/BitmapFont.h @@ -27,83 +27,79 @@ DEALINGS IN THE SOFTWARE. #include "CodalConfig.h" -#define BITMAP_FONT_WIDTH 5 -#define BITMAP_FONT_HEIGHT 5 +#define BITMAP_FONT_WIDTH 5 +#define BITMAP_FONT_HEIGHT 5 #define BITMAP_FONT_ASCII_START 32 -#define BITMAP_FONT_ASCII_END 126 +#define BITMAP_FONT_ASCII_END 126 + +namespace codal { +/** + * Class definition for a BitmapFont + * This class represents a font that can be used by the display to render text. + * + * A BitmapFont is typically 5x5, but up to 8x8. + * Each Row is represented by a byte in the array. + * + * Row Format: + * ================================================================ + * | Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 | + * ================================================================ + * | N/A | N/A | N/A | Col 1 | Col 2 | Col 3 | Col 4 | Col 5 | + * | 0x80 | 0x40 | 0x20 | 0x10 | 0x08 | 0x04 | 0x02 | 0x01 | + * + * Example: { 0x08, 0x08, 0x08, 0x0, 0x08 } + * + * The above will produce an exclaimation mark on the second column in from the left. + * + * We could compress further, but the complexity of decode would likely outweigh the gains. + */ +class BitmapFont { + public: + static const unsigned char* defaultFont; + static BitmapFont systemFont; + + const unsigned char* characters; + + int asciiEnd; -namespace codal -{ /** - * Class definition for a BitmapFont - * This class represents a font that can be used by the display to render text. + * Constructor. * - * A BitmapFont is typically 5x5, but up to 8x8. - * Each Row is represented by a byte in the array. + * Sets the font represented by this font object. * - * Row Format: - * ================================================================ - * | Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 | - * ================================================================ - * | N/A | N/A | N/A | Col 1 | Col 2 | Col 3 | Col 4 | Col 5 | - * | 0x80 | 0x40 | 0x20 | 0x10 | 0x08 | 0x04 | 0x02 | 0x01 | + * @param font A pointer to the beginning of the new font. * - * Example: { 0x08, 0x08, 0x08, 0x0, 0x08 } + * @param asciiEnd the char value at which this font finishes. + */ + BitmapFont(const unsigned char* font, int asciiEnd = BITMAP_FONT_ASCII_END); + + /** + * Default Constructor. + * + * Configures the default font for the display to use. + */ + BitmapFont(); + + /** + * Modifies the current system font to the given instance of BitmapFont. * - * The above will produce an exclaimation mark on the second column in from the left. + * @param font the new font that will be used to render characters on the display. + */ + static void setSystemFont(BitmapFont font); + + /** + * Retreives the font object used for rendering characters on the display. + */ + static BitmapFont getSystemFont(); + + /** + * Returns a pointer to the start of the memory buffer for the given ASCII character. * - * We could compress further, but the complexity of decode would likely outweigh the gains. + * @param c The character to look up + * @return A pointer to the corresponding data buffer, or NULL if the character is not available. */ - class BitmapFont - { - public: - - static const unsigned char* defaultFont; - static BitmapFont systemFont; - - const unsigned char* characters; - - int asciiEnd; - - /** - * Constructor. - * - * Sets the font represented by this font object. - * - * @param font A pointer to the beginning of the new font. - * - * @param asciiEnd the char value at which this font finishes. - */ - BitmapFont(const unsigned char* font, int asciiEnd = BITMAP_FONT_ASCII_END); - - /** - * Default Constructor. - * - * Configures the default font for the display to use. - */ - BitmapFont(); - - /** - * Modifies the current system font to the given instance of BitmapFont. - * - * @param font the new font that will be used to render characters on the display. - */ - static void setSystemFont(BitmapFont font); - - /** - * Retreives the font object used for rendering characters on the display. - */ - static BitmapFont getSystemFont(); - - /** - * Returns a pointer to the start of the memory buffer for the given ASCII character. - * - * @param c The character to look up - * @return A pointer to the corresponding data buffer, or NULL if the character is not available. - */ - const uint8_t* get(char c); - - }; -} + const uint8_t* get(char c); +}; +} // namespace codal #endif diff --git a/inc/types/CoordinateSystem.h b/inc/types/CoordinateSystem.h index 08d9e3c1..237205d6 100644 --- a/inc/types/CoordinateSystem.h +++ b/inc/types/CoordinateSystem.h @@ -30,8 +30,8 @@ DEALINGS IN THE SOFTWARE. * Co-ordinate systems that can be used. * RAW: Unaltered data. Data will be returned directly from the accelerometer. * - * SIMPLE_CARTESIAN: Data will be returned based on an easy to understand alignment, consistent with the cartesian system taught in schools. - * When held upright, facing the user: + * SIMPLE_CARTESIAN: Data will be returned based on an easy to understand alignment, consistent with the cartesian + * system taught in schools. When held upright, facing the user: * * / * +--------------------+ z @@ -57,124 +57,111 @@ DEALINGS IN THE SOFTWARE. * */ -#define COORDINATE_SPACE_ROTATED_0 0 -#define COORDINATE_SPACE_ROTATED_90 1 -#define COORDINATE_SPACE_ROTATED_180 2 -#define COORDINATE_SPACE_ROTATED_270 3 - -namespace codal -{ - enum CoordinateSystem - { - RAW, - SIMPLE_CARTESIAN, - NORTH_EAST_DOWN, - EAST_NORTH_UP, - NORTH_EAST_UP = EAST_NORTH_UP, // legacy name - }; - - struct Sample3D +#define COORDINATE_SPACE_ROTATED_0 0 +#define COORDINATE_SPACE_ROTATED_90 1 +#define COORDINATE_SPACE_ROTATED_180 2 +#define COORDINATE_SPACE_ROTATED_270 3 + +namespace codal { +enum CoordinateSystem { + RAW, + SIMPLE_CARTESIAN, + NORTH_EAST_DOWN, + EAST_NORTH_UP, + NORTH_EAST_UP = EAST_NORTH_UP, // legacy name +}; + +struct Sample3D { + int x; + int y; + int z; + + Sample3D() { - int x; - int y; - int z; - - Sample3D() - { - this->x = 0; - this->y = 0; - this->z = 0; - } - - Sample3D(int x, int y, int z) - { - this->x = x; - this->y = y; - this->z = z; - } - - Sample3D operator-(const Sample3D& other) const - { - Sample3D result; + this->x = 0; + this->y = 0; + this->z = 0; + } - result.x = x - other.x; - result.y = y - other.y; - result.z = z - other.z; - - return result; - } - - Sample3D operator+(const Sample3D& other) const - { - Sample3D result; + Sample3D(int x, int y, int z) + { + this->x = x; + this->y = y; + this->z = z; + } - result.x = x + other.x; - result.y = y + other.y; - result.z = z + other.z; + Sample3D operator-(const Sample3D& other) const + { + Sample3D result; - return result; - } + result.x = x - other.x; + result.y = y - other.y; + result.z = z - other.z; - bool operator==(const Sample3D& other) const - { - return x == other.x && y == other.y && z == other.z; - } + return result; + } - bool operator!=(const Sample3D& other) const - { - return !(x == other.x && y == other.y && z == other.z); - } + Sample3D operator+(const Sample3D& other) const + { + Sample3D result; - float dSquared(Sample3D &s) - { - float dx = x - s.x; - float dy = y - s.y; - float dz = z - s.z; + result.x = x + other.x; + result.y = y + other.y; + result.z = z + other.z; - return (dx*dx) + (dy*dy) + (dz*dz); - } + return result; + } - }; + bool operator==(const Sample3D& other) const { return x == other.x && y == other.y && z == other.z; } + bool operator!=(const Sample3D& other) const { return !(x == other.x && y == other.y && z == other.z); } - class CoordinateSpace + float dSquared(Sample3D& s) { - public: - - CoordinateSystem system; - bool upsidedown; - int rotated; - - /** - * Constructor. - * - * Creates a new coordinatespace transformation object. - * - * @param system the CoordinateSystem to generated as output. - * @param upsidedown set if the sensor is mounted inverted (upside down) on the device board. - * @param rotated defines the rotation of the sensor on the PCB, with respect to pin 1 being at the top left corner - * when viewing the device from its "natural" (user defined) orientation. n.b. if the sensor is upside down, the rotation - * should be defined w.r.t. lookign at the side of the device where the sensor is mounted. - */ - CoordinateSpace(CoordinateSystem system, bool upsidedown = false, int rotated = COORDINATE_SPACE_ROTATED_0); - - /** - * Transforms a given 3D x,y,z tuple from ENU format into that format defined in this instance. - * - * @param a the sample point to convert, in ENU format. - * @return the equivalent location of 's' in the coordinate space specified in the constructor. - */ - Sample3D transform(Sample3D s); - - /** - * Transforms a given 3D x,y,z tuple from ENU format into that format defined in this instance. - * - * @param a the sample point to convert, in ENU format. - * @param system The coordinate system to use in the result. - * @return the equivalent location of 's' in the coordinate space specified in the constructor, and coordinate system supplied. - */ - Sample3D transform(Sample3D s, CoordinateSystem system); - - }; -} + float dx = x - s.x; + float dy = y - s.y; + float dz = z - s.z; + + return (dx * dx) + (dy * dy) + (dz * dz); + } +}; + +class CoordinateSpace { + public: + CoordinateSystem system; + bool upsidedown; + int rotated; + + /** + * Constructor. + * + * Creates a new coordinatespace transformation object. + * + * @param system the CoordinateSystem to generated as output. + * @param upsidedown set if the sensor is mounted inverted (upside down) on the device board. + * @param rotated defines the rotation of the sensor on the PCB, with respect to pin 1 being at the top left corner + * when viewing the device from its "natural" (user defined) orientation. n.b. if the sensor is upside down, the + * rotation should be defined w.r.t. lookign at the side of the device where the sensor is mounted. + */ + CoordinateSpace(CoordinateSystem system, bool upsidedown = false, int rotated = COORDINATE_SPACE_ROTATED_0); + + /** + * Transforms a given 3D x,y,z tuple from ENU format into that format defined in this instance. + * + * @param a the sample point to convert, in ENU format. + * @return the equivalent location of 's' in the coordinate space specified in the constructor. + */ + Sample3D transform(Sample3D s); + + /** + * Transforms a given 3D x,y,z tuple from ENU format into that format defined in this instance. + * + * @param a the sample point to convert, in ENU format. + * @param system The coordinate system to use in the result. + * @return the equivalent location of 's' in the coordinate space specified in the constructor, and coordinate + * system supplied. + */ + Sample3D transform(Sample3D s, CoordinateSystem system); +}; +} // namespace codal #endif diff --git a/inc/types/Event.h b/inc/types/Event.h index 3a3138cb..61fbfbfc 100644 --- a/inc/types/Event.h +++ b/inc/types/Event.h @@ -28,108 +28,103 @@ DEALINGS IN THE SOFTWARE. #include "CodalConfig.h" // Wildcard event codes -#define DEVICE_ID_ANY 0 -#define DEVICE_EVT_ANY 0 +#define DEVICE_ID_ANY 0 +#define DEVICE_EVT_ANY 0 -namespace codal -{ - enum EventLaunchMode - { - CREATE_ONLY, - CREATE_AND_FIRE - }; +namespace codal { +enum EventLaunchMode { CREATE_ONLY, CREATE_AND_FIRE }; - #define DEVICE_EVENT_DEFAULT_LAUNCH_MODE CREATE_AND_FIRE +#define DEVICE_EVENT_DEFAULT_LAUNCH_MODE CREATE_AND_FIRE - /** - * Class definition for a Event - * - * It represents a common event that is generated by the various components on the codal device. - */ - class Event - { - public: - - uint16_t source; // ID of the Device Component that generated the event e.g. DEVICE_ID_BUTTON_A. - uint16_t value; // Component specific code indicating the cause of the event. +/** + * Class definition for a Event + * + * It represents a common event that is generated by the various components on the codal device. + */ +class Event { + public: + uint16_t source; // ID of the Device Component that generated the event e.g. DEVICE_ID_BUTTON_A. + uint16_t value; // Component specific code indicating the cause of the event. #if CONFIG_ENABLED(LIGHTWEIGHT_EVENTS) - uint32_t timestamp; // Time at which the event was generated. us since power on. + uint32_t timestamp; // Time at which the event was generated. us since power on. #else - CODAL_TIMESTAMP timestamp; // Time at which the event was generated. us since power on. + CODAL_TIMESTAMP timestamp; // Time at which the event was generated. us since power on. #endif - /** - * Constructor. - * - * @param src The id of the Device Component that generated the event e.g. DEVICE_ID_BUTTON_A. - * - * @param value A component specific code indicating the cause of the event. - * - * @param mode Optional definition of how the event should be processed after construction (if at all): - * CREATE_ONLY: Event is initialised, and no further processing takes place. - * CREATE_AND_FIRE: Event is initialised, and its event handlers are immediately fired (not suitable for use in interrupts!). - * - * @code - * // Create and launch an event using the default configuration - * Event evt(id,DEVICE_BUTTON_EVT_CLICK); - * - * // Create an event only, do not fire onto an EventModel. - * Event evt(id,DEVICE_BUTTON_EVT_CLICK,CREATE_AND_FIRE); - * @endcode - */ - Event(uint16_t source, uint16_t value, EventLaunchMode mode = DEVICE_EVENT_DEFAULT_LAUNCH_MODE); - - /** - * Constructor. - * - * @param src The id of the Device Component that generated the event e.g. DEVICE_ID_BUTTON_A. - * - * @param value A component specific code indicating the cause of the event. - * - * @param currentTimeUs The current time in microseconds. - * - * @param mode Optional definition of how the event should be processed after construction (if at all): - * CREATE_ONLY: Event is initialised, and no further processing takes place. - * CREATE_AND_FIRE: Event is initialised, and its event handlers are immediately fired (not suitable for use in interrupts!). - * - * @code - * // Create and launch an event using the default configuration - * Event evt(id,DEVICE_BUTTON_EVT_CLICK); - * - * // Create an event only, do not fire onto an EventModel. - * Event evt(id,DEVICE_BUTTON_EVT_CLICK,CREATE_AND_FIRE); - * @endcode - */ - Event(uint16_t source, uint16_t value, CODAL_TIMESTAMP currentTimeUs, EventLaunchMode mode = DEVICE_EVENT_DEFAULT_LAUNCH_MODE); - - /** - * Default constructor - initialises all values, and sets timestamp to the current time. - */ - Event(); - - /** - * Fires this Event onto the Default EventModel, or a custom one! - */ - void fire(); - }; + /** + * Constructor. + * + * @param src The id of the Device Component that generated the event e.g. DEVICE_ID_BUTTON_A. + * + * @param value A component specific code indicating the cause of the event. + * + * @param mode Optional definition of how the event should be processed after construction (if at all): + * CREATE_ONLY: Event is initialised, and no further processing takes place. + * CREATE_AND_FIRE: Event is initialised, and its event handlers are immediately fired (not suitable + * for use in interrupts!). + * + * @code + * // Create and launch an event using the default configuration + * Event evt(id,DEVICE_BUTTON_EVT_CLICK); + * + * // Create an event only, do not fire onto an EventModel. + * Event evt(id,DEVICE_BUTTON_EVT_CLICK,CREATE_AND_FIRE); + * @endcode + */ + Event(uint16_t source, uint16_t value, EventLaunchMode mode = DEVICE_EVENT_DEFAULT_LAUNCH_MODE); + + /** + * Constructor. + * + * @param src The id of the Device Component that generated the event e.g. DEVICE_ID_BUTTON_A. + * + * @param value A component specific code indicating the cause of the event. + * + * @param currentTimeUs The current time in microseconds. + * + * @param mode Optional definition of how the event should be processed after construction (if at all): + * CREATE_ONLY: Event is initialised, and no further processing takes place. + * CREATE_AND_FIRE: Event is initialised, and its event handlers are immediately fired (not suitable + * for use in interrupts!). + * + * @code + * // Create and launch an event using the default configuration + * Event evt(id,DEVICE_BUTTON_EVT_CLICK); + * + * // Create an event only, do not fire onto an EventModel. + * Event evt(id,DEVICE_BUTTON_EVT_CLICK,CREATE_AND_FIRE); + * @endcode + */ + Event(uint16_t source, uint16_t value, CODAL_TIMESTAMP currentTimeUs, + EventLaunchMode mode = DEVICE_EVENT_DEFAULT_LAUNCH_MODE); + + /** + * Default constructor - initialises all values, and sets timestamp to the current time. + */ + Event(); + + /** + * Fires this Event onto the Default EventModel, or a custom one! + */ + void fire(); +}; + +/** + * Enclosing class to hold a chain of events. + */ +struct EventQueueItem { + Event evt; + EventQueueItem* next; /** - * Enclosing class to hold a chain of events. - */ - struct EventQueueItem - { - Event evt; - EventQueueItem *next; - - /** - * Constructor. - * Create a new EventQueueItem. - * - * @param evt The event to be queued. - */ - EventQueueItem(Event evt); - }; -} + * Constructor. + * Create a new EventQueueItem. + * + * @param evt The event to be queued. + */ + EventQueueItem(Event evt); +}; +} // namespace codal #endif diff --git a/inc/types/Image.h b/inc/types/Image.h index fd5c156b..b4dffa56 100644 --- a/inc/types/Image.h +++ b/inc/types/Image.h @@ -29,453 +29,436 @@ DEALINGS IN THE SOFTWARE. #include "ManagedString.h" #include "RefCounted.h" -namespace codal -{ - struct ImageData : RefCounted - { - uint16_t width; // Width in pixels - uint16_t height; // Height in pixels - uint8_t data[0]; // 2D array representing the bitmap image - }; +namespace codal { +struct ImageData : RefCounted { + uint16_t width; // Width in pixels + uint16_t height; // Height in pixels + uint8_t data[0]; // 2D array representing the bitmap image +}; + +/** + * Class definition for a Image. + * + * An Image is a simple bitmap representation of an image. + * n.b. This is a mutable, managed type. + */ +class Image { + ImageData* ptr; // Pointer to payload data /** - * Class definition for a Image. - * - * An Image is a simple bitmap representation of an image. - * n.b. This is a mutable, managed type. - */ - class Image - { - ImageData *ptr; // Pointer to payload data - - - /** - * Internal constructor which provides sanity checking and initialises class properties. - * - * @param x the width of the image - * - * @param y the height of the image - * - * @param bitmap an array of integers that make up an image. - */ - void init(const int16_t x, const int16_t y, const uint8_t *bitmap); - - /** - * Internal constructor which defaults to the Empty Image instance variable - */ - void init_empty(); - - public: - static Image EmptyImage; // Shared representation of a null image. - - /** - * Get current ptr, do not decr() it, and set the current instance to empty image. - * - * This is to be used by specialized runtimes which pass ImageData around. - */ - ImageData *leakData(); - - /** - * Return a 2D array representing the bitmap image. - */ - uint8_t *getBitmap() - { - return ptr->data; - } - - /** - * Constructor. - * Create an image from a specially prepared constant array, with no copying. Will call ptr->incr(). - * - * @param ptr The literal - first two bytes should be 0xff, then width, 0, height, 0, and the bitmap. Width and height are 16 bit. The literal has to be 4-byte aligned. - * - * @code - * static const uint8_t heart[] __attribute__ ((aligned (4))) = { 0xff, 0xff, 10, 0, 5, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart - * Image i((ImageData*)(void*)heart); - * @endcode - */ - Image(ImageData *ptr); - - /** - * Default Constructor. - * Creates a new reference to the empty Image bitmap - * - * @code - * Image i(); //an empty image instance - * @endcode - */ - Image(); - - - /** - * Copy Constructor. - * Add ourselves as a reference to an existing Image. - * - * @param image The Image to reference. - * - * @code - * Image i("0,1,0,1,0\n"); - * Image i2(i); //points to i - * @endcode - */ - Image(const Image &image); - - /** - * Constructor. - * Create a blank bitmap representation of a given size. - * - * @param s A text based representation of the image given whitespace delimited numeric values. - * - * @code - * Image i("0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n"); // 5x5 image - * @endcode - */ - explicit Image(const char *s); - - /** - * Constructor. - * Create a blank bitmap representation of a given size. - * - * @param x the width of the image. - * - * @param y the height of the image. - * - * Bitmap buffer is linear, with 8 bits per pixel, row by row, - * top to bottom with no word alignment. Stride is therefore the image width in pixels. - * in where w and h are width and height respectively, the layout is therefore: - * - * |[0,0]...[w,o][1,0]...[w,1] ... [[w,h] - * - * A copy of the image is made in RAM, as images are mutable. - */ - Image(const int16_t x, const int16_t y); - - /** - * Constructor. - * Create a bitmap representation of a given size, based on a given buffer. - * - * @param x the width of the image. - * - * @param y the height of the image. - * - * @param bitmap a 2D array representing the image. - * - * @code - * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart - * Image i(10,5,heart); - * @endcode - */ - Image(const int16_t x, const int16_t y, const uint8_t *bitmap); - - /** - * Destructor. - * - * Removes buffer resources held by the instance. - */ - ~Image(); - - /** - * Copy assign operation. - * - * Called when one Image is assigned the value of another using the '=' operator. - * - * Decrement our reference count and free up the buffer as necessary. - * - * Then, update our buffer to refer to that of the supplied Image, - * and increase its reference count. - * - * @param s The Image to reference. - * - * @code - * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart - * Image i(10,5,heart); - * Image i1(); - * i1 = i; // i1 now references i - * @endcode - */ - Image& operator = (const Image& i); - - - /** - * Equality operation. - * - * Called when one Image is tested to be equal to another using the '==' operator. - * - * @param i The Image to test ourselves against. - * - * @return true if this Image is identical to the one supplied, false otherwise. - * - * @code - * DeviceDisplay display; - * Image i(); - * Image i1(); - * - * if(i == i1) //will be true - * display.scroll("true"); - * @endcode - */ - bool operator== (const Image& i); - - /** - * Resets all pixels in this image to 0. - * - * @code - * Image i("0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n"); // 5x5 image - * i.clear(); - * @endcode - */ - void clear(); - - /** - * Sets the pixel at the given co-ordinates to a given value. - * - * @param x The co-ordinate of the pixel to change. - * - * @param y The co-ordinate of the pixel to change. - * - * @param value The new value of the pixel (the brightness level 0-255) - * - * @return DEVICE_OK, or DEVICE_INVALID_PARAMETER. - * - * @code - * Image i("0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n"); // 5x5 image - * i.setPixelValue(0,0,255); - * @endcode - * - * @note all coordinates originate from the top left of an image. - */ - int setPixelValue(int16_t x , int16_t y, uint8_t value); - - /** - * Retrieves the value of a given pixel. - * - * @param x The x co-ordinate of the pixel to read. Must be within the dimensions of the image. - * - * @param y The y co-ordinate of the pixel to read. Must be within the dimensions of the image. - * - * @return The value assigned to the given pixel location (the brightness level 0-255), or DEVICE_INVALID_PARAMETER. - * - * @code - * Image i("0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n"); // 5x5 image - * i.getPixelValue(0,0); //should be 0; - * @endcode - */ - int getPixelValue(int16_t x , int16_t y); - - /** - * Replaces the content of this image with that of a given 2D array representing - * the image. - * - * @param x the width of the image. Must be within the dimensions of the image. - * - * @param y the width of the image. Must be within the dimensions of the image. - * - * @param bitmap a 2D array representing the image. - * - * @return DEVICE_OK on success, or DEVICE_INVALID_PARAMETER. - * - * @code - * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart - * Image i(); - * i.printImage(0,0,heart); - * @endcode - * - * @note all coordinates originate from the top left of an image. - */ - int printImage(int16_t x, int16_t y, const uint8_t *bitmap); - - /** - * Pastes a given bitmap at the given co-ordinates. - * - * Any pixels in the relevant area of this image are replaced. - * - * @param image The Image to paste. - * - * @param x The leftmost X co-ordinate in this image where the given image should be pasted. Defaults to 0. - * - * @param y The uppermost Y co-ordinate in this image where the given image should be pasted. Defaults to 0. - * - * @param alpha set to 1 if transparency clear pixels in given image should be treated as transparent. Set to 0 otherwise. Defaults to 0. - * - * @return The number of pixels written. - * - * @code - * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart - * Image i(10,5,heart); // a big heart - * i.paste(i, -5, 0); // a small heart - * @endcode - */ - int paste(const Image &image, int16_t x = 0, int16_t y = 0, uint8_t alpha = 0); - - /** - * Prints a character to the display at the given location - * - * @param c The character to display. - * - * @param x The x co-ordinate of on the image to place the top left of the character. Defaults to 0. - * - * @param y The y co-ordinate of on the image to place the top left of the character. Defaults to 0. - * - * @return DEVICE_OK on success, or DEVICE_INVALID_PARAMETER. - * - * @code - * Image i(5,5); - * i.print('a'); - * @endcode - */ - int print(char c, int16_t x = 0, int16_t y = 0); - - /** - * Shifts the pixels in this Image a given number of pixels to the left. - * - * @param n The number of pixels to shift. - * - * @return DEVICE_OK on success, or DEVICE_INVALID_PARAMETER. - * - * @code - * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart - * Image i(10,5,heart); // a big heart - * i.shiftLeft(5); // a small heart - * @endcode - */ - int shiftLeft(int16_t n); - - /** - * Shifts the pixels in this Image a given number of pixels to the right. - * - * @param n The number of pixels to shift. - * - * @return DEVICE_OK on success, or DEVICE_INVALID_PARAMETER. - * - * @code - * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart - * Image i(10,5,heart); // a big heart - * i.shiftLeft(5); // a small heart - * i.shiftRight(5); // a big heart - * @endcode - */ - int shiftRight(int16_t n); - - /** - * Shifts the pixels in this Image a given number of pixels to upward. - * - * @param n The number of pixels to shift. - * - * @return DEVICE_OK on success, or DEVICE_INVALID_PARAMETER. - * - * @code - * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart - * Image i(10,5,heart); - * i.shiftUp(1); - * @endcode - */ - int shiftUp(int16_t n); - - /** - * Shifts the pixels in this Image a given number of pixels to downward. - * - * @param n The number of pixels to shift. - * - * @return DEVICE_OK on success, or DEVICE_INVALID_PARAMETER. - * - * @code - * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart - * Image i(10,5,heart); - * i.shiftDown(1); - * @endcode - */ - int shiftDown(int16_t n); - - /** - * Gets the width of this image. - * - * @return The width of this image. - * - * @code - * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart - * Image i(10,5,heart); - * i.getWidth(); // equals 10... - * @endcode - */ - int getWidth() const - { - return ptr->width; - } - - /** - * Gets the height of this image. - * - * @return The height of this image. - * - * @code - * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart - * Image i(10,5,heart); - * i.getHeight(); // equals 5... - * @endcode - */ - int getHeight() const - { - return ptr->height; - } - - /** - * Gets number of bytes in the bitmap, ie., width * height. - * - * @return The size of the bitmap. - * - * @code - * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart - * Image i(10,5,heart); - * i.getSize(); // equals 50... - * @endcode - */ - int getSize() const - { - return ptr->width * ptr->height; - } - - /** - * Converts the bitmap to a csv ManagedString. - * - * @code - * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart - * Image i(10,5,heart); - * uBit.serial.printString(i.toString()); // "0,1,0,1,0,0,0,0,0,0\n..." - * @endcode - */ - ManagedString toString(); - - /** - * Crops the image to the given dimensions. - * - * @param startx the location to start the crop in the x-axis - * - * @param starty the location to start the crop in the y-axis - * - * @param width the width of the desired cropped region - * - * @param height the height of the desired cropped region - * - * @code - * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart - * Image i(10,5,heart); - * i.crop(0,0,2,2).toString() // "0,1\n1,1\n" - * @endcode - */ - Image crop(int startx, int starty, int finx, int finy); - - /** - * Check if image is read-only (i.e., residing in flash). - */ - bool isReadOnly(); - - /** - * Create a copy of the image bitmap. Used particularly, when isReadOnly() is true. - * - * @return an instance of Image which can be modified independently of the current instance - */ - Image clone(); - }; -} + * Internal constructor which provides sanity checking and initialises class properties. + * + * @param x the width of the image + * + * @param y the height of the image + * + * @param bitmap an array of integers that make up an image. + */ + void init(const int16_t x, const int16_t y, const uint8_t* bitmap); + + /** + * Internal constructor which defaults to the Empty Image instance variable + */ + void init_empty(); + + public: + static Image EmptyImage; // Shared representation of a null image. + + /** + * Get current ptr, do not decr() it, and set the current instance to empty image. + * + * This is to be used by specialized runtimes which pass ImageData around. + */ + ImageData* leakData(); + + /** + * Return a 2D array representing the bitmap image. + */ + uint8_t* getBitmap() { return ptr->data; } + + /** + * Constructor. + * Create an image from a specially prepared constant array, with no copying. Will call ptr->incr(). + * + * @param ptr The literal - first two bytes should be 0xff, then width, 0, height, 0, and the bitmap. Width and + * height are 16 bit. The literal has to be 4-byte aligned. + * + * @code + * static const uint8_t heart[] __attribute__ ((aligned (4))) = { 0xff, 0xff, 10, 0, 5, 0, 0, 1, 0, 1, 0, 0, 0, 0, + * 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, + * 0, 0, 0, 0, }; // a cute heart Image i((ImageData*)(void*)heart); + * @endcode + */ + Image(ImageData* ptr); + + /** + * Default Constructor. + * Creates a new reference to the empty Image bitmap + * + * @code + * Image i(); //an empty image instance + * @endcode + */ + Image(); + + /** + * Copy Constructor. + * Add ourselves as a reference to an existing Image. + * + * @param image The Image to reference. + * + * @code + * Image i("0,1,0,1,0\n"); + * Image i2(i); //points to i + * @endcode + */ + Image(const Image& image); + + /** + * Constructor. + * Create a blank bitmap representation of a given size. + * + * @param s A text based representation of the image given whitespace delimited numeric values. + * + * @code + * Image i("0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n"); // 5x5 image + * @endcode + */ + explicit Image(const char* s); + + /** + * Constructor. + * Create a blank bitmap representation of a given size. + * + * @param x the width of the image. + * + * @param y the height of the image. + * + * Bitmap buffer is linear, with 8 bits per pixel, row by row, + * top to bottom with no word alignment. Stride is therefore the image width in pixels. + * in where w and h are width and height respectively, the layout is therefore: + * + * |[0,0]...[w,o][1,0]...[w,1] ... [[w,h] + * + * A copy of the image is made in RAM, as images are mutable. + */ + Image(const int16_t x, const int16_t y); + + /** + * Constructor. + * Create a bitmap representation of a given size, based on a given buffer. + * + * @param x the width of the image. + * + * @param y the height of the image. + * + * @param bitmap a 2D array representing the image. + * + * @code + * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, + * 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart Image i(10,5,heart); + * @endcode + */ + Image(const int16_t x, const int16_t y, const uint8_t* bitmap); + + /** + * Destructor. + * + * Removes buffer resources held by the instance. + */ + ~Image(); + + /** + * Copy assign operation. + * + * Called when one Image is assigned the value of another using the '=' operator. + * + * Decrement our reference count and free up the buffer as necessary. + * + * Then, update our buffer to refer to that of the supplied Image, + * and increase its reference count. + * + * @param s The Image to reference. + * + * @code + * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, + * 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart Image i(10,5,heart); Image + * i1(); i1 = i; // i1 now references i + * @endcode + */ + Image& operator=(const Image& i); + + /** + * Equality operation. + * + * Called when one Image is tested to be equal to another using the '==' operator. + * + * @param i The Image to test ourselves against. + * + * @return true if this Image is identical to the one supplied, false otherwise. + * + * @code + * DeviceDisplay display; + * Image i(); + * Image i1(); + * + * if(i == i1) //will be true + * display.scroll("true"); + * @endcode + */ + bool operator==(const Image& i); + + /** + * Resets all pixels in this image to 0. + * + * @code + * Image i("0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n"); // 5x5 image + * i.clear(); + * @endcode + */ + void clear(); + + /** + * Sets the pixel at the given co-ordinates to a given value. + * + * @param x The co-ordinate of the pixel to change. + * + * @param y The co-ordinate of the pixel to change. + * + * @param value The new value of the pixel (the brightness level 0-255) + * + * @return DEVICE_OK, or DEVICE_INVALID_PARAMETER. + * + * @code + * Image i("0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n"); // 5x5 image + * i.setPixelValue(0,0,255); + * @endcode + * + * @note all coordinates originate from the top left of an image. + */ + int setPixelValue(int16_t x, int16_t y, uint8_t value); + + /** + * Retrieves the value of a given pixel. + * + * @param x The x co-ordinate of the pixel to read. Must be within the dimensions of the image. + * + * @param y The y co-ordinate of the pixel to read. Must be within the dimensions of the image. + * + * @return The value assigned to the given pixel location (the brightness level 0-255), or DEVICE_INVALID_PARAMETER. + * + * @code + * Image i("0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n"); // 5x5 image + * i.getPixelValue(0,0); //should be 0; + * @endcode + */ + int getPixelValue(int16_t x, int16_t y); + + /** + * Replaces the content of this image with that of a given 2D array representing + * the image. + * + * @param x the width of the image. Must be within the dimensions of the image. + * + * @param y the width of the image. Must be within the dimensions of the image. + * + * @param bitmap a 2D array representing the image. + * + * @return DEVICE_OK on success, or DEVICE_INVALID_PARAMETER. + * + * @code + * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, + * 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart Image i(); + * i.printImage(0,0,heart); + * @endcode + * + * @note all coordinates originate from the top left of an image. + */ + int printImage(int16_t x, int16_t y, const uint8_t* bitmap); + + /** + * Pastes a given bitmap at the given co-ordinates. + * + * Any pixels in the relevant area of this image are replaced. + * + * @param image The Image to paste. + * + * @param x The leftmost X co-ordinate in this image where the given image should be pasted. Defaults to 0. + * + * @param y The uppermost Y co-ordinate in this image where the given image should be pasted. Defaults to 0. + * + * @param alpha set to 1 if transparency clear pixels in given image should be treated as transparent. Set to 0 + * otherwise. Defaults to 0. + * + * @return The number of pixels written. + * + * @code + * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, + * 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart Image i(10,5,heart); // a big + * heart i.paste(i, -5, 0); // a small heart + * @endcode + */ + int paste(const Image& image, int16_t x = 0, int16_t y = 0, uint8_t alpha = 0); + + /** + * Prints a character to the display at the given location + * + * @param c The character to display. + * + * @param x The x co-ordinate of on the image to place the top left of the character. Defaults to 0. + * + * @param y The y co-ordinate of on the image to place the top left of the character. Defaults to 0. + * + * @return DEVICE_OK on success, or DEVICE_INVALID_PARAMETER. + * + * @code + * Image i(5,5); + * i.print('a'); + * @endcode + */ + int print(char c, int16_t x = 0, int16_t y = 0); + + /** + * Shifts the pixels in this Image a given number of pixels to the left. + * + * @param n The number of pixels to shift. + * + * @return DEVICE_OK on success, or DEVICE_INVALID_PARAMETER. + * + * @code + * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, + * 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart Image i(10,5,heart); // a big + * heart i.shiftLeft(5); // a small heart + * @endcode + */ + int shiftLeft(int16_t n); + + /** + * Shifts the pixels in this Image a given number of pixels to the right. + * + * @param n The number of pixels to shift. + * + * @return DEVICE_OK on success, or DEVICE_INVALID_PARAMETER. + * + * @code + * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, + * 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart Image i(10,5,heart); // a big + * heart i.shiftLeft(5); // a small heart i.shiftRight(5); // a big heart + * @endcode + */ + int shiftRight(int16_t n); + + /** + * Shifts the pixels in this Image a given number of pixels to upward. + * + * @param n The number of pixels to shift. + * + * @return DEVICE_OK on success, or DEVICE_INVALID_PARAMETER. + * + * @code + * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, + * 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart Image i(10,5,heart); + * i.shiftUp(1); + * @endcode + */ + int shiftUp(int16_t n); + + /** + * Shifts the pixels in this Image a given number of pixels to downward. + * + * @param n The number of pixels to shift. + * + * @return DEVICE_OK on success, or DEVICE_INVALID_PARAMETER. + * + * @code + * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, + * 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart Image i(10,5,heart); + * i.shiftDown(1); + * @endcode + */ + int shiftDown(int16_t n); + + /** + * Gets the width of this image. + * + * @return The width of this image. + * + * @code + * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, + * 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart Image i(10,5,heart); + * i.getWidth(); // equals 10... + * @endcode + */ + int getWidth() const { return ptr->width; } + + /** + * Gets the height of this image. + * + * @return The height of this image. + * + * @code + * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, + * 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart Image i(10,5,heart); + * i.getHeight(); // equals 5... + * @endcode + */ + int getHeight() const { return ptr->height; } + + /** + * Gets number of bytes in the bitmap, ie., width * height. + * + * @return The size of the bitmap. + * + * @code + * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, + * 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart Image i(10,5,heart); + * i.getSize(); // equals 50... + * @endcode + */ + int getSize() const { return ptr->width * ptr->height; } + + /** + * Converts the bitmap to a csv ManagedString. + * + * @code + * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, + * 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart Image i(10,5,heart); + * uBit.serial.printString(i.toString()); // "0,1,0,1,0,0,0,0,0,0\n..." + * @endcode + */ + ManagedString toString(); + + /** + * Crops the image to the given dimensions. + * + * @param startx the location to start the crop in the x-axis + * + * @param starty the location to start the crop in the y-axis + * + * @param width the width of the desired cropped region + * + * @param height the height of the desired cropped region + * + * @code + * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, + * 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart Image i(10,5,heart); + * i.crop(0,0,2,2).toString() // "0,1\n1,1\n" + * @endcode + */ + Image crop(int startx, int starty, int finx, int finy); + + /** + * Check if image is read-only (i.e., residing in flash). + */ + bool isReadOnly(); + + /** + * Create a copy of the image bitmap. Used particularly, when isReadOnly() is true. + * + * @return an instance of Image which can be modified independently of the current instance + */ + Image clone(); +}; +} // namespace codal #endif \ No newline at end of file diff --git a/inc/types/ManagedBuffer.h b/inc/types/ManagedBuffer.h index 13cba31b..f9f7fb7d 100644 --- a/inc/types/ManagedBuffer.h +++ b/inc/types/ManagedBuffer.h @@ -28,265 +28,248 @@ DEALINGS IN THE SOFTWARE. #include "CodalCompat.h" #include "RefCounted.h" -namespace codal -{ - struct BufferData : RefCounted - { - uint16_t length; // The length of the payload in bytes - uint8_t payload[0]; // ManagedBuffer data - }; - - enum class BufferInitialize : uint8_t - { - None = 0, - Zero - }; +namespace codal { +struct BufferData : RefCounted { + uint16_t length; // The length of the payload in bytes + uint8_t payload[0]; // ManagedBuffer data +}; + +enum class BufferInitialize : uint8_t { None = 0, Zero }; + +/** + * Class definition for a ManagedBuffer. + * A ManagedBuffer holds a series of bytes for general purpose use. + * n.b. This is a mutable, managed type. + */ +class ManagedBuffer { + BufferData* ptr; // Pointer to payload data + + public: + /** + * Default Constructor. + * Creates an empty ManagedBuffer. The 'ptr' field in all empty buffers is shared. + * + * Example: + * @code + * ManagedBuffer p(); + * @endcode + */ + ManagedBuffer(); + + /** + * Constructor. + * Creates a new ManagedBuffer of the given size. + * + * @param length The length of the buffer to create. + * + * Example: + * @code + * ManagedBuffer p(16); // Creates a ManagedBuffer 16 bytes long. + * @endcode + */ + ManagedBuffer(int length, BufferInitialize initialize = BufferInitialize::Zero); + + /** + * Constructor. + * Creates an empty ManagedBuffer of the given size, + * and fills it with the data provided. + * + * @param data The data with which to fill the buffer. + * @param length The length of the buffer to create. + * + * Example: + * @code + * uint8_t buf[] = {13,5,2}; + * ManagedBuffer p(buf, 3); // Creates a ManagedBuffer 3 bytes long. + * @endcode + */ + ManagedBuffer(uint8_t* data, int length); + + /** + * Copy Constructor. + * Add ourselves as a reference to an existing ManagedBuffer. + * + * @param buffer The ManagedBuffer to reference. + * + * Example: + * @code + * ManagedBuffer p(); + * ManagedBuffer p2(i); // Refers to the same buffer as p. + * @endcode + */ + ManagedBuffer(const ManagedBuffer& buffer); + + /** + * Constructor. + * Create a buffer from a raw BufferData pointer. It will ptr->incr(). This is to be used by specialized runtimes. + * + * @param p The pointer to use. + */ + ManagedBuffer(BufferData* p); + + /** + * Internal constructor helper. + * Configures this ManagedBuffer to refer to the static empty buffer. + */ + void initEmpty(); + + /** + * Internal constructor-initialiser. + * + * @param data The data with which to fill the buffer. + * @param length The length of the buffer to create. + * @param initialize The initialization mode to use for the allocted memory in the buffer + * + */ + void init(uint8_t* data, int length, BufferInitialize initialize); + + /** + * Destructor. + * Removes buffer resources held by the instance. + */ + ~ManagedBuffer(); + + /** + * Provide an array containing the buffer data. + * @return The contents of this buffer, as an array of bytes. + */ + uint8_t* getBytes() { return ptr->payload; } + + /** + * Get current ptr, do not decr() it, and set the current instance to an empty buffer. + * This is to be used by specialized runtimes which pass BufferData around. + */ + BufferData* leakData(); + + /** + * Copy assign operation. + * + * Called when one ManagedBuffer is assigned the value of another using the '=' operator. + * Decrements our reference count and free up the buffer as necessary. + * Then, update our buffer to refer to that of the supplied ManagedBuffer, + * and increase its reference count. + * + * @param p The ManagedBuffer to reference. + * + * Example: + * @code + * uint8_t buf = {13,5,2}; + * ManagedBuffer p1(16); + * ManagedBuffer p2(buf, 3); + * + * p1 = p2; + * @endcode + */ + ManagedBuffer& operator=(const ManagedBuffer& p); + + /** + * Array access operation (read). + * + * Called when a ManagedBuffer is dereferenced with a [] operation. + * Transparently map this through to the underlying payload for elegance of programming. + * + * Example: + * @code + * ManagedBuffer p1(16); + * uint8_t data = p1[0]; + * @endcode + */ + uint8_t operator[](int i) const { return ptr->payload[i]; } + + /** + * Array access operation (modify). + * + * Called when a ManagedBuffer is dereferenced with a [] operation. + * Transparently map this through to the underlying payload for elegance of programming. + * + * Example: + * @code + * ManagedBuffer p1(16); + * p1[0] = 42; + * @endcode + */ + uint8_t& operator[](int i) { return ptr->payload[i]; } + + /** + * Equality operation. + * + * Called when one ManagedBuffer is tested to be equal to another using the '==' operator. + * + * @param p The ManagedBuffer to test ourselves against. + * @return true if this ManagedBuffer is identical to the one supplied, false otherwise. + * + * Example: + * @code + * + * uint8_t buf = {13,5,2}; + * ManagedBuffer p1(16); + * ManagedBuffer p2(buf, 3); + * + * if(p1 == p2) // will be true + * uBit.display.scroll("same!"); + * @endcode + */ + bool operator==(const ManagedBuffer& p); + + /** + * Sets the byte at the given index to value provided. + * @param position The index of the byte to change. + * @param value The new value of the byte (0-255). + * @return DEVICE_OK, or DEVICE_INVALID_PARAMETER. + * + * Example: + * @code + * ManagedBuffer p1(16); + * p1.setByte(0,255); // Sets the first byte in the buffer to the value 255. + * @endcode + */ + int setByte(int position, uint8_t value); + + /** + * Determines the value of the given byte in the buffer. + * + * @param position The index of the byte to read. + * @return The value of the byte at the given position, or DEVICE_INVALID_PARAMETER. + * + * Example: + * @code + * ManagedBuffer p1(16); + * p1.setByte(0,255); // Sets the first byte in the buffer to the value 255. + * p1.getByte(0); // Returns 255. + * @endcode + */ + int getByte(int position); /** - * Class definition for a ManagedBuffer. - * A ManagedBuffer holds a series of bytes for general purpose use. - * n.b. This is a mutable, managed type. - */ - class ManagedBuffer - { - BufferData *ptr; // Pointer to payload data - - public: - - /** - * Default Constructor. - * Creates an empty ManagedBuffer. The 'ptr' field in all empty buffers is shared. - * - * Example: - * @code - * ManagedBuffer p(); - * @endcode - */ - ManagedBuffer(); - - /** - * Constructor. - * Creates a new ManagedBuffer of the given size. - * - * @param length The length of the buffer to create. - * - * Example: - * @code - * ManagedBuffer p(16); // Creates a ManagedBuffer 16 bytes long. - * @endcode - */ - ManagedBuffer(int length, BufferInitialize initialize = BufferInitialize::Zero); - - /** - * Constructor. - * Creates an empty ManagedBuffer of the given size, - * and fills it with the data provided. - * - * @param data The data with which to fill the buffer. - * @param length The length of the buffer to create. - * - * Example: - * @code - * uint8_t buf[] = {13,5,2}; - * ManagedBuffer p(buf, 3); // Creates a ManagedBuffer 3 bytes long. - * @endcode - */ - ManagedBuffer(uint8_t *data, int length); - - /** - * Copy Constructor. - * Add ourselves as a reference to an existing ManagedBuffer. - * - * @param buffer The ManagedBuffer to reference. - * - * Example: - * @code - * ManagedBuffer p(); - * ManagedBuffer p2(i); // Refers to the same buffer as p. - * @endcode - */ - ManagedBuffer(const ManagedBuffer &buffer); - - /** - * Constructor. - * Create a buffer from a raw BufferData pointer. It will ptr->incr(). This is to be used by specialized runtimes. - * - * @param p The pointer to use. - */ - ManagedBuffer(BufferData *p); - - /** - * Internal constructor helper. - * Configures this ManagedBuffer to refer to the static empty buffer. - */ - void initEmpty(); - - /** - * Internal constructor-initialiser. - * - * @param data The data with which to fill the buffer. - * @param length The length of the buffer to create. - * @param initialize The initialization mode to use for the allocted memory in the buffer - * - */ - void init(uint8_t *data, int length, BufferInitialize initialize); - - /** - * Destructor. - * Removes buffer resources held by the instance. - */ - ~ManagedBuffer(); - - /** - * Provide an array containing the buffer data. - * @return The contents of this buffer, as an array of bytes. - */ - uint8_t *getBytes() - { - return ptr->payload; - } - - /** - * Get current ptr, do not decr() it, and set the current instance to an empty buffer. - * This is to be used by specialized runtimes which pass BufferData around. - */ - BufferData *leakData(); - - /** - * Copy assign operation. - * - * Called when one ManagedBuffer is assigned the value of another using the '=' operator. - * Decrements our reference count and free up the buffer as necessary. - * Then, update our buffer to refer to that of the supplied ManagedBuffer, - * and increase its reference count. - * - * @param p The ManagedBuffer to reference. - * - * Example: - * @code - * uint8_t buf = {13,5,2}; - * ManagedBuffer p1(16); - * ManagedBuffer p2(buf, 3); - * - * p1 = p2; - * @endcode - */ - ManagedBuffer& operator = (const ManagedBuffer& p); - - /** - * Array access operation (read). - * - * Called when a ManagedBuffer is dereferenced with a [] operation. - * Transparently map this through to the underlying payload for elegance of programming. - * - * Example: - * @code - * ManagedBuffer p1(16); - * uint8_t data = p1[0]; - * @endcode - */ - uint8_t operator [] (int i) const - { - return ptr->payload[i]; - } - - /** - * Array access operation (modify). - * - * Called when a ManagedBuffer is dereferenced with a [] operation. - * Transparently map this through to the underlying payload for elegance of programming. - * - * Example: - * @code - * ManagedBuffer p1(16); - * p1[0] = 42; - * @endcode - */ - uint8_t& operator [] (int i) - { - return ptr->payload[i]; - } - - /** - * Equality operation. - * - * Called when one ManagedBuffer is tested to be equal to another using the '==' operator. - * - * @param p The ManagedBuffer to test ourselves against. - * @return true if this ManagedBuffer is identical to the one supplied, false otherwise. - * - * Example: - * @code - * - * uint8_t buf = {13,5,2}; - * ManagedBuffer p1(16); - * ManagedBuffer p2(buf, 3); - * - * if(p1 == p2) // will be true - * uBit.display.scroll("same!"); - * @endcode - */ - bool operator== (const ManagedBuffer& p); - - /** - * Sets the byte at the given index to value provided. - * @param position The index of the byte to change. - * @param value The new value of the byte (0-255). - * @return DEVICE_OK, or DEVICE_INVALID_PARAMETER. - * - * Example: - * @code - * ManagedBuffer p1(16); - * p1.setByte(0,255); // Sets the first byte in the buffer to the value 255. - * @endcode - */ - int setByte(int position, uint8_t value); - - /** - * Determines the value of the given byte in the buffer. - * - * @param position The index of the byte to read. - * @return The value of the byte at the given position, or DEVICE_INVALID_PARAMETER. - * - * Example: - * @code - * ManagedBuffer p1(16); - * p1.setByte(0,255); // Sets the first byte in the buffer to the value 255. - * p1.getByte(0); // Returns 255. - * @endcode - */ - int getByte(int position); - - /** - * Gets number of bytes in this buffer - * @return The size of the buffer in bytes. - * - * Example: - * @code - * ManagedBuffer p1(16); - * p1.length(); // Returns 16. - * @endcode - */ - int length() const { return ptr->length; } - - int fill(uint8_t value, int offset = 0, int length = -1); - - ManagedBuffer slice(int offset = 0, int length = -1) const; - - void shift(int offset, int start = 0, int length = -1); - - void rotate(int offset, int start = 0, int length = -1); - - int readBytes(uint8_t *dst, int offset, int length, bool swapBytes = false) const; - - int writeBytes(int dstOffset, uint8_t *src, int length, bool swapBytes = false); - - int writeBuffer(int dstOffset, const ManagedBuffer &src, int srcOffset = 0, int length = -1); - - bool isReadOnly() const { return ptr->isReadOnly(); } - - int truncate(int length); - }; -} + * Gets number of bytes in this buffer + * @return The size of the buffer in bytes. + * + * Example: + * @code + * ManagedBuffer p1(16); + * p1.length(); // Returns 16. + * @endcode + */ + int length() const { return ptr->length; } + + int fill(uint8_t value, int offset = 0, int length = -1); + + ManagedBuffer slice(int offset = 0, int length = -1) const; + + void shift(int offset, int start = 0, int length = -1); + + void rotate(int offset, int start = 0, int length = -1); + + int readBytes(uint8_t* dst, int offset, int length, bool swapBytes = false) const; + + int writeBytes(int dstOffset, uint8_t* src, int length, bool swapBytes = false); + + int writeBuffer(int dstOffset, const ManagedBuffer& src, int srcOffset = 0, int length = -1); + + bool isReadOnly() const { return ptr->isReadOnly(); } + + int truncate(int length); +}; +} // namespace codal #endif diff --git a/inc/types/ManagedString.h b/inc/types/ManagedString.h index b7658ad9..a82748df 100644 --- a/inc/types/ManagedString.h +++ b/inc/types/ManagedString.h @@ -26,404 +26,398 @@ DEALINGS IN THE SOFTWARE. #define MANAGED_STRING_H #include "CodalConfig.h" -#include "RefCounted.h" #include "ManagedBuffer.h" +#include "RefCounted.h" -namespace codal -{ - struct StringData : RefCounted - { - uint16_t len; - char data[0]; - }; +namespace codal { +struct StringData : RefCounted { + uint16_t len; + char data[0]; +}; + +// forward declaration required for a friend in a namespace... +class ManagedString; +ManagedString(operator+)(const ManagedString& lhs, const ManagedString& rhs); + +/** + * Class definition for a ManagedString. + * + * Uses basic reference counting to implement a copy-assignable, immutable string. + * + * This maps closely to the constructs found in many high level application languages, + * such as Touch Develop. + * + * Written from first principles here, for several reasons: + * 1) std::shared_ptr is not yet available on the ARMCC compiler + * + * 2) to reduce memory footprint - we don't need many of the other features in the std library + * + * 3) it makes an interesting case study for anyone interested in seeing how it works! + * + * 4) we need explicit reference counting to inter-op with low-level application langauge runtimes. + * + * 5) the reference counting needs to also work for read-only, flash-resident strings + */ +class ManagedString { + // StringData contains the reference count, the length, follwed by char[] data, all in one block. + // When referece count is 0xffff, then it's read only and should not be counted. + // Otherwise the block was malloc()ed. + // We control access to this to proide immutability and reference counting. + StringData* ptr; + + public: + /** + * Constructor. + * Create a managed string from a specially prepared string literal. + * + * @param ptr The literal - first two bytes should be 0xff, then the length in little endian, then the literal. The + * literal has to be 4-byte aligned. + * + * @code + * static const char hello[] __attribute__ ((aligned (4))) = "\xff\xff\x05\x00" "Hello"; + * ManagedString s((StringData*)(void*)hello); + * @endcode + */ + ManagedString(StringData* ptr); + + /** + * Get current ptr, do not decr() it, and set the current instance to empty string. + * + * This is to be used by specialized runtimes which pass StringData around. + */ + StringData* leakData(); + + /** + * Constructor. + * + * Create a managed string from a pointer to an 8-bit character buffer. + * + * The buffer is copied to ensure safe memory management (the supplied + * character buffer may be declared on the stack for instance). + * + * @param str The character array on which to base the new ManagedString. + * + * @code + * ManagedString s("abcdefg"); + * @endcode + */ + ManagedString(const char* str); + + /** + * Constructor. + * + * Create a managed string from a given integer. + * + * @param value The integer from which to create the ManagedString. + * + * @code + * ManagedString s(20); + * @endcode + */ + ManagedString(const int value); + + /** + * Constructor. + * Create a managed string from a given char. + * + * @param value The character from which to create the ManagedString. + * + * @code + * ManagedString s('a'); + * @endcode + */ + ManagedString(const char value); - // forward declaration required for a friend in a namespace... - class ManagedString; - ManagedString (operator+) (const ManagedString& lhs, const ManagedString& rhs); + /** + * Constructor. + * Create a ManagedString from a ManagedBuffer. All bytes in the + * ManagedBuffer are added to the ManagedString. + * + * @param buffer The ManagedBuffer from which to create the ManagedString. + * + * @code + * ManagedString s = radio.datagram.recv(); + * @endcode + */ + ManagedString(ManagedBuffer buffer); + + /** + * Constructor. + * Create a ManagedString from a pointer to an 8-bit character buffer of a given length. + * + * The buffer is copied to ensure sane memory management (the supplied + * character buffer may be declared on the stack for instance). + * + * @param str The character array on which to base the new ManagedString. + * + * @param length The length of the character array + * + * @code + * ManagedString s("abcdefg",7); + * @endcode + */ + ManagedString(const char* str, const int16_t length); + + /** + * Copy constructor. + * Makes a new ManagedString identical to the one supplied. + * + * Shares the character buffer and reference count with the supplied ManagedString. + * + * @param s The ManagedString to copy. + * + * @code + * ManagedString s("abcdefg"); + * ManagedString p(s); + * @endcode + */ + ManagedString(const ManagedString& s); + + /** + * Default constructor. + * + * Create an empty ManagedString. + * + * @code + * ManagedString s(); + * @endcode + */ + ManagedString(); + + /** + * Destructor. + * + * Free this ManagedString, and decrement the reference count to the + * internal character buffer. + * + * If we're holding the last reference, also free the character buffer. + */ + ~ManagedString(); /** - * Class definition for a ManagedString. - * - * Uses basic reference counting to implement a copy-assignable, immutable string. - * - * This maps closely to the constructs found in many high level application languages, - * such as Touch Develop. - * - * Written from first principles here, for several reasons: - * 1) std::shared_ptr is not yet available on the ARMCC compiler - * - * 2) to reduce memory footprint - we don't need many of the other features in the std library - * - * 3) it makes an interesting case study for anyone interested in seeing how it works! - * - * 4) we need explicit reference counting to inter-op with low-level application langauge runtimes. - * - * 5) the reference counting needs to also work for read-only, flash-resident strings - */ - class ManagedString + * Copy assign operation. + * + * Called when one ManagedString is assigned the value of another. + * + * If the ManagedString being assigned is already referring to a character buffer, + * decrement the reference count and free up the buffer as necessary. + * + * Then, update our character buffer to refer to that of the supplied ManagedString, + * and increase its reference count. + * + * @param s The ManagedString to copy. + * + * @code + * ManagedString s("abcd"); + * ManagedString p("efgh"); + * p = s // p now points to s, s' ref is incremented + * @endcode + */ + ManagedString& operator=(const ManagedString& s); + + /** + * Equality operation. + * + * Called when one ManagedString is tested to be equal to another using the '==' operator. + * + * @param s The ManagedString to test ourselves against. + * + * @return true if this ManagedString is identical to the one supplied, false otherwise. + * + * @code + * DeviceDisplay display; + * ManagedString s("abcd"); + * ManagedString p("efgh"); + * + * if(p == s) + * display.scroll("We are the same!"); + * else + * display.scroll("We are different!"); //p is not equal to s - this will be called + * @endcode + */ + bool operator==(const ManagedString& s); + + /** + * Inequality operation. + * + * Called when one ManagedString is tested to be not equal using the '!=' operator. + * + * @param s The ManagedString to test ourselves against. + * + * @return true if this ManagedString is identical to the one supplied, false otherwise. + * + * @code + * DeviceDisplay display; + * ManagedString s("abcd"); + * ManagedString p("efgh"); + * + * if(p != s) + * display.scroll("We are different!"); + * else + * display.scroll("We are the same!"); + * @endcode + */ + bool operator!=(const ManagedString& s); + + /** + * Inequality operation. + * + * Called when one ManagedString is tested to be less than another using the '<' operator. + * + * @param s The ManagedString to test ourselves against. + * + * @return true if this ManagedString is alphabetically less than to the one supplied, false otherwise. + * + * @code + * DeviceDisplay display; + * ManagedString s("a"); + * ManagedString p("b"); + * + * if(s < p) + * display.scroll("a is before b!"); //a is before b + * else + * display.scroll("b is before a!"); + * @endcode + */ + bool operator<(const ManagedString& s); + + /** + * Inequality operation. + * + * Called when one ManagedString is tested to be greater than another using the '>' operator. + * + * @param s The ManagedString to test ourselves against. + * + * @return true if this ManagedString is alphabetically greater than to the one supplied, false otherwise. + * + * @code + * DeviceDisplay display; + * ManagedString s("a"); + * ManagedString p("b"); + * + * if(p>a) + * display.scroll("b is after a!"); //b is after a + * else + * display.scroll("a is after b!"); + * @endcode + */ + bool operator>(const ManagedString& s); + + /** + * Extracts a ManagedString from this string, at the position provided. + * + * @param start The index of the first character to extract, indexed from zero. + * + * @param length The number of characters to extract from the start position + * + * @return a ManagedString representing the requested substring. + * + * @code + * DeviceDisplay display; + * ManagedString s("abcdefg"); + * + * display.scroll(s.substring(0,2)) // displays "ab" + * @endcode + */ + ManagedString substring(int16_t start, int16_t length); + +/** + * Concatenates two strings. + * + * @param lhs The first ManagedString to concatenate. + * @param rhs The second ManagedString to concatenate. + * + * @return a new ManagedString representing the joined strings. + * + * @code + * DeviceDisplay display; + * ManagedString s("abcd"); + * ManagedString p("efgh") + * + * display.scroll(s + p) // scrolls "abcdefgh" + * @endcode + */ +#ifndef DOXYGEN_SHOULD_SKIP_THIS // Friend members as 'const ... &' currently break breathe/exhale doc generation, so + // we MUST skip this for now. + friend ManagedString(codal::operator+)(const ManagedString& lhs, const ManagedString& rhs); +#endif + + /** + * Provides a character value at a given position in the string, indexed from zero. + * + * @param index The position of the character to return. + * + * @return the character at posisiton index, zero if index is invalid. + * + * @code + * DeviceDisplay display; + * ManagedString s("abcd"); + * + * display.scroll(s.charAt(1)) // scrolls "b" + * @endcode + */ + char charAt(int16_t index); + + /** + * Provides an immutable 8 bit wide character buffer representing this string. + * + * @return a pointer to the character buffer. + */ + const char* toCharArray() const { - // StringData contains the reference count, the length, follwed by char[] data, all in one block. - // When referece count is 0xffff, then it's read only and should not be counted. - // Otherwise the block was malloc()ed. - // We control access to this to proide immutability and reference counting. - StringData *ptr; - - public: - - /** - * Constructor. - * Create a managed string from a specially prepared string literal. - * - * @param ptr The literal - first two bytes should be 0xff, then the length in little endian, then the literal. The literal has to be 4-byte aligned. - * - * @code - * static const char hello[] __attribute__ ((aligned (4))) = "\xff\xff\x05\x00" "Hello"; - * ManagedString s((StringData*)(void*)hello); - * @endcode - */ - ManagedString(StringData *ptr); - - /** - * Get current ptr, do not decr() it, and set the current instance to empty string. - * - * This is to be used by specialized runtimes which pass StringData around. - */ - StringData *leakData(); - - /** - * Constructor. - * - * Create a managed string from a pointer to an 8-bit character buffer. - * - * The buffer is copied to ensure safe memory management (the supplied - * character buffer may be declared on the stack for instance). - * - * @param str The character array on which to base the new ManagedString. - * - * @code - * ManagedString s("abcdefg"); - * @endcode - */ - ManagedString(const char *str); - - /** - * Constructor. - * - * Create a managed string from a given integer. - * - * @param value The integer from which to create the ManagedString. - * - * @code - * ManagedString s(20); - * @endcode - */ - ManagedString(const int value); - - - /** - * Constructor. - * Create a managed string from a given char. - * - * @param value The character from which to create the ManagedString. - * - * @code - * ManagedString s('a'); - * @endcode - */ - ManagedString(const char value); - - /** - * Constructor. - * Create a ManagedString from a ManagedBuffer. All bytes in the - * ManagedBuffer are added to the ManagedString. - * - * @param buffer The ManagedBuffer from which to create the ManagedString. - * - * @code - * ManagedString s = radio.datagram.recv(); - * @endcode - */ - ManagedString(ManagedBuffer buffer); - - /** - * Constructor. - * Create a ManagedString from a pointer to an 8-bit character buffer of a given length. - * - * The buffer is copied to ensure sane memory management (the supplied - * character buffer may be declared on the stack for instance). - * - * @param str The character array on which to base the new ManagedString. - * - * @param length The length of the character array - * - * @code - * ManagedString s("abcdefg",7); - * @endcode - */ - ManagedString(const char *str, const int16_t length); - - /** - * Copy constructor. - * Makes a new ManagedString identical to the one supplied. - * - * Shares the character buffer and reference count with the supplied ManagedString. - * - * @param s The ManagedString to copy. - * - * @code - * ManagedString s("abcdefg"); - * ManagedString p(s); - * @endcode - */ - ManagedString(const ManagedString &s); - - /** - * Default constructor. - * - * Create an empty ManagedString. - * - * @code - * ManagedString s(); - * @endcode - */ - ManagedString(); - - /** - * Destructor. - * - * Free this ManagedString, and decrement the reference count to the - * internal character buffer. - * - * If we're holding the last reference, also free the character buffer. - */ - ~ManagedString(); - - /** - * Copy assign operation. - * - * Called when one ManagedString is assigned the value of another. - * - * If the ManagedString being assigned is already referring to a character buffer, - * decrement the reference count and free up the buffer as necessary. - * - * Then, update our character buffer to refer to that of the supplied ManagedString, - * and increase its reference count. - * - * @param s The ManagedString to copy. - * - * @code - * ManagedString s("abcd"); - * ManagedString p("efgh"); - * p = s // p now points to s, s' ref is incremented - * @endcode - */ - ManagedString& operator = (const ManagedString& s); - - /** - * Equality operation. - * - * Called when one ManagedString is tested to be equal to another using the '==' operator. - * - * @param s The ManagedString to test ourselves against. - * - * @return true if this ManagedString is identical to the one supplied, false otherwise. - * - * @code - * DeviceDisplay display; - * ManagedString s("abcd"); - * ManagedString p("efgh"); - * - * if(p == s) - * display.scroll("We are the same!"); - * else - * display.scroll("We are different!"); //p is not equal to s - this will be called - * @endcode - */ - bool operator== (const ManagedString& s); - - /** - * Inequality operation. - * - * Called when one ManagedString is tested to be not equal using the '!=' operator. - * - * @param s The ManagedString to test ourselves against. - * - * @return true if this ManagedString is identical to the one supplied, false otherwise. - * - * @code - * DeviceDisplay display; - * ManagedString s("abcd"); - * ManagedString p("efgh"); - * - * if(p != s) - * display.scroll("We are different!"); - * else - * display.scroll("We are the same!"); - * @endcode - */ - bool operator!= (const ManagedString& s); - - /** - * Inequality operation. - * - * Called when one ManagedString is tested to be less than another using the '<' operator. - * - * @param s The ManagedString to test ourselves against. - * - * @return true if this ManagedString is alphabetically less than to the one supplied, false otherwise. - * - * @code - * DeviceDisplay display; - * ManagedString s("a"); - * ManagedString p("b"); - * - * if(s < p) - * display.scroll("a is before b!"); //a is before b - * else - * display.scroll("b is before a!"); - * @endcode - */ - bool operator< (const ManagedString& s); - - /** - * Inequality operation. - * - * Called when one ManagedString is tested to be greater than another using the '>' operator. - * - * @param s The ManagedString to test ourselves against. - * - * @return true if this ManagedString is alphabetically greater than to the one supplied, false otherwise. - * - * @code - * DeviceDisplay display; - * ManagedString s("a"); - * ManagedString p("b"); - * - * if(p>a) - * display.scroll("b is after a!"); //b is after a - * else - * display.scroll("a is after b!"); - * @endcode - */ - bool operator> (const ManagedString& s); - - /** - * Extracts a ManagedString from this string, at the position provided. - * - * @param start The index of the first character to extract, indexed from zero. - * - * @param length The number of characters to extract from the start position - * - * @return a ManagedString representing the requested substring. - * - * @code - * DeviceDisplay display; - * ManagedString s("abcdefg"); - * - * display.scroll(s.substring(0,2)) // displays "ab" - * @endcode - */ - ManagedString substring(int16_t start, int16_t length); - - /** - * Concatenates two strings. - * - * @param lhs The first ManagedString to concatenate. - * @param rhs The second ManagedString to concatenate. - * - * @return a new ManagedString representing the joined strings. - * - * @code - * DeviceDisplay display; - * ManagedString s("abcd"); - * ManagedString p("efgh") - * - * display.scroll(s + p) // scrolls "abcdefgh" - * @endcode - */ - #ifndef DOXYGEN_SHOULD_SKIP_THIS // Friend members as 'const ... &' currently break breathe/exhale doc generation, so we MUST skip this for now. - friend ManagedString (codal::operator+) (const ManagedString& lhs, const ManagedString& rhs); - #endif - - /** - * Provides a character value at a given position in the string, indexed from zero. - * - * @param index The position of the character to return. - * - * @return the character at posisiton index, zero if index is invalid. - * - * @code - * DeviceDisplay display; - * ManagedString s("abcd"); - * - * display.scroll(s.charAt(1)) // scrolls "b" - * @endcode - */ - char charAt(int16_t index); - - - /** - * Provides an immutable 8 bit wide character buffer representing this string. - * - * @return a pointer to the character buffer. - */ - const char *toCharArray() const - { - return ptr->data; - } - - /** - * Determines the length of this ManagedString in characters. - * - * @return the length of the string in characters. - * - * @code - * DeviceDisplay display; - * ManagedString s("abcd"); - * - * display.scroll(s.length()) // scrolls "4" - * @endcode - */ - int16_t length() const - { - return ptr->len; - } - - /** - * Empty String constant - */ - static ManagedString EmptyString; - - private: - - /** - * Internal constructor helper. - * - * Configures this ManagedString to refer to the static EmptyString - */ - void initEmpty(); - - /** - * Internal constructor helper. - * - * Creates this ManagedString based on a given data. - */ - void initString(const char *str, int len); - - /** - * Private Constructor. - * - * Create a managed string based on a concat of two strings. - * The buffer is copied to ensure sane memory management (the supplied - * character buffer may be declared on the stack for instance). - * - * @param str1 The first string on which to base the new ManagedString. - * - * @param str2 The second string on which to base the new ManagedString. - */ - ManagedString(const ManagedString &s1, const ManagedString &s2); - - }; -} + return ptr->data; + } + + /** + * Determines the length of this ManagedString in characters. + * + * @return the length of the string in characters. + * + * @code + * DeviceDisplay display; + * ManagedString s("abcd"); + * + * display.scroll(s.length()) // scrolls "4" + * @endcode + */ + int16_t length() const + { + return ptr->len; + } + + /** + * Empty String constant + */ + static ManagedString EmptyString; + + private: + /** + * Internal constructor helper. + * + * Configures this ManagedString to refer to the static EmptyString + */ + void initEmpty(); + + /** + * Internal constructor helper. + * + * Creates this ManagedString based on a given data. + */ + void initString(const char* str, int len); + + /** + * Private Constructor. + * + * Create a managed string based on a concat of two strings. + * The buffer is copied to ensure sane memory management (the supplied + * character buffer may be declared on the stack for instance). + * + * @param str1 The first string on which to base the new ManagedString. + * + * @param str2 The second string on which to base the new ManagedString. + */ + ManagedString(const ManagedString& s1, const ManagedString& s2); +}; +} // namespace codal #endif diff --git a/inc/types/ManagedType.h b/inc/types/ManagedType.h index ef3b72a9..9b52cdd4 100644 --- a/inc/types/ManagedType.h +++ b/inc/types/ManagedType.h @@ -28,231 +28,216 @@ DEALINGS IN THE SOFTWARE. #include "CodalConfig.h" /** - * Class definition for a Generic Managed Type. - * - * Represents a reference counted object. - * - * @note When the destructor is called, delete is called on the object - implicitly calling the given objects destructor. - */ + * Class definition for a Generic Managed Type. + * + * Represents a reference counted object. + * + * @note When the destructor is called, delete is called on the object - implicitly calling the given objects + * destructor. + */ template -class ManagedType -{ -protected: - - int *ref; +class ManagedType { + protected: + int* ref; -public: - - T *object; + public: + T* object; /** - * Constructor for the managed type, given a class space T. - * - * @param object the object that you would like to be ref counted - of class T - * - * @code - * T object = new T(); - * ManagedType mt(t); - * @endcode - */ + * Constructor for the managed type, given a class space T. + * + * @param object the object that you would like to be ref counted - of class T + * + * @code + * T object = new T(); + * ManagedType mt(t); + * @endcode + */ ManagedType(T* object); /** - * Default constructor for the managed type, given a class space T. - */ + * Default constructor for the managed type, given a class space T. + */ ManagedType(); /** - * Copy constructor for the managed type, given a class space T. - * - * @param t another managed type instance of class type T. - * - * @code - * T* object = new T(); - * ManagedType mt(t); - * ManagedType mt1(mt); - * @endcode - */ - ManagedType(const ManagedType &t); + * Copy constructor for the managed type, given a class space T. + * + * @param t another managed type instance of class type T. + * + * @code + * T* object = new T(); + * ManagedType mt(t); + * ManagedType mt1(mt); + * @endcode + */ + ManagedType(const ManagedType& t); /** - * Destructor for the managed type, given a class space T. - */ + * Destructor for the managed type, given a class space T. + */ ~ManagedType(); /** - * Copy-assign member function for the managed type, given a class space. - * - * @code - * T* object = new T(); - * ManagedType mt(t); - * ManagedType mt1 = mt; - * @endcode - */ - ManagedType& operator = (const ManagedType&i); + * Copy-assign member function for the managed type, given a class space. + * + * @code + * T* object = new T(); + * ManagedType mt(t); + * ManagedType mt1 = mt; + * @endcode + */ + ManagedType& operator=(const ManagedType& i); /** - * Returns the references to this ManagedType. - * - * @code - * T* object = new T(); - * ManagedType mt(t); - * ManagedType mt1(mt); - * - * mt.getReferences // this will be 2! - * @endcode - */ + * Returns the references to this ManagedType. + * + * @code + * T* object = new T(); + * ManagedType mt(t); + * ManagedType mt1(mt); + * + * mt.getReferences // this will be 2! + * @endcode + */ int getReferences(); /** - * De-reference operator overload. This makes modifying ref-counted POD - * easier. - * - * @code - * ManagedType x = 0; - * *x = 1; // mutates the ref-counted integer - * @endcode - */ - T& operator*() { - return *object; - } + * De-reference operator overload. This makes modifying ref-counted POD + * easier. + * + * @code + * ManagedType x = 0; + * *x = 1; // mutates the ref-counted integer + * @endcode + */ + T& operator*() { return *object; } /** - * Method call operator overload. This forwards the call to the underlying - * object. - * - * @code - * ManagedType x = new T(); - * x->m(); // resolves to T::m - */ - T* operator->() { - if (object == NULL) - target_panic(DEVICE_NULL_DEREFERENCE); + * Method call operator overload. This forwards the call to the underlying + * object. + * + * @code + * ManagedType x = new T(); + * x->m(); // resolves to T::m + */ + T* operator->() + { + if (object == NULL) target_panic(DEVICE_NULL_DEREFERENCE); return object; } /** - * Shorthand for `x.operator->()` - */ - T* get() { - return object; - } + * Shorthand for `x.operator->()` + */ + T* get() { return object; } /** - * A simple inequality overload to compare two ManagedType instances. - */ - bool operator!=(const ManagedType& x) { - return !(this == x); - } + * A simple inequality overload to compare two ManagedType instances. + */ + bool operator!=(const ManagedType& x) { return !(this == x); } /** - * A simple equality overload to compare two ManagedType instances. - */ - bool operator==(const ManagedType& x) { - return this->object == x.object; - } + * A simple equality overload to compare two ManagedType instances. + */ + bool operator==(const ManagedType& x) { return this->object == x.object; } }; /** - * Constructor for the managed type, given a class space T. - * - * @param object the object that you would like to be ref counted - of class T - * - * @code - * T object = new T(); - * ManagedType mt(t); - * @endcode - */ -template + * Constructor for the managed type, given a class space T. + * + * @param object the object that you would like to be ref counted - of class T + * + * @code + * T object = new T(); + * ManagedType mt(t); + * @endcode + */ +template ManagedType::ManagedType(T* object) { this->object = object; - ref = (int *)malloc(sizeof(int)); - *ref = 1; + ref = (int*)malloc(sizeof(int)); + *ref = 1; } /** - * Default constructor for the managed type, given a class space T. - */ -template + * Default constructor for the managed type, given a class space T. + */ +template ManagedType::ManagedType() { this->object = NULL; - ref = (int *)malloc(sizeof(int)); - *ref = 0; + ref = (int*)malloc(sizeof(int)); + *ref = 0; } /** - * Copy constructor for the managed type, given a class space T. - * - * @param t another managed type instance of class type T. - * - * @code - * T* object = new T(); - * ManagedType mt(t); - * ManagedType mt1(mt); - * @endcode - */ -template -ManagedType::ManagedType(const ManagedType &t) + * Copy constructor for the managed type, given a class space T. + * + * @param t another managed type instance of class type T. + * + * @code + * T* object = new T(); + * ManagedType mt(t); + * ManagedType mt1(mt); + * @endcode + */ +template +ManagedType::ManagedType(const ManagedType& t) { this->object = t.object; - this->ref = t.ref; + this->ref = t.ref; (*ref)++; } /** - * Destructor for the managed type, given a class space T. - */ -template + * Destructor for the managed type, given a class space T. + */ +template ManagedType::~ManagedType() { // Special case - we were created using a default constructor, and never assigned a value. - if (*ref == 0) - { + if (*ref == 0) { // Simply destroy our reference counter and we're done. free(ref); } // Normal case - we have a valid piece of data. // Decrement our reference counter and free all allocated memory if we're deleting the last reference. - else if (--(*ref) == 0) - { + else if (--(*ref) == 0) { delete object; free(ref); } } /** - * Copy-assign member function for the managed type, given a class space. - * - * @code - * T* object = new T(); - * ManagedType mt(t); - * ManagedType mt1 = mt; - * @endcode - */ -template -ManagedType& ManagedType::operator = (const ManagedType&t) + * Copy-assign member function for the managed type, given a class space. + * + * @code + * T* object = new T(); + * ManagedType mt(t); + * ManagedType mt1 = mt; + * @endcode + */ +template +ManagedType& ManagedType::operator=(const ManagedType& t) { - if (this == &t) - return *this; + if (this == &t) return *this; // Special case - we were created using a default constructor, and never assigned a value. - if (*ref == 0) - { + if (*ref == 0) { // Simply destroy our reference counter, as we're about to adopt another. free(ref); } - else if (--(*ref) == 0) - { + else if (--(*ref) == 0) { delete object; free(ref); } object = t.object; - ref = t.ref; + ref = t.ref; (*ref)++; @@ -260,17 +245,17 @@ ManagedType& ManagedType::operator = (const ManagedType&t) } /** - * Returns the references to this ManagedType. - * - * @code - * T* object = new T(); - * ManagedType mt(t); - * ManagedType mt1(mt); - * - * mt.getReferences // this will be 2! - * @endcode - */ -template + * Returns the references to this ManagedType. + * + * @code + * T* object = new T(); + * ManagedType mt(t); + * ManagedType mt1(mt); + * + * mt.getReferences // this will be 2! + * @endcode + */ +template int ManagedType::getReferences() { return (*ref); diff --git a/inc/types/Matrix4.h b/inc/types/Matrix4.h index 816ed01d..d5af3d0e 100644 --- a/inc/types/Matrix4.h +++ b/inc/types/Matrix4.h @@ -27,180 +27,177 @@ DEALINGS IN THE SOFTWARE. #include "CodalConfig.h" -namespace codal -{ +namespace codal { /** -* Class definition for a simple matrix, that is optimised for nx4 or 4xn matrices. -* -* This class is heavily optimised for these commonly used matrices as used in 3D geometry. -* Whilst this class does support basic operations on matrices of any dimension, it is not intended as a -* general purpose matrix class as inversion operations are only provided for 4x4 matrices. -* For programmers needing more flexible Matrix support, the Matrix and MatrixMath classes from -* Ernsesto Palacios provide a good basis: -* -* https://developer.mbed.org/cookbook/MatrixClass -* https://developer.mbed.org/users/Yo_Robot/code/MatrixMath/ -*/ -class Matrix4 -{ - float *data; // Linear buffer representing the matrix. - int rows; // The number of rows in the matrix. - int cols; // The number of columns in the matrix. - -public: - - /** - * Constructor. - * Create a matrix of the given size. - * - * @param rows the number of rows in the matrix to be created. - * - * @param cols the number of columns in the matrix to be created. - * - * @code - * Matrix4(10, 4); // Creates a Matrix with 10 rows and 4 columns. - * @endcode - */ - Matrix4(int rows, int cols); - - /** - * Constructor. - * Create a matrix that is an identical copy of the given matrix. - * - * @param matrix The matrix to copy. - * - * @code - * Matrix newMatrix(matrix); . - * @endcode - */ - Matrix4(const Matrix4 &matrix); - - /** - * Determines the number of columns in this matrix. - * - * @return The number of columns in the matrix. - * - * @code - * int c = matrix.width(); - * @endcode - */ - int width(); - - /** - * Determines the number of rows in this matrix. - * - * @return The number of rows in the matrix. - * - * @code - * int r = matrix.height(); - * @endcode - */ - int height(); - - /** - * Reads the matrix element at the given position. - * - * @param row The row of the element to read. - * - * @param col The column of the element to read. - * - * @return The value of the matrix element at the given position. 0 is returned if the given index is out of range. - * - * @code - * float v = matrix.get(1,2); - * @endcode - */ - float get(int row, int col); - - /** - * Writes the matrix element at the given position. - * - * @param row The row of the element to write. - * - * @param col The column of the element to write. - * - * @param v The new value of the element. - * - * @code - * matrix.set(1,2,42.0); - * @endcode - */ - void set(int row, int col, float v); - - /** - * Transposes this matrix. - * - * @return the resultant matrix. - * - * @code - * matrix.transpose(); - * @endcode - */ - Matrix4 transpose(); - - /** - * Multiplies this matrix with the given matrix (if possible). - * - * @param matrix the matrix to multiply this matrix's values against. - * - * @param transpose Transpose the matrices before multiplication. Defaults to false. - * - * @return the resultant matrix. An empty matrix is returned if the operation canot be completed. - * - * @code - * Matrix result = matrixA.multiply(matrixB); - * @endcode - */ - Matrix4 multiply(Matrix4 &matrix, bool transpose = false); - - /** - * Multiplies the transpose of this matrix with the given matrix (if possible). - * - * @param matrix the matrix to multiply this matrix's values against. - * - * @return the resultant matrix. An empty matrix is returned if the operation canot be completed. - * - * @code - * Matrix result = matrixA.multiplyT(matrixB); - * @endcode - */ - Matrix4 multiplyT(Matrix4 &matrix); - - /** - * Performs an optimised inversion of a 4x4 matrix. - * Only 4x4 matrices are supported by this operation. - * - * @return the resultant matrix. An empty matrix is returned if the operation canot be completed. - * - * @code - * Matrix result = matrixA.invert(); - * @endcode - */ - Matrix4 invert(); - - /** - * Destructor. - * - * Frees any memory consumed by this Matrix4 instance. - */ - ~Matrix4(); + * Class definition for a simple matrix, that is optimised for nx4 or 4xn matrices. + * + * This class is heavily optimised for these commonly used matrices as used in 3D geometry. + * Whilst this class does support basic operations on matrices of any dimension, it is not intended as a + * general purpose matrix class as inversion operations are only provided for 4x4 matrices. + * For programmers needing more flexible Matrix support, the Matrix and MatrixMath classes from + * Ernsesto Palacios provide a good basis: + * + * https://developer.mbed.org/cookbook/MatrixClass + * https://developer.mbed.org/users/Yo_Robot/code/MatrixMath/ + */ +class Matrix4 { + float* data; // Linear buffer representing the matrix. + int rows; // The number of rows in the matrix. + int cols; // The number of columns in the matrix. + + public: + /** + * Constructor. + * Create a matrix of the given size. + * + * @param rows the number of rows in the matrix to be created. + * + * @param cols the number of columns in the matrix to be created. + * + * @code + * Matrix4(10, 4); // Creates a Matrix with 10 rows and 4 columns. + * @endcode + */ + Matrix4(int rows, int cols); + + /** + * Constructor. + * Create a matrix that is an identical copy of the given matrix. + * + * @param matrix The matrix to copy. + * + * @code + * Matrix newMatrix(matrix); . + * @endcode + */ + Matrix4(const Matrix4& matrix); + + /** + * Determines the number of columns in this matrix. + * + * @return The number of columns in the matrix. + * + * @code + * int c = matrix.width(); + * @endcode + */ + int width(); + + /** + * Determines the number of rows in this matrix. + * + * @return The number of rows in the matrix. + * + * @code + * int r = matrix.height(); + * @endcode + */ + int height(); + + /** + * Reads the matrix element at the given position. + * + * @param row The row of the element to read. + * + * @param col The column of the element to read. + * + * @return The value of the matrix element at the given position. 0 is returned if the given index is out of range. + * + * @code + * float v = matrix.get(1,2); + * @endcode + */ + float get(int row, int col); + + /** + * Writes the matrix element at the given position. + * + * @param row The row of the element to write. + * + * @param col The column of the element to write. + * + * @param v The new value of the element. + * + * @code + * matrix.set(1,2,42.0); + * @endcode + */ + void set(int row, int col, float v); + + /** + * Transposes this matrix. + * + * @return the resultant matrix. + * + * @code + * matrix.transpose(); + * @endcode + */ + Matrix4 transpose(); + + /** + * Multiplies this matrix with the given matrix (if possible). + * + * @param matrix the matrix to multiply this matrix's values against. + * + * @param transpose Transpose the matrices before multiplication. Defaults to false. + * + * @return the resultant matrix. An empty matrix is returned if the operation canot be completed. + * + * @code + * Matrix result = matrixA.multiply(matrixB); + * @endcode + */ + Matrix4 multiply(Matrix4& matrix, bool transpose = false); + + /** + * Multiplies the transpose of this matrix with the given matrix (if possible). + * + * @param matrix the matrix to multiply this matrix's values against. + * + * @return the resultant matrix. An empty matrix is returned if the operation canot be completed. + * + * @code + * Matrix result = matrixA.multiplyT(matrixB); + * @endcode + */ + Matrix4 multiplyT(Matrix4& matrix); + + /** + * Performs an optimised inversion of a 4x4 matrix. + * Only 4x4 matrices are supported by this operation. + * + * @return the resultant matrix. An empty matrix is returned if the operation canot be completed. + * + * @code + * Matrix result = matrixA.invert(); + * @endcode + */ + Matrix4 invert(); + + /** + * Destructor. + * + * Frees any memory consumed by this Matrix4 instance. + */ + ~Matrix4(); }; /** - * Multiplies the transpose of this matrix with the given matrix (if possible). - * - * @return the resultant matrix. An empty matrix is returned if the operation canot be completed. - * - * @code - * Matrix result = matrixA.multiplyT(matrixB); - * @endcode - */ -inline Matrix4 Matrix4::multiplyT(Matrix4 &matrix) + * Multiplies the transpose of this matrix with the given matrix (if possible). + * + * @return the resultant matrix. An empty matrix is returned if the operation canot be completed. + * + * @code + * Matrix result = matrixA.multiplyT(matrixB); + * @endcode + */ +inline Matrix4 Matrix4::multiplyT(Matrix4& matrix) { return multiply(matrix, true); } -} // namespace codal +} // namespace codal #endif diff --git a/inc/types/RefCounted.h b/inc/types/RefCounted.h index 48a583a0..303f8172 100644 --- a/inc/types/RefCounted.h +++ b/inc/types/RefCounted.h @@ -28,76 +28,71 @@ DEALINGS IN THE SOFTWARE. #include "CodalConfig.h" #include "CodalDevice.h" -namespace codal -{ +namespace codal { +/** + * Base class for payload for ref-counted objects. Used by ManagedString and DeviceImage. + * There is no constructor, as this struct is typically malloc()ed. + */ +struct RefCounted { + public: /** - * Base class for payload for ref-counted objects. Used by ManagedString and DeviceImage. - * There is no constructor, as this struct is typically malloc()ed. - */ - struct RefCounted - { - public: - /** - * The high 15 bits hold the number of outstanding references. The lowest bit is always 1 - * to make sure it doesn't look like C++ vtable. - * Should never be even or one (object should be deleted then). - * When it's set to 0xffff, it means the object sits in flash and should not be counted. - */ - volatile uint16_t refCount; - - #if CONFIG_ENABLED(DEVICE_TAG) - uint16_t tag; - #endif - - /** - * Increment reference count. - */ - void incr(); - - /** - * Decrement reference count. - */ - void decr(); - - /** - * Initializes for one outstanding reference. - */ - void init(); - - /** - * Releases the current instance. - */ - void destroy(); - - /** - * Checks if the object resides in flash memory. - * - * @return true if the object resides in flash memory, false otherwise. - */ - bool isReadOnly(); - }; - - - #if CONFIG_ENABLED(DEVICE_TAG) - // Note that there might be binary dependencies on these values (and layout of - // RefCounted and derived classes), so the existing ones are best left unchanged. - #define REF_TAG_STRING 1 - #define REF_TAG_BUFFER 2 - #define REF_TAG_IMAGE 3 - #define REF_TAG_USER 32 - - #define REF_COUNTED_DEF_EMPTY(...) \ - static const uint16_t emptyData[] \ - __attribute__((aligned(4))) = {0xffff, REF_TAG, __VA_ARGS__}; - #define REF_COUNTED_INIT(ptr) \ - ptr->init(); \ - ptr->tag = REF_TAG - #else - #define REF_COUNTED_DEF_EMPTY(className, ...) \ - static const uint16_t emptyData[] __attribute__((aligned(4))) = {0xffff, __VA_ARGS__}; - #define REF_COUNTED_INIT(ptr) ptr->init() - #endif -} + * The high 15 bits hold the number of outstanding references. The lowest bit is always 1 + * to make sure it doesn't look like C++ vtable. + * Should never be even or one (object should be deleted then). + * When it's set to 0xffff, it means the object sits in flash and should not be counted. + */ + volatile uint16_t refCount; + +#if CONFIG_ENABLED(DEVICE_TAG) + uint16_t tag; +#endif + + /** + * Increment reference count. + */ + void incr(); + /** + * Decrement reference count. + */ + void decr(); + + /** + * Initializes for one outstanding reference. + */ + void init(); + + /** + * Releases the current instance. + */ + void destroy(); + + /** + * Checks if the object resides in flash memory. + * + * @return true if the object resides in flash memory, false otherwise. + */ + bool isReadOnly(); +}; + +#if CONFIG_ENABLED(DEVICE_TAG) +// Note that there might be binary dependencies on these values (and layout of +// RefCounted and derived classes), so the existing ones are best left unchanged. +#define REF_TAG_STRING 1 +#define REF_TAG_BUFFER 2 +#define REF_TAG_IMAGE 3 +#define REF_TAG_USER 32 + +#define REF_COUNTED_DEF_EMPTY(...) \ + static const uint16_t emptyData[] __attribute__((aligned(4))) = {0xffff, REF_TAG, __VA_ARGS__}; +#define REF_COUNTED_INIT(ptr) \ + ptr->init(); \ + ptr->tag = REF_TAG +#else +#define REF_COUNTED_DEF_EMPTY(className, ...) \ + static const uint16_t emptyData[] __attribute__((aligned(4))) = {0xffff, __VA_ARGS__}; +#define REF_COUNTED_INIT(ptr) ptr->init() +#endif +} // namespace codal #endif diff --git a/source/core/CodalAssert.cpp b/source/core/CodalAssert.cpp index d9be998d..4c3541a1 100644 --- a/source/core/CodalAssert.cpp +++ b/source/core/CodalAssert.cpp @@ -1,56 +1,57 @@ -#include "codal_target_hal.h" #include "CodalAssert.h" + #include "CodalDmesg.h" +#include "codal_target_hal.h" -uint32_t test_failures = 0; +uint32_t test_failures = 0; uint32_t test_successes = 0; -void __codal_assert__( const char * file, const int line, bool condition, const char * expr, const char * message ) { - DMESGN( "%s:%d; %s -> ", file, line, expr ); +void __codal_assert__(const char* file, const int line, bool condition, const char* expr, const char* message) +{ + DMESGN("%s:%d; %s -> ", file, line, expr); - if( condition ) { - DMESGF( "PASS" ); + if (condition) { + DMESGF("PASS"); test_successes++; return; } - DMESGF( "FAIL" ); - if( message != NULL ) - DMESGF( "\t%s", message ); - - #if CONFIG_ENABLED(CODAL_ASSERT_PANIC) - target_panic( 999 ); - #else - DMESGF( "\tFailed %d tests", ++test_failures ); - #endif + DMESGF("FAIL"); + if (message != NULL) DMESGF("\t%s", message); + +#if CONFIG_ENABLED(CODAL_ASSERT_PANIC) + target_panic(999); +#else + DMESGF("\tFailed %d tests", ++test_failures); +#endif } -void __codal_fault__( const char * file, const int line, const char * message ) { - DMESGN( "%s:%d; ASSERT_FAULT (user invoked)", file, line ); - if( message != NULL ) - DMESGF( "\t%s", message ); - - #if CONFIG_ENABLED(CODAL_ASSERT_PANIC) - target_panic( 999 ); - #endif +void __codal_fault__(const char* file, const int line, const char* message) +{ + DMESGN("%s:%d; ASSERT_FAULT (user invoked)", file, line); + if (message != NULL) DMESGF("\t%s", message); + +#if CONFIG_ENABLED(CODAL_ASSERT_PANIC) + target_panic(999); +#endif } -void __codal_assert_pass__( const char * file, const int line, const char * message ) { +void __codal_assert_pass__(const char* file, const int line, const char* message) +{ test_successes++; - DMESGF( "Test SUCCESS in %s:%d (PASS: %d, FAIL: %d)", file, line, test_successes, test_failures ); - if( message != NULL ) - DMESGF( "\t%s", message ); + DMESGF("Test SUCCESS in %s:%d (PASS: %d, FAIL: %d)", file, line, test_successes, test_failures); + if (message != NULL) DMESGF("\t%s", message); } -void __codal_assert_fail__( const char * file, const int line, const char * message ) { - DMESGF( "Test FAIL in %s:%d (PASS: %d, FAIL: %d)", file, line, test_successes, test_failures ); - - if( message != NULL ) - DMESGF( "\t%s", message ); - - #if CONFIG_ENABLED(CODAL_ASSERT_PANIC) - target_panic( 999 ); - #else - DMESGF( "\tFailed %d tests", ++test_failures ); - #endif +void __codal_assert_fail__(const char* file, const int line, const char* message) +{ + DMESGF("Test FAIL in %s:%d (PASS: %d, FAIL: %d)", file, line, test_successes, test_failures); + + if (message != NULL) DMESGF("\t%s", message); + +#if CONFIG_ENABLED(CODAL_ASSERT_PANIC) + target_panic(999); +#else + DMESGF("\tFailed %d tests", ++test_failures); +#endif } \ No newline at end of file diff --git a/source/core/CodalCompat.cpp b/source/core/CodalCompat.cpp index 7a0a3856..6cf18acc 100644 --- a/source/core/CodalCompat.cpp +++ b/source/core/CodalCompat.cpp @@ -23,36 +23,35 @@ DEALINGS IN THE SOFTWARE. */ /** - * This file contains functions used to maintain compatability and portability. - * It also contains constants that are used elsewhere in the DAL. - */ -#include "CodalConfig.h" + * This file contains functions used to maintain compatability and portability. + * It also contains constants that are used elsewhere in the DAL. + */ #include "CodalCompat.h" + +#include "CodalConfig.h" #include "ErrorNo.h" static uint32_t random_value; /** - * Performs an in buffer reverse of a given char array. - * - * @param s the string to reverse. - * - * @return DEVICE_OK, or DEVICE_INVALID_PARAMETER. - */ -int codal::string_reverse(char *s) + * Performs an in buffer reverse of a given char array. + * + * @param s the string to reverse. + * + * @return DEVICE_OK, or DEVICE_INVALID_PARAMETER. + */ +int codal::string_reverse(char* s) { - //sanity check... - if(s == NULL) - return DEVICE_INVALID_PARAMETER; + // sanity check... + if (s == NULL) return DEVICE_INVALID_PARAMETER; - char *j; + char* j; int c; j = s + strlen(s) - 1; - while(s < j) - { - c = *s; + while (s < j) { + c = *s; *s++ = *j; *j-- = c; } @@ -61,35 +60,32 @@ int codal::string_reverse(char *s) } /** - * Converts a given integer into a string representation. - * - * @param n The number to convert. - * - * @param s A pointer to the buffer where the resulting string will be stored. - * - * @return DEVICE_OK, or DEVICE_INVALID_PARAMETER. - */ -int codal::itoa(int n, char *s) + * Converts a given integer into a string representation. + * + * @param n The number to convert. + * + * @param s A pointer to the buffer where the resulting string will be stored. + * + * @return DEVICE_OK, or DEVICE_INVALID_PARAMETER. + */ +int codal::itoa(int n, char* s) { - int i = 0; + int i = 0; int positive = (n >= 0); - if (s == NULL) - return DEVICE_INVALID_PARAMETER; + if (s == NULL) return DEVICE_INVALID_PARAMETER; // Record the sign of the number, // Ensure our working value is positive. - if (positive) - n = -n; + if (positive) n = -n; // Calculate each character, starting with the LSB. do { - s[i++] = abs(n % 10) + '0'; + s[i++] = abs(n % 10) + '0'; } while (abs(n /= 10) > 0); // Add a negative sign as needed - if (!positive) - s[i++] = '-'; + if (!positive) s[i++] = '-'; // Terminate the string. s[i] = '\0'; @@ -110,21 +106,17 @@ int codal::random(int max) { uint32_t m, result; - if (max <= 0) - return DEVICE_INVALID_PARAMETER; + if (max <= 0) return DEVICE_INVALID_PARAMETER; - if (random_value == 0) - seed_random(0xC0DA1); + if (random_value == 0) seed_random(0xC0DA1); // Our maximum return value is actually one less than passed max--; - do - { - m = (uint32_t)max; + do { + m = (uint32_t)max; result = 0; - do - { + do { // Cycle the LFSR (Linear Feedback Shift Register). // We use an optimal sequence with a period of 2^32-1, as defined by Bruce Schneier here // (a true legend in the field!), @@ -134,9 +126,7 @@ int codal::random(int max) // https://www.schneier.com/paper-pseudorandom-sequence.html uint32_t rnd = random_value; - rnd = ((((rnd >> 31) ^ (rnd >> 6) ^ (rnd >> 4) ^ (rnd >> 2) ^ (rnd >> 1) ^ rnd) & - 0x0000001) - << 31) | + rnd = ((((rnd >> 31) ^ (rnd >> 6) ^ (rnd >> 4) ^ (rnd >> 2) ^ (rnd >> 1) ^ rnd) & 0x0000001) << 31) | (rnd >> 1); random_value = rnd; diff --git a/source/core/CodalComponent.cpp b/source/core/CodalComponent.cpp index 59124de3..24049c95 100644 --- a/source/core/CodalComponent.cpp +++ b/source/core/CodalComponent.cpp @@ -23,6 +23,7 @@ DEALINGS IN THE SOFTWARE. */ #include "CodalComponent.h" + #include "CodalFiber.h" #include "EventModel.h" #include "Timer.h" @@ -34,42 +35,40 @@ CodalComponent* CodalComponent::components[DEVICE_COMPONENT_COUNT]; uint8_t CodalComponent::configuration = 0; #if DEVICE_COMPONENT_COUNT > 255 - #error "DEVICE_COMPONENT_COUNT has to fit in uint8_t" +#error "DEVICE_COMPONENT_COUNT has to fit in uint8_t" #endif -uint16_t CodalComponent::generateDynamicID() { +uint16_t CodalComponent::generateDynamicID() +{ static uint16_t __nextDynamicID = DEVICE_ID_DYNAMIC_MIN; - + // Have we blown off the end of our dynamic space? - if( __nextDynamicID > DEVICE_ID_DYNAMIC_MAX ) - target_panic( PanicCode::DEVICE_RESORUCES_EXHAUSTED ); - + if (__nextDynamicID > DEVICE_ID_DYNAMIC_MAX) target_panic(PanicCode::DEVICE_RESORUCES_EXHAUSTED); + return __nextDynamicID++; } /** - * The periodic callback for all components. - */ + * The periodic callback for all components. + */ void component_callback(Event evt) { uint8_t i = 0; - if(evt.value == DEVICE_COMPONENT_EVT_SYSTEM_TICK) - { - while(i < DEVICE_COMPONENT_COUNT) - { - if(CodalComponent::components[i] && CodalComponent::components[i]->status & DEVICE_COMPONENT_STATUS_SYSTEM_TICK) + if (evt.value == DEVICE_COMPONENT_EVT_SYSTEM_TICK) { + while (i < DEVICE_COMPONENT_COUNT) { + if (CodalComponent::components[i] && + CodalComponent::components[i]->status & DEVICE_COMPONENT_STATUS_SYSTEM_TICK) CodalComponent::components[i]->periodicCallback(); i++; } } - if(evt.value == DEVICE_SCHEDULER_EVT_IDLE) - { - while(i < DEVICE_COMPONENT_COUNT) - { - if(CodalComponent::components[i] && CodalComponent::components[i]->status & DEVICE_COMPONENT_STATUS_IDLE_TICK) + if (evt.value == DEVICE_SCHEDULER_EVT_IDLE) { + while (i < DEVICE_COMPONENT_COUNT) { + if (CodalComponent::components[i] && + CodalComponent::components[i]->status & DEVICE_COMPONENT_STATUS_IDLE_TICK) CodalComponent::components[i]->idleCallback(); i++; @@ -78,17 +77,15 @@ void component_callback(Event evt) } /** - * Adds the current CodalComponent instance to our array of components. - */ + * Adds the current CodalComponent instance to our array of components. + */ void CodalComponent::addComponent() { uint8_t i = 0; // iterate through our list until an empty space is found. - while(i < DEVICE_COMPONENT_COUNT) - { - if(components[i] == NULL) - { + while (i < DEVICE_COMPONENT_COUNT) { + if (components[i] == NULL) { components[i] = this; break; } @@ -96,14 +93,15 @@ void CodalComponent::addComponent() i++; } - if(!(configuration & DEVICE_COMPONENT_LISTENERS_CONFIGURED) && EventModel::defaultEventBus) - { - int ret = system_timer_event_every_us(SCHEDULER_TICK_PERIOD_US, DEVICE_ID_COMPONENT, DEVICE_COMPONENT_EVT_SYSTEM_TICK); + if (!(configuration & DEVICE_COMPONENT_LISTENERS_CONFIGURED) && EventModel::defaultEventBus) { + int ret = system_timer_event_every_us(SCHEDULER_TICK_PERIOD_US, DEVICE_ID_COMPONENT, + DEVICE_COMPONENT_EVT_SYSTEM_TICK); - if(ret == DEVICE_OK) - { - EventModel::defaultEventBus->listen(DEVICE_ID_COMPONENT, DEVICE_COMPONENT_EVT_SYSTEM_TICK, component_callback, MESSAGE_BUS_LISTENER_IMMEDIATE); - EventModel::defaultEventBus->listen(DEVICE_ID_SCHEDULER, DEVICE_SCHEDULER_EVT_IDLE, component_callback, MESSAGE_BUS_LISTENER_IMMEDIATE); + if (ret == DEVICE_OK) { + EventModel::defaultEventBus->listen(DEVICE_ID_COMPONENT, DEVICE_COMPONENT_EVT_SYSTEM_TICK, + component_callback, MESSAGE_BUS_LISTENER_IMMEDIATE); + EventModel::defaultEventBus->listen(DEVICE_ID_SCHEDULER, DEVICE_SCHEDULER_EVT_IDLE, component_callback, + MESSAGE_BUS_LISTENER_IMMEDIATE); CodalComponent::configuration |= DEVICE_COMPONENT_LISTENERS_CONFIGURED; } @@ -111,16 +109,14 @@ void CodalComponent::addComponent() } /** - * Removes the current CodalComponent instance from our array of components. - */ + * Removes the current CodalComponent instance from our array of components. + */ void CodalComponent::removeComponent() { uint8_t i = 0; - while(i < DEVICE_COMPONENT_COUNT) - { - if(components[i] == this) - { + while (i < DEVICE_COMPONENT_COUNT) { + if (components[i] == this) { components[i] = NULL; return; } @@ -134,25 +130,24 @@ void CodalComponent::removeComponent() */ void CodalComponent::setAllSleep(bool doSleep) { - deepSleepAll( doSleep ? deepSleepCallbackBegin : deepSleepCallbackEnd, NULL); + deepSleepAll(doSleep ? deepSleepCallbackBegin : deepSleepCallbackEnd, NULL); } /** - * Perform functions related to deep sleep. - */ -int CodalComponent::deepSleepCallback( deepSleepCallbackReason reason, deepSleepCallbackData *data) -{ - switch ( reason) - { + * Perform functions related to deep sleep. + */ +int CodalComponent::deepSleepCallback(deepSleepCallbackReason reason, deepSleepCallbackData* data) +{ + switch (reason) { case deepSleepCallbackBegin: case deepSleepCallbackBeginWithWakeUps: - setSleep(true); - break; + setSleep(true); + break; case deepSleepCallbackEnd: case deepSleepCallbackEndWithWakeUps: - setSleep(false); - break; + setSleep(false); + break; default: break; @@ -162,34 +157,29 @@ int CodalComponent::deepSleepCallback( deepSleepCallbackReason reason, deepSleep } /** - * Perform functions related to deep sleep. - */ -void CodalComponent::deepSleepAll( deepSleepCallbackReason reason, deepSleepCallbackData *data) + * Perform functions related to deep sleep. + */ +void CodalComponent::deepSleepAll(deepSleepCallbackReason reason, deepSleepCallbackData* data) { // usually, dependencies of component X are added before X itself, // so iterate backwards (so from high-level components to low-level) // when putting stuff to sleep, and forwards when waking up - switch ( reason) - { + switch (reason) { case deepSleepCallbackPrepare: case deepSleepCallbackBegin: case deepSleepCallbackBeginWithWakeUps: case deepSleepCallbackCountWakeUps: - for (unsigned i = 0; i < DEVICE_COMPONENT_COUNT; i++) - { - if (components[i]) - components[i]->deepSleepCallback( reason, data); + for (unsigned i = 0; i < DEVICE_COMPONENT_COUNT; i++) { + if (components[i]) components[i]->deepSleepCallback(reason, data); } break; case deepSleepCallbackEnd: case deepSleepCallbackEndWithWakeUps: case deepSleepCallbackClearWakeUps: - for (int i = DEVICE_COMPONENT_COUNT - 1; i >= 0; i--) - { - if (components[i]) - components[i]->deepSleepCallback( reason, data); + for (int i = DEVICE_COMPONENT_COUNT - 1; i >= 0; i--) { + if (components[i]) components[i]->deepSleepCallback(reason, data); } break; } diff --git a/source/core/CodalDevice.cpp b/source/core/CodalDevice.cpp index 2a2ae18c..87464412 100644 --- a/source/core/CodalDevice.cpp +++ b/source/core/CodalDevice.cpp @@ -23,6 +23,7 @@ DEALINGS IN THE SOFTWARE. */ #include "CodalDevice.h" + #include "CodalDmesg.h" using namespace codal; diff --git a/source/core/CodalDmesg.cpp b/source/core/CodalDmesg.cpp index cd9ee253..5693b93e 100644 --- a/source/core/CodalDmesg.cpp +++ b/source/core/CodalDmesg.cpp @@ -25,9 +25,9 @@ DEALINGS IN THE SOFTWARE. #include "CodalDmesg.h" #if DEVICE_DMESG_BUFFER_SIZE > 0 -#include "CodalDevice.h" -#include "CodalConfig.h" #include "CodalCompat.h" +#include "CodalConfig.h" +#include "CodalDevice.h" #include "Timer.h" CodalLogStore codalLogStore; @@ -35,48 +35,43 @@ static void (*dmesg_flush_fn)(void) = NULL; using namespace codal; -static void logwrite(const char *msg); +static void logwrite(const char* msg); REAL_TIME_FUNC -static void logwriten(const char *msg, int l) +static void logwriten(const char* msg, int l) { target_disable_irq(); - if (codalLogStore.ptr + l >= sizeof(codalLogStore.buffer)) - { - *(uint32_t *)codalLogStore.buffer = 0x0a2e2e2e; // "...\n" - codalLogStore.ptr = 4; - if (l >= (int)sizeof(codalLogStore.buffer) - 5) - { + if (codalLogStore.ptr + l >= sizeof(codalLogStore.buffer)) { + *(uint32_t*)codalLogStore.buffer = 0x0a2e2e2e; // "...\n" + codalLogStore.ptr = 4; + if (l >= (int)sizeof(codalLogStore.buffer) - 5) { msg = "DMESG line too long!\n"; - l = 21; + l = 21; } } - char *dst = &codalLogStore.buffer[codalLogStore.ptr]; - int tmp = l; - while (tmp--) - *dst++ = *msg++; + char* dst = &codalLogStore.buffer[codalLogStore.ptr]; + int tmp = l; + while (tmp--) *dst++ = *msg++; *dst = 0; codalLogStore.ptr += l; target_enable_irq(); } -static void logwrite(const char *msg) +static void logwrite(const char* msg) { logwriten(msg, strlen(msg)); } -static void writeNum(char *buf, uint32_t n, bool full) +static void writeNum(char* buf, uint32_t n, bool full) { - int i = 0; + int i = 0; int sh = 28; - while (sh >= 0) - { + while (sh >= 0) { int d = (n >> sh) & 0xf; - if (full || d || sh == 0 || i) - { + if (full || d || sh == 0 || i) { buf[i++] = d > 9 ? 'A' + d - 10 : '0' + d; } sh -= 4; @@ -88,35 +83,33 @@ static void logwritenum(uint32_t n, bool full, bool hex) { char buff[20]; - if (hex) - { + if (hex) { writeNum(buff, n, full); logwrite("0x"); } - else - { + else { itoa(n, buff); } logwrite(buff); } -static void logwritedouble( double v, int precision = 8 ) +static void logwritedouble(double v, int precision = 8) { - int iVal = (int)v; + int iVal = (int)v; double fRem = v - (double)iVal; - logwritenum( iVal, false, false ); + logwritenum(iVal, false, false); logwrite("."); - while( precision-- > 0 ) { + while (precision-- > 0) { fRem = fRem * 10.0; - logwritenum( (uint32_t)fRem, false, false ); + logwritenum((uint32_t)fRem, false, false); fRem -= (int)fRem; } } -void codal_dmesg_nocrlf(const char *format, ...) +void codal_dmesg_nocrlf(const char* format, ...) { va_list arg; va_start(arg, format); @@ -124,7 +117,7 @@ void codal_dmesg_nocrlf(const char *format, ...) va_end(arg); } -void codal_dmesg(const char *format, ...) +void codal_dmesg(const char* format, ...) { va_list arg; va_start(arg, format); @@ -132,7 +125,7 @@ void codal_dmesg(const char *format, ...) va_end(arg); } -void codal_dmesg_with_flush(const char *format, ...) +void codal_dmesg_with_flush(const char* format, ...) { va_list arg; va_start(arg, format); @@ -148,84 +141,80 @@ void codal_dmesg_set_flush_fn(void (*fn)(void)) void codal_dmesg_flush() { - if (dmesg_flush_fn) - dmesg_flush_fn(); + if (dmesg_flush_fn) dmesg_flush_fn(); } -void codal_vdmesg(const char *format, bool crlf, va_list ap) +void codal_vdmesg(const char* format, bool crlf, va_list ap) { - const char *end = format; + const char* end = format; - #if CONFIG_ENABLED(DMESG_SHOW_TIMES) - logwritenum( (uint32_t)system_timer_current_time(), false, false ); - logwrite( "\t" ); - #endif +#if CONFIG_ENABLED(DMESG_SHOW_TIMES) + logwritenum((uint32_t)system_timer_current_time(), false, false); + logwrite("\t"); +#endif - #if CONFIG_ENABLED(DMESG_SHOW_FIBERS) - logwritenum( (uint32_t)((uint64_t)currentFiber & 0x000000000000FFFF), false, true ); - logwrite( "\t" ); - #endif +#if CONFIG_ENABLED(DMESG_SHOW_FIBERS) + logwritenum((uint32_t)((uint64_t)currentFiber & 0x000000000000FFFF), false, true); + logwrite("\t"); +#endif int param = 0; - while (*end) - { - if (*end++ == '%') - { + while (*end) { + if (*end++ == '%') { logwriten(format, end - format - 1); param = 0; -l_parse_continue: - switch (*end++) - { - case '0' ... '9': { - int val = (int)*(end-1) - (int)'0'; - param = (param * 10) + val; - goto l_parse_continue; // Note that labels are only valid within a single method context, so this is semi-safe - } break; - - case 'c': { - uint32_t val = va_arg(ap, uint32_t); - logwriten((const char *)&val, 1); - } break; - case 'u': // should be printed as unsigned, but will do for now - case 'd': { - uint32_t val = va_arg(ap, uint32_t); - logwritenum(val, false, false); - } break; - case 'x': { - uint32_t val = va_arg(ap, uint32_t); - logwritenum(val, false, true); - } break; - case 'p': - case 'X': { - uint32_t val = va_arg(ap, uint32_t); - logwritenum(val, true, true); - } break; - case 's': { - uint32_t val = va_arg(ap, uint32_t); - logwrite((char *)(void *)val); - } break; - case 'f': { - double val = va_arg(ap, double); - if( param > 0 ) - logwritedouble( val, param ); - else - logwritedouble( val, 4 ); - } break; - case '%': - logwrite("%"); - break; - default: - logwrite("???"); - break; + l_parse_continue: + switch (*end++) { + case '0' ... '9': { + int val = (int)*(end - 1) - (int)'0'; + param = (param * 10) + val; + goto l_parse_continue; // Note that labels are only valid within a single method context, so this + // is semi-safe + } break; + + case 'c': { + uint32_t val = va_arg(ap, uint32_t); + logwriten((const char*)&val, 1); + } break; + case 'u': // should be printed as unsigned, but will do for now + case 'd': { + uint32_t val = va_arg(ap, uint32_t); + logwritenum(val, false, false); + } break; + case 'x': { + uint32_t val = va_arg(ap, uint32_t); + logwritenum(val, false, true); + } break; + case 'p': + case 'X': { + uint32_t val = va_arg(ap, uint32_t); + logwritenum(val, true, true); + } break; + case 's': { + uint32_t val = va_arg(ap, uint32_t); + logwrite((char*)(void*)val); + } break; + case 'f': { + double val = va_arg(ap, double); + if (param > 0) + logwritedouble(val, param); + else + logwritedouble(val, 4); + } break; + case '%': + logwrite("%"); + break; + default: + logwrite("???"); + break; } format = end; } } logwriten(format, end - format); - if (crlf) - logwrite("\r\n"); + if (crlf) logwrite("\r\n"); } #endif diff --git a/source/core/CodalFiber.cpp b/source/core/CodalFiber.cpp index 05ef46a4..fee1d4ce 100644 --- a/source/core/CodalFiber.cpp +++ b/source/core/CodalFiber.cpp @@ -22,33 +22,32 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "CodalConfig.h" #include "CodalFiber.h" + +#include "CodalConfig.h" +#include "CodalDmesg.h" #include "Timer.h" #include "codal_target_hal.h" -#include "CodalDmesg.h" #define INITIAL_STACK_DEPTH (fiber_initial_stack_base() - 0x04) - /* * Statically allocated values used to create and destroy Fibers. * required to be defined here to allow persistence during context switches. */ -namespace codal -{ -Fiber *currentFiber = NULL; // The context in which the current fiber is executing. -static Fiber *forkedFiber = NULL; // The context in which a newly created child fiber is executing. -static Fiber *idleFiber = NULL; // the idle task - performs a power efficient sleep, and system maintenance tasks. +namespace codal { +Fiber* currentFiber = NULL; // The context in which the current fiber is executing. +static Fiber* forkedFiber = NULL; // The context in which a newly created child fiber is executing. +static Fiber* idleFiber = NULL; // the idle task - performs a power efficient sleep, and system maintenance tasks. /* * Scheduler state. */ -static Fiber *runQueue = NULL; // The list of runnable fibers. -static Fiber *sleepQueue = NULL; // The list of blocked fibers waiting on a fiber_sleep() operation. -static Fiber *waitQueue = NULL; // The list of blocked fibers waiting on an event. -static Fiber *fiberPool = NULL; // Pool of unused fibers, just waiting for a job to do. -static Fiber *fiberList = NULL; // List of all active Fibers (excludes those in the fiberPool) +static Fiber* runQueue = NULL; // The list of runnable fibers. +static Fiber* sleepQueue = NULL; // The list of blocked fibers waiting on a fiber_sleep() operation. +static Fiber* waitQueue = NULL; // The list of blocked fibers waiting on an event. +static Fiber* fiberPool = NULL; // Pool of unused fibers, just waiting for a job to do. +static Fiber* fiberList = NULL; // List of all active Fibers (excludes those in the fiberPool) /* * Scheduler wide flags @@ -58,13 +57,13 @@ static uint8_t fiber_flags = 0; /* * Fibers may perform wait/notify semantics on events. If set, these operations will be permitted on this EventModel. */ -static EventModel *messageBus = NULL; -} +static EventModel* messageBus = NULL; +} // namespace codal using namespace codal; REAL_TIME_FUNC -void codal::queue_fiber(Fiber *f, Fiber **queue) +void codal::queue_fiber(Fiber* f, Fiber** queue) { target_disable_irq(); @@ -73,35 +72,31 @@ void codal::queue_fiber(Fiber *f, Fiber **queue) // Add the fiber to the tail of the queue. Although this involves scanning the // list, it results in fairer scheduling. - if (*queue == NULL) - { + if (*queue == NULL) { f->qnext = NULL; f->qprev = NULL; - *queue = f; + *queue = f; } - else - { + else { // Scan to the end of the queue. // We don't maintain a tail pointer to save RAM (queues are nrmally very short). - Fiber *last = *queue; + Fiber* last = *queue; - while (last->qnext != NULL) - last = last->qnext; + while (last->qnext != NULL) last = last->qnext; last->qnext = f; - f->qprev = last; - f->qnext = NULL; + f->qprev = last; + f->qnext = NULL; } target_enable_irq(); } REAL_TIME_FUNC -void codal::dequeue_fiber(Fiber *f) +void codal::dequeue_fiber(Fiber* f) { // If this fiber is already dequeued, nothing the there's nothing to do. - if (f->queue == NULL) - return; + if (f->queue == NULL) return; // Remove this fiber fromm whichever queue it is on. target_disable_irq(); @@ -111,8 +106,7 @@ void codal::dequeue_fiber(Fiber *f) else *(f->queue) = f->qnext; - if(f->qnext) - f->qnext->qprev = f->qprev; + if (f->qnext) f->qnext->qprev = f->qprev; f->qnext = NULL; f->qprev = NULL; @@ -121,25 +115,23 @@ void codal::dequeue_fiber(Fiber *f) target_enable_irq(); } -Fiber * codal::get_fiber_list() +Fiber* codal::get_fiber_list() { return fiberList; } REAL_TIME_FUNC -Fiber *getFiberContext() +Fiber* getFiberContext() { - Fiber *f; + Fiber* f; target_disable_irq(); - if (fiberPool != NULL) - { + if (fiberPool != NULL) { f = fiberPool; dequeue_fiber(f); } - else - { + else { f = new Fiber(); if (f == NULL) { @@ -150,7 +142,7 @@ Fiber *getFiberContext() f->tcb = tcb_allocate(); f->stack_bottom = 0; - f->stack_top = 0; + f->stack_top = 0; } target_enable_irq(); @@ -158,28 +150,27 @@ Fiber *getFiberContext() // Ensure this fiber is in suitable state for reuse. f->flags = 0; - #if CONFIG_ENABLED(DEVICE_FIBER_USER_DATA) +#if CONFIG_ENABLED(DEVICE_FIBER_USER_DATA) f->user_data = 0; - #endif +#endif tcb_configure_stack_base(f->tcb, fiber_initial_stack_base()); // Add the new Fiber to the list of all fibers target_disable_irq(); - f->next = fiberList; + f->next = fiberList; fiberList = f; target_enable_irq(); return f; } -void codal::scheduler_init(EventModel &_messageBus) +void codal::scheduler_init(EventModel& _messageBus) { // If we're already initialised, then nothing to do. - if (fiber_scheduler_running()) - return; + if (fiber_scheduler_running()) return; - // Store a reference to the messageBus provided. + // Store a reference to the messageBus provided. // This parameter will be NULL if we're being run without a message bus. messageBus = &_messageBus; @@ -196,14 +187,14 @@ void codal::scheduler_init(EventModel &_messageBus) tcb_configure_sp(idleFiber->tcb, INITIAL_STACK_DEPTH); tcb_configure_lr(idleFiber->tcb, (PROCESSOR_WORD_TYPE)&idle_task); - if (messageBus) - { + if (messageBus) { // Register to receive events in the NOTIFY channel - this is used to implement wait-notify semantics messageBus->listen(DEVICE_ID_NOTIFY, DEVICE_EVT_ANY, scheduler_event, MESSAGE_BUS_LISTENER_IMMEDIATE); messageBus->listen(DEVICE_ID_NOTIFY_ONE, DEVICE_EVT_ANY, scheduler_event, MESSAGE_BUS_LISTENER_IMMEDIATE); system_timer_event_every_us(SCHEDULER_TICK_PERIOD_US, DEVICE_ID_SCHEDULER, DEVICE_SCHEDULER_EVT_TICK); - messageBus->listen(DEVICE_ID_SCHEDULER, DEVICE_SCHEDULER_EVT_TICK, scheduler_tick, MESSAGE_BUS_LISTENER_IMMEDIATE); + messageBus->listen(DEVICE_ID_SCHEDULER, DEVICE_SCHEDULER_EVT_TICK, scheduler_tick, + MESSAGE_BUS_LISTENER_IMMEDIATE); } fiber_flags |= DEVICE_SCHEDULER_RUNNING; @@ -212,31 +203,28 @@ void codal::scheduler_init(EventModel &_messageBus) REAL_TIME_FUNC int codal::fiber_scheduler_running() { - if (fiber_flags & DEVICE_SCHEDULER_RUNNING) - return 1; + if (fiber_flags & DEVICE_SCHEDULER_RUNNING) return 1; return 0; } void codal::scheduler_tick(Event evt) { - Fiber *f = sleepQueue; - Fiber *t; + Fiber* f = sleepQueue; + Fiber* t; #if !CONFIG_ENABLED(LIGHTWEIGHT_EVENTS) evt.timestamp /= 1000; #endif // Check the sleep queue, and wake up any fibers as necessary. - while (f != NULL) - { + while (f != NULL) { t = f->qnext; - if (evt.timestamp >= f->context) - { + if (evt.timestamp >= f->context) { // Wakey wakey! dequeue_fiber(f); - queue_fiber(f,&runQueue); + queue_fiber(f, &runQueue); } f = t; @@ -245,43 +233,39 @@ void codal::scheduler_tick(Event evt) void codal::scheduler_event(Event evt) { - Fiber *f = waitQueue; - Fiber *t; + Fiber* f = waitQueue; + Fiber* t; int notifyOneComplete = 0; // This should never happen. // It is however, safe to simply ignore any events provided, as if no messageBus if recorded, // no fibers are permitted to block on events. - if (messageBus == NULL) - return; + if (messageBus == NULL) return; // Check the wait queue, and wake up any fibers as necessary. - while (f != NULL) - { + while (f != NULL) { t = f->qnext; // extract the event data this fiber is blocked on. - uint16_t id = f->context & 0xFFFF; + uint16_t id = f->context & 0xFFFF; uint16_t value = (f->context & 0xFFFF0000) >> 16; // Special case for the NOTIFY_ONE channel... - if ((evt.source == DEVICE_ID_NOTIFY_ONE && id == DEVICE_ID_NOTIFY) && (value == DEVICE_EVT_ANY || value == evt.value)) - { - if (!notifyOneComplete) - { + if ((evt.source == DEVICE_ID_NOTIFY_ONE && id == DEVICE_ID_NOTIFY) && + (value == DEVICE_EVT_ANY || value == evt.value)) { + if (!notifyOneComplete) { // Wakey wakey! dequeue_fiber(f); - queue_fiber(f,&runQueue); + queue_fiber(f, &runQueue); notifyOneComplete = 1; } } // Normal case. - else if ((id == DEVICE_ID_ANY || id == evt.source) && (value == DEVICE_EVT_ANY || value == evt.value)) - { + else if ((id == DEVICE_ID_ANY || id == evt.source) && (value == DEVICE_EVT_ANY || value == evt.value)) { // Wakey wakey! dequeue_fiber(f); - queue_fiber(f,&runQueue); + queue_fiber(f, &runQueue); } f = t; @@ -294,24 +278,22 @@ void codal::scheduler_event(Event evt) static Fiber* handle_fob() { - Fiber *f = currentFiber; + Fiber* f = currentFiber; // This is a blocking call, so if we're in a fork on block context, // it's time to spawn a new fiber... - if (f->flags & DEVICE_FIBER_FLAG_FOB) - { + if (f->flags & DEVICE_FIBER_FLAG_FOB) { // Allocate a TCB from the new fiber. This will come from the tread pool if available, // else a new one will be allocated on the heap. - if (!forkedFiber) - forkedFiber = getFiberContext(); + if (!forkedFiber) forkedFiber = getFiberContext(); - // If we're out of memory, there's nothing we can do. + // If we're out of memory, there's nothing we can do. // keep running in the context of the current thread as a best effort. if (forkedFiber != NULL) { #if CONFIG_ENABLED(DEVICE_FIBER_USER_DATA) forkedFiber->user_data = f->user_data; - f->user_data = NULL; + f->user_data = NULL; #endif f = forkedFiber; } @@ -322,13 +304,12 @@ static Fiber* handle_fob() void codal::fiber_sleep(unsigned long t) { // If the scheduler is not running, then simply perform a spin wait and exit. - if (!fiber_scheduler_running()) - { + if (!fiber_scheduler_running()) { target_wait(t); return; } - Fiber *f = handle_fob(); + Fiber* f = handle_fob(); // Calculate and store the time we want to wake up. f->context = system_timer_current_time() + t; @@ -347,18 +328,16 @@ int codal::fiber_wait_for_event(uint16_t id, uint16_t value) { int ret = fiber_wake_on_event(id, value); - if(ret == DEVICE_OK) - schedule(); + if (ret == DEVICE_OK) schedule(); return ret; } int codal::fiber_wake_on_event(uint16_t id, uint16_t value) { - if (messageBus == NULL || !fiber_scheduler_running()) - return DEVICE_NOT_SUPPORTED; + if (messageBus == NULL || !fiber_scheduler_running()) return DEVICE_NOT_SUPPORTED; - Fiber *f = handle_fob(); + Fiber* f = handle_fob(); // Encode the event data in the context field. It's handy having a 32 bit core. :-) f->context = (uint32_t)value << 16 | id; @@ -386,15 +365,13 @@ int codal::fiber_wake_on_event(uint16_t id, uint16_t value) int codal::invoke(void (*entry_fn)(void)) { // Validate our parameters. - if (entry_fn == NULL) - return DEVICE_INVALID_PARAMETER; + if (entry_fn == NULL) return DEVICE_INVALID_PARAMETER; - if (!fiber_scheduler_running()) - return DEVICE_NOT_SUPPORTED; + if (!fiber_scheduler_running()) return DEVICE_NOT_SUPPORTED; - if (currentFiber->flags & (DEVICE_FIBER_FLAG_FOB | DEVICE_FIBER_FLAG_PARENT | DEVICE_FIBER_FLAG_CHILD) || HAS_THREAD_USER_DATA) - { - // If we attempt a fork on block whilst already in a fork on block context, or if the thread + if (currentFiber->flags & (DEVICE_FIBER_FLAG_FOB | DEVICE_FIBER_FLAG_PARENT | DEVICE_FIBER_FLAG_CHILD) || + HAS_THREAD_USER_DATA) { + // If we attempt a fork on block whilst already in a fork on block context, or if the thread // already has user data set, simply launch a fiber to deal with the request and we're done. create_fiber(entry_fn); return DEVICE_OK; @@ -409,8 +386,7 @@ int codal::invoke(void (*entry_fn)(void)) // 2) We've already tried to execute the code, it blocked, and we've backtracked. // If we're returning from the user function and we forked another fiber then cleanup and exit. - if (currentFiber->flags & DEVICE_FIBER_FLAG_PARENT) - { + if (currentFiber->flags & DEVICE_FIBER_FLAG_PARENT) { currentFiber->flags &= ~DEVICE_FIBER_FLAG_FOB; currentFiber->flags &= ~DEVICE_FIBER_FLAG_PARENT; return DEVICE_OK; @@ -421,31 +397,28 @@ int codal::invoke(void (*entry_fn)(void)) // spawn a thread to deal with it. currentFiber->flags |= DEVICE_FIBER_FLAG_FOB; entry_fn(); - #if CONFIG_ENABLED(DEVICE_FIBER_USER_DATA) +#if CONFIG_ENABLED(DEVICE_FIBER_USER_DATA) currentFiber->user_data = NULL; - #endif +#endif currentFiber->flags &= ~DEVICE_FIBER_FLAG_FOB; // If this is is an exiting fiber that for spawned to handle a blocking call, recycle it. // The fiber will then re-enter the scheduler, so no need for further cleanup. - if (currentFiber->flags & DEVICE_FIBER_FLAG_CHILD) - release_fiber(); + if (currentFiber->flags & DEVICE_FIBER_FLAG_CHILD) release_fiber(); - return DEVICE_OK; + return DEVICE_OK; } -int codal::invoke(void (*entry_fn)(void *), void *param) +int codal::invoke(void (*entry_fn)(void*), void* param) { // Validate our parameters. - if (entry_fn == NULL) - return DEVICE_INVALID_PARAMETER; + if (entry_fn == NULL) return DEVICE_INVALID_PARAMETER; - if (!fiber_scheduler_running()) - return DEVICE_NOT_SUPPORTED; + if (!fiber_scheduler_running()) return DEVICE_NOT_SUPPORTED; - if (currentFiber->flags & (DEVICE_FIBER_FLAG_FOB | DEVICE_FIBER_FLAG_PARENT | DEVICE_FIBER_FLAG_CHILD) || HAS_THREAD_USER_DATA) - { - // If we attempt a fork on block whilst already in a fork on block context, or if the thread + if (currentFiber->flags & (DEVICE_FIBER_FLAG_FOB | DEVICE_FIBER_FLAG_PARENT | DEVICE_FIBER_FLAG_CHILD) || + HAS_THREAD_USER_DATA) { + // If we attempt a fork on block whilst already in a fork on block context, or if the thread // already has user data set, simply launch a fiber to deal with the request and we're done. create_fiber(entry_fn, param); return DEVICE_OK; @@ -460,8 +433,7 @@ int codal::invoke(void (*entry_fn)(void *), void *param) // 2) We've already tried to execute the code, it blocked, and we've backtracked. // If we're returning from the user function and we forked another fiber then cleanup and exit. - if (currentFiber->flags & DEVICE_FIBER_FLAG_PARENT) - { + if (currentFiber->flags & DEVICE_FIBER_FLAG_PARENT) { currentFiber->flags &= ~DEVICE_FIBER_FLAG_FOB; currentFiber->flags &= ~DEVICE_FIBER_FLAG_PARENT; return DEVICE_OK; @@ -472,15 +444,14 @@ int codal::invoke(void (*entry_fn)(void *), void *param) // spawn a thread to deal with it. currentFiber->flags |= DEVICE_FIBER_FLAG_FOB; entry_fn(param); - #if CONFIG_ENABLED(DEVICE_FIBER_USER_DATA) +#if CONFIG_ENABLED(DEVICE_FIBER_USER_DATA) currentFiber->user_data = NULL; - #endif +#endif currentFiber->flags &= ~DEVICE_FIBER_FLAG_FOB; // If this is is an exiting fiber that for spawned to handle a blocking call, recycle it. // The fiber will then re-enter the scheduler, so no need for further cleanup. - if (currentFiber->flags & DEVICE_FIBER_FLAG_CHILD) - release_fiber(param); + if (currentFiber->flags & DEVICE_FIBER_FLAG_CHILD) release_fiber(param); return DEVICE_OK; } @@ -497,7 +468,7 @@ void codal::launch_new_fiber(void (*ep)(void), void (*cp)(void)) release_fiber(); } -void codal::launch_new_fiber_param(void (*ep)(void *), void (*cp)(void *), void *pm) +void codal::launch_new_fiber_param(void (*ep)(void*), void (*cp)(void*), void* pm) { // Execute the thread's entrypoint. ep(pm); @@ -509,24 +480,22 @@ void codal::launch_new_fiber_param(void (*ep)(void *), void (*cp)(void *), void release_fiber(pm); } - -Fiber *__create_fiber(uint32_t ep, uint32_t cp, uint32_t pm, int parameterised) +Fiber* __create_fiber(uint32_t ep, uint32_t cp, uint32_t pm, int parameterised) { // Validate our parameters. - if (ep == 0 || cp == 0) - return NULL; + if (ep == 0 || cp == 0) return NULL; // Allocate a TCB from the new fiber. This will come from the fiber pool if available, // else a new one will be allocated on the heap. - Fiber *newFiber = getFiberContext(); + Fiber* newFiber = getFiberContext(); // If we're out of memory, there's nothing we can do. - if (newFiber == NULL) - return NULL; + if (newFiber == NULL) return NULL; tcb_configure_args(newFiber->tcb, ep, cp, pm); tcb_configure_sp(newFiber->tcb, INITIAL_STACK_DEPTH); - tcb_configure_lr(newFiber->tcb, parameterised ? (PROCESSOR_WORD_TYPE) &launch_new_fiber_param : (PROCESSOR_WORD_TYPE) &launch_new_fiber); + tcb_configure_lr(newFiber->tcb, parameterised ? (PROCESSOR_WORD_TYPE)&launch_new_fiber_param + : (PROCESSOR_WORD_TYPE)&launch_new_fiber); // Add new fiber to the run queue. queue_fiber(newFiber, &runQueue); @@ -534,26 +503,23 @@ Fiber *__create_fiber(uint32_t ep, uint32_t cp, uint32_t pm, int parameterised) return newFiber; } -Fiber *codal::create_fiber(void (*entry_fn)(void), void (*completion_fn)(void)) +Fiber* codal::create_fiber(void (*entry_fn)(void), void (*completion_fn)(void)) { - if (!fiber_scheduler_running()) - return NULL; + if (!fiber_scheduler_running()) return NULL; - return __create_fiber((uint32_t) entry_fn, (uint32_t)completion_fn, 0, 0); + return __create_fiber((uint32_t)entry_fn, (uint32_t)completion_fn, 0, 0); } -Fiber *codal::create_fiber(void (*entry_fn)(void *), void *param, void (*completion_fn)(void *)) +Fiber* codal::create_fiber(void (*entry_fn)(void*), void* param, void (*completion_fn)(void*)) { - if (!fiber_scheduler_running()) - return NULL; + if (!fiber_scheduler_running()) return NULL; - return __create_fiber((uint32_t) entry_fn, (uint32_t)completion_fn, (uint32_t) param, 1); + return __create_fiber((uint32_t)entry_fn, (uint32_t)completion_fn, (uint32_t)param, 1); } -void codal::release_fiber(void *) +void codal::release_fiber(void*) { - if (!fiber_scheduler_running()) - return; + if (!fiber_scheduler_running()) return; release_fiber(); } @@ -561,8 +527,7 @@ void codal::release_fiber(void *) REAL_TIME_FUNC void codal::release_fiber(void) { - if (!fiber_scheduler_running()) - return; + if (!fiber_scheduler_running()) return; // Remove ourselves form the runqueue. dequeue_fiber(currentFiber); @@ -572,11 +537,11 @@ void codal::release_fiber(void) // limit the number of fibers in the pool int numFree = 0; - for (Fiber *p = fiberPool; p; p = p->qnext) { + for (Fiber* p = fiberPool; p; p = p->qnext) { if (!p->qnext && numFree > 3) { p->qprev->qnext = NULL; free(p->tcb); - free((void *)p->stack_bottom); + free((void*)p->stack_bottom); memset(p, 0, sizeof(*p)); free(p); break; @@ -590,18 +555,14 @@ void codal::release_fiber(void) // Remove the fiber from the list of active fibers target_disable_irq(); - if (fiberList == currentFiber) - { + if (fiberList == currentFiber) { fiberList = fiberList->next; } - else - { - Fiber *p = fiberList; + else { + Fiber* p = fiberList; - while (p) - { - if (p->next == currentFiber) - { + while (p) { + if (p->next == currentFiber) { p->next = currentFiber->next; break; } @@ -615,7 +576,7 @@ void codal::release_fiber(void) schedule(); } -void codal::verify_stack_size(Fiber *f) +void codal::verify_stack_size(Fiber* f) { // Ensure the stack buffer is large enough to hold the stack Reallocate if necessary. PROCESSOR_WORD_TYPE stackDepth; @@ -628,13 +589,12 @@ void codal::verify_stack_size(Fiber *f) bufferSize = f->stack_top - f->stack_bottom; // If we're too small, increase our buffer size. - if (bufferSize < stackDepth) - { + if (bufferSize < stackDepth) { // We are only here, when the current stack is the stack of fiber [f]. // Make sure the contents of [currentFiber] variable reflects that, otherwise // an external memory allocator might get confused when scanning fiber stacks. - Fiber *prevCurrFiber = currentFiber; - currentFiber = f; + Fiber* prevCurrFiber = currentFiber; + currentFiber = f; // GCC would normally assume malloc() and free() can't access currentFiber variable // and thus skip emitting the store above. @@ -646,8 +606,7 @@ void codal::verify_stack_size(Fiber *f) bufferSize = (stackDepth + 32) & 0xffffffe0; // Release the old memory - if (f->stack_bottom != 0) - free((void *)f->stack_bottom); + if (f->stack_bottom != 0) free((void*)f->stack_bottom); // Allocate a new one of the appropriate size. f->stack_bottom = (PROCESSOR_WORD_TYPE)malloc(bufferSize); @@ -671,18 +630,16 @@ int codal::scheduler_waitqueue_empty() void codal::schedule() { - if (!fiber_scheduler_running()) - return; + if (!fiber_scheduler_running()) return; // First, take a reference to the currently running fiber; - Fiber *oldFiber = currentFiber; + Fiber* oldFiber = currentFiber; // First, see if we're in Fork on Block context. If so, we simply want to store the full context // of the currently running thread in a newly created fiber, and restore the context of the // currently running fiber, back to the point where it entered FOB. - if (currentFiber->flags & DEVICE_FIBER_FLAG_FOB) - { + if (currentFiber->flags & DEVICE_FIBER_FLAG_FOB) { // Record that the fibers have a parent/child relationship currentFiber->flags |= DEVICE_FIBER_FLAG_PARENT; forkedFiber->flags |= DEVICE_FIBER_FLAG_CHILD; @@ -702,8 +659,7 @@ void codal::schedule() // We may now be either the newly created thread, or the one that created it. // if the DEVICE_FIBER_FLAG_PARENT flag is still set, we're the old thread, so // restore the current fiber to its stored context and we're done. - if (currentFiber->flags & DEVICE_FIBER_FLAG_PARENT) - restore_register_context(currentFiber->tcb); + if (currentFiber->flags & DEVICE_FIBER_FLAG_PARENT) restore_register_context(currentFiber->tcb); // If we're the new thread, we must have been unblocked by the scheduler, so simply return // and continue processing. @@ -723,8 +679,7 @@ void codal::schedule() // Otherwise, just pick the head of the run queue. currentFiber = runQueue; - if (currentFiber == idleFiber && oldFiber->flags & DEVICE_FIBER_FLAG_DO_NOT_PAGE) - { + if (currentFiber == idleFiber && oldFiber->flags & DEVICE_FIBER_FLAG_DO_NOT_PAGE) { // Run the idle task right here using the old fiber's stack. // Keep idling while the runqueue is empty, or there is data to process. @@ -732,11 +687,9 @@ void codal::schedule() // as we are running on top of this fiber's stack. currentFiber = oldFiber; - do - { + do { idle(); - } - while (runQueue == NULL); + } while (runQueue == NULL); // Switch to a non-idle fiber. // If this fiber is the same as the old one then there'll be no switching at all. @@ -745,24 +698,19 @@ void codal::schedule() // Swap to the context of the chosen fiber, and we're done. // Don't bother with the overhead of switching if there's only one fiber on the runqueue! - if (currentFiber != oldFiber) - { - + if (currentFiber != oldFiber) { // Special case for the idle task, as we don't maintain a stack context (just to save memory). - if (currentFiber == idleFiber) - { + if (currentFiber == idleFiber) { tcb_configure_sp(idleFiber->tcb, INITIAL_STACK_DEPTH); tcb_configure_lr(idleFiber->tcb, (PROCESSOR_WORD_TYPE)&idle_task); } // If we're returning for IDLE or our last fiber has been destroyed, we don't need to waste time // saving the processor context - Just swap in the new fiber, and discard changes to stack and register context. - if (oldFiber == idleFiber || oldFiber->queue == &fiberPool) - { + if (oldFiber == idleFiber || oldFiber->queue == &fiberPool) { swap_context(NULL, 0, currentFiber->tcb, currentFiber->stack_top); } - else - { + else { // Ensure the stack allocation of the fiber being scheduled out is large enough verify_stack_size(oldFiber); @@ -778,15 +726,13 @@ void codal::idle() // We will return to idle after processing any idle events that add anything // to our run queue, we use the DEVICE_SCHEDULER_IDLE flag to determine this // scenario. - if(!(fiber_flags & DEVICE_SCHEDULER_IDLE)) - { + if (!(fiber_flags & DEVICE_SCHEDULER_IDLE)) { fiber_flags |= DEVICE_SCHEDULER_IDLE; Event(DEVICE_ID_SCHEDULER, DEVICE_SCHEDULER_EVT_IDLE); } // If the above did create any useful work, enter power efficient sleep. - if(scheduler_runqueue_empty()) - { + if (scheduler_runqueue_empty()) { // unset our DEVICE_SCHEDULER_IDLE flag, we have processed all of the events // because we enforce MESSAGE_BUS_LISTENER_IMMEDIATE for listeners placed // on the scheduler. @@ -797,8 +743,7 @@ void codal::idle() void codal::idle_task() { - while(1) - { + while (1) { idle(); schedule(); } @@ -809,41 +754,38 @@ int codal::fiber_scheduler_get_deepsleep_pending() return fiber_flags & DEVICE_SCHEDULER_DEEPSLEEP ? 1 : 0; } -void codal::fiber_scheduler_set_deepsleep_pending( int pending) +void codal::fiber_scheduler_set_deepsleep_pending(int pending) { - if ( pending) + if (pending) fiber_flags |= DEVICE_SCHEDULER_DEEPSLEEP; else fiber_flags &= ~DEVICE_SCHEDULER_DEEPSLEEP; } -FiberLock::FiberLock( int initial, FiberLockMode mode ) +FiberLock::FiberLock(int initial, FiberLockMode mode) { - this->queue = NULL; - this->locked = initial; + this->queue = NULL; + this->locked = initial; this->resetTo = initial; - this->mode = mode; + this->mode = mode; } - REAL_TIME_FUNC void FiberLock::wait() { // If the scheduler is not running, then simply exit, as we're running monothreaded. - if (!fiber_scheduler_running()) - return; + if (!fiber_scheduler_running()) return; target_disable_irq(); int l = --locked; target_enable_irq(); - //DMESGF( "%d, wait(%d)", (uint32_t)this & 0xFFFF, locked ); + // DMESGF( "%d, wait(%d)", (uint32_t)this & 0xFFFF, locked ); - if (l < 0) - { + if (l < 0) { // wait() is a blocking call, so if we're in a fork on block context, // it's time to spawn a new fiber... - Fiber *f = handle_fob(); + Fiber* f = handle_fob(); // Remove fiber from the run queue dequeue_fiber(f); @@ -856,8 +798,7 @@ void FiberLock::wait() // It is possible that and IRQ has performed a notify() operation however. // If so, put ourself back on the run queue and spin the scheduler (in case we performed a fork-on-block) target_disable_irq(); - if (locked < l) - { + if (locked < l) { // Remove fiber from the run queue dequeue_fiber(f); @@ -874,10 +815,9 @@ void FiberLock::wait() void FiberLock::notify() { locked++; - //DMESGF( "%d, notify(%d)", (uint32_t)this & 0xFFFF, locked ); - Fiber *f = queue; - if (f) - { + // DMESGF( "%d, notify(%d)", (uint32_t)this & 0xFFFF, locked ); + Fiber* f = queue; + if (f) { dequeue_fiber(f); queue_fiber(f, &runQueue); } @@ -885,23 +825,20 @@ void FiberLock::notify() void FiberLock::notifyAll() { - //DMESGF( "%d, notifyAll(%d)", (uint32_t)this & 0xFFFF, locked ); - Fiber *f = queue; - while (f) - { + // DMESGF( "%d, notifyAll(%d)", (uint32_t)this & 0xFFFF, locked ); + Fiber* f = queue; + while (f) { this->notify(); f = queue; } - if( this->mode == FiberLockMode::MUTEX ) - this->locked = this->resetTo; + if (this->mode == FiberLockMode::MUTEX) this->locked = this->resetTo; - //DMESGF( "%d, { notifyAll(%d) }", (uint32_t)this & 0xFFFF, locked ); + // DMESGF( "%d, { notifyAll(%d) }", (uint32_t)this & 0xFFFF, locked ); } int FiberLock::getWaitCount() { - if( locked > -1 ) - return 0; + if (locked > -1) return 0; return 0 - locked; } diff --git a/source/core/CodalHeapAllocator.cpp b/source/core/CodalHeapAllocator.cpp index 289bf55c..1d2a9ea9 100644 --- a/source/core/CodalHeapAllocator.cpp +++ b/source/core/CodalHeapAllocator.cpp @@ -23,57 +23,57 @@ DEALINGS IN THE SOFTWARE. */ /** - * A simple 32 bit block based memory allocator. This allows one or more memory segments to - * be designated as heap storage, and is designed to run in a static memory area or inside the standard C - * heap for use by the codal device runtime. This is required for several reasons: - * - * 1) It reduces memory fragmentation due to the high churn sometime placed on the heap - * by ManagedTypes, fibers and user code. Underlying heap implentations are often have very simplistic - * allocation pilicies and suffer from fragmentation in prolonged use - which can cause programs to - * stop working after a period of time. The algorithm implemented here is simple, but highly tolerant to - * large amounts of churn. - * - * 2) It allows us to reuse the 8K of SRAM set aside for SoftDevice as additional heap storage - * when BLE is not in use. - * - * 3) It gives a simple example of how memory allocation works! :-) - * - * P.S. This is a very simple allocator, therefore not without its weaknesses. Why don't you consider - * what these are, and consider the tradeoffs against simplicity... - * - * @note The need for this should be reviewed in the future, if a different memory allocator is - * made available in the mbed platform. - * - * TODO: Consider caching recently freed blocks to improve allocation time. - */ + * A simple 32 bit block based memory allocator. This allows one or more memory segments to + * be designated as heap storage, and is designed to run in a static memory area or inside the standard C + * heap for use by the codal device runtime. This is required for several reasons: + * + * 1) It reduces memory fragmentation due to the high churn sometime placed on the heap + * by ManagedTypes, fibers and user code. Underlying heap implentations are often have very simplistic + * allocation pilicies and suffer from fragmentation in prolonged use - which can cause programs to + * stop working after a period of time. The algorithm implemented here is simple, but highly tolerant to + * large amounts of churn. + * + * 2) It allows us to reuse the 8K of SRAM set aside for SoftDevice as additional heap storage + * when BLE is not in use. + * + * 3) It gives a simple example of how memory allocation works! :-) + * + * P.S. This is a very simple allocator, therefore not without its weaknesses. Why don't you consider + * what these are, and consider the tradeoffs against simplicity... + * + * @note The need for this should be reviewed in the future, if a different memory allocator is + * made available in the mbed platform. + * + * TODO: Consider caching recently freed blocks to improve allocation time. + */ -#include "CodalConfig.h" #include "CodalHeapAllocator.h" -#include "platform_includes.h" -#include "CodalDevice.h" + #include "CodalCompat.h" +#include "CodalConfig.h" +#include "CodalDevice.h" #include "CodalDmesg.h" #include "ErrorNo.h" +#include "platform_includes.h" using namespace codal; #if CONFIG_ENABLED(DEVICE_HEAP_ALLOCATOR) // A list of all active heap regions, and their dimensions in memory. -HeapDefinition heap[DEVICE_MAXIMUM_HEAPS] = { }; -uint8_t heap_count = 0; +HeapDefinition heap[DEVICE_MAXIMUM_HEAPS] = {}; +uint8_t heap_count = 0; #if (CODAL_DEBUG >= CODAL_DEBUG_HEAP) // Diplays a usage summary about a given heap... -void device_heap_print(HeapDefinition &heap) +void device_heap_print(HeapDefinition& heap) { - PROCESSOR_WORD_TYPE blockSize; - PROCESSOR_WORD_TYPE *block; - int totalFreeBlock = 0; - int totalUsedBlock = 0; + PROCESSOR_WORD_TYPE blockSize; + PROCESSOR_WORD_TYPE* block; + int totalFreeBlock = 0; + int totalUsedBlock = 0; - if (heap.heap_start == NULL) - { + if (heap.heap_start == NULL) { DMESG("--- HEAP NOT INITIALISED ---"); return; } @@ -86,13 +86,12 @@ void device_heap_print(HeapDefinition &heap) target_disable_irq(); block = heap.heap_start; - while (block < heap.heap_end) - { + while (block < heap.heap_end) { blockSize = *block & ~DEVICE_HEAP_BLOCK_FREE; if (*block & DEVICE_HEAP_BLOCK_FREE) - DMESGN("[F:%d] ", blockSize*DEVICE_HEAP_BLOCK_SIZE); + DMESGN("[F:%d] ", blockSize * DEVICE_HEAP_BLOCK_SIZE); else - DMESGN("[U:%d] ", blockSize*DEVICE_HEAP_BLOCK_SIZE); + DMESGN("[U:%d] ", blockSize * DEVICE_HEAP_BLOCK_SIZE); if (*block & DEVICE_HEAP_BLOCK_FREE) totalFreeBlock += blockSize; @@ -106,15 +105,14 @@ void device_heap_print(HeapDefinition &heap) target_enable_irq(); DMESG("\n"); - DMESG("mb_total_free : %d", totalFreeBlock*DEVICE_HEAP_BLOCK_SIZE); - DMESG("mb_total_used : %d", totalUsedBlock*DEVICE_HEAP_BLOCK_SIZE); + DMESG("mb_total_free : %d", totalFreeBlock * DEVICE_HEAP_BLOCK_SIZE); + DMESG("mb_total_used : %d", totalUsedBlock * DEVICE_HEAP_BLOCK_SIZE); } // Diagnostics function. Displays a usage summary about all initialised heaps. void device_heap_print() { - for (int i=0; i < heap_count; i++) - { + for (int i = 0; i < heap_count; i++) { DMESG("\nHEAP %d: ", i); device_heap_print(heap[i]); } @@ -122,33 +120,33 @@ void device_heap_print() #endif /** - * Create and initialise a given memory region as for heap storage. - * After this is called, any future calls to malloc, new, free or delete may use the new heap. - * The heap allocator will attempt to allocate memory from heaps in the order that they are created. - * i.e. memory will be allocated from first heap created until it is full, then the second heap, and so on. - * - * @param start The start address of memory to use as a heap region. - * - * @param end The end address of memory to use as a heap region. - * - * @return DEVICE_OK on success, or DEVICE_NO_RESOURCES if the heap could not be allocated. - * - * @note Only code that #includes DeviceHeapAllocator.h will use this heap. This includes all codal device runtime - * code, and user code targetting the runtime. External code can choose to include this file, or - * simply use the standard heap. - */ + * Create and initialise a given memory region as for heap storage. + * After this is called, any future calls to malloc, new, free or delete may use the new heap. + * The heap allocator will attempt to allocate memory from heaps in the order that they are created. + * i.e. memory will be allocated from first heap created until it is full, then the second heap, and so on. + * + * @param start The start address of memory to use as a heap region. + * + * @param end The end address of memory to use as a heap region. + * + * @return DEVICE_OK on success, or DEVICE_NO_RESOURCES if the heap could not be allocated. + * + * @note Only code that #includes DeviceHeapAllocator.h will use this heap. This includes all codal device runtime + * code, and user code targetting the runtime. External code can choose to include this file, or + * simply use the standard heap. + */ int device_create_heap(PROCESSOR_WORD_TYPE start, PROCESSOR_WORD_TYPE end) { - HeapDefinition *h = &heap[heap_count]; + HeapDefinition* h = &heap[heap_count]; #if CONFIG_ENABLED(CODAL_LOW_LEVEL_VALIDATION) // Ensure we don't exceed the maximum number of heap segments. - if (heap_count == DEVICE_MAXIMUM_HEAPS) - return DEVICE_NO_RESOURCES; + if (heap_count == DEVICE_MAXIMUM_HEAPS) return DEVICE_NO_RESOURCES; // Sanity check. Ensure range is valid, large enough and word aligned. - if (end <= start || end - start < DEVICE_HEAP_BLOCK_SIZE*2 || end % DEVICE_HEAP_BLOCK_SIZE != 0 || start % DEVICE_HEAP_BLOCK_SIZE != 0) + if (end <= start || end - start < DEVICE_HEAP_BLOCK_SIZE * 2 || end % DEVICE_HEAP_BLOCK_SIZE != 0 || + start % DEVICE_HEAP_BLOCK_SIZE != 0) return DEVICE_INVALID_PARAMETER; #endif @@ -156,11 +154,12 @@ int device_create_heap(PROCESSOR_WORD_TYPE start, PROCESSOR_WORD_TYPE end) target_disable_irq(); // Record the dimensions of this new heap - h->heap_start = (PROCESSOR_WORD_TYPE *)start; - h->heap_end = (PROCESSOR_WORD_TYPE *)end; + h->heap_start = (PROCESSOR_WORD_TYPE*)start; + h->heap_end = (PROCESSOR_WORD_TYPE*)end; // Initialise the heap as being completely empty and available for use. - *h->heap_start = DEVICE_HEAP_BLOCK_FREE | (((PROCESSOR_WORD_TYPE) h->heap_end - (PROCESSOR_WORD_TYPE) h->heap_start) / DEVICE_HEAP_BLOCK_SIZE); + *h->heap_start = DEVICE_HEAP_BLOCK_FREE | + (((PROCESSOR_WORD_TYPE)h->heap_end - (PROCESSOR_WORD_TYPE)h->heap_start) / DEVICE_HEAP_BLOCK_SIZE); heap_count++; @@ -176,30 +175,29 @@ int device_create_heap(PROCESSOR_WORD_TYPE start, PROCESSOR_WORD_TYPE end) uint32_t device_heap_size(uint8_t heap_index) { - if (heap_index >= heap_count) - return 0; - HeapDefinition *h = &heap[heap_index]; + if (heap_index >= heap_count) return 0; + HeapDefinition* h = &heap[heap_index]; return (uint8_t*)h->heap_end - (uint8_t*)h->heap_start; } /** - * Attempt to allocate a given amount of memory from a given heap area. - * - * @param size The amount of memory, in bytes, to allocate. - * @param heap The heap to allocate memory from. - * - * @return A pointer to the allocated memory, or NULL if insufficient memory is available. - */ + * Attempt to allocate a given amount of memory from a given heap area. + * + * @param size The amount of memory, in bytes, to allocate. + * @param heap The heap to allocate memory from. + * + * @return A pointer to the allocated memory, or NULL if insufficient memory is available. + */ REAL_TIME_FUNC -void *device_malloc_in(size_t size, HeapDefinition &heap) +void* device_malloc_in(size_t size, HeapDefinition& heap) { - PROCESSOR_WORD_TYPE blockSize = 0; - PROCESSOR_WORD_TYPE blocksNeeded = size % DEVICE_HEAP_BLOCK_SIZE == 0 ? size / DEVICE_HEAP_BLOCK_SIZE : size / DEVICE_HEAP_BLOCK_SIZE + 1; - PROCESSOR_WORD_TYPE *block; - PROCESSOR_WORD_TYPE *next; + PROCESSOR_WORD_TYPE blockSize = 0; + PROCESSOR_WORD_TYPE blocksNeeded = + size % DEVICE_HEAP_BLOCK_SIZE == 0 ? size / DEVICE_HEAP_BLOCK_SIZE : size / DEVICE_HEAP_BLOCK_SIZE + 1; + PROCESSOR_WORD_TYPE* block; + PROCESSOR_WORD_TYPE* next; - if (size <= 0) - return NULL; + if (size <= 0) return NULL; // Account for the index block; blocksNeeded++; @@ -210,11 +208,9 @@ void *device_malloc_in(size_t size, HeapDefinition &heap) // We implement a first fit algorithm with cache to handle rapid churn... // We also defragment free blocks as we search, to optimise this and future searches. block = heap.heap_start; - while (block < heap.heap_end) - { + while (block < heap.heap_end) { // If the block is used, then keep looking. - if(!(*block & DEVICE_HEAP_BLOCK_FREE)) - { + if (!(*block & DEVICE_HEAP_BLOCK_FREE)) { block += *block; continue; } @@ -224,10 +220,8 @@ void *device_malloc_in(size_t size, HeapDefinition &heap) // We have a free block. Let's see if the subsequent ones are too. If so, we can merge... next = block + blockSize; - while (*next & DEVICE_HEAP_BLOCK_FREE) - { - if (next >= heap.heap_end) - break; + while (*next & DEVICE_HEAP_BLOCK_FREE) { + if (next >= heap.heap_end) break; // We can merge! blockSize += (*next & ~DEVICE_HEAP_BLOCK_FREE); @@ -238,31 +232,27 @@ void *device_malloc_in(size_t size, HeapDefinition &heap) // We have a free block. Let's see if it's big enough. // If so, we have a winner. - if (blockSize >= blocksNeeded) - break; + if (blockSize >= blocksNeeded) break; // Otherwise, keep looking... block += blockSize; } // We're full! - if (block >= heap.heap_end) - { + if (block >= heap.heap_end) { target_enable_irq(); return NULL; } // If we're at the end of memory or have very near match then mark the whole segment as in use. - if (blockSize <= blocksNeeded+1 || block+blocksNeeded+1 >= heap.heap_end) - { + if (blockSize <= blocksNeeded + 1 || block + blocksNeeded + 1 >= heap.heap_end) { // Just mark the whole block as used. *block &= ~DEVICE_HEAP_BLOCK_FREE; } - else - { + else { // We need to split the block. - PROCESSOR_WORD_TYPE *splitBlock = block + blocksNeeded; - *splitBlock = blockSize - blocksNeeded; + PROCESSOR_WORD_TYPE* splitBlock = block + blocksNeeded; + *splitBlock = blockSize - blocksNeeded; *splitBlock |= DEVICE_HEAP_BLOCK_FREE; *block = blocksNeeded; @@ -271,34 +261,35 @@ void *device_malloc_in(size_t size, HeapDefinition &heap) // Enable Interrupts target_enable_irq(); - return block+1; + return block + 1; } /** - * Attempt to allocate a given amount of memory from any of our configured heap areas. - * - * @param size The amount of memory, in bytes, to allocate. - * - * @return A pointer to the allocated memory, or NULL if insufficient memory is available. - */ + * Attempt to allocate a given amount of memory from any of our configured heap areas. + * + * @param size The amount of memory, in bytes, to allocate. + * + * @return A pointer to the allocated memory, or NULL if insufficient memory is available. + */ REAL_TIME_FUNC -void* device_malloc (size_t size) +void* device_malloc(size_t size) { static uint8_t initialised = 0; - void *p; + void* p; - if (size <= 0) - return NULL; + if (size <= 0) return NULL; - if (!initialised) - { + if (!initialised) { heap_count = 0; #if CONFIG_ENABLED(CODAL_LOW_LEVEL_VALIDATION) - if(device_create_heap((PROCESSOR_WORD_TYPE)(codal_heap_start), (PROCESSOR_WORD_TYPE)(DEVICE_STACK_BASE) - (PROCESSOR_WORD_TYPE)(DEVICE_STACK_SIZE)) == DEVICE_INVALID_PARAMETER) + if (device_create_heap((PROCESSOR_WORD_TYPE)(codal_heap_start), + (PROCESSOR_WORD_TYPE)(DEVICE_STACK_BASE) - (PROCESSOR_WORD_TYPE)(DEVICE_STACK_SIZE)) == + DEVICE_INVALID_PARAMETER) target_panic(DEVICE_HEAP_ERROR); #else - device_create_heap((PROCESSOR_WORD_TYPE)(codal_heap_start), (PROCESSOR_WORD_TYPE)(DEVICE_STACK_BASE) - (PROCESSOR_WORD_TYPE)(DEVICE_STACK_SIZE)); + device_create_heap((PROCESSOR_WORD_TYPE)(codal_heap_start), + (PROCESSOR_WORD_TYPE)(DEVICE_STACK_BASE) - (PROCESSOR_WORD_TYPE)(DEVICE_STACK_SIZE)); #endif initialised = 1; } @@ -307,20 +298,17 @@ void* device_malloc (size_t size) p = device_malloc_in(size, heap[0]); #else // Assign the memory from the first heap created that has space. - for (int i=0; i < heap_count; i++) - { + for (int i = 0; i < heap_count; i++) { p = device_malloc_in(size, heap[i]); - if (p != NULL) - break; + if (p != NULL) break; } #endif - if (p != NULL) - { + if (p != NULL) { #if (CODAL_DEBUG >= CODAL_DEBUG_HEAP) - DMESG("device_malloc: ALLOCATED: %d [%p]", size, p); + DMESG("device_malloc: ALLOCATED: %d [%p]", size, p); #endif - return p; + return p; } // We're totally out of options (and memory!). @@ -337,37 +325,33 @@ void* device_malloc (size_t size) } /** - * Release a given area of memory from the heap. - * - * @param mem The memory area to release. - */ + * Release a given area of memory from the heap. + * + * @param mem The memory area to release. + */ REAL_TIME_FUNC -void device_free (void *mem) +void device_free(void* mem) { - PROCESSOR_WORD_TYPE *memory = (PROCESSOR_WORD_TYPE *)mem; - PROCESSOR_WORD_TYPE *cb = memory-1; - int i=0; + PROCESSOR_WORD_TYPE* memory = (PROCESSOR_WORD_TYPE*)mem; + PROCESSOR_WORD_TYPE* cb = memory - 1; + int i = 0; #if (CODAL_DEBUG >= CODAL_DEBUG_HEAP) - if (heap_count > 0) - DMESG("device_free: %p", mem); + if (heap_count > 0) DMESG("device_free: %p", mem); #endif // Sanity check. - if (memory == NULL) - return; + if (memory == NULL) return; - // If this memory was created from a heap registered with us, free it. + // If this memory was created from a heap registered with us, free it. #if (DEVICE_MAXIMUM_HEAPS > 1) - for (i=0; i < heap_count; i++) + for (i = 0; i < heap_count; i++) #endif { - if(memory > heap[i].heap_start && memory < heap[i].heap_end) - { + if (memory > heap[i].heap_start && memory < heap[i].heap_end) { // The memory block given is part of this heap, so we can simply // flag that this memory area is now free, and we're done. - if (*cb == 0 || *cb & DEVICE_HEAP_BLOCK_FREE) - target_panic(DEVICE_HEAP_ERROR); + if (*cb == 0 || *cb & DEVICE_HEAP_BLOCK_FREE) target_panic(DEVICE_HEAP_ERROR); *cb |= DEVICE_HEAP_BLOCK_FREE; return; } @@ -377,30 +361,28 @@ void device_free (void *mem) target_panic(DEVICE_HEAP_ERROR); } -void* calloc (size_t num, size_t size) +void* calloc(size_t num, size_t size) { - void *mem = malloc(num*size); + void* mem = malloc(num * size); if (mem) { // without this write, GCC will happily optimize malloc() above into calloc() // and remove the memset ((uint32_t*)mem)[0] = 1; - memset(mem, 0, num*size); + memset(mem, 0, num * size); } return mem; } -extern "C" void* device_realloc (void* ptr, size_t size) +extern "C" void* device_realloc(void* ptr, size_t size) { - void *mem = malloc(size); + void* mem = malloc(size); // handle the simplest case - no previous memory allocted. - if (ptr != NULL && mem != NULL) - { - + if (ptr != NULL && mem != NULL) { // Otherwise we need to copy and free up the old data. - PROCESSOR_WORD_TYPE *cb = ((PROCESSOR_WORD_TYPE *)ptr) - 1; + PROCESSOR_WORD_TYPE* cb = ((PROCESSOR_WORD_TYPE*)ptr) - 1; PROCESSOR_WORD_TYPE blockSize = *cb & ~DEVICE_HEAP_BLOCK_FREE; memcpy(mem, ptr, min(blockSize * sizeof(PROCESSOR_WORD_TYPE), size)); @@ -410,18 +392,17 @@ extern "C" void* device_realloc (void* ptr, size_t size) return mem; } -void *malloc(size_t sz) __attribute__ ((weak, alias ("device_malloc"))); -void free(void *mem) __attribute__ ((weak, alias ("device_free"))); -void* realloc (void* ptr, size_t size) __attribute__ ((weak, alias ("device_realloc"))); - +void* malloc(size_t sz) __attribute__((weak, alias("device_malloc"))); +void free(void* mem) __attribute__((weak, alias("device_free"))); +void* realloc(void* ptr, size_t size) __attribute__((weak, alias("device_realloc"))); // make sure the libc allocator is not pulled in -void *_malloc_r(struct _reent *, size_t len) +void* _malloc_r(struct _reent*, size_t len) { return malloc(len); } -void _free_r(struct _reent *, void *addr) +void _free_r(struct _reent*, void* addr) { free(addr); } diff --git a/source/core/CodalListener.cpp b/source/core/CodalListener.cpp index e12fc778..fc7b5d80 100644 --- a/source/core/CodalListener.cpp +++ b/source/core/CodalListener.cpp @@ -23,101 +23,98 @@ DEALINGS IN THE SOFTWARE. */ /** - * This structure defines a Listener used to invoke functions, or member - * functions if an instance of EventModel receives an event whose id and value - * match this Listener's id and value. - */ -#include "CodalConfig.h" + * This structure defines a Listener used to invoke functions, or member + * functions if an instance of EventModel receives an event whose id and value + * match this Listener's id and value. + */ #include "CodalListener.h" +#include "CodalConfig.h" + using namespace codal; /** - * Constructor. - * - * Create a new Message Bus Listener. - * - * @param id The ID of the component you want to listen to. - * - * @param value The event value you would like to listen to from that component - * - * @param handler A function pointer to call when the event is detected. - * - * @param flags User specified, implementation specific flags, that allow behaviour of this events listener - * to be tuned. - */ + * Constructor. + * + * Create a new Message Bus Listener. + * + * @param id The ID of the component you want to listen to. + * + * @param value The event value you would like to listen to from that component + * + * @param handler A function pointer to call when the event is detected. + * + * @param flags User specified, implementation specific flags, that allow behaviour of this events listener + * to be tuned. + */ Listener::Listener(uint16_t id, uint16_t value, void (*handler)(Event), uint16_t flags) { - this->id = id; - this->value = value; - this->cb = handler; - this->cb_arg = NULL; - this->flags = flags; - this->next = NULL; + this->id = id; + this->value = value; + this->cb = handler; + this->cb_arg = NULL; + this->flags = flags; + this->next = NULL; this->evt_queue = NULL; } /** - * Constructor. - * - * Create a new Message Bus Listener, this constructor accepts an additional - * parameter "arg", which is passed to the handler. - * - * @param id The ID of the component you want to listen to. - * - * @param value The event value you would like to listen to from that component - * - * @param handler A function pointer to call when the event is detected. - * - * @param arg A pointer to some data that will be given to the handler. - * - * @param flags User specified, implementation specific flags, that allow behaviour of this events listener - * to be tuned. - */ -Listener::Listener(uint16_t id, uint16_t value, void (*handler)(Event, void *), void* arg, uint16_t flags) + * Constructor. + * + * Create a new Message Bus Listener, this constructor accepts an additional + * parameter "arg", which is passed to the handler. + * + * @param id The ID of the component you want to listen to. + * + * @param value The event value you would like to listen to from that component + * + * @param handler A function pointer to call when the event is detected. + * + * @param arg A pointer to some data that will be given to the handler. + * + * @param flags User specified, implementation specific flags, that allow behaviour of this events listener + * to be tuned. + */ +Listener::Listener(uint16_t id, uint16_t value, void (*handler)(Event, void*), void* arg, uint16_t flags) { - this->id = id; - this->value = value; - this->cb_param = handler; - this->cb_arg = arg; - this->flags = flags | MESSAGE_BUS_LISTENER_PARAMETERISED; - this->next = NULL; + this->id = id; + this->value = value; + this->cb_param = handler; + this->cb_arg = arg; + this->flags = flags | MESSAGE_BUS_LISTENER_PARAMETERISED; + this->next = NULL; this->evt_queue = NULL; } /** - * Destructor. Ensures all resources used by this listener are freed. - */ + * Destructor. Ensures all resources used by this listener are freed. + */ Listener::~Listener() { - if(this->flags & MESSAGE_BUS_LISTENER_METHOD) - delete cb_method; + if (this->flags & MESSAGE_BUS_LISTENER_METHOD) delete cb_method; } /** - * Queues and event up to be processed. - * - * @param e The event to queue - */ + * Queues and event up to be processed. + * + * @param e The event to queue + */ void Listener::queue(Event e) { int queueDepth; - EventQueueItem *p = evt_queue; + EventQueueItem* p = evt_queue; if (evt_queue == NULL) evt_queue = new EventQueueItem(e); - else - { + else { queueDepth = 1; - while (p->next != NULL) - { + while (p->next != NULL) { p = p->next; queueDepth++; } - if (queueDepth < MESSAGE_BUS_LISTENER_MAX_QUEUE_DEPTH) - p->next = new EventQueueItem(e); + if (queueDepth < MESSAGE_BUS_LISTENER_MAX_QUEUE_DEPTH) p->next = new EventQueueItem(e); } } diff --git a/source/core/CodalUtil.cpp b/source/core/CodalUtil.cpp index d9ee8a17..ef31e225 100644 --- a/source/core/CodalUtil.cpp +++ b/source/core/CodalUtil.cpp @@ -23,45 +23,40 @@ DEALINGS IN THE SOFTWARE. */ /** - * This file contains functions used to maintain compatability and portability. - * It also contains constants that are used elsewhere in the DAL. - */ + * This file contains functions used to maintain compatability and portability. + * It also contains constants that are used elsewhere in the DAL. + */ #include "CodalUtil.h" using namespace codal; KeyValueTableEntry* KeyValueTable::find(const uint32_t key) const { - // Now find the nearest sample range to that specified. - KeyValueTableEntry *p = (KeyValueTableEntry *)data + (length - 1); - KeyValueTableEntry *result = p; + // Now find the nearest sample range to that specified. + KeyValueTableEntry* p = (KeyValueTableEntry*)data + (length - 1); + KeyValueTableEntry* result = p; - while (p >= (KeyValueTableEntry *)data) - { - if (p->key < key) - break; + while (p >= (KeyValueTableEntry*)data) { + if (p->key < key) break; - result = p; - p--; - } + result = p; + p--; + } - return result; + return result; } - uint32_t KeyValueTable::get(const uint32_t key) const { - return find(key)->value; + return find(key)->value; } uint32_t KeyValueTable::getKey(const uint32_t key) const { - return find(key)->key; + return find(key)->key; } bool KeyValueTable::hasKey(const uint32_t key) const { - return (find(key)->key == key); + return (find(key)->key == key); } - - diff --git a/source/core/MemberFunctionCallback.cpp b/source/core/MemberFunctionCallback.cpp index bade8ea2..1160ca27 100644 --- a/source/core/MemberFunctionCallback.cpp +++ b/source/core/MemberFunctionCallback.cpp @@ -23,37 +23,38 @@ DEALINGS IN THE SOFTWARE. */ /** - * Class definition for a MemberFunctionCallback. - * - * C++ member functions (also known as methods) have a more complex - * representation than normal C functions. This class allows a reference to - * a C++ member function to be stored then called at a later date. - * - * This class is used extensively by the DeviceMessageBus to deliver - * events to C++ methods. - */ + * Class definition for a MemberFunctionCallback. + * + * C++ member functions (also known as methods) have a more complex + * representation than normal C functions. This class allows a reference to + * a C++ member function to be stored then called at a later date. + * + * This class is used extensively by the DeviceMessageBus to deliver + * events to C++ methods. + */ -#include "CodalConfig.h" #include "MemberFunctionCallback.h" +#include "CodalConfig.h" + using namespace codal; /** - * Calls the method reference held by this MemberFunctionCallback. - * - * @param e The event to deliver to the method - */ + * Calls the method reference held by this MemberFunctionCallback. + * + * @param e The event to deliver to the method + */ void MemberFunctionCallback::fire(Event e) { invoke(object, method, e); } /** - * A comparison of two MemberFunctionCallback objects. - * - * @return true if the given MemberFunctionCallback is equivalent to this one, false otherwise. - */ -bool MemberFunctionCallback::operator==(const MemberFunctionCallback &mfc) + * A comparison of two MemberFunctionCallback objects. + * + * @return true if the given MemberFunctionCallback is equivalent to this one, false otherwise. + */ +bool MemberFunctionCallback::operator==(const MemberFunctionCallback& mfc) { - return (object == mfc.object && (memcmp(method,mfc.method,sizeof(method))==0)); + return (object == mfc.object && (memcmp(method, mfc.method, sizeof(method)) == 0)); } diff --git a/source/core/codal_default_target_hal.cpp b/source/core/codal_default_target_hal.cpp index a8d53e09..6662190f 100644 --- a/source/core/codal_default_target_hal.cpp +++ b/source/core/codal_default_target_hal.cpp @@ -47,29 +47,28 @@ __attribute__((weak)) void target_deepsleep() // Preprocessor Directive to ignore redecleration when using clang #ifndef __clang__ - /** - * Default implementation of atomic fetch and add opertaion. - * GCC provides this where possible, but this is not supported on some CPU architectures... - * - * @param ptr pointer to the memory to access. - * @param value the value to add to the memory location. - * @return the value of th ememory location BEFORE the add operation took place. - */ - __attribute__((weak)) short unsigned int __sync_fetch_and_add_2 (volatile void *ptr, short unsigned int value) - { - - #if CONFIG_ENABLED(DISABLE_IRQ_FOR_SOFTWARE_ATOMICS) - target_disable_irq(); - #endif +/** + * Default implementation of atomic fetch and add opertaion. + * GCC provides this where possible, but this is not supported on some CPU architectures... + * + * @param ptr pointer to the memory to access. + * @param value the value to add to the memory location. + * @return the value of th ememory location BEFORE the add operation took place. + */ +__attribute__((weak)) short unsigned int __sync_fetch_and_add_2(volatile void* ptr, short unsigned int value) +{ +#if CONFIG_ENABLED(DISABLE_IRQ_FOR_SOFTWARE_ATOMICS) + target_disable_irq(); +#endif - uint16_t *p = (uint16_t *)ptr; - uint16_t old = *p; - *p += value; + uint16_t* p = (uint16_t*)ptr; + uint16_t old = *p; + *p += value; - #if CONFIG_ENABLED(DISABLE_IRQ_FOR_SOFTWARE_ATOMICS) - target_enable_irq(); - #endif +#if CONFIG_ENABLED(DISABLE_IRQ_FOR_SOFTWARE_ATOMICS) + target_enable_irq(); +#endif - return old; - } + return old; +} #endif diff --git a/source/core/gcc_compat.cpp b/source/core/gcc_compat.cpp index a8f9b984..9fa1ef07 100644 --- a/source/core/gcc_compat.cpp +++ b/source/core/gcc_compat.cpp @@ -1,42 +1,43 @@ #include "gcc_compat.h" -#include "codal_target_hal.h" + #include "CodalAssert.h" +#include "codal_target_hal.h" #if __GNUC__ > 11 extern "C" { - int _close( int fd ) - { - assert_fault( "Newlib syscalls are not supported!" ); - return -1; - } +int _close(int fd) +{ + assert_fault("Newlib syscalls are not supported!"); + return -1; +} - int _getpid() - { - assert_fault( "Newlib syscalls are not supported!" ); - return -1; - } +int _getpid() +{ + assert_fault("Newlib syscalls are not supported!"); + return -1; +} - int _kill(int pid, int sig) - { - assert_fault( "Newlib syscalls are not supported!" ); - return -1; - } +int _kill(int pid, int sig) +{ + assert_fault("Newlib syscalls are not supported!"); + return -1; +} - int _lseek(int file, int ptr, int dir) - { - assert_fault( "Newlib syscalls are not supported!" ); - return -1; - } +int _lseek(int file, int ptr, int dir) +{ + assert_fault("Newlib syscalls are not supported!"); + return -1; +} - int _read(int file, char *ptr, int len) - { - assert_fault( "Newlib syscalls are not supported!" ); - return -1; - } - int _write(int file, char *ptr, int len) - { - assert_fault( "Newlib syscalls are not supported!" ); - return -1; - } +int _read(int file, char* ptr, int len) +{ + assert_fault("Newlib syscalls are not supported!"); + return -1; +} +int _write(int file, char* ptr, int len) +{ + assert_fault("Newlib syscalls are not supported!"); + return -1; +} } #endif \ No newline at end of file diff --git a/source/driver-models/AbstractButton.cpp b/source/driver-models/AbstractButton.cpp index 7d3ffe22..4fd3f546 100644 --- a/source/driver-models/AbstractButton.cpp +++ b/source/driver-models/AbstractButton.cpp @@ -22,10 +22,11 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "CodalConfig.h" #include "AbstractButton.h" -#include "Timer.h" + +#include "CodalConfig.h" #include "EventModel.h" +#include "Timer.h" using namespace codal; @@ -76,10 +77,7 @@ void AbstractButton::disable() status &= ~DEVICE_COMPONENT_RUNNING; } - /** * Destructor */ -AbstractButton::~AbstractButton() -{ -} +AbstractButton::~AbstractButton() {} diff --git a/source/driver-models/Accelerometer.cpp b/source/driver-models/Accelerometer.cpp index 2b6072af..9b7c3436 100644 --- a/source/driver-models/Accelerometer.cpp +++ b/source/driver-models/Accelerometer.cpp @@ -23,43 +23,43 @@ DEALINGS IN THE SOFTWARE. */ #include "Accelerometer.h" -#include "ErrorNo.h" -#include "Event.h" + #include "CodalCompat.h" #include "CodalFiber.h" +#include "ErrorNo.h" +#include "Event.h" using namespace codal; - /** - * Constructor. - * Create a software abstraction of an FXSO8700 combined accelerometer/magnetometer - * - * @param _i2c an instance of I2C used to communicate with the device. - * - * @param address the default I2C address of the accelerometer. Defaults to: FXS8700_DEFAULT_ADDR. - * + * Constructor. + * Create a software abstraction of an FXSO8700 combined accelerometer/magnetometer + * + * @param _i2c an instance of I2C used to communicate with the device. + * + * @param address the default I2C address of the accelerometer. Defaults to: FXS8700_DEFAULT_ADDR. + * */ -Accelerometer::Accelerometer(CoordinateSpace &cspace, uint16_t id) : sample(), sampleENU(), coordinateSpace(cspace) +Accelerometer::Accelerometer(CoordinateSpace& cspace, uint16_t id) : sample(), sampleENU(), coordinateSpace(cspace) { // Store our identifiers. - this->id = id; + this->id = id; this->status = 0; // Set a default rate of 50Hz and a +/-2g range. this->samplePeriod = 20; - this->sampleRange = 2; + this->sampleRange = 2; // Initialise gesture history - this->sigma = 0; - this->impulseSigma = 0; - this->lastGesture = ACCELEROMETER_EVT_NONE; - this->currentGesture = ACCELEROMETER_EVT_NONE; - this->shake.x = 0; - this->shake.y = 0; - this->shake.z = 0; - this->shake.count = 0; - this->shake.timer = 0; + this->sigma = 0; + this->impulseSigma = 0; + this->lastGesture = ACCELEROMETER_EVT_NONE; + this->currentGesture = ACCELEROMETER_EVT_NONE; + this->shake.x = 0; + this->shake.y = 0; + this->shake.z = 0; + this->shake.count = 0; + this->shake.timer = 0; this->shake.impulse_2 = 1; this->shake.impulse_3 = 1; this->shake.impulse_6 = 1; @@ -67,17 +67,17 @@ Accelerometer::Accelerometer(CoordinateSpace &cspace, uint16_t id) : sample(), s } /** - * Stores data from the accelerometer sensor in our buffer, and perform gesture tracking. - * - * On first use, this member function will attempt to add this component to the - * list of fiber components in order to constantly update the values stored - * by this object. - * - * This lazy instantiation means that we do not - * obtain the overhead from non-chalantly adding this component to fiber components. - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the read request fails. - */ + * Stores data from the accelerometer sensor in our buffer, and perform gesture tracking. + * + * On first use, this member function will attempt to add this component to the + * list of fiber components in order to constantly update the values stored + * by this object. + * + * This lazy instantiation means that we do not + * obtain the overhead from non-chalantly adding this component to fiber components. + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the read request fails. + */ int Accelerometer::update() { // Store the new data, after performing any necessary coordinate transformations. @@ -96,18 +96,19 @@ int Accelerometer::update() }; /** - * A service function. - * It calculates the current scalar acceleration of the device (x^2 + y^2 + z^2). - * It does not, however, square root the result, as this is a relatively high cost operation. - * - * This is left to application code should it be needed. - * - * @return the sum of the square of the acceleration of the device across all axes. - */ + * A service function. + * It calculates the current scalar acceleration of the device (x^2 + y^2 + z^2). + * It does not, however, square root the result, as this is a relatively high cost operation. + * + * This is left to application code should it be needed. + * + * @return the sum of the square of the acceleration of the device across all axes. + */ uint32_t Accelerometer::instantaneousAccelerationSquared() { // Use pythagoras theorem to determine the combined force acting on the device. - return (uint32_t)sample.x*(uint32_t)sample.x + (uint32_t)sample.y*(uint32_t)sample.y + (uint32_t)sample.z*(uint32_t)sample.z; + return (uint32_t)sample.x * (uint32_t)sample.x + (uint32_t)sample.y * (uint32_t)sample.y + + (uint32_t)sample.z * (uint32_t)sample.z; } /** @@ -123,97 +124,85 @@ uint16_t Accelerometer::instantaneousPosture() bool shakeDetected = false; // Test for shake events. - // We detect a shake by measuring zero crossings in each axis. In other words, if we see a strong acceleration to the left followed by - // a strong acceleration to the right, then we can infer a shake. Similarly, we can do this for each axis (left/right, up/down, in/out). + // We detect a shake by measuring zero crossings in each axis. In other words, if we see a strong acceleration to + // the left followed by a strong acceleration to the right, then we can infer a shake. Similarly, we can do this for + // each axis (left/right, up/down, in/out). // - // If we see enough zero crossings in succession (ACCELEROMETER_SHAKE_COUNT_THRESHOLD), then we decide that the device - // has been shaken. - if ((sample.x < -ACCELEROMETER_SHAKE_TOLERANCE && shake.x) || (sample.x > ACCELEROMETER_SHAKE_TOLERANCE && !shake.x)) - { + // If we see enough zero crossings in succession (ACCELEROMETER_SHAKE_COUNT_THRESHOLD), then we decide that the + // device has been shaken. + if ((sample.x < -ACCELEROMETER_SHAKE_TOLERANCE && shake.x) || + (sample.x > ACCELEROMETER_SHAKE_TOLERANCE && !shake.x)) { shakeDetected = true; - shake.x = !shake.x; + shake.x = !shake.x; } - if ((sample.y < -ACCELEROMETER_SHAKE_TOLERANCE && shake.y) || (sample.y > ACCELEROMETER_SHAKE_TOLERANCE && !shake.y)) - { + if ((sample.y < -ACCELEROMETER_SHAKE_TOLERANCE && shake.y) || + (sample.y > ACCELEROMETER_SHAKE_TOLERANCE && !shake.y)) { shakeDetected = true; - shake.y = !shake.y; + shake.y = !shake.y; } - if ((sample.z < -ACCELEROMETER_SHAKE_TOLERANCE && shake.z) || (sample.z > ACCELEROMETER_SHAKE_TOLERANCE && !shake.z)) - { + if ((sample.z < -ACCELEROMETER_SHAKE_TOLERANCE && shake.z) || + (sample.z > ACCELEROMETER_SHAKE_TOLERANCE && !shake.z)) { shakeDetected = true; - shake.z = !shake.z; + shake.z = !shake.z; } // If we detected a zero crossing in this sample period, count this. - if (shakeDetected && shake.count < ACCELEROMETER_SHAKE_COUNT_THRESHOLD) - { + if (shakeDetected && shake.count < ACCELEROMETER_SHAKE_COUNT_THRESHOLD) { shake.count++; - if (shake.count == 1) - shake.timer = 0; + if (shake.count == 1) shake.timer = 0; - if (shake.count == ACCELEROMETER_SHAKE_COUNT_THRESHOLD) - { + if (shake.count == ACCELEROMETER_SHAKE_COUNT_THRESHOLD) { shake.shaken = 1; - shake.timer = 0; + shake.timer = 0; return ACCELEROMETER_EVT_SHAKE; } } // measure how long we have been detecting a SHAKE event. - if (shake.count > 0) - { + if (shake.count > 0) { shake.timer++; // If we've issued a SHAKE event already, and sufficient time has assed, allow another SHAKE event to be issued. - if (shake.shaken && shake.timer >= ACCELEROMETER_SHAKE_RTX) - { + if (shake.shaken && shake.timer >= ACCELEROMETER_SHAKE_RTX) { shake.shaken = 0; - shake.timer = 0; - shake.count = 0; + shake.timer = 0; + shake.count = 0; } - // Decay our count of zero crossings over time. We don't want them to accumulate if the user performs slow moving motions. - else if (!shake.shaken && shake.timer >= ACCELEROMETER_SHAKE_DAMPING) - { + // Decay our count of zero crossings over time. We don't want them to accumulate if the user performs slow + // moving motions. + else if (!shake.shaken && shake.timer >= ACCELEROMETER_SHAKE_DAMPING) { shake.timer = 0; - if (shake.count > 0) - shake.count--; + if (shake.count > 0) shake.count--; } } uint32_t force = instantaneousAccelerationSquared(); - if (force < ACCELEROMETER_FREEFALL_THRESHOLD) - return ACCELEROMETER_EVT_FREEFALL; + if (force < ACCELEROMETER_FREEFALL_THRESHOLD) return ACCELEROMETER_EVT_FREEFALL; // Determine our posture. - if (sample.x < (-1000 + ACCELEROMETER_TILT_TOLERANCE)) - return ACCELEROMETER_EVT_TILT_LEFT; + if (sample.x < (-1000 + ACCELEROMETER_TILT_TOLERANCE)) return ACCELEROMETER_EVT_TILT_LEFT; - if (sample.x > (1000 - ACCELEROMETER_TILT_TOLERANCE)) - return ACCELEROMETER_EVT_TILT_RIGHT; + if (sample.x > (1000 - ACCELEROMETER_TILT_TOLERANCE)) return ACCELEROMETER_EVT_TILT_RIGHT; - if (sample.y < (-1000 + ACCELEROMETER_TILT_TOLERANCE)) - return ACCELEROMETER_EVT_TILT_DOWN; + if (sample.y < (-1000 + ACCELEROMETER_TILT_TOLERANCE)) return ACCELEROMETER_EVT_TILT_DOWN; - if (sample.y > (1000 - ACCELEROMETER_TILT_TOLERANCE)) - return ACCELEROMETER_EVT_TILT_UP; + if (sample.y > (1000 - ACCELEROMETER_TILT_TOLERANCE)) return ACCELEROMETER_EVT_TILT_UP; - if (sample.z < (-1000 + ACCELEROMETER_TILT_TOLERANCE)) - return ACCELEROMETER_EVT_FACE_UP; + if (sample.z < (-1000 + ACCELEROMETER_TILT_TOLERANCE)) return ACCELEROMETER_EVT_FACE_UP; - if (sample.z > (1000 - ACCELEROMETER_TILT_TOLERANCE)) - return ACCELEROMETER_EVT_FACE_DOWN; + if (sample.z > (1000 - ACCELEROMETER_TILT_TOLERANCE)) return ACCELEROMETER_EVT_FACE_DOWN; return ACCELEROMETER_EVT_NONE; } /** - * Updates the basic gesture recognizer. This performs instantaneous pose recognition, and also some low pass filtering to promote - * stability. - */ + * Updates the basic gesture recognizer. This performs instantaneous pose recognition, and also some low pass filtering + * to promote stability. + */ void Accelerometer::updateGesture() { // Check for High/Low G force events - typically impulses, impacts etc. @@ -221,25 +210,20 @@ void Accelerometer::updateGesture() // For these events, we don't perform any low pass filtering. uint32_t force = instantaneousAccelerationSquared(); - if (force > ACCELEROMETER_2G_THRESHOLD) - { - if (force > ACCELEROMETER_2G_THRESHOLD && !shake.impulse_2) - { + if (force > ACCELEROMETER_2G_THRESHOLD) { + if (force > ACCELEROMETER_2G_THRESHOLD && !shake.impulse_2) { Event e(DEVICE_ID_GESTURE, ACCELEROMETER_EVT_2G); - shake.impulse_2 = 1; + shake.impulse_2 = 1; } - if (force > ACCELEROMETER_3G_THRESHOLD && !shake.impulse_3) - { + if (force > ACCELEROMETER_3G_THRESHOLD && !shake.impulse_3) { Event e(DEVICE_ID_GESTURE, ACCELEROMETER_EVT_3G); shake.impulse_3 = 1; } - if (force > ACCELEROMETER_6G_THRESHOLD && !shake.impulse_6) - { + if (force > ACCELEROMETER_6G_THRESHOLD && !shake.impulse_6) { Event e(DEVICE_ID_GESTURE, ACCELEROMETER_EVT_6G); shake.impulse_6 = 1; } - if (force > ACCELEROMETER_8G_THRESHOLD && !shake.impulse_8) - { + if (force > ACCELEROMETER_8G_THRESHOLD && !shake.impulse_8) { Event e(DEVICE_ID_GESTURE, ACCELEROMETER_EVT_8G); shake.impulse_8 = 1; } @@ -253,105 +237,98 @@ void Accelerometer::updateGesture() else shake.impulse_2 = shake.impulse_3 = shake.impulse_6 = shake.impulse_8 = 0; - // Determine what it looks like we're doing based on the latest sample... uint16_t g = instantaneousPosture(); - if (g == ACCELEROMETER_EVT_SHAKE) - { + if (g == ACCELEROMETER_EVT_SHAKE) { lastGesture = ACCELEROMETER_EVT_SHAKE; Event e(DEVICE_ID_GESTURE, ACCELEROMETER_EVT_SHAKE); return; } // Perform some low pass filtering to reduce jitter from any detected effects - if (g == currentGesture) - { - if (sigma < ACCELEROMETER_GESTURE_DAMPING) - sigma++; + if (g == currentGesture) { + if (sigma < ACCELEROMETER_GESTURE_DAMPING) sigma++; } - else - { + else { currentGesture = g; - sigma = 0; + sigma = 0; } // If we've reached threshold, update our record and raise the relevant event... - if (currentGesture != lastGesture && sigma >= ACCELEROMETER_GESTURE_DAMPING) - { + if (currentGesture != lastGesture && sigma >= ACCELEROMETER_GESTURE_DAMPING) { lastGesture = currentGesture; Event e(DEVICE_ID_GESTURE, lastGesture); } } /** - * Attempts to set the sample rate of the accelerometer to the specified value (in ms). - * - * @param period the requested time between samples, in milliseconds. - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR is the request fails. - * - * @code - * // sample rate is now 20 ms. - * accelerometer.setPeriod(20); - * @endcode - * - * @note The requested rate may not be possible on the hardware. In this case, the - * nearest lower rate is chosen. - */ + * Attempts to set the sample rate of the accelerometer to the specified value (in ms). + * + * @param period the requested time between samples, in milliseconds. + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR is the request fails. + * + * @code + * // sample rate is now 20 ms. + * accelerometer.setPeriod(20); + * @endcode + * + * @note The requested rate may not be possible on the hardware. In this case, the + * nearest lower rate is chosen. + */ int Accelerometer::setPeriod(int period) { int result; samplePeriod = period; - result = configure(); + result = configure(); samplePeriod = getPeriod(); return result; - } /** - * Reads the currently configured sample rate of the accelerometer. - * - * @return The time between samples, in milliseconds. - */ + * Reads the currently configured sample rate of the accelerometer. + * + * @return The time between samples, in milliseconds. + */ int Accelerometer::getPeriod() { return (int)samplePeriod; } /** - * Attempts to set the sample range of the accelerometer to the specified value (in g). - * - * @param range The requested sample range of samples, in g. - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR is the request fails. - * - * @code - * // the sample range of the accelerometer is now 8G. - * accelerometer.setRange(8); - * @endcode - * - * @note The requested range may not be possible on the hardware. In this case, the - * nearest lower range is chosen. - */ + * Attempts to set the sample range of the accelerometer to the specified value (in g). + * + * @param range The requested sample range of samples, in g. + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR is the request fails. + * + * @code + * // the sample range of the accelerometer is now 8G. + * accelerometer.setRange(8); + * @endcode + * + * @note The requested range may not be possible on the hardware. In this case, the + * nearest lower range is chosen. + */ int Accelerometer::setRange(int range) { int result; sampleRange = range; - result = configure(); + result = configure(); sampleRange = getRange(); return result; } /** - * Reads the currently configured sample range of the accelerometer. - * - * @return The sample range, in g. - */ + * Reads the currently configured sample range of the accelerometer. + * + * @return The sample range, in g. + */ int Accelerometer::getRange() { return (int)sampleRange; @@ -416,116 +393,110 @@ int Accelerometer::getZ() } /** - * Provides a rotation compensated pitch of the device, based on the latest update retrieved from the accelerometer. - * - * @return The pitch of the device, in degrees. - * - * @code - * accelerometer.getPitch(); - * @endcode - */ + * Provides a rotation compensated pitch of the device, based on the latest update retrieved from the accelerometer. + * + * @return The pitch of the device, in degrees. + * + * @code + * accelerometer.getPitch(); + * @endcode + */ int Accelerometer::getPitch() { - return (int) ((360*getPitchRadians()) / (2*PI)); + return (int)((360 * getPitchRadians()) / (2 * PI)); } /** - * Provides a rotation compensated pitch of the device, based on the latest update retrieved from the accelerometer. - * - * @return The pitch of the device, in radians. - * - * @code - * accelerometer.getPitchRadians(); - * @endcode - */ + * Provides a rotation compensated pitch of the device, based on the latest update retrieved from the accelerometer. + * + * @return The pitch of the device, in radians. + * + * @code + * accelerometer.getPitchRadians(); + * @endcode + */ float Accelerometer::getPitchRadians() { requestUpdate(); - if (!(status & ACCELEROMETER_IMU_DATA_VALID)) - recalculatePitchRoll(); + if (!(status & ACCELEROMETER_IMU_DATA_VALID)) recalculatePitchRoll(); return pitch; } /** - * Provides a rotation compensated roll of the device, based on the latest update retrieved from the accelerometer. - * - * @return The roll of the device, in degrees. - * - * @code - * accelerometer.getRoll(); - * @endcode - */ + * Provides a rotation compensated roll of the device, based on the latest update retrieved from the accelerometer. + * + * @return The roll of the device, in degrees. + * + * @code + * accelerometer.getRoll(); + * @endcode + */ int Accelerometer::getRoll() { - return (int) ((360*getRollRadians()) / (2*PI)); + return (int)((360 * getRollRadians()) / (2 * PI)); } /** - * Provides a rotation compensated roll of the device, based on the latest update retrieved from the accelerometer. - * - * @return The roll of the device, in radians. - * - * @code - * accelerometer.getRollRadians(); - * @endcode - */ + * Provides a rotation compensated roll of the device, based on the latest update retrieved from the accelerometer. + * + * @return The roll of the device, in radians. + * + * @code + * accelerometer.getRollRadians(); + * @endcode + */ float Accelerometer::getRollRadians() { requestUpdate(); - if (!(status & ACCELEROMETER_IMU_DATA_VALID)) - recalculatePitchRoll(); + if (!(status & ACCELEROMETER_IMU_DATA_VALID)) recalculatePitchRoll(); return roll; } /** - * Recalculate roll and pitch values for the current sample. - * - * @note We only do this at most once per sample, as the necessary trigonemteric functions are rather - * heavyweight for a CPU without a floating point unit. - */ + * Recalculate roll and pitch values for the current sample. + * + * @note We only do this at most once per sample, as the necessary trigonemteric functions are rather + * heavyweight for a CPU without a floating point unit. + */ void Accelerometer::recalculatePitchRoll() { - double x = (double) sample.x; - double y = (double) sample.y; - double z = (double) sample.z; + double x = (double)sample.x; + double y = (double)sample.y; + double z = (double)sample.z; - roll = atan2(x, -z); - pitch = atan2(y, (x*sin(roll) - z*cos(roll))); + roll = atan2(x, -z); + pitch = atan2(y, (x * sin(roll) - z * cos(roll))); // Handle to the two "negative quadrants", such that we get an output in the +/- 18- degree range. // This ensures that the pitch values are consistent with the roll values. - if (z > 0.0) - { + if (z > 0.0) { double reference = pitch > 0.0 ? (PI / 2.0) : (-PI / 2.0); - pitch = reference + (reference - pitch); + pitch = reference + (reference - pitch); } status |= ACCELEROMETER_IMU_DATA_VALID; } /** - * Retrieves the last recorded gesture. - * - * @return The last gesture that was detected. - * - * Example: - * @code - * - * if (accelerometer.getGesture() == SHAKE) - * display.scroll("SHAKE!"); - * @endcode - */ + * Retrieves the last recorded gesture. + * + * @return The last gesture that was detected. + * + * Example: + * @code + * + * if (accelerometer.getGesture() == SHAKE) + * display.scroll("SHAKE!"); + * @endcode + */ uint16_t Accelerometer::getGesture() { return lastGesture; } /** - * Destructor for FXS8700, where we deregister from the array of fiber components. - */ -Accelerometer::~Accelerometer() -{ -} - + * Destructor for FXS8700, where we deregister from the array of fiber components. + */ +Accelerometer::~Accelerometer() {} diff --git a/source/driver-models/CodalUSB.cpp b/source/driver-models/CodalUSB.cpp index 1e0a9629..29642fcc 100644 --- a/source/driver-models/CodalUSB.cpp +++ b/source/driver-models/CodalUSB.cpp @@ -34,15 +34,15 @@ DEALINGS IN THE SOFTWARE. #define NUM_ENDPOINTS(x) (x) #endif -#include "ErrorNo.h" #include "CodalDmesg.h" +#include "ErrorNo.h" #include "codal_target_hal.h" using namespace codal; #define send(p, l) ctrlIn->write(p, l) -CodalUSB *CodalUSB::usbInstance = NULL; +CodalUSB* CodalUSB::usbInstance = NULL; // #define LOG DMESG #define LOG(...) @@ -56,12 +56,12 @@ static uint8_t usb_configured = 0; static const ConfigDescriptor static_config = {9, 2, 0, 0, 1, 0, USB_CONFIG_BUS_POWERED, 0}; static const DeviceDescriptor default_device_desc = { - 0x12, // bLength - 0x01, // bDescriptorType + 0x12, // bLength + 0x01, // bDescriptorType #if CONFIG_ENABLED(DEVICE_WEBUSB) - 0x0210, // bcdUSBL + 0x0210, // bcdUSBL #else - 0x0200, // bcdUSBL + 0x0200, // bcdUSBL #endif #if 0 @@ -73,17 +73,17 @@ static const DeviceDescriptor default_device_desc = { // Class etc specified per-interface 0x00, 0x00, 0x00, #endif - 0x40, // bMaxPacketSize0 - USB_DEFAULT_VID, // - USB_DEFAULT_PID, // - 0x4202, // bcdDevice - leave unchanged for the HF2 to work - 0x01, // iManufacturer - 0x02, // iProduct - 0x03, // SerialNumber - 0x01 // bNumConfigs + 0x40, // bMaxPacketSize0 + USB_DEFAULT_VID, // + USB_DEFAULT_PID, // + 0x4202, // bcdDevice - leave unchanged for the HF2 to work + 0x01, // iManufacturer + 0x02, // iProduct + 0x03, // SerialNumber + 0x01 // bNumConfigs }; -static const char *default_strings[] = { +static const char* default_strings[] = { "CoDAL Devices", "Generic CoDAL device", "4242", @@ -91,52 +91,51 @@ static const char *default_strings[] = { #if CONFIG_ENABLED(DEVICE_WEBUSB) #define VENDOR_WEBUSB 0x40 -#define VENDOR_MS20 0x41 +#define VENDOR_MS20 0x41 -#define WINUSB_SIZE() \ - (sizeof(msOS20Descriptor) + numWebUSBInterfaces * sizeof(msOS20FunctionDescriptor)) +#define WINUSB_SIZE() (sizeof(msOS20Descriptor) + numWebUSBInterfaces * sizeof(msOS20FunctionDescriptor)) static const uint8_t bosDescriptor[] = { - 0x05, // Length - 0x0F, // Binary Object Store descriptor - 0x39, 0x00, // Total length - 0x02, // Number of device capabilities + 0x05, // Length + 0x0F, // Binary Object Store descriptor + 0x39, 0x00, // Total length + 0x02, // Number of device capabilities // WebUSB Platform Capability descriptor (bVendorCode == 0x01). - 0x18, // Length - 0x10, // Device Capability descriptor - 0x05, // Platform Capability descriptor - 0x00, // Reserved - 0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47, // WebUSB GUID - 0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65, // WebUSB GUID - 0x00, 0x01, // Version 1.0 - VENDOR_WEBUSB, // Vendor request code - 0x00, // landing page - - 0x1C, // Length - 0x10, // Device Capability descriptor - 0x05, // Platform Capability descriptor - 0x00, // Reserved - 0xDF, 0x60, 0xDD, 0xD8, 0x89, 0x45, 0xC7, 0x4C, // MS OS 2.0 GUID - 0x9C, 0xD2, 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F, // MS OS 2.0 GUID - 0x00, 0x00, 0x03, 0x06, // Windows version - 0xff, 0xff, // Descriptor set length; bosDescriptor[sizeof(bosDescriptor)-4] - VENDOR_MS20, // Vendor request code - 0x00 // Alternate enumeration code + 0x18, // Length + 0x10, // Device Capability descriptor + 0x05, // Platform Capability descriptor + 0x00, // Reserved + 0x38, 0xB6, 0x08, 0x34, 0xA9, 0x09, 0xA0, 0x47, // WebUSB GUID + 0x8B, 0xFD, 0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65, // WebUSB GUID + 0x00, 0x01, // Version 1.0 + VENDOR_WEBUSB, // Vendor request code + 0x00, // landing page + + 0x1C, // Length + 0x10, // Device Capability descriptor + 0x05, // Platform Capability descriptor + 0x00, // Reserved + 0xDF, 0x60, 0xDD, 0xD8, 0x89, 0x45, 0xC7, 0x4C, // MS OS 2.0 GUID + 0x9C, 0xD2, 0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F, // MS OS 2.0 GUID + 0x00, 0x00, 0x03, 0x06, // Windows version + 0xff, 0xff, // Descriptor set length; bosDescriptor[sizeof(bosDescriptor)-4] + VENDOR_MS20, // Vendor request code + 0x00 // Alternate enumeration code }; static const uint8_t msOS20FunctionDescriptor[] = { // Microsoft OS 2.0 function subset header - 0x08, 0x00, // Descriptor size (8 bytes) - 0x02, 0x00, // MS OS 2.0 function subset header - 0xff, // first interface no; msOS20FunctionDescriptor[4] - 0x00, // Reserved - 160, 0x00, // Size, MS OS 2.0 function subset + 0x08, 0x00, // Descriptor size (8 bytes) + 0x02, 0x00, // MS OS 2.0 function subset header + 0xff, // first interface no; msOS20FunctionDescriptor[4] + 0x00, // Reserved + 160, 0x00, // Size, MS OS 2.0 function subset // Microsoft OS 2.0 compatible ID descriptor (table 13) - 20, 0x00, // wLength - 0x03, 0x00, // MS_OS_20_FEATURE_COMPATIBLE_ID - 'W', 'I', 'N', 'U', 'S', 'B', // + 20, 0x00, // wLength + 0x03, 0x00, // MS_OS_20_FEATURE_COMPATIBLE_ID + 'W', 'I', 'N', 'U', 'S', 'B', // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // interface guids @@ -144,22 +143,21 @@ static const uint8_t msOS20FunctionDescriptor[] = { // 42, 0, // - 'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0, 'I', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, - 'a', 0, 'c', 0, 'e', 0, 'G', 0, 'U', 0, 'I', 0, 'D', 0, 's', 0, 0, 0, + 'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0, 'e', 0, 'I', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0, 'a', 0, 'c', 0, 'e', + 0, 'G', 0, 'U', 0, 'I', 0, 'D', 0, 's', 0, 0, 0, // 80, 0, // - '{', 0, '9', 0, '2', 0, 'C', 0, 'E', 0, '6', 0, '4', 0, '6', 0, '2', 0, '-', 0, '9', 0, 'C', 0, - '7', 0, '7', 0, '-', 0, '4', 0, '6', 0, 'F', 0, 'E', 0, '-', 0, '9', 0, '3', 0, '3', 0, 'B', 0, - '-', 0, '3', 0, '1', 0, 'C', 0, 'B', 0, '9', 0, 'C', 0, '5', 0, 'A', 0, 'A', 0, '3', 0, 'B', 0, - 'A', 0, '}', 0, 0, 0, 0, 0}; + '{', 0, '9', 0, '2', 0, 'C', 0, 'E', 0, '6', 0, '4', 0, '6', 0, '2', 0, '-', 0, '9', 0, 'C', 0, '7', 0, '7', 0, '-', + 0, '4', 0, '6', 0, 'F', 0, 'E', 0, '-', 0, '9', 0, '3', 0, '3', 0, 'B', 0, '-', 0, '3', 0, '1', 0, 'C', 0, 'B', 0, + '9', 0, 'C', 0, '5', 0, 'A', 0, 'A', 0, '3', 0, 'B', 0, 'A', 0, '}', 0, 0, 0, 0, 0}; static const uint8_t msOS20Descriptor[] = { // Microsoft OS 2.0 descriptor set header (table 10) - 0x0A, 0x00, // Descriptor size (10 bytes) - 0x00, 0x00, // MS OS 2.0 descriptor set header - 0x00, 0x00, 0x03, 0x06, // Windows version (8.1) (0x06030000) - 0xff, 0xff, // Size, MS OS 2.0 descriptor set + 0x0A, 0x00, // Descriptor size (10 bytes) + 0x00, 0x00, // MS OS 2.0 descriptor set header + 0x00, 0x00, 0x03, 0x06, // Windows version (8.1) (0x06030000) + 0xff, 0xff, // Size, MS OS 2.0 descriptor set }; #endif @@ -168,18 +166,18 @@ static const InterfaceInfo codalDummyIfaceInfo = { 0, 0, { - 0, // numEndpoints - 0xff, /// class code - vendor-specific - 0xff, // subclass - 0xff, // protocol - 0x00, // string - 0x00, // alt + 0, // numEndpoints + 0xff, /// class code - vendor-specific + 0xff, // subclass + 0xff, // protocol + 0x00, // string + 0x00, // alt }, {0, 0}, {0, 0}, }; -const InterfaceInfo *CodalDummyUSBInterface::getInterfaceInfo() +const InterfaceInfo* CodalDummyUSBInterface::getInterfaceInfo() { return &codalDummyIfaceInfo; } @@ -187,89 +185,83 @@ const InterfaceInfo *CodalDummyUSBInterface::getInterfaceInfo() CodalUSB::CodalUSB(uint16_t id) { // Store our identifiers. - this->id = id; - this->status = 0; - usbInstance = this; - endpointsUsed = 1; // CTRL endpoint - ctrlIn = NULL; - ctrlOut = NULL; + this->id = id; + this->status = 0; + usbInstance = this; + endpointsUsed = 1; // CTRL endpoint + ctrlIn = NULL; + ctrlOut = NULL; numStringDescriptors = sizeof(default_strings) / sizeof(default_strings[0]); - stringDescriptors = default_strings; - deviceDescriptor = &default_device_desc; - startDelayCount = 1; - interfaces = NULL; - numWebUSBInterfaces = 0; - maxPower = 50; // 100mA; if set to 500mA can't connect to iOS devices + stringDescriptors = default_strings; + deviceDescriptor = &default_device_desc; + startDelayCount = 1; + interfaces = NULL; + numWebUSBInterfaces = 0; + maxPower = 50; // 100mA; if set to 500mA can't connect to iOS devices } -void CodalUSBInterface::fillInterfaceInfo(InterfaceDescriptor *descp) +void CodalUSBInterface::fillInterfaceInfo(InterfaceDescriptor* descp) { - const InterfaceInfo *info = this->getInterfaceInfo(); - InterfaceDescriptor desc = { - sizeof(InterfaceDescriptor), - 4, // type - this->interfaceIdx, - info->iface.alternate, - info->iface.numEndpoints, - info->iface.interfaceClass, - info->iface.interfaceSubClass, - info->iface.protocol, - info->iface.iInterfaceString, + const InterfaceInfo* info = this->getInterfaceInfo(); + InterfaceDescriptor desc = { + sizeof(InterfaceDescriptor), + 4, // type + this->interfaceIdx, + info->iface.alternate, + info->iface.numEndpoints, + info->iface.interfaceClass, + info->iface.interfaceSubClass, + info->iface.protocol, + info->iface.iInterfaceString, }; *descp = desc; } int CodalUSB::sendConfig() { - const InterfaceInfo *info; + const InterfaceInfo* info; int numInterfaces = 0; - int clen = sizeof(ConfigDescriptor); + int clen = sizeof(ConfigDescriptor); // calculate the total size of our interfaces. - for (CodalUSBInterface *iface = interfaces; iface; iface = iface->next) - { + for (CodalUSBInterface* iface = interfaces; iface; iface = iface->next) { info = iface->getInterfaceInfo(); - clen += sizeof(InterfaceDescriptor) + - info->iface.numEndpoints * sizeof(EndpointDescriptor) + + clen += sizeof(InterfaceDescriptor) + info->iface.numEndpoints * sizeof(EndpointDescriptor) + info->supplementalDescriptorSize; numInterfaces++; } - uint8_t *buf = new uint8_t[clen]; + uint8_t* buf = new uint8_t[clen]; memcpy(buf, &static_config, sizeof(ConfigDescriptor)); - ((ConfigDescriptor *)buf)->clen = clen; - ((ConfigDescriptor *)buf)->numInterfaces = numInterfaces; - ((ConfigDescriptor *)buf)->maxPower = maxPower; - clen = sizeof(ConfigDescriptor); + ((ConfigDescriptor*)buf)->clen = clen; + ((ConfigDescriptor*)buf)->numInterfaces = numInterfaces; + ((ConfigDescriptor*)buf)->maxPower = maxPower; + clen = sizeof(ConfigDescriptor); -#define ADD_DESC(desc) \ - memcpy(buf + clen, &desc, sizeof(desc)); \ +#define ADD_DESC(desc) \ + memcpy(buf + clen, &desc, sizeof(desc)); \ clen += sizeof(desc) // send our descriptors - for (CodalUSBInterface *iface = interfaces; iface; iface = iface->next) - { + for (CodalUSBInterface* iface = interfaces; iface; iface = iface->next) { info = iface->getInterfaceInfo(); InterfaceDescriptor desc; iface->fillInterfaceInfo(&desc); ADD_DESC(desc); - if (info->supplementalDescriptorSize) - { + if (info->supplementalDescriptorSize) { memcpy(buf + clen, info->supplementalDescriptor, info->supplementalDescriptorSize); clen += info->supplementalDescriptorSize; } - if (info->iface.numEndpoints == 0) - { + if (info->iface.numEndpoints == 0) { // OK } - if (info->iface.numEndpoints >= 1) - { + if (info->iface.numEndpoints >= 1) { EndpointDescriptor epdescIn = { sizeof(EndpointDescriptor), - 5, // type + 5, // type (uint8_t)(0x80 | iface->in->ep), info->epIn.attr, USB_MAX_PKT_SIZE, @@ -278,11 +270,10 @@ int CodalUSB::sendConfig() ADD_DESC(epdescIn); } - if (info->iface.numEndpoints >= 2) - { + if (info->iface.numEndpoints >= 2) { EndpointDescriptor epdescOut = { sizeof(EndpointDescriptor), - 5, // type + 5, // type iface->out->ep, info->epIn.attr, USB_MAX_PKT_SIZE, @@ -291,13 +282,12 @@ int CodalUSB::sendConfig() ADD_DESC(epdescOut); } - if (info->iface.numEndpoints >= 3) - { + if (info->iface.numEndpoints >= 3) { usb_assert(0); } } - usb_assert(clen == ((ConfigDescriptor *)buf)->clen); + usb_assert(clen == ((ConfigDescriptor*)buf)->clen); send(buf, clen); @@ -309,19 +299,16 @@ int CodalUSB::sendConfig() // languageID - United States static const uint8_t string0[] = {4, 3, 9, 4}; -int CodalUSB::sendDescriptors(USBSetup &setup) +int CodalUSB::sendDescriptors(USBSetup& setup) { uint8_t type = setup.wValueH; - if (type == USB_CONFIGURATION_DESCRIPTOR_TYPE) - return sendConfig(); + if (type == USB_CONFIGURATION_DESCRIPTOR_TYPE) return sendConfig(); - if (type == USB_DEVICE_DESCRIPTOR_TYPE) - return send(deviceDescriptor, sizeof(DeviceDescriptor)); + if (type == USB_DEVICE_DESCRIPTOR_TYPE) return send(deviceDescriptor, sizeof(DeviceDescriptor)); #if CONFIG_ENABLED(DEVICE_WEBUSB) - if (type == USB_BOS_DESCRIPTOR_TYPE && numWebUSBInterfaces > 0) - { + if (type == USB_BOS_DESCRIPTOR_TYPE && numWebUSBInterfaces > 0) { uint8_t buf[sizeof(bosDescriptor)]; memcpy(buf, bosDescriptor, sizeof(buf)); buf[sizeof(bosDescriptor) - 4] = WINUSB_SIZE() & 0xff; @@ -330,72 +317,61 @@ int CodalUSB::sendDescriptors(USBSetup &setup) } #endif - if (type == USB_STRING_DESCRIPTOR_TYPE) - { + if (type == USB_STRING_DESCRIPTOR_TYPE) { // check if we exceed our bounds. - if (setup.wValueL > numStringDescriptors) - return DEVICE_NOT_SUPPORTED; + if (setup.wValueL > numStringDescriptors) return DEVICE_NOT_SUPPORTED; - if (setup.wValueL == 0) - return send(string0, sizeof(string0)); + if (setup.wValueL == 0) return send(string0, sizeof(string0)); StringDescriptor desc; - const char *str = stringDescriptors[setup.wValueL - 1]; - if (!str) - return DEVICE_NOT_SUPPORTED; + const char* str = stringDescriptors[setup.wValueL - 1]; + if (!str) return DEVICE_NOT_SUPPORTED; - desc.type = 3; + desc.type = 3; uint32_t len = strlen(str) * 2 + 2; - desc.len = len; + desc.len = len; usb_assert(len <= sizeof(desc)); int i = 0; - while (*str) - desc.data[i++] = *str++; + while (*str) desc.data[i++] = *str++; // send the string descriptor the host asked for. return send(&desc, desc.len); } - else - { + else { return interfaceRequest(setup, false); } return DEVICE_NOT_SUPPORTED; } -CodalUSB *CodalUSB::getInstance() +CodalUSB* CodalUSB::getInstance() { - if (usbInstance == NULL) - usbInstance = new CodalUSB; + if (usbInstance == NULL) usbInstance = new CodalUSB; return usbInstance; } -int CodalUSB::add(CodalUSBInterface &interface) +int CodalUSB::add(CodalUSBInterface& interface) { usb_assert(!usb_configured); uint8_t epsConsumed = NUM_ENDPOINTS(interface.getInterfaceInfo()->allocateEndpoints); - if (endpointsUsed + epsConsumed > DEVICE_USB_ENDPOINTS) - return DEVICE_NO_RESOURCES; + if (endpointsUsed + epsConsumed > DEVICE_USB_ENDPOINTS) return DEVICE_NO_RESOURCES; interface.interfaceIdx = 0xff; - CodalUSBInterface *iface; + CodalUSBInterface* iface; interface.next = NULL; - for (iface = interfaces; iface; iface = iface->next) - { - if (!iface->next) - break; + for (iface = interfaces; iface; iface = iface->next) { + if (!iface->next) break; #if CONFIG_ENABLED(DEVICE_WEBUSB) // adding a non-web interface - it comes before all web interfaces - if (!interface.enableWebUSB() && iface->next->enableWebUSB()) - { + if (!interface.enableWebUSB() && iface->next->enableWebUSB()) { interface.next = iface->next; break; } @@ -417,10 +393,10 @@ int CodalUSB::isInitialised() return usb_initialised > 0; } -int CodalUSB::interfaceRequest(USBSetup &setup, bool isClass) +int CodalUSB::interfaceRequest(USBSetup& setup, bool isClass) { int ifaceIdx = -1; - int epIdx = -1; + int epIdx = -1; if ((setup.bmRequestType & USB_REQ_DESTINATION) == USB_REQ_INTERFACE) ifaceIdx = setup.wIndex & 0xff; @@ -429,16 +405,12 @@ int CodalUSB::interfaceRequest(USBSetup &setup, bool isClass) LOG("iface req: ifaceIdx=%d epIdx=%d", ifaceIdx, epIdx); - for (CodalUSBInterface *iface = interfaces; iface; iface = iface->next) - { + for (CodalUSBInterface* iface = interfaces; iface; iface = iface->next) { if (iface->interfaceIdx == ifaceIdx || - ((iface->in && iface->in->ep == epIdx) || (iface->out && iface->out->ep == epIdx))) - { - int res = - isClass ? iface->classRequest(*ctrlIn, setup) : iface->stdRequest(*ctrlIn, setup); + ((iface->in && iface->in->ep == epIdx) || (iface->out && iface->out->ep == epIdx))) { + int res = isClass ? iface->classRequest(*ctrlIn, setup) : iface->stdRequest(*ctrlIn, setup); LOG("iface req res=%d", res); - if (res == DEVICE_OK) - return DEVICE_OK; + if (res == DEVICE_OK) return DEVICE_OK; } } @@ -446,142 +418,127 @@ int CodalUSB::interfaceRequest(USBSetup &setup, bool isClass) } #define sendzlp() send(&usb_status, 0) -#define stall ctrlIn->stall +#define stall ctrlIn->stall -void CodalUSB::setupRequest(USBSetup &setup) +void CodalUSB::setupRequest(USBSetup& setup) { - LOG("SETUP Req=%x type=%x val=%x:%x idx=%x len=%d", setup.bRequest, setup.bmRequestType, - setup.wValueH, setup.wValueL, setup.wIndex, setup.wLength); + LOG("SETUP Req=%x type=%x val=%x:%x idx=%x len=%d", setup.bRequest, setup.bmRequestType, setup.wValueH, + setup.wValueL, setup.wIndex, setup.wLength); int transactionStatus = DEVICE_OK; // Standard Requests - uint16_t wValue = (setup.wValueH << 8) | setup.wValueL; + uint16_t wValue = (setup.wValueH << 8) | setup.wValueL; uint8_t request_type = setup.bmRequestType; - uint16_t wStatus = 0; + uint16_t wStatus = 0; ctrlIn->wLength = setup.wLength; - if ((request_type & USB_REQ_TYPE) == USB_REQ_STANDARD) - { + if ((request_type & USB_REQ_TYPE) == USB_REQ_STANDARD) { LOG("STD REQ"); - switch (setup.bRequest) - { - case USB_REQ_GET_STATUS: - LOG("STA"); - if (request_type == (USB_REQ_DEVICETOHOST | USB_REQ_STANDARD | USB_REQ_DEVICE)) - { - wStatus = usb_status; - } - send(&wStatus, sizeof(wStatus)); - break; - - case USB_REQ_CLEAR_FEATURE: - LOG("CLR FEA"); - if ((request_type == (USB_REQ_HOSTTODEVICE | USB_REQ_STANDARD | USB_REQ_DEVICE)) && - (wValue == USB_DEVICE_REMOTE_WAKEUP)) - usb_status &= ~USB_FEATURE_REMOTE_WAKEUP_ENABLED; - - if (request_type == (USB_REQ_HOSTTODEVICE | USB_REQ_STANDARD | USB_REQ_ENDPOINT)) - { - for (CodalUSBInterface *iface = interfaces; iface; iface = iface->next) - { - if (iface->in && iface->in->ep == (setup.wIndex & 0x7f)) - iface->in->clearStall(); - else if (iface->out && iface->out->ep == (setup.wIndex & 0x7f)) - iface->out->clearStall(); + switch (setup.bRequest) { + case USB_REQ_GET_STATUS: + LOG("STA"); + if (request_type == (USB_REQ_DEVICETOHOST | USB_REQ_STANDARD | USB_REQ_DEVICE)) { + wStatus = usb_status; + } + send(&wStatus, sizeof(wStatus)); + break; + + case USB_REQ_CLEAR_FEATURE: + LOG("CLR FEA"); + if ((request_type == (USB_REQ_HOSTTODEVICE | USB_REQ_STANDARD | USB_REQ_DEVICE)) && + (wValue == USB_DEVICE_REMOTE_WAKEUP)) + usb_status &= ~USB_FEATURE_REMOTE_WAKEUP_ENABLED; + + if (request_type == (USB_REQ_HOSTTODEVICE | USB_REQ_STANDARD | USB_REQ_ENDPOINT)) { + for (CodalUSBInterface* iface = interfaces; iface; iface = iface->next) { + if (iface->in && iface->in->ep == (setup.wIndex & 0x7f)) + iface->in->clearStall(); + else if (iface->out && iface->out->ep == (setup.wIndex & 0x7f)) + iface->out->clearStall(); + } } - } - sendzlp(); - break; - case USB_REQ_SET_FEATURE: - LOG("SET FEA"); - if ((request_type == (USB_REQ_HOSTTODEVICE | USB_REQ_STANDARD | USB_REQ_DEVICE)) && - (wValue == USB_DEVICE_REMOTE_WAKEUP)) - usb_status |= USB_FEATURE_REMOTE_WAKEUP_ENABLED; - sendzlp(); - break; - case USB_REQ_SET_ADDRESS: - LOG("SET ADDR"); - usb_set_address_pre(wValue); - sendzlp(); - usb_set_address(wValue); - break; - case USB_REQ_GET_DESCRIPTOR: - LOG("GET DESC"); - transactionStatus = sendDescriptors(setup); - break; - case USB_REQ_SET_DESCRIPTOR: - LOG("SET DESC"); - stall(); - break; - case USB_REQ_GET_CONFIGURATION: - LOG("GET CONF"); - wStatus = 1; - send(&wStatus, 1); - break; - - case USB_REQ_SET_CONFIGURATION: - LOG("SET CONF"); - if (USB_REQ_DEVICE == (request_type & USB_REQ_DESTINATION)) - { - usb_initialised = setup.wValueL; sendzlp(); - } - else - transactionStatus = DEVICE_NOT_SUPPORTED; - break; + break; + case USB_REQ_SET_FEATURE: + LOG("SET FEA"); + if ((request_type == (USB_REQ_HOSTTODEVICE | USB_REQ_STANDARD | USB_REQ_DEVICE)) && + (wValue == USB_DEVICE_REMOTE_WAKEUP)) + usb_status |= USB_FEATURE_REMOTE_WAKEUP_ENABLED; + sendzlp(); + break; + case USB_REQ_SET_ADDRESS: + LOG("SET ADDR"); + usb_set_address_pre(wValue); + sendzlp(); + usb_set_address(wValue); + break; + case USB_REQ_GET_DESCRIPTOR: + LOG("GET DESC"); + transactionStatus = sendDescriptors(setup); + break; + case USB_REQ_SET_DESCRIPTOR: + LOG("SET DESC"); + stall(); + break; + case USB_REQ_GET_CONFIGURATION: + LOG("GET CONF"); + wStatus = 1; + send(&wStatus, 1); + break; + + case USB_REQ_SET_CONFIGURATION: + LOG("SET CONF"); + if (USB_REQ_DEVICE == (request_type & USB_REQ_DESTINATION)) { + usb_initialised = setup.wValueL; + sendzlp(); + } + else + transactionStatus = DEVICE_NOT_SUPPORTED; + break; } } #if CONFIG_ENABLED(DEVICE_WEBUSB) - else if ((request_type & USB_REQ_TYPE) == USB_REQ_VENDOR) - { - switch (setup.bRequest) - { - case VENDOR_MS20: - if (numWebUSBInterfaces == 0) - { - transactionStatus = DEVICE_NOT_SUPPORTED; - } - else - { - uint8_t buf[WINUSB_SIZE()]; - memcpy(buf, msOS20Descriptor, sizeof(msOS20Descriptor)); - buf[8] = WINUSB_SIZE(); - buf[9] = WINUSB_SIZE() >> 8; - uint32_t ptr = sizeof(msOS20Descriptor); - - for (CodalUSBInterface *iface = interfaces; iface; iface = iface->next) - { - if (iface->enableWebUSB()) - { - memcpy(buf + ptr, msOS20FunctionDescriptor, - sizeof(msOS20FunctionDescriptor)); - buf[ptr + 4] = iface->interfaceIdx; - ptr += sizeof(msOS20FunctionDescriptor); - } + else if ((request_type & USB_REQ_TYPE) == USB_REQ_VENDOR) { + switch (setup.bRequest) { + case VENDOR_MS20: + if (numWebUSBInterfaces == 0) { + transactionStatus = DEVICE_NOT_SUPPORTED; } + else { + uint8_t buf[WINUSB_SIZE()]; + memcpy(buf, msOS20Descriptor, sizeof(msOS20Descriptor)); + buf[8] = WINUSB_SIZE(); + buf[9] = WINUSB_SIZE() >> 8; + uint32_t ptr = sizeof(msOS20Descriptor); + + for (CodalUSBInterface* iface = interfaces; iface; iface = iface->next) { + if (iface->enableWebUSB()) { + memcpy(buf + ptr, msOS20FunctionDescriptor, sizeof(msOS20FunctionDescriptor)); + buf[ptr + 4] = iface->interfaceIdx; + ptr += sizeof(msOS20FunctionDescriptor); + } + } - usb_assert(ptr == sizeof(buf)); + usb_assert(ptr == sizeof(buf)); - send(buf, sizeof(buf)); - } - break; + send(buf, sizeof(buf)); + } + break; - case VENDOR_WEBUSB: - // this is the place for the WebUSB landing page, if we ever want to do that - transactionStatus = DEVICE_NOT_IMPLEMENTED; - break; + case VENDOR_WEBUSB: + // this is the place for the WebUSB landing page, if we ever want to do that + transactionStatus = DEVICE_NOT_IMPLEMENTED; + break; } } #endif - else - { + else { transactionStatus = interfaceRequest(setup, true); } - if (transactionStatus < 0) - stall(); + if (transactionStatus < 0) stall(); // sending response clears this - make sure we did usb_assert(ctrlIn->wLength == 0); @@ -589,62 +546,53 @@ void CodalUSB::setupRequest(USBSetup &setup) void CodalUSB::interruptHandler() { - for (CodalUSBInterface *iface = interfaces; iface; iface = iface->next) - iface->endpointRequest(); + for (CodalUSBInterface* iface = interfaces; iface; iface = iface->next) iface->endpointRequest(); } void CodalUSB::initEndpoints() { uint8_t endpointCount = 1; - uint8_t ifaceCount = 0; + uint8_t ifaceCount = 0; - if (ctrlIn) - { + if (ctrlIn) { delete ctrlIn; delete ctrlOut; } - ctrlIn = new UsbEndpointIn(0, USB_EP_TYPE_CONTROL); + ctrlIn = new UsbEndpointIn(0, USB_EP_TYPE_CONTROL); ctrlOut = new UsbEndpointOut(0, USB_EP_TYPE_CONTROL); #if CONFIG_ENABLED(DEVICE_WEBUSB) numWebUSBInterfaces = 0; #endif - for (CodalUSBInterface *iface = interfaces; iface; iface = iface->next) - { + for (CodalUSBInterface* iface = interfaces; iface; iface = iface->next) { iface->interfaceIdx = ifaceCount++; #if CONFIG_ENABLED(DEVICE_WEBUSB) - if (iface->enableWebUSB()) - numWebUSBInterfaces++; + if (iface->enableWebUSB()) numWebUSBInterfaces++; #endif - const InterfaceInfo *info = iface->getInterfaceInfo(); + const InterfaceInfo* info = iface->getInterfaceInfo(); usb_assert(0 <= info->allocateEndpoints && info->allocateEndpoints <= 2); - usb_assert(info->allocateEndpoints <= info->iface.numEndpoints && - info->iface.numEndpoints <= 2); + usb_assert(info->allocateEndpoints <= info->iface.numEndpoints && info->iface.numEndpoints <= 2); - if (iface->in) - { + if (iface->in) { delete iface->in; iface->in = NULL; } - if (iface->out) - { + if (iface->out) { delete iface->out; iface->out = NULL; } uint8_t numep = NUM_ENDPOINTS(info->allocateEndpoints); - if (info->iface.numEndpoints > 0) - { + if (info->iface.numEndpoints > 0) { iface->in = new UsbEndpointIn(endpointCount, info->epIn.attr); - if (info->iface.numEndpoints > 1) - { + if (info->iface.numEndpoints > 1) { iface->out = new UsbEndpointOut(endpointCount + (numep - 1), info->epIn.attr); } } @@ -657,19 +605,16 @@ void CodalUSB::initEndpoints() int CodalUSB::start() { - if (--startDelayCount > 0) - { + if (--startDelayCount > 0) { DMESG("USB start delayed"); return DEVICE_OK; } DMESG("USB start"); - if (DEVICE_USB_ENDPOINTS == 0) - return DEVICE_NOT_SUPPORTED; + if (DEVICE_USB_ENDPOINTS == 0) return DEVICE_NOT_SUPPORTED; - if (usb_configured) - return DEVICE_OK; + if (usb_configured) return DEVICE_OK; usb_configured = 1; diff --git a/source/driver-models/Compass.cpp b/source/driver-models/Compass.cpp index 18a4a6bc..499a229e 100644 --- a/source/driver-models/Compass.cpp +++ b/source/driver-models/Compass.cpp @@ -23,10 +23,11 @@ DEALINGS IN THE SOFTWARE. */ #include "Compass.h" -#include "ErrorNo.h" -#include "Event.h" + #include "CodalCompat.h" #include "CodalFiber.h" +#include "ErrorNo.h" +#include "Event.h" #define CALIBRATED_SAMPLE(sample, axis) (((sample.axis - calibration.centre.axis) * calibration.scale.axis) >> 10) @@ -40,7 +41,7 @@ using namespace codal; * @param coordinateSpace the orientation of the sensor. Defaults to: SIMPLE_CARTESIAN * */ -Compass::Compass(CoordinateSpace &cspace, uint16_t id) : sample(), sampleENU(), coordinateSpace(cspace) +Compass::Compass(CoordinateSpace& cspace, uint16_t id) : sample(), sampleENU(), coordinateSpace(cspace) { accelerometer = NULL; init(id); @@ -55,7 +56,8 @@ Compass::Compass(CoordinateSpace &cspace, uint16_t id) : sample(), sampleENU(), * @param coordinateSpace the orientation of the sensor. Defaults to: SIMPLE_CARTESIAN * */ -Compass::Compass(Accelerometer &accel, CoordinateSpace &cspace, uint16_t id) : sample(), sampleENU(), coordinateSpace(cspace) +Compass::Compass(Accelerometer& accel, CoordinateSpace& cspace, uint16_t id) + : sample(), sampleENU(), coordinateSpace(cspace) { accelerometer = &accel; init(id); @@ -69,7 +71,7 @@ Compass::Compass(Accelerometer &accel, CoordinateSpace &cspace, uint16_t id) : void Compass::init(uint16_t id) { // Store our identifiers. - this->id = id; + this->id = id; this->status = 0; // Set a default rate of 50Hz. @@ -82,7 +84,6 @@ void Compass::init(uint16_t id) status |= DEVICE_COMPONENT_RUNNING; } - /** * Gets the current heading of the device, relative to magnetic north. * @@ -100,14 +101,11 @@ void Compass::init(uint16_t id) */ int Compass::heading() { - if(status & COMPASS_STATUS_CALIBRATING) - return DEVICE_CALIBRATION_IN_PROGRESS; + if (status & COMPASS_STATUS_CALIBRATING) return DEVICE_CALIBRATION_IN_PROGRESS; - if(!(status & COMPASS_STATUS_CALIBRATED)) - calibrate(); + if (!(status & COMPASS_STATUS_CALIBRATED)) calibrate(); - if(accelerometer != NULL) - return tiltCompensatedBearing(); + if (accelerometer != NULL) return tiltCompensatedBearing(); return basicBearing(); } @@ -129,7 +127,7 @@ int Compass::getFieldStrength() double y = s.y; double z = s.z; - return (int) sqrt(x*x + y*y + z*z); + return (int)sqrt(x * x + y * y + z * z); } /** @@ -148,8 +146,7 @@ int Compass::getFieldStrength() int Compass::calibrate() { // Only perform one calibration process at a time. - if(isCalibrating()) - return DEVICE_CALIBRATION_IN_PROGRESS; + if (isCalibrating()) return DEVICE_CALIBRATION_IN_PROGRESS; requestUpdate(); @@ -165,9 +162,9 @@ int Compass::calibrate() // Record that we've finished calibrating. status &= ~COMPASS_STATUS_CALIBRATING; - // If there are no changes to our sample data, we either have no calibration algorithm, or it couldn't complete succesfully. - if(!(status & COMPASS_STATUS_CALIBRATED)) - return DEVICE_CALIBRATION_REQUIRED; + // If there are no changes to our sample data, we either have no calibration algorithm, or it couldn't complete + // succesfully. + if (!(status & COMPASS_STATUS_CALIBRATED)) return DEVICE_CALIBRATION_REQUIRED; return DEVICE_OK; } @@ -231,7 +228,7 @@ void Compass::clearCalibration() * * @param acceleromter Reference to the accelerometer to use. */ -void Compass::setAccelerometer(Accelerometer &accelerometer) +void Compass::setAccelerometer(Accelerometer& accelerometer) { this->accelerometer = &accelerometer; } @@ -252,11 +249,10 @@ int Compass::setPeriod(int period) int result; samplePeriod = period; - result = configure(); + result = configure(); samplePeriod = getPeriod(); return result; - } /** @@ -288,7 +284,8 @@ int Compass::update() sampleENU.y = CALIBRATED_SAMPLE(sampleENU, y); sampleENU.z = CALIBRATED_SAMPLE(sampleENU, z); - // Store the user accessible data, in the requested coordinate space, and taking into account component placement of the sensor. + // Store the user accessible data, in the requested coordinate space, and taking into account component placement of + // the sensor. sample = coordinateSpace.transform(sampleENU); // Indicate that a new sample is available @@ -361,32 +358,32 @@ int Compass::getZ() int Compass::tiltCompensatedBearing() { // Precompute the tilt compensation parameters to improve readability. - float phi = accelerometer->getRollRadians(); + float phi = accelerometer->getRollRadians(); float theta = accelerometer->getPitchRadians(); Sample3D s = getSample(NORTH_EAST_DOWN); - float x = (float) s.x; - float y = (float) s.y; - float z = (float) s.z; + float x = (float)s.x; + float y = (float)s.y; + float z = (float)s.z; // Precompute cos and sin of pitch and roll angles to make the calculation a little more efficient. - float sinPhi = sin(phi); - float cosPhi = cos(phi); + float sinPhi = sin(phi); + float cosPhi = cos(phi); float sinTheta = sin(theta); float cosTheta = cos(theta); - // Calculate the tilt compensated bearing, and convert to degrees. - float bearing = (360*atan2(x*cosTheta + y*sinTheta*sinPhi + z*sinTheta*cosPhi, z*sinPhi - y*cosPhi)) / (2*PI); + // Calculate the tilt compensated bearing, and convert to degrees. + float bearing = + (360 * atan2(x * cosTheta + y * sinTheta * sinPhi + z * sinTheta * cosPhi, z * sinPhi - y * cosPhi)) / (2 * PI); // Handle the 90 degree offset caused by the NORTH_EAST_DOWN based calculation. bearing = 90 - bearing; // Ensure the calculated bearing is in the 0..359 degree range. - if (bearing < 0) - bearing += 360.0f; + if (bearing < 0) bearing += 360.0f; - return (int) (bearing); + return (int)(bearing); } /** @@ -396,22 +393,17 @@ int Compass::basicBearing() { // Convert to floating point to reduce rounding errors Sample3D cs = this->getSample(SIMPLE_CARTESIAN); - float x = (float) cs.x; - float y = (float) cs.y; + float x = (float)cs.x; + float y = (float)cs.y; - float bearing = (atan2(x,y))*180/PI; + float bearing = (atan2(x, y)) * 180 / PI; - if (bearing < 0) - bearing += 360.0; + if (bearing < 0) bearing += 360.0; return (int)bearing; } /** - * Destructor. - */ -Compass::~Compass() -{ -} - - + * Destructor. + */ +Compass::~Compass() {} diff --git a/source/driver-models/Display.cpp b/source/driver-models/Display.cpp index a34c61c4..26bdf7e1 100644 --- a/source/driver-models/Display.cpp +++ b/source/driver-models/Display.cpp @@ -23,10 +23,11 @@ DEALINGS IN THE SOFTWARE. */ /** - * Class definition for an abstract display. - * - */ + * Class definition for an abstract display. + * + */ #include "Display.h" + #include "ErrorNo.h" using namespace codal; @@ -41,10 +42,10 @@ using namespace codal; */ Display::Display(int width, int height, uint16_t id) : image(width, height) { - this->width = width; - this->height = height; + this->width = width; + this->height = height; this->brightness = 255; - this->id = id; + this->id = id; } /** @@ -78,55 +79,45 @@ int Display::getHeight() */ int Display::setBrightness(int b) { - //sanitise the brightness level - if(b < 0 || b > 255) - return DEVICE_INVALID_PARAMETER; + // sanitise the brightness level + if (b < 0 || b > 255) return DEVICE_INVALID_PARAMETER; this->brightness = b; return DEVICE_OK; } - /** - * Fetches the current brightness of this display. - * - * @return the brightness of this display, in the range 0..255. - */ + * Fetches the current brightness of this display. + * + * @return the brightness of this display, in the range 0..255. + */ int Display::getBrightness() { return this->brightness; } - /** - * Enable the display. - */ -void Display::enable() -{ -} + * Enable the display. + */ +void Display::enable() {} /** - * Disable the display. - */ -void Display::disable() -{ -} + * Disable the display. + */ +void Display::disable() {} /** - * Captures the bitmap currently being rendered on the display. - * - * @return an Image containing the captured data. - */ + * Captures the bitmap currently being rendered on the display. + * + * @return an Image containing the captured data. + */ Image Display::screenShot() { - return image.crop(0,0, width, height); + return image.crop(0, 0, width, height); } - /** - * Destructor. - */ -Display::~Display() -{ -} \ No newline at end of file + * Destructor. + */ +Display::~Display() {} \ No newline at end of file diff --git a/source/driver-models/Gyroscope.cpp b/source/driver-models/Gyroscope.cpp index 1d568af7..9d1a1a10 100644 --- a/source/driver-models/Gyroscope.cpp +++ b/source/driver-models/Gyroscope.cpp @@ -24,51 +24,51 @@ DEALINGS IN THE SOFTWARE. */ #include "Gyroscope.h" -#include "ErrorNo.h" -#include "Event.h" + #include "CodalCompat.h" #include "CodalFiber.h" +#include "ErrorNo.h" +#include "Event.h" using namespace codal; - /** - * Constructor. - * Create a software abstraction of an FXSO8700 combined accelerometer/magnetometer - * - * @param _i2c an instance of I2C used to communicate with the device. - * - * @param address the default I2C address of the accelerometer. Defaults to: FXS8700_DEFAULT_ADDR. - * + * Constructor. + * Create a software abstraction of an FXSO8700 combined accelerometer/magnetometer + * + * @param _i2c an instance of I2C used to communicate with the device. + * + * @param address the default I2C address of the accelerometer. Defaults to: FXS8700_DEFAULT_ADDR. + * */ -Gyroscope::Gyroscope(CoordinateSpace &cspace, uint16_t id) : sample(), sampleENU(), coordinateSpace(cspace) +Gyroscope::Gyroscope(CoordinateSpace& cspace, uint16_t id) : sample(), sampleENU(), coordinateSpace(cspace) { // Store our identifiers. - this->id = id; + this->id = id; this->status = 0; // Set a default rate of 50Hz and a +/-2g range. this->samplePeriod = 20; - this->sampleRange = 2; + this->sampleRange = 2; } /** - * Stores data from the accelerometer sensor in our buffer, and perform gesture tracking. - * - * On first use, this member function will attempt to add this component to the - * list of fiber components in order to constantly update the values stored - * by this object. - * - * This lazy instantiation means that we do not - * obtain the overhead from non-chalantly adding this component to fiber components. - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the read request fails. - */ + * Stores data from the accelerometer sensor in our buffer, and perform gesture tracking. + * + * On first use, this member function will attempt to add this component to the + * list of fiber components in order to constantly update the values stored + * by this object. + * + * This lazy instantiation means that we do not + * obtain the overhead from non-chalantly adding this component to fiber components. + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the read request fails. + */ int Gyroscope::update(Sample3D s) { // Store the new data, after performing any necessary coordinate transformations. sampleENU = s; - sample = coordinateSpace.transform(s); + sample = coordinateSpace.transform(s); // Indicate that pitch and roll data is now stale, and needs to be recalculated if needed. status &= ~GYROSCOPE_IMU_DATA_VALID; @@ -80,90 +80,90 @@ int Gyroscope::update(Sample3D s) }; /** - * A service function. - * It calculates the current scalar acceleration of the device (x^2 + y^2 + z^2). - * It does not, however, square root the result, as this is a relatively high cost operation. - * - * This is left to application code should it be needed. - * - * @return the sum of the square of the acceleration of the device across all axes. - */ + * A service function. + * It calculates the current scalar acceleration of the device (x^2 + y^2 + z^2). + * It does not, however, square root the result, as this is a relatively high cost operation. + * + * This is left to application code should it be needed. + * + * @return the sum of the square of the acceleration of the device across all axes. + */ uint32_t Gyroscope::instantaneousAccelerationSquared() { requestUpdate(); // Use pythagoras theorem to determine the combined force acting on the device. - return (uint32_t)sample.x*(uint32_t)sample.x + (uint32_t)sample.y*(uint32_t)sample.y + (uint32_t)sample.z*(uint32_t)sample.z; + return (uint32_t)sample.x * (uint32_t)sample.x + (uint32_t)sample.y * (uint32_t)sample.y + + (uint32_t)sample.z * (uint32_t)sample.z; } /** - * Attempts to set the sample rate of the accelerometer to the specified value (in ms). - * - * @param period the requested time between samples, in milliseconds. - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR is the request fails. - * - * @code - * // sample rate is now 20 ms. - * accelerometer.setPeriod(20); - * @endcode - * - * @note The requested rate may not be possible on the hardware. In this case, the - * nearest lower rate is chosen. - */ + * Attempts to set the sample rate of the accelerometer to the specified value (in ms). + * + * @param period the requested time between samples, in milliseconds. + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR is the request fails. + * + * @code + * // sample rate is now 20 ms. + * accelerometer.setPeriod(20); + * @endcode + * + * @note The requested rate may not be possible on the hardware. In this case, the + * nearest lower rate is chosen. + */ int Gyroscope::setPeriod(int period) { int result; samplePeriod = period; - result = configure(); + result = configure(); samplePeriod = getPeriod(); return result; - } /** - * Reads the currently configured sample rate of the accelerometer. - * - * @return The time between samples, in milliseconds. - */ + * Reads the currently configured sample rate of the accelerometer. + * + * @return The time between samples, in milliseconds. + */ int Gyroscope::getPeriod() { return (int)samplePeriod; } /** - * Attempts to set the sample range of the accelerometer to the specified value (in g). - * - * @param range The requested sample range of samples, in g. - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR is the request fails. - * - * @code - * // the sample range of the accelerometer is now 8G. - * accelerometer.setRange(8); - * @endcode - * - * @note The requested range may not be possible on the hardware. In this case, the - * nearest lower range is chosen. - */ + * Attempts to set the sample range of the accelerometer to the specified value (in g). + * + * @param range The requested sample range of samples, in g. + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR is the request fails. + * + * @code + * // the sample range of the accelerometer is now 8G. + * accelerometer.setRange(8); + * @endcode + * + * @note The requested range may not be possible on the hardware. In this case, the + * nearest lower range is chosen. + */ int Gyroscope::setRange(int range) { int result; sampleRange = range; - result = configure(); + result = configure(); sampleRange = getRange(); return result; } /** - * Reads the currently configured sample range of the accelerometer. - * - * @return The sample range, in g. - */ + * Reads the currently configured sample range of the accelerometer. + * + * @return The sample range, in g. + */ int Gyroscope::getRange() { return (int)sampleRange; @@ -228,9 +228,6 @@ int Gyroscope::getZ() } /** - * Destructor for FXS8700, where we deregister from the array of fiber components. - */ -Gyroscope::~Gyroscope() -{ -} - + * Destructor for FXS8700, where we deregister from the array of fiber components. + */ +Gyroscope::~Gyroscope() {} diff --git a/source/driver-models/I2C.cpp b/source/driver-models/I2C.cpp index f4441e8a..fd371cea 100644 --- a/source/driver-models/I2C.cpp +++ b/source/driver-models/I2C.cpp @@ -23,273 +23,263 @@ DEALINGS IN THE SOFTWARE. */ #include "I2C.h" + #include "ErrorNo.h" -namespace codal +namespace codal { +/** + * Constructor. + */ +I2C::I2C(Pin& sda, Pin& scl) {} + +/** + * Change the pins used by this I2C peripheral to those provided. + * + * @param sda the Pin to use for the I2C SDA line. + * @param scl the Pin to use for the I2C SCL line. + * @return DEVICE_OK on success, or DEVICE_NOT_IMPLEMENTED / DEVICE_NOT_SUPPORTED if the request cannot be performed. + */ +int I2C::redirect(Pin& sda, Pin& scl) +{ + return DEVICE_NOT_IMPLEMENTED; +} + +/** + * Set the frequency of the I2C interface + * + * @param frequency The bus frequency in hertz + */ +int I2C::setFrequency(uint32_t frequency) +{ + return DEVICE_NOT_IMPLEMENTED; +} + +/** + * Issues a START condition on the I2C bus + */ +int I2C::start() +{ + return DEVICE_NOT_IMPLEMENTED; +} + +/** + * Issues a STOP condition on the I2C bus + */ +int I2C::stop() +{ + return DEVICE_NOT_IMPLEMENTED; +} + +/** + * Writes the given byte to the I2C bus. + * + * The CPU will busy wait until the transmission is complete. + * + * @param data The byte to write. + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the the write request failed. + */ +int I2C::write(uint8_t data) +{ + return DEVICE_NOT_IMPLEMENTED; +} + +/** + * Reads a single byte from the I2C bus. + * The CPU will busy wait until the transmission is complete. + * + * @return the byte read from the I2C bus, or DEVICE_I2C_ERROR if the the write request failed. + */ +int I2C::read(AcknowledgeType ack) +{ + return DEVICE_NOT_IMPLEMENTED; +} + +/** + * Issues a standard, 2 byte I2C command write to the I2C bus. + * This consists of: + * - Asserting a Start condition on the bus + * - Selecting the Slave address (as an 8 bit address) + * - Writing the raw 8 bit data provided + * - Asserting a Stop condition on the bus + * + * The CPU will busy wait until the transmission is complete. + * + * @param address The 8bit I2C address of the device to write to + * @param data the byte command to write + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the the write request failed. + */ +int I2C::write(uint16_t address, uint8_t data) +{ + return write(address, &data, 1); +} + +/** + * Issues a standard, I2C command write to the I2C bus. + * This consists of: + * - Asserting a Start condition on the bus + * - Selecting the Slave address (as an 8 bit address) + * - Writing a number of raw data bytes provided + * - Asserting a Stop condition on the bus + * + * The CPU will busy wait until the transmission is complete. + * + * @param address The 8bit I2C address of the device to write to + * @param data pointer to the bytes to write + * @param len the number of bytes to write + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the the write request failed. + */ +int I2C::write(uint16_t address, uint8_t* data, int len, bool repeated) +{ + if (data == NULL || len <= 0) return DEVICE_INVALID_PARAMETER; // Send a start condition + + start(); + + // Send the address of the slave, with a write bit set. + write((uint8_t)address); + + // Send the body of the data + for (int i = 0; i < len; i++) write(data[i]); + + // Send a stop condition + if (!repeated) stop(); + + return DEVICE_OK; +} + +/** + * Performs a typical register write operation to the I2C slave device provided. + * This consists of: + * - Asserting a Start condition on the bus + * - Selecting the Slave address (as an 8 bit address) + * - Writing the 8 bit register address provided + * - Writing the 8 bit value provided + * - Asserting a Stop condition on the bus + * + * The CPU will busy wait until the transmission is complete.. + * + * @param address 8bit address of the device to write to + * @param reg The 8bit address of the register to write to. + * @param value The value to write. + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the the write request failed. + */ +int I2C::writeRegister(uint16_t address, uint8_t reg, uint8_t value) { - /** - * Constructor. - */ - I2C::I2C(Pin &sda, Pin &scl) - { - } - - /** - * Change the pins used by this I2C peripheral to those provided. - * - * @param sda the Pin to use for the I2C SDA line. - * @param scl the Pin to use for the I2C SCL line. - * @return DEVICE_OK on success, or DEVICE_NOT_IMPLEMENTED / DEVICE_NOT_SUPPORTED if the request cannot be performed. - */ - int I2C::redirect(Pin &sda, Pin &scl) - { - return DEVICE_NOT_IMPLEMENTED; - } - - /** - * Set the frequency of the I2C interface - * - * @param frequency The bus frequency in hertz - */ - int I2C::setFrequency(uint32_t frequency) - { - return DEVICE_NOT_IMPLEMENTED; - } - - /** - * Issues a START condition on the I2C bus - */ - int I2C::start() - { - return DEVICE_NOT_IMPLEMENTED; - } - - /** - * Issues a STOP condition on the I2C bus - */ - int I2C::stop() - { - return DEVICE_NOT_IMPLEMENTED; - } - - /** - * Writes the given byte to the I2C bus. - * - * The CPU will busy wait until the transmission is complete. - * - * @param data The byte to write. - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the the write request failed. - */ - int I2C::write(uint8_t data) - { - return DEVICE_NOT_IMPLEMENTED; - } - - /** - * Reads a single byte from the I2C bus. - * The CPU will busy wait until the transmission is complete. - * - * @return the byte read from the I2C bus, or DEVICE_I2C_ERROR if the the write request failed. - */ - int I2C::read(AcknowledgeType ack) - { - return DEVICE_NOT_IMPLEMENTED; - } - - /** - * Issues a standard, 2 byte I2C command write to the I2C bus. - * This consists of: - * - Asserting a Start condition on the bus - * - Selecting the Slave address (as an 8 bit address) - * - Writing the raw 8 bit data provided - * - Asserting a Stop condition on the bus - * - * The CPU will busy wait until the transmission is complete. - * - * @param address The 8bit I2C address of the device to write to - * @param data the byte command to write - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the the write request failed. - */ - int I2C::write(uint16_t address, uint8_t data) - { - return write(address, &data, 1); - } - - /** - * Issues a standard, I2C command write to the I2C bus. - * This consists of: - * - Asserting a Start condition on the bus - * - Selecting the Slave address (as an 8 bit address) - * - Writing a number of raw data bytes provided - * - Asserting a Stop condition on the bus - * - * The CPU will busy wait until the transmission is complete. - * - * @param address The 8bit I2C address of the device to write to - * @param data pointer to the bytes to write - * @param len the number of bytes to write - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the the write request failed. - */ - int I2C::write(uint16_t address, uint8_t *data, int len, bool repeated) - { - if (data == NULL || len <= 0) - return DEVICE_INVALID_PARAMETER; // Send a start condition - - start(); - - // Send the address of the slave, with a write bit set. - write((uint8_t)address); - - // Send the body of the data - for (int i = 0; i < len; i++) - write(data[i]); - - // Send a stop condition - if (!repeated) - stop(); - - return DEVICE_OK; - } - - /** - * Performs a typical register write operation to the I2C slave device provided. - * This consists of: - * - Asserting a Start condition on the bus - * - Selecting the Slave address (as an 8 bit address) - * - Writing the 8 bit register address provided - * - Writing the 8 bit value provided - * - Asserting a Stop condition on the bus - * - * The CPU will busy wait until the transmission is complete.. - * - * @param address 8bit address of the device to write to - * @param reg The 8bit address of the register to write to. - * @param value The value to write. - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the the write request failed. - */ - int I2C::writeRegister(uint16_t address, uint8_t reg, uint8_t value) - { - uint8_t command[2]; - command[0] = reg; - command[1] = value; - - return write(address, command, 2); - } - - /** - * Issues a standard, 2 byte I2C command read to the I2C bus. - * This consists of: - * - Asserting a Start condition on the bus - * - Selecting the Slave address (as an 8 bit address) - * - reading "len" bytes of raw 8 bit data into the buffer provided - * - Asserting a Stop condition on the bus - * - * The CPU will busy wait until the transmission is complete. - * - * @param address The 8bit I2C address of the device to read from - * @param data pointer to store the the bytes read - * @param len the number of bytes to read into the buffer - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the the read request failed. - */ - int I2C::read(uint16_t address, uint8_t *data, int len, bool repeated) - { - int i = 0; - - if (data == NULL || len <= 0) - return DEVICE_INVALID_PARAMETER; - - // Send a start condition - start(); - - // Send the address of the slave, with a read bit set. - write((uint8_t)(address | 0x01)); - - // Read the body of the data - for (i = 0; i < len-1; i++) - data[i] = read(); - - data[i] = read(NACK); - - // Send a stop condition - if (!repeated) - stop(); - - return DEVICE_OK; - } - - /** - * Performs a typical register read operation to the I2C slave device provided. - * This consists of: - * - Asserting a Start condition on the bus - * - Selecting the Slave address (as an 8 bit address, I2C WRITE) - * - Selecting a RAM register address in the slave - * - Asserting a Stop condition on the bus - * - Asserting a Start condition on the bus - * - Selecting the Slave address (as an 8 bit address, I2C READ) - * - Performing an 8 bit read operation (of the requested register) - * - Asserting a Stop condition on the bus - * - * The CPU will busy wait until the transmission is complete.. - * - * @param address 8bit I2C address of the device to read from - * @param reg The 8bit register address of the to read. - * @param data A pointer to a memory location to store the result of the read operation - * @param length The number of mytes to read - * @param repeated Use a repeated START/START/STOP transaction if true, or independent START/STOP/START/STOP transactions if fasle. Default: true - * - * @return DEVICE_OK or DEVICE_I2C_ERROR if the the read request failed. - */ - int I2C::readRegister(uint16_t address, uint8_t reg, uint8_t *data, int length, bool repeated) - { - int result; - - if (repeated) - result = write(address, ®, 1, true); - else - result = write(address, reg); - - if (result != DEVICE_OK) - return result; - - result = read(address, data, length); - if (result != DEVICE_OK) - return result; - - return DEVICE_OK; - } - - /** - * Issues a single byte read command, and returns the value read, or an error. - * - * Blocks the calling thread until complete. - * - * @param address The address of the I2C device to write to. - * @param reg The address of the register to access. - * - * @return the byte read on success, DEVICE_INVALID_PARAMETER or DEVICE_I2C_ERROR if the the read request failed. - */ - int I2C::readRegister(uint8_t address, uint8_t reg) - { - int result; - uint8_t data; - - result = readRegister(address, reg, &data, 1); - - return (result == DEVICE_OK) ? (int)data : result; - } - - int I2C::write(int address, char *data, int len, bool repeated) - { - return write((uint16_t)address, (uint8_t *)data, len, repeated); - } - - int I2C::read(int address, char *data, int len, bool repeated) - { - return read((uint16_t)address, (uint8_t *)data, len, repeated); - } + uint8_t command[2]; + command[0] = reg; + command[1] = value; + + return write(address, command, 2); } +/** + * Issues a standard, 2 byte I2C command read to the I2C bus. + * This consists of: + * - Asserting a Start condition on the bus + * - Selecting the Slave address (as an 8 bit address) + * - reading "len" bytes of raw 8 bit data into the buffer provided + * - Asserting a Stop condition on the bus + * + * The CPU will busy wait until the transmission is complete. + * + * @param address The 8bit I2C address of the device to read from + * @param data pointer to store the the bytes read + * @param len the number of bytes to read into the buffer + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the the read request failed. + */ +int I2C::read(uint16_t address, uint8_t* data, int len, bool repeated) +{ + int i = 0; + + if (data == NULL || len <= 0) return DEVICE_INVALID_PARAMETER; + + // Send a start condition + start(); + + // Send the address of the slave, with a read bit set. + write((uint8_t)(address | 0x01)); + + // Read the body of the data + for (i = 0; i < len - 1; i++) data[i] = read(); + + data[i] = read(NACK); + + // Send a stop condition + if (!repeated) stop(); + + return DEVICE_OK; +} + +/** + * Performs a typical register read operation to the I2C slave device provided. + * This consists of: + * - Asserting a Start condition on the bus + * - Selecting the Slave address (as an 8 bit address, I2C WRITE) + * - Selecting a RAM register address in the slave + * - Asserting a Stop condition on the bus + * - Asserting a Start condition on the bus + * - Selecting the Slave address (as an 8 bit address, I2C READ) + * - Performing an 8 bit read operation (of the requested register) + * - Asserting a Stop condition on the bus + * + * The CPU will busy wait until the transmission is complete.. + * + * @param address 8bit I2C address of the device to read from + * @param reg The 8bit register address of the to read. + * @param data A pointer to a memory location to store the result of the read operation + * @param length The number of mytes to read + * @param repeated Use a repeated START/START/STOP transaction if true, or independent START/STOP/START/STOP + * transactions if fasle. Default: true + * + * @return DEVICE_OK or DEVICE_I2C_ERROR if the the read request failed. + */ +int I2C::readRegister(uint16_t address, uint8_t reg, uint8_t* data, int length, bool repeated) +{ + int result; + + if (repeated) + result = write(address, ®, 1, true); + else + result = write(address, reg); + + if (result != DEVICE_OK) return result; + + result = read(address, data, length); + if (result != DEVICE_OK) return result; + + return DEVICE_OK; +} + +/** + * Issues a single byte read command, and returns the value read, or an error. + * + * Blocks the calling thread until complete. + * + * @param address The address of the I2C device to write to. + * @param reg The address of the register to access. + * + * @return the byte read on success, DEVICE_INVALID_PARAMETER or DEVICE_I2C_ERROR if the the read request failed. + */ +int I2C::readRegister(uint8_t address, uint8_t reg) +{ + int result; + uint8_t data; + + result = readRegister(address, reg, &data, 1); + + return (result == DEVICE_OK) ? (int)data : result; +} + +int I2C::write(int address, char* data, int len, bool repeated) +{ + return write((uint16_t)address, (uint8_t*)data, len, repeated); +} + +int I2C::read(int address, char* data, int len, bool repeated) +{ + return read((uint16_t)address, (uint8_t*)data, len, repeated); +} +} // namespace codal diff --git a/source/driver-models/PinPeripheral.cpp b/source/driver-models/PinPeripheral.cpp index 930bcd96..fcdc5c93 100644 --- a/source/driver-models/PinPeripheral.cpp +++ b/source/driver-models/PinPeripheral.cpp @@ -22,8 +22,8 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "Pin.h" #include "CodalDmesg.h" +#include "Pin.h" using namespace codal; @@ -33,66 +33,62 @@ using namespace codal; * to allow it to be used by a different peripheral. * * @param pin the Pin to be released. - * @return DEVICE_OK on success, or DEVICE_NOT_IMPLEMENTED if unsupported, or DEVICE_INVALID_PARAMETER if the pin is not bound to this peripheral. + * @return DEVICE_OK on success, or DEVICE_NOT_IMPLEMENTED if unsupported, or DEVICE_INVALID_PARAMETER if the pin is not + * bound to this peripheral. */ -int PinPeripheral::releasePin(Pin &pin) +int PinPeripheral::releasePin(Pin& pin) { return DEVICE_NOT_IMPLEMENTED; } /** - * Determines if this peripheral has locked any attached pins to this peripheral. - * During a locked period, any attempts to release or reassign those pins to a differnet peripheral are ignored. - * This mechanism is primarily useful to use functions such as Pin::setDigitalValue() within a peripheral driver, - * but without releasing the pin's binding to that peripheral. - * - * @return true if this peripherals pin bindings are locked, false otherwise. - */ + * Determines if this peripheral has locked any attached pins to this peripheral. + * During a locked period, any attempts to release or reassign those pins to a differnet peripheral are ignored. + * This mechanism is primarily useful to use functions such as Pin::setDigitalValue() within a peripheral driver, + * but without releasing the pin's binding to that peripheral. + * + * @return true if this peripherals pin bindings are locked, false otherwise. + */ bool PinPeripheral::isPinLocked() { return pinLock; } /** - * Controls if this peripheral has locked any attached pins to this peripheral. - * During a locked period, any attempts to release or reassign those pins to a differnet peripheral are ignored. - * This mechanism is primarily useful to use functions such as Pin::setDigitalValue() within a peripheral driver, - * but without releasing the pin's binding to that peripheral. - * - * @param true if this peripherals pin bindings are to be locked, false otherwise. - */ + * Controls if this peripheral has locked any attached pins to this peripheral. + * During a locked period, any attempts to release or reassign those pins to a differnet peripheral are ignored. + * This mechanism is primarily useful to use functions such as Pin::setDigitalValue() within a peripheral driver, + * but without releasing the pin's binding to that peripheral. + * + * @param true if this peripherals pin bindings are to be locked, false otherwise. + */ void PinPeripheral::setPinLock(bool locked) { pinLock = locked; } /** - * Utility function, to assist in redirect() operations and consistent use of disconnect()/connect() by peripherals. - * Safely disconnects pin from any attached peripherals, upfates pin to the new pin, and attaches to the given peripheral. - * Also validates out NULL cases. - * - * @param p Typically a mutable instance variable, holding the current pin used by a given peripheral. - * @param newPin The pin which is replacing the value of pin. - */ -int PinPeripheral::reassignPin(void *p, Pin *newPin) + * Utility function, to assist in redirect() operations and consistent use of disconnect()/connect() by peripherals. + * Safely disconnects pin from any attached peripherals, upfates pin to the new pin, and attaches to the given + * peripheral. Also validates out NULL cases. + * + * @param p Typically a mutable instance variable, holding the current pin used by a given peripheral. + * @param newPin The pin which is replacing the value of pin. + */ +int PinPeripheral::reassignPin(void* p, Pin* newPin) { - Pin **pin = (Pin **)p; + Pin** pin = (Pin**)p; - if (pin == NULL) - return DEVICE_INVALID_PARAMETER; + if (pin == NULL) return DEVICE_INVALID_PARAMETER; // If the pin is changing state, reelase any old peripherals and attach the new one. - if (*pin != newPin) - { - if (*pin) - (*pin)->disconnect(); + if (*pin != newPin) { + if (*pin) (*pin)->disconnect(); - if (newPin) - newPin->connect(*this); + if (newPin) newPin->connect(*this); *pin = newPin; } return DEVICE_OK; } - diff --git a/source/driver-models/SPI.cpp b/source/driver-models/SPI.cpp index 62d16620..5f7a5e3d 100644 --- a/source/driver-models/SPI.cpp +++ b/source/driver-models/SPI.cpp @@ -23,11 +23,11 @@ DEALINGS IN THE SOFTWARE. */ #include "SPI.h" -#include "ErrorNo.h" + #include "CodalFiber.h" +#include "ErrorNo.h" -namespace codal -{ +namespace codal { /** * Change the pins used by this I2C peripheral to those provided. @@ -37,7 +37,7 @@ namespace codal * @param sclk the Pin to use for the SPI clock line. * @return DEVICE_OK on success, or DEVICE_NOT_IMPLEMENTED / DEVICE_NOT_SUPPORTED if the request cannot be performed. */ -int SPI::redirect(Pin &mosi, Pin &miso, Pin &sclk) +int SPI::redirect(Pin& mosi, Pin& miso, Pin& sclk) { return DEVICE_NOT_IMPLEMENTED; } @@ -48,18 +48,14 @@ int SPI::redirect(Pin &mosi, Pin &miso, Pin &sclk) * * Either buffer can be NULL. */ -int SPI::transfer(const uint8_t *txBuffer, uint32_t txSize, uint8_t *rxBuffer, uint32_t rxSize) +int SPI::transfer(const uint8_t* txBuffer, uint32_t txSize, uint8_t* rxBuffer, uint32_t rxSize) { uint32_t len = txSize; - if (rxSize > len) - len = rxSize; - for (uint32_t i = 0; i < len; ++i) - { + if (rxSize > len) len = rxSize; + for (uint32_t i = 0; i < len; ++i) { int c = write(i < txSize ? txBuffer[i] : 0); - if (c < 0) - return DEVICE_SPI_ERROR; - if (i < rxSize) - rxBuffer[i] = c; + if (c < 0) return DEVICE_SPI_ERROR; + if (i < rxSize) rxBuffer[i] = c; } return DEVICE_OK; } @@ -70,12 +66,12 @@ int SPI::transfer(const uint8_t *txBuffer, uint32_t txSize, uint8_t *rxBuffer, u * * Either buffer can be NULL. */ -int SPI::startTransfer(const uint8_t *txBuffer, uint32_t txSize, uint8_t *rxBuffer, uint32_t rxSize, - PVoidCallback doneHandler, void *arg) +int SPI::startTransfer(const uint8_t* txBuffer, uint32_t txSize, uint8_t* rxBuffer, uint32_t rxSize, + PVoidCallback doneHandler, void* arg) { int r = transfer(txBuffer, txSize, rxBuffer, rxSize); // it's important this doesn't get invoked recursievely, since that leads to stack overflow create_fiber(doneHandler, arg); return r; } -} +} // namespace codal diff --git a/source/driver-models/Sensor.cpp b/source/driver-models/Sensor.cpp index cea63109..6c337e22 100644 --- a/source/driver-models/Sensor.cpp +++ b/source/driver-models/Sensor.cpp @@ -24,14 +24,16 @@ DEALINGS IN THE SOFTWARE. */ /** - * Class definition for a generic analog sensor, that takes the general form of a logarithmic response to a sensed value, in a potential divider. - * Implements a base class for such a sensor, using the Steinhart-Hart equation to delineate a result. + * Class definition for a generic analog sensor, that takes the general form of a logarithmic response to a sensed + * value, in a potential divider. Implements a base class for such a sensor, using the Steinhart-Hart equation to + * delineate a result. */ #include "Sensor.h" -#include "ErrorNo.h" + #include "CodalCompat.h" #include "CodalFiber.h" +#include "ErrorNo.h" #include "Timer.h" using namespace codal; @@ -49,8 +51,9 @@ Sensor::Sensor(uint16_t id, uint16_t sensitivity, uint16_t samplePeriod) this->setSensitivity(sensitivity); // Configure for a 2 Hz update frequency by default. - if(EventModel::defaultEventBus) - EventModel::defaultEventBus->listen(this->id, SENSOR_UPDATE_NEEDED, this, &Sensor::onSampleEvent, MESSAGE_BUS_LISTENER_IMMEDIATE); + if (EventModel::defaultEventBus) + EventModel::defaultEventBus->listen(this->id, SENSOR_UPDATE_NEEDED, this, &Sensor::onSampleEvent, + MESSAGE_BUS_LISTENER_IMMEDIATE); this->setPeriod(samplePeriod); } @@ -80,14 +83,13 @@ void Sensor::updateSample() { uint32_t value = readValue(); - // If this is the first reading performed, take it a a baseline. Otherwise, perform a decay average to smooth out the data. - if (!(this->status & SENSOR_INITIALISED)) - { + // If this is the first reading performed, take it a a baseline. Otherwise, perform a decay average to smooth out + // the data. + if (!(this->status & SENSOR_INITIALISED)) { sensorValue = (uint16_t)value; - this->status |= SENSOR_INITIALISED; + this->status |= SENSOR_INITIALISED; } - else - { + else { sensorValue = ((sensorValue * (1023 - sensitivity)) + (value * sensitivity)) >> 10; } @@ -99,26 +101,29 @@ void Sensor::updateSample() */ void Sensor::checkThresholding() { - if ((this->status & SENSOR_HIGH_THRESHOLD_ENABLED) && (!(this->status & SENSOR_HIGH_THRESHOLD_PASSED)) && (sensorValue >= highThreshold)) - { + if ((this->status & SENSOR_HIGH_THRESHOLD_ENABLED) && (!(this->status & SENSOR_HIGH_THRESHOLD_PASSED)) && + (sensorValue >= highThreshold)) { Event(this->id, SENSOR_THRESHOLD_HIGH); - this->status |= SENSOR_HIGH_THRESHOLD_PASSED; + this->status |= SENSOR_HIGH_THRESHOLD_PASSED; this->status &= ~SENSOR_LOW_THRESHOLD_PASSED; } - if ((this->status & SENSOR_LOW_THRESHOLD_ENABLED) && (!(this->status & SENSOR_LOW_THRESHOLD_PASSED)) && (sensorValue <= lowThreshold)) + if ((this->status & SENSOR_LOW_THRESHOLD_ENABLED) && (!(this->status & SENSOR_LOW_THRESHOLD_PASSED)) && + (sensorValue <= lowThreshold)) { Event(this->id, SENSOR_THRESHOLD_LOW); - this->status |= SENSOR_LOW_THRESHOLD_PASSED; + this->status |= SENSOR_LOW_THRESHOLD_PASSED; this->status &= ~SENSOR_HIGH_THRESHOLD_PASSED; } } /** - * Set sensitivity value for the data. A decay average is taken of sampled data to smooth it into more accurate information. + * Set sensitivity value for the data. A decay average is taken of sampled data to smooth it into more accurate + * information. * - * @param value A value between 0..1023 that detemrines the level of smoothing. Set to 1023 to disable smoothing. Default value is 868 + * @param value A value between 0..1023 that detemrines the level of smoothing. Set to 1023 to disable smoothing. + * Default value is 868 * * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if the request fails. */ @@ -164,19 +169,17 @@ int Sensor::getPeriod() int Sensor::setLowThreshold(uint16_t value) { // Protect against churn if the same threshold is set repeatedly. - if ((this->status & SENSOR_LOW_THRESHOLD_ENABLED) && lowThreshold == value) - return DEVICE_OK; + if ((this->status & SENSOR_LOW_THRESHOLD_ENABLED) && lowThreshold == value) return DEVICE_OK; // We need to update our threshold lowThreshold = value; // Reset any exisiting threshold state, and enable threshold detection. this->status &= ~SENSOR_LOW_THRESHOLD_PASSED; - this->status |= SENSOR_LOW_THRESHOLD_ENABLED; + this->status |= SENSOR_LOW_THRESHOLD_ENABLED; // If a HIGH threshold has been set, ensure it's above the LOW threshold. - if(this->status & SENSOR_HIGH_THRESHOLD_ENABLED) - setHighThreshold(max(lowThreshold+1, highThreshold)); + if (this->status & SENSOR_HIGH_THRESHOLD_ENABLED) setHighThreshold(max(lowThreshold + 1, highThreshold)); return DEVICE_OK; } @@ -191,19 +194,17 @@ int Sensor::setLowThreshold(uint16_t value) int Sensor::setHighThreshold(uint16_t value) { // Protect against churn if the same threshold is set repeatedly. - if ((this->status & SENSOR_HIGH_THRESHOLD_ENABLED) && highThreshold == value) - return DEVICE_OK; + if ((this->status & SENSOR_HIGH_THRESHOLD_ENABLED) && highThreshold == value) return DEVICE_OK; // We need to update our threshold highThreshold = value; // Reset any exisiting threshold state, and enable threshold detection. this->status &= ~SENSOR_HIGH_THRESHOLD_PASSED; - this->status |= SENSOR_HIGH_THRESHOLD_ENABLED; + this->status |= SENSOR_HIGH_THRESHOLD_ENABLED; // If a HIGH threshold has been set, ensure it's above the LOW threshold. - if(this->status & SENSOR_LOW_THRESHOLD_ENABLED) - setLowThreshold(min(highThreshold - 1, lowThreshold)); + if (this->status & SENSOR_LOW_THRESHOLD_ENABLED) setLowThreshold(min(highThreshold - 1, lowThreshold)); return DEVICE_OK; } @@ -215,8 +216,7 @@ int Sensor::setHighThreshold(uint16_t value) */ int Sensor::getLowThreshold() { - if (!(this->status & SENSOR_LOW_THRESHOLD_ENABLED)) - return DEVICE_INVALID_PARAMETER; + if (!(this->status & SENSOR_LOW_THRESHOLD_ENABLED)) return DEVICE_INVALID_PARAMETER; return lowThreshold; } @@ -228,8 +228,7 @@ int Sensor::getLowThreshold() */ int Sensor::getHighThreshold() { - if (!(this->status & SENSOR_HIGH_THRESHOLD_ENABLED)) - return DEVICE_INVALID_PARAMETER; + if (!(this->status & SENSOR_HIGH_THRESHOLD_ENABLED)) return DEVICE_INVALID_PARAMETER; return highThreshold; } @@ -237,6 +236,4 @@ int Sensor::getHighThreshold() /** * Destructor. */ -Sensor::~Sensor() -{ -} +Sensor::~Sensor() {} diff --git a/source/driver-models/Serial.cpp b/source/driver-models/Serial.cpp index 7d956491..17c3ee81 100644 --- a/source/driver-models/Serial.cpp +++ b/source/driver-models/Serial.cpp @@ -1,6 +1,7 @@ #include "Serial.h" -#include "NotifyEvents.h" + #include "CodalDmesg.h" +#include "NotifyEvents.h" using namespace codal; @@ -17,35 +18,30 @@ using namespace codal; void Serial::dataReceived(char c) { - if(!(status & CODAL_SERIAL_STATUS_RX_BUFF_INIT)) - return; + if (!(status & CODAL_SERIAL_STATUS_RX_BUFF_INIT)) return; int delimeterOffset = 0; - int delimLength = this->delimeters.length(); + int delimLength = this->delimeters.length(); - //iterate through our delimeters (if any) to see if there is a match - while(delimeterOffset < delimLength) - { - //fire an event if there is to block any waiting fibers - if(this->delimeters.charAt(delimeterOffset) == c) - Event(this->id, CODAL_SERIAL_EVT_DELIM_MATCH); + // iterate through our delimeters (if any) to see if there is a match + while (delimeterOffset < delimLength) { + // fire an event if there is to block any waiting fibers + if (this->delimeters.charAt(delimeterOffset) == c) Event(this->id, CODAL_SERIAL_EVT_DELIM_MATCH); delimeterOffset++; } uint16_t newHead = (rxBuffHead + 1) % rxBuffSize; - //look ahead to our newHead value to see if we are about to collide with the tail - if(newHead != rxBuffTail) - { - //if we are not, store the character, and update our actual head. + // look ahead to our newHead value to see if we are about to collide with the tail + if (newHead != rxBuffTail) { + // if we are not, store the character, and update our actual head. this->rxBuff[rxBuffHead] = c; - rxBuffHead = newHead; + rxBuffHead = newHead; - //if we have any fibers waiting for a specific number of characters, unblock them - if(rxBuffHeadMatch >= 0) - if(rxBuffHead == rxBuffHeadMatch) - { + // if we have any fibers waiting for a specific number of characters, unblock them + if (rxBuffHeadMatch >= 0) + if (rxBuffHead == rxBuffHeadMatch) { rxBuffHeadMatch = -1; Event(this->id, CODAL_SERIAL_EVT_HEAD_MATCH); } @@ -53,59 +49,54 @@ void Serial::dataReceived(char c) status |= CODAL_SERIAL_STATUS_RXD; } else - //otherwise, our buffer is full, send an event to the user... + // otherwise, our buffer is full, send an event to the user... Event(this->id, CODAL_SERIAL_EVT_RX_FULL); } void Serial::dataTransmitted() { - if(!(status & CODAL_SERIAL_STATUS_TX_BUFF_INIT)) - return; + if (!(status & CODAL_SERIAL_STATUS_TX_BUFF_INIT)) return; - //send our current char + // send our current char putc((char)txBuff[txBuffTail]); - //unblock any waiting fibers that are waiting for transmission to finish. + // unblock any waiting fibers that are waiting for transmission to finish. uint16_t nextTail = (txBuffTail + 1) % txBuffSize; - if(nextTail == txBuffHead) - { + if (nextTail == txBuffHead) { Event(DEVICE_ID_NOTIFY, CODAL_SERIAL_EVT_TX_EMPTY); disableInterrupt(TxInterrupt); } - //update our tail! + // update our tail! txBuffTail = nextTail; } -int Serial::setTxInterrupt(uint8_t *string, int len, SerialMode mode) +int Serial::setTxInterrupt(uint8_t* string, int len, SerialMode mode) { int copiedBytes = 0; - while(copiedBytes < len) - { + while (copiedBytes < len) { uint16_t nextHead = (txBuffHead + 1) % txBuffSize; - if(nextHead == txBuffTail) - { + if (nextHead == txBuffTail) { enableInterrupt(TxInterrupt); - if(mode == SYNC_SLEEP) - fiber_wait_for_event(DEVICE_ID_NOTIFY, CODAL_SERIAL_EVT_TX_EMPTY); + if (mode == SYNC_SLEEP) fiber_wait_for_event(DEVICE_ID_NOTIFY, CODAL_SERIAL_EVT_TX_EMPTY); - if(mode == SYNC_SPINWAIT) - while(txBufferedSize() > 0); + if (mode == SYNC_SPINWAIT) + while (txBufferedSize() > 0) + ; - if(mode == ASYNC) - break; + if (mode == ASYNC) break; } this->txBuff[txBuffHead] = string[copiedBytes]; - txBuffHead = nextHead; + txBuffHead = nextHead; copiedBytes++; } - //set the TX interrupt + // set the TX interrupt enableInterrupt(TxInterrupt); return copiedBytes; @@ -113,67 +104,64 @@ int Serial::setTxInterrupt(uint8_t *string, int len, SerialMode mode) void Serial::idleCallback() { - if (this->status & CODAL_SERIAL_STATUS_RXD) - { + if (this->status & CODAL_SERIAL_STATUS_RXD) { Event(this->id, CODAL_SERIAL_EVT_DATA_RECEIVED); this->status &= ~CODAL_SERIAL_STATUS_RXD; } } /** - * Locks the mutex so that others can't use this serial instance for reception - */ + * Locks the mutex so that others can't use this serial instance for reception + */ void Serial::lockRx() { status |= CODAL_SERIAL_STATUS_RX_IN_USE; } /** - * Locks the mutex so that others can't use this serial instance for transmission - */ + * Locks the mutex so that others can't use this serial instance for transmission + */ void Serial::lockTx() { status |= CODAL_SERIAL_STATUS_TX_IN_USE; } /** - * Unlocks the mutex so that others can use this serial instance for reception - */ + * Unlocks the mutex so that others can use this serial instance for reception + */ void Serial::unlockRx() { status &= ~CODAL_SERIAL_STATUS_RX_IN_USE; } /** - * Unlocks the mutex so that others can use this serial instance for transmission - */ + * Unlocks the mutex so that others can use this serial instance for transmission + */ void Serial::unlockTx() { status &= ~CODAL_SERIAL_STATUS_TX_IN_USE; } /** - * We do not want to always have our buffers initialised, especially if users to not - * use them. We only bring them up on demand. - */ + * We do not want to always have our buffers initialised, especially if users to not + * use them. We only bring them up on demand. + */ int Serial::initialiseRx() { - if((status & CODAL_SERIAL_STATUS_RX_BUFF_INIT)) - { - //ensure that we receive no interrupts after freeing our buffer + if ((status & CODAL_SERIAL_STATUS_RX_BUFF_INIT)) { + // ensure that we receive no interrupts after freeing our buffer disableInterrupt(RxInterrupt); free(this->rxBuff); } status &= ~CODAL_SERIAL_STATUS_RX_BUFF_INIT; - if((this->rxBuff = (uint8_t *)malloc(rxBuffSize)) == NULL) - return DEVICE_NO_RESOURCES; + if ((this->rxBuff = (uint8_t*)malloc(rxBuffSize)) == NULL) return DEVICE_NO_RESOURCES; this->rxBuffHead = 0; this->rxBuffTail = 0; - //set the receive interrupt + // set the receive interrupt status |= CODAL_SERIAL_STATUS_RX_BUFF_INIT; enableInterrupt(RxInterrupt); @@ -181,22 +169,20 @@ int Serial::initialiseRx() } /** - * We do not want to always have our buffers initialised, especially if users to not - * use them. We only bring them up on demand. - */ + * We do not want to always have our buffers initialised, especially if users to not + * use them. We only bring them up on demand. + */ int Serial::initialiseTx() { - if((status & CODAL_SERIAL_STATUS_TX_BUFF_INIT)) - { - //ensure that we receive no interrupts after freeing our buffer + if ((status & CODAL_SERIAL_STATUS_TX_BUFF_INIT)) { + // ensure that we receive no interrupts after freeing our buffer disableInterrupt(TxInterrupt); free(this->txBuff); } status &= ~CODAL_SERIAL_STATUS_TX_BUFF_INIT; - if((this->txBuff = (uint8_t *)malloc(txBuffSize)) == NULL) - return DEVICE_NO_RESOURCES; + if ((this->txBuff = (uint8_t*)malloc(txBuffSize)) == NULL) return DEVICE_NO_RESOURCES; this->txBuffHead = 0; this->txBuffTail = 0; @@ -222,19 +208,18 @@ int Serial::initialiseTx() * @note this method assumes that the linear buffer has the appropriate amount of * memory to contain the copy operation */ -void Serial::circularCopy(uint8_t *circularBuff, uint8_t circularBuffSize, uint8_t *linearBuff, uint16_t tailPosition, uint16_t headPosition) +void Serial::circularCopy(uint8_t* circularBuff, uint8_t circularBuffSize, uint8_t* linearBuff, uint16_t tailPosition, + uint16_t headPosition) { int toBuffIndex = 0; - while(tailPosition != headPosition) - { + while (tailPosition != headPosition) { linearBuff[toBuffIndex++] = circularBuff[tailPosition]; tailPosition = (tailPosition + 1) % circularBuffSize; } } - /** * Constructor. * Create an instance of DeviceSerial @@ -306,7 +291,7 @@ Serial::Serial(Pin& tx, Pin& rx, uint8_t rxBufferSize, uint8_t txBufferSize, uin */ int Serial::sendChar(char c, SerialMode mode) { - return send((uint8_t *)&c, 1, mode); + return send((uint8_t*)&c, 1, mode); } /** @@ -335,7 +320,7 @@ int Serial::sendChar(char c, SerialMode mode) */ int Serial::send(ManagedString s, SerialMode mode) { - return send((uint8_t *)s.toCharArray(), s.length(), mode); + return send((uint8_t*)s.toCharArray(), s.length(), mode); } /** @@ -364,23 +349,19 @@ int Serial::send(ManagedString s, SerialMode mode) * is using the serial instance for transmission, DEVICE_INVALID_PARAMETER * if buffer is invalid, or the given bufferLen is <= 0. */ -int Serial::send(uint8_t *buffer, int bufferLen, SerialMode mode) +int Serial::send(uint8_t* buffer, int bufferLen, SerialMode mode) { - if(txInUse()) - return DEVICE_SERIAL_IN_USE; + if (txInUse()) return DEVICE_SERIAL_IN_USE; - if(bufferLen <= 0 || buffer == NULL) - return DEVICE_INVALID_PARAMETER; + if (bufferLen <= 0 || buffer == NULL) return DEVICE_INVALID_PARAMETER; lockTx(); - //lazy initialisation of our tx buffer - if(!(status & CODAL_SERIAL_STATUS_TX_BUFF_INIT)) - { + // lazy initialisation of our tx buffer + if (!(status & CODAL_SERIAL_STATUS_TX_BUFF_INIT)) { int result = initialiseTx(); - if(result != DEVICE_OK) - return result; + if (result != DEVICE_OK) return result; } int bytesWritten = setTxInterrupt(buffer, bufferLen, mode); @@ -396,72 +377,63 @@ void Serial::printf(const char* format, ...) va_list arg; va_start(arg, format); - const char *end = format; + const char* end = format; // We might want to call disable / enable interrupts on the serial line if print is called from ISR context char buff[20]; - while (*end) - { + while (*end) { char current = *end++; - if (current == '%') - { - uint32_t val = va_arg(arg, uint32_t); - char* str = (char *)((void *)val); - char* buffPtr = buff; - char c = 0; + if (current == '%') { + uint32_t val = va_arg(arg, uint32_t); + char* str = (char*)((void*)val); + char* buffPtr = buff; + char c = 0; bool firstDigitFound = false; - bool lowerCase = false; - switch (*end++) - { - - case 'c': - putc((char)val); - break; - case 'd': - memset(buff, 0, 20); - itoa(val, buff); - while((c = *buffPtr++) != 0) - putc(c); - break; - - case 's': - while((c = *str++) != 0) - putc(c); - break; - - case '%': - putc('%'); - break; - - case 'x': - lowerCase = true; - // fall through - case 'X': - for (uint8_t i = 8; i > 0; i--) - { - uint8_t digit = ((uint8_t) (val >> ((i - 1) * 4)) & 0x0f) + (uint8_t) '0'; - if (digit > '9') - { - if (lowerCase) - digit += 39; - else - digit += 7; + bool lowerCase = false; + switch (*end++) { + case 'c': + putc((char)val); + break; + case 'd': + memset(buff, 0, 20); + itoa(val, buff); + while ((c = *buffPtr++) != 0) putc(c); + break; + + case 's': + while ((c = *str++) != 0) putc(c); + break; + + case '%': + putc('%'); + break; + + case 'x': + lowerCase = true; + // fall through + case 'X': + for (uint8_t i = 8; i > 0; i--) { + uint8_t digit = ((uint8_t)(val >> ((i - 1) * 4)) & 0x0f) + (uint8_t)'0'; + if (digit > '9') { + if (lowerCase) + digit += 39; + else + digit += 7; + } + if (digit != '0') { + putc((char)digit); + firstDigitFound = true; + } + else if (firstDigitFound || i == 1) + putc((char)digit); } - if (digit != '0') - { - putc((char)digit); - firstDigitFound = true; - } - else if (firstDigitFound || i == 1) - putc((char)digit); - } - break; - case 'p': - default: - putc('?'); - putc('?'); - putc('?'); - break; + break; + case 'p': + default: + putc('?'); + putc('?'); + putc('?'); + break; } } else @@ -497,18 +469,15 @@ void Serial::printf(const char* format, ...) */ int Serial::read(SerialMode mode) { - if(rxInUse()) - return DEVICE_SERIAL_IN_USE; + if (rxInUse()) return DEVICE_SERIAL_IN_USE; lockRx(); - //lazy initialisation of our buffers - if(!(status & CODAL_SERIAL_STATUS_RX_BUFF_INIT)) - { + // lazy initialisation of our buffers + if (!(status & CODAL_SERIAL_STATUS_RX_BUFF_INIT)) { int result = initialiseRx(); - if(result != DEVICE_OK) - return result; + if (result != DEVICE_OK) return result; } int c = getChar(mode); @@ -542,19 +511,16 @@ int Serial::read(SerialMode mode) */ int Serial::getChar(SerialMode mode) { - if(mode == ASYNC) - { - if(!isReadable()) - return DEVICE_NO_DATA; + if (mode == ASYNC) { + if (!isReadable()) return DEVICE_NO_DATA; } - if(mode == SYNC_SPINWAIT) - while(!isReadable()); + if (mode == SYNC_SPINWAIT) + while (!isReadable()) + ; - if(mode == SYNC_SLEEP) - { - if(!isReadable()) - eventAfter(1, mode); + if (mode == SYNC_SLEEP) { + if (!isReadable()) eventAfter(1, mode); } char c = rxBuff[rxBuffTail]; @@ -594,12 +560,11 @@ ManagedString Serial::read(int size, SerialMode mode) memclr(&buff, size + 1); - int returnedSize = read((uint8_t *)buff, size, mode); + int returnedSize = read((uint8_t*)buff, size, mode); - if(returnedSize <= 0) - return ManagedString(); + if (returnedSize <= 0) return ManagedString(); - return ManagedString((char *)buff, returnedSize); + return ManagedString((char*)buff, returnedSize); } /** @@ -629,51 +594,41 @@ ManagedString Serial::read(int size, SerialMode mode) * @return the number of characters read, or CODAL_SERIAL_IN_USE if another fiber * is using the instance for receiving. */ -int Serial::read(uint8_t *buffer, int bufferLen, SerialMode mode) +int Serial::read(uint8_t* buffer, int bufferLen, SerialMode mode) { - if(rxInUse()) - return DEVICE_SERIAL_IN_USE; + if (rxInUse()) return DEVICE_SERIAL_IN_USE; lockRx(); - //lazy initialisation of our rx buffer - if(!(status & CODAL_SERIAL_STATUS_RX_BUFF_INIT)) - { + // lazy initialisation of our rx buffer + if (!(status & CODAL_SERIAL_STATUS_RX_BUFF_INIT)) { int result = initialiseRx(); - if(result != DEVICE_OK) - return result; + if (result != DEVICE_OK) return result; } int bufferIndex = 0; int temp = 0; - if(mode == ASYNC) - { - while(bufferIndex < bufferLen && (temp = getChar(mode)) != DEVICE_NO_DATA) - { + if (mode == ASYNC) { + while (bufferIndex < bufferLen && (temp = getChar(mode)) != DEVICE_NO_DATA) { buffer[bufferIndex] = (char)temp; bufferIndex++; } } - if(mode == SYNC_SPINWAIT) - { - while(bufferIndex < bufferLen) - { + if (mode == SYNC_SPINWAIT) { + while (bufferIndex < bufferLen) { buffer[bufferIndex] = (char)getChar(mode); bufferIndex++; } } - if(mode == SYNC_SLEEP) - { - if(bufferLen > rxBufferedSize()) - eventAfter(bufferLen - rxBufferedSize(), mode); + if (mode == SYNC_SLEEP) { + if (bufferLen > rxBufferedSize()) eventAfter(bufferLen - rxBufferedSize(), mode); - while(bufferIndex < bufferLen) - { + while (bufferIndex < bufferLen) { buffer[bufferIndex] = (char)getChar(mode); bufferIndex++; } @@ -715,73 +670,64 @@ int Serial::read(uint8_t *buffer, int bufferLen, SerialMode mode) */ ManagedString Serial::readUntil(ManagedString delimeters, SerialMode mode) { - if(rxInUse()) - return ManagedString(); + if (rxInUse()) return ManagedString(); - //lazy initialisation of our rx buffer - if(!(status & CODAL_SERIAL_STATUS_RX_BUFF_INIT)) - { + // lazy initialisation of our rx buffer + if (!(status & CODAL_SERIAL_STATUS_RX_BUFF_INIT)) { int result = initialiseRx(); - if(result != DEVICE_OK) - return result; + if (result != DEVICE_OK) return result; } lockRx(); - int localTail = rxBuffTail; + int localTail = rxBuffTail; int preservedTail = rxBuffTail; int foundIndex = -1; - //ASYNC mode just iterates through our stored characters checking for any matches. - while(localTail != rxBuffHead && foundIndex == -1) - { - //we use localTail to prevent modification of the actual tail. + // ASYNC mode just iterates through our stored characters checking for any matches. + while (localTail != rxBuffHead && foundIndex == -1) { + // we use localTail to prevent modification of the actual tail. char c = rxBuff[localTail]; - for(int delimeterIterator = 0; delimeterIterator < delimeters.length(); delimeterIterator++) - if(delimeters.charAt(delimeterIterator) == c) - foundIndex = localTail; + for (int delimeterIterator = 0; delimeterIterator < delimeters.length(); delimeterIterator++) + if (delimeters.charAt(delimeterIterator) == c) foundIndex = localTail; localTail = (localTail + 1) % rxBuffSize; } - //if our mode is SYNC_SPINWAIT and we didn't see any matching characters in our buffer - //spin until we find a match! - if(mode == SYNC_SPINWAIT) - { - while(foundIndex == -1) - { - while(localTail == rxBuffHead); + // if our mode is SYNC_SPINWAIT and we didn't see any matching characters in our buffer + // spin until we find a match! + if (mode == SYNC_SPINWAIT) { + while (foundIndex == -1) { + while (localTail == rxBuffHead) + ; char c = rxBuff[localTail]; - for(int delimeterIterator = 0; delimeterIterator < delimeters.length(); delimeterIterator++) - if(delimeters.charAt(delimeterIterator) == c) - foundIndex = localTail; + for (int delimeterIterator = 0; delimeterIterator < delimeters.length(); delimeterIterator++) + if (delimeters.charAt(delimeterIterator) == c) foundIndex = localTail; localTail = (localTail + 1) % rxBuffSize; } } - //if our mode is SYNC_SLEEP, we set up an event to be fired when we see a - //matching character. - if(mode == SYNC_SLEEP && foundIndex == -1) - { + // if our mode is SYNC_SLEEP, we set up an event to be fired when we see a + // matching character. + if (mode == SYNC_SLEEP && foundIndex == -1) { eventOn(delimeters, mode); foundIndex = rxBuffHead - 1; - if (foundIndex < 0) - foundIndex += rxBuffSize; + if (foundIndex < 0) foundIndex += rxBuffSize; this->delimeters = ManagedString(); } - if(foundIndex >= 0) - { - //calculate our local buffer size - int localBuffSize = (preservedTail > foundIndex) ? (rxBuffSize - preservedTail) + foundIndex : foundIndex - preservedTail; + if (foundIndex >= 0) { + // calculate our local buffer size + int localBuffSize = + (preservedTail > foundIndex) ? (rxBuffSize - preservedTail) + foundIndex : foundIndex - preservedTail; uint8_t localBuff[localBuffSize + 1]; @@ -789,12 +735,12 @@ ManagedString Serial::readUntil(ManagedString delimeters, SerialMode mode) circularCopy(rxBuff, rxBuffSize, localBuff, preservedTail, foundIndex); - //plus one for the character we listened for... + // plus one for the character we listened for... rxBuffTail = (rxBuffTail + localBuffSize + 1) % rxBuffSize; unlockRx(); - return ManagedString((char *)localBuff, localBuffSize); + return ManagedString((char*)localBuff, localBuffSize); } unlockRx(); @@ -807,7 +753,8 @@ ManagedString Serial::readUntil(ManagedString delimeters, SerialMode mode) * as it changes and restore it if redirect() is called. * * @param baudrate the new baudrate. See: - * - https://github.com/mbedmicro/mbed/blob/master/libraries/mbed/targets/hal/TARGET_NORDIC/TARGET_MCU_NRF51822/serial_api.c + * - + * https://github.com/mbedmicro/mbed/blob/master/libraries/mbed/targets/hal/TARGET_NORDIC/TARGET_MCU_NRF51822/serial_api.c * for permitted baud rates. * * @return DEVICE_INVALID_PARAMETER if baud rate is less than 0, otherwise DEVICE_OK. @@ -816,13 +763,11 @@ ManagedString Serial::readUntil(ManagedString delimeters, SerialMode mode) */ int Serial::setBaud(int baudrate) { - if(baudrate < 0) - return DEVICE_INVALID_PARAMETER; + if (baudrate < 0) return DEVICE_INVALID_PARAMETER; int ret = setBaudrate((uint32_t)baudrate); - if (ret == DEVICE_OK) - this->baudrate = baudrate; + if (ret == DEVICE_OK) this->baudrate = baudrate; return ret; } @@ -838,8 +783,7 @@ int Serial::setBaud(int baudrate) */ int Serial::redirect(Pin& tx, Pin& rx) { - if(txInUse() || rxInUse()) - return DEVICE_SERIAL_IN_USE; + if (txInUse() || rxInUse()) return DEVICE_SERIAL_IN_USE; lockTx(); lockRx(); @@ -847,20 +791,18 @@ int Serial::redirect(Pin& tx, Pin& rx) reassignPin(&this->tx, &tx); reassignPin(&this->rx, &rx); - if(txBufferedSize() > 0) - disableInterrupt(TxInterrupt); + if (txBufferedSize() > 0) disableInterrupt(TxInterrupt); disableInterrupt(RxInterrupt); // To be compatible with V1 behaviour - rx.setPull( PullMode::Up ); + rx.setPull(PullMode::Up); configurePins(tx, rx); enableInterrupt(RxInterrupt); - if(txBufferedSize() > 0) - enableInterrupt(TxInterrupt); + if (txBufferedSize() > 0) enableInterrupt(TxInterrupt); this->setBaud(this->baudrate); @@ -891,19 +833,16 @@ int Serial::redirect(Pin& tx, Pin& rx) */ int Serial::eventAfter(int len, SerialMode mode) { - if(mode == SYNC_SPINWAIT) - return DEVICE_INVALID_PARAMETER; + if (mode == SYNC_SPINWAIT) return DEVICE_INVALID_PARAMETER; // Schedule this fiber to wake on an event from the serial port, if necessary - if(mode == SYNC_SLEEP) - fiber_wake_on_event(this->id, CODAL_SERIAL_EVT_HEAD_MATCH); + if (mode == SYNC_SLEEP) fiber_wake_on_event(this->id, CODAL_SERIAL_EVT_HEAD_MATCH); - //configure our head match... + // configure our head match... this->rxBuffHeadMatch = (rxBuffHead + len) % rxBuffSize; // Deschedule this fiber, if necessary - if(mode == SYNC_SLEEP) - schedule(); + if (mode == SYNC_SLEEP) schedule(); return DEVICE_OK; } @@ -931,18 +870,15 @@ int Serial::eventAfter(int len, SerialMode mode) */ int Serial::eventOn(ManagedString delimeters, SerialMode mode) { - if(mode == SYNC_SPINWAIT) - return DEVICE_INVALID_PARAMETER; + if (mode == SYNC_SPINWAIT) return DEVICE_INVALID_PARAMETER; - //configure our head match... + // configure our head match... this->delimeters = delimeters; - //block! - if(mode == SYNC_SLEEP) - fiber_wait_for_event(this->id, CODAL_SERIAL_EVT_DELIM_MATCH); + // block! + if (mode == SYNC_SLEEP) fiber_wait_for_event(this->id, CODAL_SERIAL_EVT_DELIM_MATCH); return DEVICE_OK; - } /** @@ -955,12 +891,10 @@ int Serial::eventOn(ManagedString delimeters, SerialMode mode) */ int Serial::isReadable() { - if(!(status & CODAL_SERIAL_STATUS_RX_BUFF_INIT)) - { + if (!(status & CODAL_SERIAL_STATUS_RX_BUFF_INIT)) { int result = initialiseRx(); - if(result != DEVICE_OK) - return result; + if (result != DEVICE_OK) return result; } return (rxBuffTail != rxBuffHead) ? 1 : 0; @@ -989,14 +923,12 @@ int Serial::isWriteable() */ int Serial::setRxBufferSize(uint8_t size) { - if(rxInUse()) - return DEVICE_SERIAL_IN_USE; + if (rxInUse()) return DEVICE_SERIAL_IN_USE; lockRx(); // + 1 so there is a usable buffer size, of the size the user requested. - if (size != 255) - size++; + if (size != 255) size++; this->rxBuffSize = size; @@ -1017,14 +949,12 @@ int Serial::setRxBufferSize(uint8_t size) */ int Serial::setTxBufferSize(uint8_t size) { - if(txInUse()) - return DEVICE_SERIAL_IN_USE; + if (txInUse()) return DEVICE_SERIAL_IN_USE; lockTx(); // + 1 so there is a usable buffer size, of the size the user requested. - if (size != 255) - size++; + if (size != 255) size++; this->txBuffSize = size; @@ -1064,8 +994,7 @@ int Serial::getTxBufferSize() */ int Serial::clearRxBuffer() { - if(rxInUse()) - return DEVICE_SERIAL_IN_USE; + if (rxInUse()) return DEVICE_SERIAL_IN_USE; lockRx(); @@ -1085,8 +1014,7 @@ int Serial::clearRxBuffer() */ int Serial::clearTxBuffer() { - if(txInUse()) - return DEVICE_SERIAL_IN_USE; + if (txInUse()) return DEVICE_SERIAL_IN_USE; lockTx(); @@ -1105,8 +1033,7 @@ int Serial::clearTxBuffer() */ int Serial::rxBufferedSize() { - if(rxBuffTail > rxBuffHead) - return (rxBuffSize - rxBuffTail) + rxBuffHead; + if (rxBuffTail > rxBuffHead) return (rxBuffSize - rxBuffTail) + rxBuffHead; return rxBuffHead - rxBuffTail; } @@ -1119,8 +1046,7 @@ int Serial::rxBufferedSize() */ int Serial::txBufferedSize() { - if(txBuffTail > txBuffHead) - return (txBuffSize - txBuffTail) + txBuffHead; + if (txBuffTail > txBuffHead) return (txBuffSize - txBuffTail) + txBuffHead; return txBuffHead - txBuffTail; } @@ -1149,7 +1075,4 @@ int Serial::txInUse() return (status & CODAL_SERIAL_STATUS_TX_IN_USE); } -Serial::~Serial() -{ - -} \ No newline at end of file +Serial::~Serial() {} \ No newline at end of file diff --git a/source/driver-models/Timer.cpp b/source/driver-models/Timer.cpp index 23500ebc..8ac85714 100644 --- a/source/driver-models/Timer.cpp +++ b/source/driver-models/Timer.cpp @@ -23,25 +23,26 @@ DEALINGS IN THE SOFTWARE. */ /** - * Definitions for the Device system timer. - * - * This module provides: - * - * 1) a concept of global system time since power up - * 2) a simple periodic multiplexing API for the underlying mbed implementation. - * - * The latter is useful to avoid costs associated with multiple mbed Ticker instances - * in codal components, as each incurs a significant additional RAM overhead (circa 80 bytes). - */ + * Definitions for the Device system timer. + * + * This module provides: + * + * 1) a concept of global system time since power up + * 2) a simple periodic multiplexing API for the underlying mbed implementation. + * + * The latter is useful to avoid costs associated with multiple mbed Ticker instances + * in codal components, as each incurs a significant additional RAM overhead (circa 80 bytes). + */ #include "Timer.h" -#include "Event.h" + #include "CodalCompat.h" -#include "ErrorNo.h" -#include "codal_target_hal.h" #include "CodalDmesg.h" #include "CodalFiber.h" +#include "ErrorNo.h" +#include "Event.h" #include "NotifyEvents.h" +#include "codal_target_hal.h" using namespace codal; @@ -53,8 +54,7 @@ static uint32_t cycleScale = 0; void timer_callback(uint16_t chan) { - if (system_timer) - { + if (system_timer) { if (chan & (1 << system_timer->ccPeriodChannel)) system_timer->trigger(true); else @@ -73,24 +73,21 @@ void Timer::triggerIn(CODAL_TIMESTAMP t) } REAL_TIME_FUNC -TimerEvent *Timer::getTimerEvent() +TimerEvent* Timer::getTimerEvent() { // Find the first unused slot, and assign it. - for (int i=0; i < eventListSize; i++) - { - if (timerEventList[i].id == 0) - return &timerEventList[i]; + for (int i = 0; i < eventListSize; i++) { + if (timerEventList[i].id == 0) return &timerEventList[i]; } // TODO: should try to realloc the list here. return NULL; } -void Timer::releaseTimerEvent(TimerEvent *event) +void Timer::releaseTimerEvent(TimerEvent* event) { event->id = 0; - if (nextTimerEvent == event) - nextTimerEvent = NULL; + if (nextTimerEvent == event) nextTimerEvent = NULL; } /** @@ -100,19 +97,18 @@ Timer::Timer(LowLevelTimer& t, uint8_t ccPeriodChannel, uint8_t ccEventChannel) { // Register ourselves as the defualt timer - most recent timer wins. system_timer = this; - this->ccPeriodChannel = ccPeriodChannel; - this->ccEventChannel = ccEventChannel; + this->ccEventChannel = ccEventChannel; // Create an empty event list of the default size. - eventListSize = CODAL_TIMER_DEFAULT_EVENT_LIST_SIZE; - timerEventList = (TimerEvent *) malloc(sizeof(TimerEvent) * CODAL_TIMER_DEFAULT_EVENT_LIST_SIZE); + eventListSize = CODAL_TIMER_DEFAULT_EVENT_LIST_SIZE; + timerEventList = (TimerEvent*)malloc(sizeof(TimerEvent) * CODAL_TIMER_DEFAULT_EVENT_LIST_SIZE); memclr(timerEventList, sizeof(TimerEvent) * CODAL_TIMER_DEFAULT_EVENT_LIST_SIZE); nextTimerEvent = NULL; // Reset clock - currentTime = 0; + currentTime = 0; currentTimeUs = 0; timer.setIRQ(timer_callback); @@ -166,16 +162,14 @@ int Timer::enableInterrupts() REAL_TIME_FUNC int Timer::setEvent(CODAL_TIMESTAMP period, uint16_t id, uint16_t value, bool repeat, uint32_t flags) { - TimerEvent *evt = getTimerEvent(); - if (evt == NULL) - return DEVICE_NO_RESOURCES; + TimerEvent* evt = getTimerEvent(); + if (evt == NULL) return DEVICE_NO_RESOURCES; - evt->set(getTimeUs() + period, repeat ? period: 0, id, value, flags); + evt->set(getTimeUs() + period, repeat ? period : 0, id, value, flags); target_disable_irq(); - if (nextTimerEvent == NULL || evt->timestamp < nextTimerEvent->timestamp) - { + if (nextTimerEvent == NULL || evt->timestamp < nextTimerEvent->timestamp) { nextTimerEvent = evt; triggerIn(period); } @@ -185,7 +179,6 @@ int Timer::setEvent(CODAL_TIMESTAMP period, uint16_t id, uint16_t value, bool re return DEVICE_OK; } - /** * Cancels any events matching the given id and value. * @@ -199,19 +192,16 @@ int Timer::cancel(uint16_t id, uint16_t value) int res = DEVICE_INVALID_PARAMETER; target_disable_irq(); - if (nextTimerEvent && nextTimerEvent->id == id && nextTimerEvent->value == value) - { + if (nextTimerEvent && nextTimerEvent->id == id && nextTimerEvent->value == value) { nextTimerEvent->id = 0; recomputeNextTimerEvent(); res = DEVICE_OK; } else - for (int i=0; iid != 0 && (nextTimerEvent == NULL || (e->timestamp < nextTimerEvent->timestamp))) - nextTimerEvent = e; + for (int i = 0; i < eventListSize; i++) { + if (e->id != 0 && (nextTimerEvent == NULL || (e->timestamp < nextTimerEvent->timestamp))) nextTimerEvent = e; e++; } @@ -353,30 +341,23 @@ void Timer::recomputeNextTimerEvent() */ void Timer::trigger(bool isFallback) { - if (isFallback) - timer.setCompare(ccPeriodChannel, timer.captureCounter() + 10000000); + if (isFallback) timer.setCompare(ccPeriodChannel, timer.captureCounter() + 10000000); int eventsFired; sync(); // Now, walk the list and trigger any events that are pending. - do - { - eventsFired = 0; - TimerEvent *e = timerEventList; - - for (int i = 0; iid != 0) - { - if (currentTimeUs >= e->timestamp) - { - uint16_t id = e->id; + do { + eventsFired = 0; + TimerEvent* e = timerEventList; + + for (int i = 0; i < eventListSize; i++) { + if (e->id != 0) { + if (currentTimeUs >= e->timestamp) { + uint16_t id = e->id; uint16_t value = e->value; - - // Release before triggering event. Otherwise, an immediate event handler // can cancel this event, another event might be put in its place // and we end up releasing (or repeating) a completely different event. @@ -385,23 +366,23 @@ void Timer::trigger(bool isFallback) else e->timestamp += e->period; - // We need to trigger this event. - #if CONFIG_ENABLED(LIGHTWEIGHT_EVENTS) + // We need to trigger this event. +#if CONFIG_ENABLED(LIGHTWEIGHT_EVENTS) Event evt(id, value, currentTime); - #else +#else Event evt(id, value, currentTimeUs); - #endif +#endif // TODO: Handle rollover case above... eventsFired++; } - else if ( e->flags & CODAL_TIMER_EVENT_FLAGS_WAKEUP && fiber_scheduler_get_deepsleep_pending() && e->timestamp < currentTimeUs + 100000) - { - #if CONFIG_ENABLED(LIGHTWEIGHT_EVENTS) + else if (e->flags & CODAL_TIMER_EVENT_FLAGS_WAKEUP && fiber_scheduler_get_deepsleep_pending() && + e->timestamp < currentTimeUs + 100000) { +#if CONFIG_ENABLED(LIGHTWEIGHT_EVENTS) Event evt(DEVICE_ID_NOTIFY, POWER_EVT_CANCEL_DEEPSLEEP, currentTime); - #else +#else Event evt(DEVICE_ID_NOTIFY, POWER_EVT_CANCEL_DEEPSLEEP, currentTimeUs); - #endif +#endif } } e++; @@ -416,17 +397,14 @@ void Timer::trigger(bool isFallback) /** * Find the next event with the WAKEUP flag */ -TimerEvent *Timer::deepSleepWakeUpEvent() +TimerEvent* Timer::deepSleepWakeUpEvent() { - TimerEvent *wakeUpEvent = NULL; + TimerEvent* wakeUpEvent = NULL; - TimerEvent *eNext = timerEventList + eventListSize; - for ( TimerEvent *e = timerEventList; e < eNext; e++) - { - if ( e->id != 0 && e->flags & CODAL_TIMER_EVENT_FLAGS_WAKEUP) - { - if ( wakeUpEvent == NULL || (e->timestamp < wakeUpEvent->timestamp)) - wakeUpEvent = e; + TimerEvent* eNext = timerEventList + eventListSize; + for (TimerEvent* e = timerEventList; e < eNext; e++) { + if (e->id != 0 && e->flags & CODAL_TIMER_EVENT_FLAGS_WAKEUP) { + if (wakeUpEvent == NULL || (e->timestamp < wakeUpEvent->timestamp)) wakeUpEvent = e; } } @@ -434,21 +412,21 @@ TimerEvent *Timer::deepSleepWakeUpEvent() } /** - * Determine the current time and the corresponding timer counter, - * to enable the caller to take over tracking time. - * - * @param counter reference to a variable to receive the current timer counter - * - * @return the current time since power on in microseconds - */ + * Determine the current time and the corresponding timer counter, + * to enable the caller to take over tracking time. + * + * @param counter reference to a variable to receive the current timer counter + * + * @return the current time since power on in microseconds + */ REAL_TIME_FUNC -CODAL_TIMESTAMP Timer::deepSleepBegin( CODAL_TIMESTAMP &counter) +CODAL_TIMESTAMP Timer::deepSleepBegin(CODAL_TIMESTAMP& counter) { // Need to disable all IRQs - for example if SPI IRQ is triggered during // sync(), it might call into getTimeUs(), which would call sync() target_disable_irq(); - uint32_t val = timer.captureCounter(); + uint32_t val = timer.captureCounter(); uint32_t elapsed = 0; #if CONFIG_ENABLED(CODAL_TIMER_32BIT) @@ -479,31 +457,30 @@ CODAL_TIMESTAMP Timer::deepSleepBegin( CODAL_TIMESTAMP &counter) } /** - * After taking over time tracking with system_timer_deepsleep_begin, - * hand back control by supplying a new timer counter value with - * corresponding elapsed time since taking over tracking. - * - * The counter and elapsed time may be zero if the time has been maintained - * meanwhile by calling system_timer_current_time_us(). - * - * Event timestamps are are shifted towards the present. - * "after" and "every" events that would have fired during deep sleep - * will fire once as if firing late, then "every" events will - * resume the same relative timings. - * - * @param counter the current timer counter. - * @param micros time elapsed since system_timer_deepsleep_begin - * - * @return DEVICE_OK or DEVICE_NOT_SUPPORTED if no timer has been registered. - */ + * After taking over time tracking with system_timer_deepsleep_begin, + * hand back control by supplying a new timer counter value with + * corresponding elapsed time since taking over tracking. + * + * The counter and elapsed time may be zero if the time has been maintained + * meanwhile by calling system_timer_current_time_us(). + * + * Event timestamps are are shifted towards the present. + * "after" and "every" events that would have fired during deep sleep + * will fire once as if firing late, then "every" events will + * resume the same relative timings. + * + * @param counter the current timer counter. + * @param micros time elapsed since system_timer_deepsleep_begin + * + * @return DEVICE_OK or DEVICE_NOT_SUPPORTED if no timer has been registered. + */ REAL_TIME_FUNC -void Timer::deepSleepEnd( CODAL_TIMESTAMP counter, CODAL_TIMESTAMP micros) +void Timer::deepSleepEnd(CODAL_TIMESTAMP counter, CODAL_TIMESTAMP micros) { // On entry, the timer IRQ is disabled and must not be enabled target_disable_irq(); - if ( micros > 0) - { + if (micros > 0) { currentTimeUs += micros; CODAL_TIMESTAMP millis = micros / 1000; @@ -518,9 +495,9 @@ void Timer::deepSleepEnd( CODAL_TIMESTAMP counter, CODAL_TIMESTAMP micros) } #if CONFIG_ENABLED(CODAL_TIMER_32BIT) - sigma = (uint32_t) counter; + sigma = (uint32_t)counter; #else - sigma = (uint16_t) counter; + sigma = (uint16_t)counter; #endif } @@ -531,25 +508,18 @@ void Timer::deepSleepEnd( CODAL_TIMESTAMP counter, CODAL_TIMESTAMP micros) // For some periodic events that will mean some events are dropped, // but subsequent events will be on the same schedule as before deep sleep. CODAL_TIMESTAMP present = currentTimeUs + CODAL_TIMER_MINIMUM_PERIOD; - nextTimerEvent = NULL; - TimerEvent *eNext = timerEventList + eventListSize; - for ( TimerEvent *e = timerEventList; e < eNext; e++) - { - if ( e->id != 0) - { - if ( e->period == 0) - { - if ( e->timestamp < present) - e->timestamp = present; + nextTimerEvent = NULL; + TimerEvent* eNext = timerEventList + eventListSize; + for (TimerEvent* e = timerEventList; e < eNext; e++) { + if (e->id != 0) { + if (e->period == 0) { + if (e->timestamp < present) e->timestamp = present; } - else - { - while ( e->timestamp + e->period < present) - e->timestamp += e->period; + else { + while (e->timestamp + e->period < present) e->timestamp += e->period; } - if ( nextTimerEvent == NULL || nextTimerEvent->timestamp > e->timestamp) - nextTimerEvent = e; + if (nextTimerEvent == NULL || nextTimerEvent->timestamp > e->timestamp) nextTimerEvent = e; } } @@ -557,8 +527,7 @@ void Timer::deepSleepEnd( CODAL_TIMESTAMP counter, CODAL_TIMESTAMP micros) timer.setCompare(ccPeriodChannel, counterNow + 10000000); - if (nextTimerEvent) - timer.setCompare( ccEventChannel, counterNow + CODAL_TIMER_MINIMUM_PERIOD); + if (nextTimerEvent) timer.setCompare(ccEventChannel, counterNow + CODAL_TIMER_MINIMUM_PERIOD); target_enable_irq(); } @@ -568,12 +537,11 @@ void Timer::deepSleepEnd( CODAL_TIMESTAMP counter, CODAL_TIMESTAMP micros) * @param timestamp reference to a variable to receive the time. * @return true if there is an event. */ -bool Timer::deepSleepWakeUpTime( CODAL_TIMESTAMP ×tamp) +bool Timer::deepSleepWakeUpTime(CODAL_TIMESTAMP& timestamp) { - TimerEvent *wakeUpEvent = deepSleepWakeUpEvent(); + TimerEvent* wakeUpEvent = deepSleepWakeUpEvent(); - if ( wakeUpEvent == NULL) - return false; + if (wakeUpEvent == NULL) return false; timestamp = wakeUpEvent->timestamp; return true; @@ -582,10 +550,7 @@ bool Timer::deepSleepWakeUpTime( CODAL_TIMESTAMP ×tamp) /** * Destructor for this Timer instance */ -Timer::~Timer() -{ -} - +Timer::~Timer() {} /* * @@ -593,105 +558,99 @@ Timer::~Timer() * */ /** - * Determines the time since the device was powered on. - * - * @return the current time since power on in milliseconds - */ + * Determines the time since the device was powered on. + * + * @return the current time since power on in milliseconds + */ CODAL_TIMESTAMP codal::system_timer_current_time() { - if(system_timer == NULL) - return 0; + if (system_timer == NULL) return 0; return system_timer->getTime(); } /** - * Determines the time since the device was powered on. - * - * @return the current time since power on in microseconds - */ + * Determines the time since the device was powered on. + * + * @return the current time since power on in microseconds + */ REAL_TIME_FUNC CODAL_TIMESTAMP codal::system_timer_current_time_us() { - if(system_timer == NULL) - return 0; + if (system_timer == NULL) return 0; return system_timer->getTimeUs(); } /** - * Configure an event to occur every period us. - * - * @param period the interval between events - * - * @param the value to fire against the current system_timer id. - * - * @param flags CODAL_TIMER_EVENT_FLAGS_WAKEUP for event to trigger deep sleep wake-up. - * - * @return DEVICE_OK or DEVICE_NOT_SUPPORTED if no timer has been registered. - */ + * Configure an event to occur every period us. + * + * @param period the interval between events + * + * @param the value to fire against the current system_timer id. + * + * @param flags CODAL_TIMER_EVENT_FLAGS_WAKEUP for event to trigger deep sleep wake-up. + * + * @return DEVICE_OK or DEVICE_NOT_SUPPORTED if no timer has been registered. + */ int codal::system_timer_event_every_us(CODAL_TIMESTAMP period, uint16_t id, uint16_t value, uint32_t flags) { - if(system_timer == NULL) - return DEVICE_NOT_SUPPORTED; + if (system_timer == NULL) return DEVICE_NOT_SUPPORTED; return system_timer->eventEveryUs(period, id, value, flags); } /** - * Configure an event to occur after period us. - * - * @param period the interval between events - * - * @param the value to fire against the current system_timer id. - * - * @param flags CODAL_TIMER_EVENT_FLAGS_WAKEUP for event to trigger deep sleep wake-up. - * - * @return DEVICE_OK or DEVICE_NOT_SUPPORTED if no timer has been registered. - */ + * Configure an event to occur after period us. + * + * @param period the interval between events + * + * @param the value to fire against the current system_timer id. + * + * @param flags CODAL_TIMER_EVENT_FLAGS_WAKEUP for event to trigger deep sleep wake-up. + * + * @return DEVICE_OK or DEVICE_NOT_SUPPORTED if no timer has been registered. + */ REAL_TIME_FUNC int codal::system_timer_event_after_us(CODAL_TIMESTAMP period, uint16_t id, uint16_t value, uint32_t flags) { - if(system_timer == NULL) - return DEVICE_NOT_SUPPORTED; + if (system_timer == NULL) return DEVICE_NOT_SUPPORTED; return system_timer->eventAfterUs(period, id, value, flags); } /** - * Configure an event to occur every period milliseconds. - * - * @param period the interval between events - * - * @param the value to fire against the current system_timer id. - * - * @param flags CODAL_TIMER_EVENT_FLAGS_WAKEUP for event to trigger deep sleep wake-up. - * - * @return DEVICE_OK or DEVICE_NOT_SUPPORTED if no timer has been registered. - */ + * Configure an event to occur every period milliseconds. + * + * @param period the interval between events + * + * @param the value to fire against the current system_timer id. + * + * @param flags CODAL_TIMER_EVENT_FLAGS_WAKEUP for event to trigger deep sleep wake-up. + * + * @return DEVICE_OK or DEVICE_NOT_SUPPORTED if no timer has been registered. + */ int codal::system_timer_event_every(CODAL_TIMESTAMP period, uint16_t id, uint16_t value, uint32_t flags) { - if(system_timer == NULL) - return DEVICE_NOT_SUPPORTED; + if (system_timer == NULL) return DEVICE_NOT_SUPPORTED; return system_timer->eventEvery(period, id, value, flags); } /** - * Configure an event to occur after period millseconds. - * - * @param period the interval between events - * - * @param the value to fire against the current system_timer id. - * - * @param flags CODAL_TIMER_EVENT_FLAGS_WAKEUP for event to trigger deep sleep wake-up. - * - * @return DEVICE_OK or DEVICE_NOT_SUPPORTED if no timer has been registered. - */ + * Configure an event to occur after period millseconds. + * + * @param period the interval between events + * + * @param the value to fire against the current system_timer id. + * + * @param flags CODAL_TIMER_EVENT_FLAGS_WAKEUP for event to trigger deep sleep wake-up. + * + * @return DEVICE_OK or DEVICE_NOT_SUPPORTED if no timer has been registered. + */ int codal::system_timer_event_after(CODAL_TIMESTAMP period, uint16_t id, uint16_t value, uint32_t flags) { - if(system_timer == NULL) - return DEVICE_NOT_SUPPORTED; + if (system_timer == NULL) return DEVICE_NOT_SUPPORTED; return system_timer->eventAfter(period, id, value, flags); } @@ -705,8 +664,7 @@ int codal::system_timer_event_after(CODAL_TIMESTAMP period, uint16_t id, uint16_ */ int codal::system_timer_cancel_event(uint16_t id, uint16_t value) { - if(system_timer == NULL) - return DEVICE_NOT_SUPPORTED; + if (system_timer == NULL) return DEVICE_NOT_SUPPORTED; return system_timer->cancel(id, value); } @@ -715,7 +673,8 @@ int codal::system_timer_cancel_event(uint16_t id, uint16_t value) * An auto calibration method that uses the hardware timer to compute the number of cycles * per us. * - * The result of this method is then used to compute accurate us waits using instruction counting in system_timer_wait_us. + * The result of this method is then used to compute accurate us waits using instruction counting in + * system_timer_wait_us. * * If this method is not called, a less accurate timer implementation is used in system_timer_wait_us. * @@ -723,13 +682,12 @@ int codal::system_timer_cancel_event(uint16_t id, uint16_t value) */ int codal::system_timer_calibrate_cycles() { - if(system_timer == NULL) - return DEVICE_NOT_SUPPORTED; + if (system_timer == NULL) return DEVICE_NOT_SUPPORTED; uint32_t start = system_timer->getTimeUs(); system_timer_wait_cycles(10000); uint32_t end = system_timer->getTimeUs(); - cycleScale = (10000) / (end - start - 5); + cycleScale = (10000) / (end - start - 5); return DEVICE_OK; } @@ -746,11 +704,11 @@ void codal::system_timer_wait_cycles(uint32_t cycles) __asm__ __volatile__( ".syntax unified\n" "1: \n" - " subs %0, #1 \n" // subtract 1 from %0 (n) - " bne 1b \n" // if result is not 0 jump to 1 - : "+r" (cycles) // '%0' is n variable with RW constraints - : // no input - : // no clobber + " subs %0, #1 \n" // subtract 1 from %0 (n) + " bne 1b \n" // if result is not 0 jump to 1 + : "+r"(cycles) // '%0' is n variable with RW constraints + : // no input + : // no clobber ); } @@ -767,15 +725,14 @@ void codal::system_timer_wait_cycles(uint32_t cycles) REAL_TIME_FUNC int codal::system_timer_wait_us(uint32_t period) { - if(system_timer == NULL) - return DEVICE_NOT_SUPPORTED; + if (system_timer == NULL) return DEVICE_NOT_SUPPORTED; - if(cycleScale) + if (cycleScale) system_timer_wait_cycles(period * cycleScale); - else - { + else { CODAL_TIMESTAMP start = system_timer->getTimeUs(); - while(system_timer->getTimeUs() < start + period); + while (system_timer->getTimeUs() < start + period) + ; } return DEVICE_OK; @@ -796,19 +753,18 @@ int codal::system_timer_wait_ms(uint32_t period) } /** - * Called from power manager before deep sleep. - * @param counter reference to a variable to receive the current timer counter - * - * @return the current time since power on in microseconds - */ -CODAL_TIMESTAMP codal::system_timer_deepsleep_begin( CODAL_TIMESTAMP &counter) -{ - if(system_timer == NULL) - { + * Called from power manager before deep sleep. + * @param counter reference to a variable to receive the current timer counter + * + * @return the current time since power on in microseconds + */ +CODAL_TIMESTAMP codal::system_timer_deepsleep_begin(CODAL_TIMESTAMP& counter) +{ + if (system_timer == NULL) { counter = 0; return 0; } - return system_timer->deepSleepBegin( counter); + return system_timer->deepSleepBegin(counter); } /** @@ -818,12 +774,11 @@ CODAL_TIMESTAMP codal::system_timer_deepsleep_begin( CODAL_TIMESTAMP &counter) * * @return DEVICE_OK or DEVICE_NOT_SUPPORTED if no timer has been registered. */ -int codal::system_timer_deepsleep_end( CODAL_TIMESTAMP counter, CODAL_TIMESTAMP micros) +int codal::system_timer_deepsleep_end(CODAL_TIMESTAMP counter, CODAL_TIMESTAMP micros) { - if(system_timer == NULL) - return DEVICE_NOT_SUPPORTED; + if (system_timer == NULL) return DEVICE_NOT_SUPPORTED; - system_timer->deepSleepEnd( counter, micros); + system_timer->deepSleepEnd(counter, micros); return DEVICE_OK; } @@ -832,11 +787,9 @@ int codal::system_timer_deepsleep_end( CODAL_TIMESTAMP counter, CODAL_TIMESTAMP * @param timestamp reference to a variable to receive the time. * @return true if there is an event. */ -bool codal::system_timer_deepsleep_wakeup_time( CODAL_TIMESTAMP ×tamp) +bool codal::system_timer_deepsleep_wakeup_time(CODAL_TIMESTAMP& timestamp) { - if(system_timer == NULL) - return false; + if (system_timer == NULL) return false; return system_timer->deepSleepWakeUpTime(timestamp); } - diff --git a/source/drivers/AnalogSensor.cpp b/source/drivers/AnalogSensor.cpp index 8a4b88aa..17ccafc3 100644 --- a/source/drivers/AnalogSensor.cpp +++ b/source/drivers/AnalogSensor.cpp @@ -25,8 +25,9 @@ DEALINGS IN THE SOFTWARE. #include "AnalogSensor.h" /** - * Class definition for a generic analog sensor, that takes the general form of a logarithmic response to a sensed value, in a potential divider. - * Implements a base class for such a sensor, using the Steinhart-Hart equation to delineate a result. + * Class definition for a generic analog sensor, that takes the general form of a logarithmic response to a sensed + * value, in a potential divider. Implements a base class for such a sensor, using the Steinhart-Hart equation to + * delineate a result. */ using namespace codal; @@ -39,7 +40,7 @@ using namespace codal; * @param pin The pin on which to sense * @param id The ID of this component e.g. DEVICE_ID_THERMOMETER */ -AnalogSensor::AnalogSensor(Pin &pin, uint16_t id) : Sensor( id), pin(pin) +AnalogSensor::AnalogSensor(Pin& pin, uint16_t id) : Sensor(id), pin(pin) { updateSample(); } @@ -55,6 +56,4 @@ int AnalogSensor::readValue() /** * Destructor. */ -AnalogSensor::~AnalogSensor() -{ -} \ No newline at end of file +AnalogSensor::~AnalogSensor() {} \ No newline at end of file diff --git a/source/drivers/AnimatedDisplay.cpp b/source/drivers/AnimatedDisplay.cpp index 6dac17dc..76cc0716 100644 --- a/source/drivers/AnimatedDisplay.cpp +++ b/source/drivers/AnimatedDisplay.cpp @@ -23,78 +23,74 @@ DEALINGS IN THE SOFTWARE. */ /** - * Class definition for AnimatedDisplay. - * - * This class provides a high level abstraction level to show text and graphic animations on a - * Display, e.g. on an LED matrix display. - */ + * Class definition for AnimatedDisplay. + * + * This class provides a high level abstraction level to show text and graphic animations on a + * Display, e.g. on an LED matrix display. + */ #include "AnimatedDisplay.h" + +#include "CodalDmesg.h" #include "CodalFiber.h" #include "NotifyEvents.h" -#include "CodalDmesg.h" using namespace codal; - /** - * Constructor. - * - * Create a software representation of an animated display. - * This class provides a high level abstraction level to show text and graphic animations on a - * Display, e.g. on an LED matrix display. - * - * @param display The Display instance that is used to show the text and graphic animations of this class - * @param id The id the display should use when sending events on the MessageBus. Defaults to DEVICE_ID_DISPLAY. - * - */ -AnimatedDisplay::AnimatedDisplay(Display& _display, uint16_t id) : display(_display), font(), printingText(), scrollingImage() +/** + * Constructor. + * + * Create a software representation of an animated display. + * This class provides a high level abstraction level to show text and graphic animations on a + * Display, e.g. on an LED matrix display. + * + * @param display The Display instance that is used to show the text and graphic animations of this class + * @param id The id the display should use when sending events on the MessageBus. Defaults to DEVICE_ID_DISPLAY. + * + */ +AnimatedDisplay::AnimatedDisplay(Display& _display, uint16_t id) + : display(_display), font(), printingText(), scrollingImage() { - this->id = id; + this->id = id; this->status = 0; status |= DEVICE_COMPONENT_STATUS_SYSTEM_TICK; status |= DEVICE_COMPONENT_RUNNING; - animationMode = AnimationMode::ANIMATION_MODE_NONE; - animationDelay = 0; - animationTick = 0; - scrollingChar = 0; - scrollingPosition = 0; - printingChar = 0; + animationMode = AnimationMode::ANIMATION_MODE_NONE; + animationDelay = 0; + animationTick = 0; + scrollingChar = 0; + scrollingPosition = 0; + printingChar = 0; scrollingImagePosition = 0; - scrollingImageStride = 0; + scrollingImageStride = 0; scrollingImageRendered = false; } /** - * Periodic callback, that we use to perform any animations we have running. - */ + * Periodic callback, that we use to perform any animations we have running. + */ void AnimatedDisplay::animationUpdate() { // If there's no ongoing animation, then nothing to do. - if (animationMode == ANIMATION_MODE_NONE) - return; + if (animationMode == ANIMATION_MODE_NONE) return; - animationTick += (SCHEDULER_TICK_PERIOD_US/1000); + animationTick += (SCHEDULER_TICK_PERIOD_US / 1000); - if(animationTick >= animationDelay) - { + if (animationTick >= animationDelay) { animationTick = 0; - if (animationMode == ANIMATION_MODE_SCROLL_TEXT) - this->updateScrollText(); + if (animationMode == ANIMATION_MODE_SCROLL_TEXT) this->updateScrollText(); - if (animationMode == ANIMATION_MODE_PRINT_TEXT) - this->updatePrintText(); + if (animationMode == ANIMATION_MODE_PRINT_TEXT) this->updatePrintText(); - if (animationMode == ANIMATION_MODE_SCROLL_IMAGE) - this->updateScrollImage(); + if (animationMode == ANIMATION_MODE_SCROLL_IMAGE) this->updateScrollImage(); if (animationMode == ANIMATION_MODE_ANIMATE_IMAGE || animationMode == ANIMATION_MODE_ANIMATE_IMAGE_WITH_CLEAR) this->updateAnimateImage(); - if(animationMode == ANIMATION_MODE_PRINT_CHARACTER) - { + if (animationMode == ANIMATION_MODE_PRINT_CHARACTER) { animationMode = ANIMATION_MODE_NONE; this->sendAnimationCompleteEvent(); } @@ -102,9 +98,9 @@ void AnimatedDisplay::animationUpdate() } /** - * Broadcasts an event onto the defult EventModel indicating that the - * current animation has completed. - */ + * Broadcasts an event onto the defult EventModel indicating that the + * current animation has completed. + */ void AnimatedDisplay::sendAnimationCompleteEvent() { // Signal that we've completed an animation. @@ -115,9 +111,9 @@ void AnimatedDisplay::sendAnimationCompleteEvent() } /** - * Internal scrollText update method. - * Shift the screen image by one pixel to the left. If necessary, paste in the next char. - */ + * Internal scrollText update method. + * Shift the screen image by one pixel to the left. If necessary, paste in the next char. + */ void AnimatedDisplay::updateScrollText() { /** @@ -128,7 +124,8 @@ void AnimatedDisplay::updateScrollText() { scrollingPosition = 0; - display.image.print(scrollingChar < scrollingText.length() ? scrollingText.charAt(scrollingChar) : ' ', display.getWidth(), 0); + display.image.print(scrollingChar < scrollingText.length() ? scrollingText.charAt(scrollingChar) : ' ', + display.getWidth(), 0); if (scrollingChar > scrollingText.length()) { @@ -142,19 +139,16 @@ void AnimatedDisplay::updateScrollText() display.image.shiftLeft(1); - if (scrollingPosition < BITMAP_FONT_WIDTH && scrollingChar < scrollingText.length()) - { - const uint8_t *v = font.get(scrollingText.charAt(scrollingChar)); + if (scrollingPosition < BITMAP_FONT_WIDTH && scrollingChar < scrollingText.length()) { + const uint8_t* v = font.get(scrollingText.charAt(scrollingChar)); if (v == NULL) { v = font.get(' '); } uint8_t mask = 1 << (BITMAP_FONT_WIDTH - scrollingPosition - 1); - uint8_t x = display.getWidth()-1; + uint8_t x = display.getWidth() - 1; - for (int y=0; y= scrollingText.length()) - { + if (scrollingChar >= scrollingText.length()) { animationMode = ANIMATION_MODE_NONE; this->sendAnimationCompleteEvent(); return; @@ -177,15 +169,14 @@ void AnimatedDisplay::updateScrollText() } /** - * Internal printText update method. - * Paste the next character in the string. - */ + * Internal printText update method. + * Paste the next character in the string. + */ void AnimatedDisplay::updatePrintText() { - display.image.print(printingChar < printingText.length() ? printingText.charAt(printingChar) : ' ',0,0); + display.image.print(printingChar < printingText.length() ? printingText.charAt(printingChar) : ' ', 0, 0); - if (printingChar > printingText.length()) - { + if (printingChar > printingText.length()) { animationMode = ANIMATION_MODE_NONE; this->sendAnimationCompleteEvent(); @@ -196,15 +187,15 @@ void AnimatedDisplay::updatePrintText() } /** - * Internal scrollImage update method. - * Paste the stored bitmap at the appropriate point. - */ + * Internal scrollImage update method. + * Paste the stored bitmap at the appropriate point. + */ void AnimatedDisplay::updateScrollImage() { display.image.clear(); - if (((display.image.paste(scrollingImage, scrollingImagePosition, 0, 0) == 0) && scrollingImageRendered) || scrollingImageStride == 0) - { + if (((display.image.paste(scrollingImage, scrollingImagePosition, 0, 0) == 0) && scrollingImageRendered) || + scrollingImageStride == 0) { animationMode = ANIMATION_MODE_NONE; this->sendAnimationCompleteEvent(); @@ -216,16 +207,15 @@ void AnimatedDisplay::updateScrollImage() } /** - * Internal animateImage update method. - * Paste the stored bitmap at the appropriate point and stop on the last frame. - */ + * Internal animateImage update method. + * Paste the stored bitmap at the appropriate point and stop on the last frame. + */ void AnimatedDisplay::updateAnimateImage() { - //wait until we have rendered the last position to give a continuous animation. - if (scrollingImagePosition <= -scrollingImage.getWidth() + (display.getWidth() + scrollingImageStride) && scrollingImageRendered) - { - if (animationMode == ANIMATION_MODE_ANIMATE_IMAGE_WITH_CLEAR) - display.image.clear(); + // wait until we have rendered the last position to give a continuous animation. + if (scrollingImagePosition <= -scrollingImage.getWidth() + (display.getWidth() + scrollingImageStride) && + scrollingImageRendered) { + if (animationMode == ANIMATION_MODE_ANIMATE_IMAGE_WITH_CLEAR) display.image.clear(); animationMode = ANIMATION_MODE_NONE; @@ -233,13 +223,11 @@ void AnimatedDisplay::updateAnimateImage() return; } - if(scrollingImagePosition > 0) - display.image.shiftLeft(-scrollingImageStride); + if (scrollingImagePosition > 0) display.image.shiftLeft(-scrollingImageStride); display.image.paste(scrollingImage, scrollingImagePosition, 0, 0); - if(scrollingImageStride == 0) - { + if (scrollingImageStride == 0) { animationMode = ANIMATION_MODE_NONE; this->sendAnimationCompleteEvent(); } @@ -250,17 +238,16 @@ void AnimatedDisplay::updateAnimateImage() } /** - * Resets the current given animation. - */ + * Resets the current given animation. + */ void AnimatedDisplay::stopAnimation() { // Reset any ongoing animation. - if (animationMode != ANIMATION_MODE_NONE) - { + if (animationMode != ANIMATION_MODE_NONE) { animationMode = ANIMATION_MODE_NONE; // Indicate that we've completed an animation. - Event(id,DISPLAY_EVT_ANIMATION_COMPLETE); + Event(id, DISPLAY_EVT_ANIMATION_COMPLETE); // Wake up aall fibers that may blocked on the animation (if any). Event(DEVICE_ID_NOTIFY, DISPLAY_EVT_FREE); @@ -271,9 +258,9 @@ void AnimatedDisplay::stopAnimation() } /** - * Blocks the current fiber until the display is available (i.e. does not effect is being displayed). - * Animations are queued until their time to display. - */ + * Blocks the current fiber until the display is available (i.e. does not effect is being displayed). + * Animations are queued until their time to display. + */ void AnimatedDisplay::waitForFreeDisplay() { // If there's an ongoing animation, wait for our turn to display. @@ -282,51 +269,46 @@ void AnimatedDisplay::waitForFreeDisplay() } /** - * Blocks the current fiber until the current animation has finished. - * If the scheduler is not running, this call will essentially perform a spinning wait. - */ + * Blocks the current fiber until the current animation has finished. + * If the scheduler is not running, this call will essentially perform a spinning wait. + */ void AnimatedDisplay::fiberWait() { if (fiber_wait_for_event(DEVICE_ID_DISPLAY, DISPLAY_EVT_ANIMATION_COMPLETE) == DEVICE_NOT_SUPPORTED) - while(animationMode != ANIMATION_MODE_NONE && animationMode != ANIMATION_MODE_STOPPED) - target_wait_for_event(); + while (animationMode != ANIMATION_MODE_NONE && animationMode != ANIMATION_MODE_STOPPED) target_wait_for_event(); } /** - * Prints the given character to the display, if it is not in use. - * - * @param c The character to display. - * - * @param delay Optional parameter - the time for which to show the character. Zero displays the character forever, - * or until the Displays next use. - * - * @return DEVICE_OK, DEVICE_BUSY is the screen is in use, or DEVICE_INVALID_PARAMETER. - * - * @code - * display.printCharAsync('p'); - * display.printCharAsync('p',100); - * @endcode - */ + * Prints the given character to the display, if it is not in use. + * + * @param c The character to display. + * + * @param delay Optional parameter - the time for which to show the character. Zero displays the character forever, + * or until the Displays next use. + * + * @return DEVICE_OK, DEVICE_BUSY is the screen is in use, or DEVICE_INVALID_PARAMETER. + * + * @code + * display.printCharAsync('p'); + * display.printCharAsync('p',100); + * @endcode + */ int AnimatedDisplay::printCharAsync(char c, int delay) { - //sanitise this value - if(delay < 0) - return DEVICE_INVALID_PARAMETER; + // sanitise this value + if (delay < 0) return DEVICE_INVALID_PARAMETER; // If the display is free, it's our turn to display. - if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED) - { + if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED) { display.image.print(c, 0, 0); - if (delay > 0) - { + if (delay > 0) { animationDelay = delay; - animationTick = 0; - animationMode = ANIMATION_MODE_PRINT_CHARACTER; + animationTick = 0; + animationMode = ANIMATION_MODE_PRINT_CHARACTER; } } - else - { + else { return DEVICE_BUSY; } @@ -334,40 +316,36 @@ int AnimatedDisplay::printCharAsync(char c, int delay) } /** - * Prints the given ManagedString to the display, one character at a time. - * Returns immediately, and executes the animation asynchronously. - * - * @param s The string to display. - * - * @param delay The time to delay between characters, in milliseconds. Must be > 0. - * Defaults to: DISPLAY_DEFAULT_PRINT_SPEED. - * - * @return DEVICE_OK, or DEVICE_INVALID_PARAMETER. - * - * @code - * display.printAsync("abc123",400); - * @endcode - */ + * Prints the given ManagedString to the display, one character at a time. + * Returns immediately, and executes the animation asynchronously. + * + * @param s The string to display. + * + * @param delay The time to delay between characters, in milliseconds. Must be > 0. + * Defaults to: DISPLAY_DEFAULT_PRINT_SPEED. + * + * @return DEVICE_OK, or DEVICE_INVALID_PARAMETER. + * + * @code + * display.printAsync("abc123",400); + * @endcode + */ int AnimatedDisplay::printAsync(ManagedString s, int delay) { - if (s.length() == 1) - return printCharAsync(s.charAt(0)); + if (s.length() == 1) return printCharAsync(s.charAt(0)); - //sanitise this value - if (delay <= 0 ) - return DEVICE_INVALID_PARAMETER; + // sanitise this value + if (delay <= 0) return DEVICE_INVALID_PARAMETER; - if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED) - { - printingChar = 0; - printingText = s; + if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED) { + printingChar = 0; + printingText = s; animationDelay = delay; - animationTick = 0; + animationTick = 0; animationMode = ANIMATION_MODE_PRINT_TEXT; } - else - { + else { return DEVICE_BUSY; } @@ -375,42 +353,38 @@ int AnimatedDisplay::printAsync(ManagedString s, int delay) } /** - * Prints the given image to the display, if the display is not in use. - * Returns immediately, and executes the animation asynchronously. - * - * @param i The image to display. - * - * @param x The horizontal position on the screen to display the image. Defaults to 0. - * - * @param y The vertical position on the screen to display the image. Defaults to 0. - * - * @param alpha Treats the brightness level '0' as transparent. Defaults to 0. - * - * @param delay The time to delay between characters, in milliseconds. Defaults to 0. - * - * @code - * Image i("1,1,1,1,1\n1,1,1,1,1\n"); - * display.printprintAsync(i,400); - * @endcode - */ + * Prints the given image to the display, if the display is not in use. + * Returns immediately, and executes the animation asynchronously. + * + * @param i The image to display. + * + * @param x The horizontal position on the screen to display the image. Defaults to 0. + * + * @param y The vertical position on the screen to display the image. Defaults to 0. + * + * @param alpha Treats the brightness level '0' as transparent. Defaults to 0. + * + * @param delay The time to delay between characters, in milliseconds. Defaults to 0. + * + * @code + * Image i("1,1,1,1,1\n1,1,1,1,1\n"); + * display.printprintAsync(i,400); + * @endcode + */ int AnimatedDisplay::printAsync(Image i, int x, int y, int alpha, int delay) { - if(delay < 0) - return DEVICE_INVALID_PARAMETER; + if (delay < 0) return DEVICE_INVALID_PARAMETER; - if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED) - { + if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED) { display.image.paste(i, x, y, alpha); - if(delay > 0) - { + if (delay > 0) { animationDelay = delay; - animationTick = 0; - animationMode = ANIMATION_MODE_PRINT_CHARACTER; + animationTick = 0; + animationMode = ANIMATION_MODE_PRINT_CHARACTER; } } - else - { + else { return DEVICE_BUSY; } @@ -418,39 +392,35 @@ int AnimatedDisplay::printAsync(Image i, int x, int y, int alpha, int delay) } /** - * Prints the given character to the display. - * - * @param c The character to display. - * - * @param delay Optional parameter - the time for which to show the character. Zero displays the character forever, - * or until the Displays next use. - * - * @return DEVICE_OK, DEVICE_CANCELLED or DEVICE_INVALID_PARAMETER. - * - * @code - * display.printAsync('p'); - * display.printAsync('p',100); - * @endcode - */ + * Prints the given character to the display. + * + * @param c The character to display. + * + * @param delay Optional parameter - the time for which to show the character. Zero displays the character forever, + * or until the Displays next use. + * + * @return DEVICE_OK, DEVICE_CANCELLED or DEVICE_INVALID_PARAMETER. + * + * @code + * display.printAsync('p'); + * display.printAsync('p',100); + * @endcode + */ int AnimatedDisplay::printChar(char c, int delay) { - if (delay < 0) - return DEVICE_INVALID_PARAMETER; + if (delay < 0) return DEVICE_INVALID_PARAMETER; // If there's an ongoing animation, wait for our turn to display. this->waitForFreeDisplay(); // If the display is free, it's our turn to display. // If someone called stopAnimation(), then we simply skip... - if (animationMode == ANIMATION_MODE_NONE) - { + if (animationMode == ANIMATION_MODE_NONE) { this->printCharAsync(c, delay); - if (delay > 0) - fiberWait(); + if (delay > 0) fiberWait(); } - else - { + else { return DEVICE_CANCELLED; } @@ -458,46 +428,41 @@ int AnimatedDisplay::printChar(char c, int delay) } /** - * Prints the given string to the display, one character at a time. - * - * Blocks the calling thread until all the text has been displayed. - * - * @param s The string to display. - * - * @param delay The time to delay between characters, in milliseconds. Defaults - * to: DISPLAY_DEFAULT_PRINT_SPEED. - * - * @return DEVICE_OK, DEVICE_CANCELLED or DEVICE_INVALID_PARAMETER. - * - * @code - * display.print("abc123",400); - * @endcode - */ + * Prints the given string to the display, one character at a time. + * + * Blocks the calling thread until all the text has been displayed. + * + * @param s The string to display. + * + * @param delay The time to delay between characters, in milliseconds. Defaults + * to: DISPLAY_DEFAULT_PRINT_SPEED. + * + * @return DEVICE_OK, DEVICE_CANCELLED or DEVICE_INVALID_PARAMETER. + * + * @code + * display.print("abc123",400); + * @endcode + */ int AnimatedDisplay::print(ManagedString s, int delay) { - //sanitise this value - if(delay <= 0 ) - return DEVICE_INVALID_PARAMETER; + // sanitise this value + if (delay <= 0) return DEVICE_INVALID_PARAMETER; // If there's an ongoing animation, wait for our turn to display. this->waitForFreeDisplay(); // If the display is free, it's our turn to display. // If someone called stopAnimation(), then we simply skip... - if (animationMode == ANIMATION_MODE_NONE) - { - if (s.length() == 1) - { + if (animationMode == ANIMATION_MODE_NONE) { + if (s.length() == 1) { return printCharAsync(s.charAt(0)); } - else - { + else { this->printAsync(s, delay); fiberWait(); } } - else - { + else { return DEVICE_CANCELLED; } @@ -505,45 +470,41 @@ int AnimatedDisplay::print(ManagedString s, int delay) } /** - * Prints the given image to the display. - * Blocks the calling thread until all the image has been displayed. - * - * @param i The image to display. - * - * @param x The horizontal position on the screen to display the image. Defaults to 0. - * - * @param y The vertical position on the screen to display the image. Defaults to 0. - * - * @param alpha Treats the brightness level '0' as transparent. Defaults to 0. - * - * @param delay The time to display the image for, or zero to show the image forever. Defaults to 0. - * - * @return DEVICE_OK, DEVICE_BUSY if the display is already in use, or DEVICE_INVALID_PARAMETER. - * - * @code - * Image i("1,1,1,1,1\n1,1,1,1,1\n"); - * display.print(i,400); - * @endcode - */ + * Prints the given image to the display. + * Blocks the calling thread until all the image has been displayed. + * + * @param i The image to display. + * + * @param x The horizontal position on the screen to display the image. Defaults to 0. + * + * @param y The vertical position on the screen to display the image. Defaults to 0. + * + * @param alpha Treats the brightness level '0' as transparent. Defaults to 0. + * + * @param delay The time to display the image for, or zero to show the image forever. Defaults to 0. + * + * @return DEVICE_OK, DEVICE_BUSY if the display is already in use, or DEVICE_INVALID_PARAMETER. + * + * @code + * Image i("1,1,1,1,1\n1,1,1,1,1\n"); + * display.print(i,400); + * @endcode + */ int AnimatedDisplay::print(Image i, int x, int y, int alpha, int delay) { - if(delay < 0) - return DEVICE_INVALID_PARAMETER; + if (delay < 0) return DEVICE_INVALID_PARAMETER; // If there's an ongoing animation, wait for our turn to display. this->waitForFreeDisplay(); // If the display is free, it's our turn to display. // If someone called stopAnimation(), then we simply skip... - if (animationMode == ANIMATION_MODE_NONE) - { + if (animationMode == ANIMATION_MODE_NONE) { this->printAsync(i, x, y, alpha, delay); - if (delay > 0) - fiberWait(); + if (delay > 0) fiberWait(); } - else - { + else { return DEVICE_CANCELLED; } @@ -551,39 +512,36 @@ int AnimatedDisplay::print(Image i, int x, int y, int alpha, int delay) } /** - * Scrolls the given string to the display, from right to left. - * Returns immediately, and executes the animation asynchronously. - * - * @param s The string to display. - * - * @param delay The time to delay between characters, in milliseconds. Defaults - * to: DISPLAY_DEFAULT_SCROLL_SPEED. - * - * @return DEVICE_OK, DEVICE_BUSY if the display is already in use, or DEVICE_INVALID_PARAMETER. - * - * @code - * display.scrollAsync("abc123",100); - * @endcode - */ + * Scrolls the given string to the display, from right to left. + * Returns immediately, and executes the animation asynchronously. + * + * @param s The string to display. + * + * @param delay The time to delay between characters, in milliseconds. Defaults + * to: DISPLAY_DEFAULT_SCROLL_SPEED. + * + * @return DEVICE_OK, DEVICE_BUSY if the display is already in use, or DEVICE_INVALID_PARAMETER. + * + * @code + * display.scrollAsync("abc123",100); + * @endcode + */ int AnimatedDisplay::scrollAsync(ManagedString s, int delay) { - //sanitise this value - if(delay <= 0) - return DEVICE_INVALID_PARAMETER; + // sanitise this value + if (delay <= 0) return DEVICE_INVALID_PARAMETER; // If the display is free, it's our turn to display. - if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED) - { + if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED) { scrollingPosition = 0; - scrollingChar = 0; - scrollingText = s; + scrollingChar = 0; + scrollingText = s; animationDelay = delay; - animationTick = 0; - animationMode = ANIMATION_MODE_SCROLL_TEXT; + animationTick = 0; + animationMode = ANIMATION_MODE_SCROLL_TEXT; } - else - { + else { return DEVICE_BUSY; } @@ -591,43 +549,40 @@ int AnimatedDisplay::scrollAsync(ManagedString s, int delay) } /** - * Scrolls the given image across the display, from right to left. - * Returns immediately, and executes the animation asynchronously. - * - * @param image The image to display. - * - * @param delay The time between updates, in milliseconds. Defaults - * to: DISPLAY_DEFAULT_SCROLL_SPEED. - * - * @param stride The number of pixels to shift by in each update. Defaults to DISPLAY_DEFAULT_SCROLL_STRIDE. - * - * @return DEVICE_OK, DEVICE_BUSY if the display is already in use, or DEVICE_INVALID_PARAMETER. - * - * @code - * Image i("1,1,1,1,1\n1,1,1,1,1\n"); - * display.scrollAsync(i,100,1); - * @endcode - */ + * Scrolls the given image across the display, from right to left. + * Returns immediately, and executes the animation asynchronously. + * + * @param image The image to display. + * + * @param delay The time between updates, in milliseconds. Defaults + * to: DISPLAY_DEFAULT_SCROLL_SPEED. + * + * @param stride The number of pixels to shift by in each update. Defaults to DISPLAY_DEFAULT_SCROLL_STRIDE. + * + * @return DEVICE_OK, DEVICE_BUSY if the display is already in use, or DEVICE_INVALID_PARAMETER. + * + * @code + * Image i("1,1,1,1,1\n1,1,1,1,1\n"); + * display.scrollAsync(i,100,1); + * @endcode + */ int AnimatedDisplay::scrollAsync(Image image, int delay, int stride) { - //sanitise the delay value - if(delay <= 0) - return DEVICE_INVALID_PARAMETER; + // sanitise the delay value + if (delay <= 0) return DEVICE_INVALID_PARAMETER; // If the display is free, it's our turn to display. - if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED) - { + if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED) { scrollingImagePosition = stride < 0 ? display.getWidth() : -image.getWidth(); - scrollingImageStride = stride; - scrollingImage = image; + scrollingImageStride = stride; + scrollingImage = image; scrollingImageRendered = false; animationDelay = stride == 0 ? 0 : delay; - animationTick = 0; - animationMode = ANIMATION_MODE_SCROLL_IMAGE; + animationTick = 0; + animationMode = ANIMATION_MODE_SCROLL_IMAGE; } - else - { + else { return DEVICE_BUSY; } @@ -635,41 +590,38 @@ int AnimatedDisplay::scrollAsync(Image image, int delay, int stride) } /** - * Scrolls the given string across the display, from right to left. - * Blocks the calling thread until all text has been displayed. - * - * @param s The string to display. - * - * @param delay The time to delay between characters, in milliseconds. Defaults - * to: DEVICE_DEFAULT_SCROLL_SPEED. - * - * @return DEVICE_OK, DEVICE_CANCELLED or DEVICE_INVALID_PARAMETER. - * - * @code - * display.scroll("abc123",100); - * @endcode - */ + * Scrolls the given string across the display, from right to left. + * Blocks the calling thread until all text has been displayed. + * + * @param s The string to display. + * + * @param delay The time to delay between characters, in milliseconds. Defaults + * to: DEVICE_DEFAULT_SCROLL_SPEED. + * + * @return DEVICE_OK, DEVICE_CANCELLED or DEVICE_INVALID_PARAMETER. + * + * @code + * display.scroll("abc123",100); + * @endcode + */ int AnimatedDisplay::scroll(ManagedString s, int delay) { - //sanitise this value - if(delay <= 0) - return DEVICE_INVALID_PARAMETER; + // sanitise this value + if (delay <= 0) return DEVICE_INVALID_PARAMETER; // If there's an ongoing animation, wait for our turn to display. this->waitForFreeDisplay(); // If the display is free, it's our turn to display. // If someone called stopAnimation(), then we simply skip... - if (animationMode == ANIMATION_MODE_NONE) - { + if (animationMode == ANIMATION_MODE_NONE) { // Start the effect. this->scrollAsync(s, delay); // Wait for completion. fiberWait(); } - else - { + else { return DEVICE_CANCELLED; } @@ -677,44 +629,41 @@ int AnimatedDisplay::scroll(ManagedString s, int delay) } /** - * Scrolls the given image across the display, from right to left. - * Blocks the calling thread until all the text has been displayed. - * - * @param image The image to display. - * - * @param delay The time between updates, in milliseconds. Defaults - * to: DISPLAY_DEFAULT_SCROLL_SPEED. - * - * @param stride The number of pixels to shift by in each update. Defaults to DISPLAY_DEFAULT_SCROLL_STRIDE. - * - * @return DEVICE_OK, DEVICE_CANCELLED or DEVICE_INVALID_PARAMETER. - * - * @code - * Image i("1,1,1,1,1\n1,1,1,1,1\n"); - * display.scroll(i,100,1); - * @endcode - */ + * Scrolls the given image across the display, from right to left. + * Blocks the calling thread until all the text has been displayed. + * + * @param image The image to display. + * + * @param delay The time between updates, in milliseconds. Defaults + * to: DISPLAY_DEFAULT_SCROLL_SPEED. + * + * @param stride The number of pixels to shift by in each update. Defaults to DISPLAY_DEFAULT_SCROLL_STRIDE. + * + * @return DEVICE_OK, DEVICE_CANCELLED or DEVICE_INVALID_PARAMETER. + * + * @code + * Image i("1,1,1,1,1\n1,1,1,1,1\n"); + * display.scroll(i,100,1); + * @endcode + */ int AnimatedDisplay::scroll(Image image, int delay, int stride) { - //sanitise the delay value - if(delay <= 0) - return DEVICE_INVALID_PARAMETER; + // sanitise the delay value + if (delay <= 0) return DEVICE_INVALID_PARAMETER; // If there's an ongoing animation, wait for our turn to display. this->waitForFreeDisplay(); // If the display is free, it's our turn to display. // If someone called stopAnimation(), then we simply skip... - if (animationMode == ANIMATION_MODE_NONE) - { + if (animationMode == ANIMATION_MODE_NONE) { // Start the effect. this->scrollAsync(image, delay, stride); // Wait for completion. fiberWait(); } - else - { + else { return DEVICE_CANCELLED; } @@ -722,55 +671,55 @@ int AnimatedDisplay::scroll(Image image, int delay, int stride) } /** - * "Animates" the current image across the display with a given stride, finishing on the last frame of the animation. - * Returns immediately. - * - * @param image The image to display. - * - * @param delay The time to delay between each update of the display, in milliseconds. - * - * @param stride The number of pixels to shift by in each update. - * - * @param startingPosition the starting position on the display for the animation - * to begin at. Defaults to DISPLAY_ANIMATE_DEFAULT_POS. - * - * @param autoClear defines whether or not the display is automatically cleared once the animation is complete. By default, the display is cleared. Set this parameter to zero to disable the autoClear operation. - * - * @return DEVICE_OK, DEVICE_BUSY if the screen is in use, or DEVICE_INVALID_PARAMETER. - * - * @code - * const int heart_w = 10; - * const int heart_h = 5; - * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; - * - * Image i(heart_w,heart_h,heart); - * display.animateAsync(i,100,5); - * @endcode - */ + * "Animates" the current image across the display with a given stride, finishing on the last frame of the animation. + * Returns immediately. + * + * @param image The image to display. + * + * @param delay The time to delay between each update of the display, in milliseconds. + * + * @param stride The number of pixels to shift by in each update. + * + * @param startingPosition the starting position on the display for the animation + * to begin at. Defaults to DISPLAY_ANIMATE_DEFAULT_POS. + * + * @param autoClear defines whether or not the display is automatically cleared once the animation is complete. By + * default, the display is cleared. Set this parameter to zero to disable the autoClear operation. + * + * @return DEVICE_OK, DEVICE_BUSY if the screen is in use, or DEVICE_INVALID_PARAMETER. + * + * @code + * const int heart_w = 10; + * const int heart_h = 5; + * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, + * 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; + * + * Image i(heart_w,heart_h,heart); + * display.animateAsync(i,100,5); + * @endcode + */ int AnimatedDisplay::animateAsync(Image image, int delay, int stride, int startingPosition, int autoClear) { - //sanitise the delay value - if(delay <= 0) - return DEVICE_INVALID_PARAMETER; + // sanitise the delay value + if (delay <= 0) return DEVICE_INVALID_PARAMETER; // If the display is free, we can display. - if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED) - { + if (animationMode == ANIMATION_MODE_NONE || animationMode == ANIMATION_MODE_STOPPED) { // Assume right to left functionality, to align with scrollString() stride = -stride; - //calculate starting position which is offset by the stride - scrollingImagePosition = (startingPosition == DISPLAY_ANIMATE_DEFAULT_POS) ? display.getWidth() + stride : startingPosition; - scrollingImageStride = stride; - scrollingImage = image; + // calculate starting position which is offset by the stride + scrollingImagePosition = + (startingPosition == DISPLAY_ANIMATE_DEFAULT_POS) ? display.getWidth() + stride : startingPosition; + scrollingImageStride = stride; + scrollingImage = image; scrollingImageRendered = false; animationDelay = stride == 0 ? 0 : delay; - animationTick = delay-1; - animationMode = autoClear ? ANIMATION_MODE_ANIMATE_IMAGE_WITH_CLEAR : ANIMATION_MODE_ANIMATE_IMAGE; + animationTick = delay - 1; + animationMode = autoClear ? ANIMATION_MODE_ANIMATE_IMAGE_WITH_CLEAR : ANIMATION_MODE_ANIMATE_IMAGE; } - else - { + else { return DEVICE_BUSY; } @@ -778,71 +727,69 @@ int AnimatedDisplay::animateAsync(Image image, int delay, int stride, int starti } /** - * "Animates" the current image across the display with a given stride, finishing on the last frame of the animation. - * Blocks the calling thread until the animation is complete. - * - * - * @param delay The time to delay between each update of the display, in milliseconds. - * - * @param stride The number of pixels to shift by in each update. - * - * @param startingPosition the starting position on the display for the animation - * to begin at. Defaults to DISPLAY_ANIMATE_DEFAULT_POS. - * - * @param autoClear defines whether or not the display is automatically cleared once the animation is complete. By default, the display is cleared. Set this parameter to zero to disable the autoClear operation. - * - * @return DEVICE_OK, DEVICE_CANCELLED or DEVICE_INVALID_PARAMETER. - * - * @code - * const int heart_w = 10; - * const int heart_h = 5; - * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; - * - * Image i(heart_w,heart_h,heart); - * display.animate(i,100,5); - * @endcode - */ + * "Animates" the current image across the display with a given stride, finishing on the last frame of the animation. + * Blocks the calling thread until the animation is complete. + * + * + * @param delay The time to delay between each update of the display, in milliseconds. + * + * @param stride The number of pixels to shift by in each update. + * + * @param startingPosition the starting position on the display for the animation + * to begin at. Defaults to DISPLAY_ANIMATE_DEFAULT_POS. + * + * @param autoClear defines whether or not the display is automatically cleared once the animation is complete. By + * default, the display is cleared. Set this parameter to zero to disable the autoClear operation. + * + * @return DEVICE_OK, DEVICE_CANCELLED or DEVICE_INVALID_PARAMETER. + * + * @code + * const int heart_w = 10; + * const int heart_h = 5; + * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, + * 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; + * + * Image i(heart_w,heart_h,heart); + * display.animate(i,100,5); + * @endcode + */ int AnimatedDisplay::animate(Image image, int delay, int stride, int startingPosition, int autoClear) { - //sanitise the delay value - if(delay <= 0) - return DEVICE_INVALID_PARAMETER; + // sanitise the delay value + if (delay <= 0) return DEVICE_INVALID_PARAMETER; // If there's an ongoing animation, wait for our turn to display. this->waitForFreeDisplay(); // If the display is free, it's our turn to display. // If someone called stopAnimation(), then we simply skip... - if (animationMode == ANIMATION_MODE_NONE) - { + if (animationMode == ANIMATION_MODE_NONE) { // Start the effect. this->animateAsync(image, delay, stride, startingPosition, autoClear); // Wait for completion. - //TODO: Put this in when we merge tight-validation - //if (delay > 0) - fiberWait(); + // TODO: Put this in when we merge tight-validation + // if (delay > 0) + fiberWait(); } - else - { + else { return DEVICE_CANCELLED; } return DEVICE_OK; } - /** -* Frame update method, invoked periodically to update animations if neccessary. -*/ + * Frame update method, invoked periodically to update animations if neccessary. + */ void AnimatedDisplay::periodicCallback() { this->animationUpdate(); } /** -* Destructor for AnimatedDisplay, where we deregister this instance from the array of system components. -*/ + * Destructor for AnimatedDisplay, where we deregister this instance from the array of system components. + */ AnimatedDisplay::~AnimatedDisplay() { status &= ~DEVICE_COMPONENT_STATUS_SYSTEM_TICK; diff --git a/source/drivers/AsciiKeyMap.cpp b/source/drivers/AsciiKeyMap.cpp index 131e3078..36135236 100644 --- a/source/drivers/AsciiKeyMap.cpp +++ b/source/drivers/AsciiKeyMap.cpp @@ -1,561 +1,585 @@ #include "AsciiKeyMap.h" + #include "USB_HID_Keys.h" using namespace codal; -//define all Key sequences to be used +// define all Key sequences to be used static const Key seq_backspace[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_BACKSPACE }, + {.reg = KEYMAP_KEY_DOWN | KEY_BACKSPACE}, }; static const Key seq_tab[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_TAB }, + {.reg = KEYMAP_KEY_DOWN | KEY_TAB}, }; static const Key seq_newline[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_ENTER }, + {.reg = KEYMAP_KEY_DOWN | KEY_ENTER}, }; static const Key seq_space[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_SPACE }, + {.reg = KEYMAP_KEY_DOWN | KEY_SPACE}, }; static const Key seq_exclamation_point[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_1 }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_1}, }; static const Key seq_quote[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_1 }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_1}, }; static const Key seq_pound[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_3 }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_3}, }; static const Key seq_dollar[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_4 }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_4}, }; static const Key seq_percent[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_5 }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_5}, }; static const Key seq_amp[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_7 }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_7}, }; static const Key seq_apostrophe[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_APOSTROPHE }, + {.reg = KEYMAP_KEY_DOWN | KEY_APOSTROPHE}, }; static const Key seq_left_paren[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_9 }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_9}, }; static const Key seq_right_paren[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_0 }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_0}, }; static const Key seq_ast[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_8 }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_8}, }; static const Key seq_plus[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_EQUAL }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_EQUAL}, }; static const Key seq_comma[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_COMMA }, + {.reg = KEYMAP_KEY_DOWN | KEY_COMMA}, }; static const Key seq_minus[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_MINUS }, + {.reg = KEYMAP_KEY_DOWN | KEY_MINUS}, }; static const Key seq_dot[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_DOT }, + {.reg = KEYMAP_KEY_DOWN | KEY_DOT}, }; static const Key seq_slash[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_SLASH }, + {.reg = KEYMAP_KEY_DOWN | KEY_SLASH}, }; static const Key seq_0[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_0 }, + {.reg = KEYMAP_KEY_DOWN | KEY_0}, }; static const Key seq_1[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_1 }, + {.reg = KEYMAP_KEY_DOWN | KEY_1}, }; static const Key seq_2[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_2 }, + {.reg = KEYMAP_KEY_DOWN | KEY_2}, }; static const Key seq_3[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_3 }, + {.reg = KEYMAP_KEY_DOWN | KEY_3}, }; static const Key seq_4[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_4 }, + {.reg = KEYMAP_KEY_DOWN | KEY_4}, }; static const Key seq_5[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_5 }, + {.reg = KEYMAP_KEY_DOWN | KEY_5}, }; static const Key seq_6[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_6 }, + {.reg = KEYMAP_KEY_DOWN | KEY_6}, }; static const Key seq_7[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_7 }, + {.reg = KEYMAP_KEY_DOWN | KEY_7}, }; static const Key seq_8[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_8 }, + {.reg = KEYMAP_KEY_DOWN | KEY_8}, }; static const Key seq_9[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_9 }, + {.reg = KEYMAP_KEY_DOWN | KEY_9}, }; static const Key seq_colon[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_SEMICOLON }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_SEMICOLON}, }; static const Key seq_semicolon[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_SEMICOLON }, + {.reg = KEYMAP_KEY_DOWN | KEY_SEMICOLON}, }; static const Key seq_angle_left[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_COMMA }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_COMMA}, }; static const Key seq_equal[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_EQUAL }, + {.reg = KEYMAP_KEY_DOWN | KEY_EQUAL}, }; static const Key seq_angle_right[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_DOT }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_DOT}, }; static const Key seq_question[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_SLASH }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_SLASH}, }; static const Key seq_at[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_2 }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_2}, }; static const Key seq_A[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_A }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_A}, }; static const Key seq_B[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_B }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_B}, }; static const Key seq_C[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_C }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_C}, }; static const Key seq_D[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_D }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_D}, }; static const Key seq_E[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_E }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_E}, }; static const Key seq_F[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_F }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_F}, }; static const Key seq_G[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_G }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_G}, }; static const Key seq_H[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_H }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_H}, }; static const Key seq_I[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_I }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_I}, }; static const Key seq_J[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_J }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_J}, }; static const Key seq_K[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_K }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_K}, }; static const Key seq_L[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_L }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_L}, }; static const Key seq_M[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_M }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_M}, }; static const Key seq_N[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_N }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_N}, }; static const Key seq_O[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_O }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_O}, }; static const Key seq_P[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_P }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_P}, }; static const Key seq_Q[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_Q }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_Q}, }; static const Key seq_R[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_R }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_R}, }; static const Key seq_S[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_S }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_S}, }; static const Key seq_T[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_T }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_T}, }; static const Key seq_U[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_U }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_U}, }; static const Key seq_V[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_V }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_V}, }; static const Key seq_W[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_W }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_W}, }; static const Key seq_X[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_X }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_X}, }; static const Key seq_Y[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_Y }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_Y}, }; static const Key seq_Z[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_Z }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_Z}, }; static const Key seq_brace_left[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_LEFTBRACE }, + {.reg = KEYMAP_KEY_DOWN | KEY_LEFTBRACE}, }; static const Key seq_backslash[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_BACKSLASH }, + {.reg = KEYMAP_KEY_DOWN | KEY_BACKSLASH}, }; static const Key seq_brace_right[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_RIGHTBRACE }, + {.reg = KEYMAP_KEY_DOWN | KEY_RIGHTBRACE}, }; static const Key seq_hat[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_6 }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_6}, }; static const Key seq_underscore[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_MINUS }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_MINUS}, }; static const Key seq_grave[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_GRAVE }, + {.reg = KEYMAP_KEY_DOWN | KEY_GRAVE}, }; static const Key seq_a[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_A }, + {.reg = KEYMAP_KEY_DOWN | KEY_A}, }; static const Key seq_b[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_B }, + {.reg = KEYMAP_KEY_DOWN | KEY_B}, }; static const Key seq_c[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_C }, + {.reg = KEYMAP_KEY_DOWN | KEY_C}, }; static const Key seq_d[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_D }, + {.reg = KEYMAP_KEY_DOWN | KEY_D}, }; static const Key seq_e[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_E }, + {.reg = KEYMAP_KEY_DOWN | KEY_E}, }; static const Key seq_f[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_F }, + {.reg = KEYMAP_KEY_DOWN | KEY_F}, }; static const Key seq_g[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_G }, + {.reg = KEYMAP_KEY_DOWN | KEY_G}, }; static const Key seq_h[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_H }, + {.reg = KEYMAP_KEY_DOWN | KEY_H}, }; static const Key seq_i[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_I }, + {.reg = KEYMAP_KEY_DOWN | KEY_I}, }; static const Key seq_j[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_J }, + {.reg = KEYMAP_KEY_DOWN | KEY_J}, }; static const Key seq_k[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_K }, + {.reg = KEYMAP_KEY_DOWN | KEY_K}, }; static const Key seq_l[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_L }, + {.reg = KEYMAP_KEY_DOWN | KEY_L}, }; static const Key seq_m[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_M }, + {.reg = KEYMAP_KEY_DOWN | KEY_M}, }; static const Key seq_n[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_N }, + {.reg = KEYMAP_KEY_DOWN | KEY_N}, }; static const Key seq_o[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_O }, + {.reg = KEYMAP_KEY_DOWN | KEY_O}, }; static const Key seq_p[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_P }, + {.reg = KEYMAP_KEY_DOWN | KEY_P}, }; static const Key seq_q[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_Q }, + {.reg = KEYMAP_KEY_DOWN | KEY_Q}, }; static const Key seq_r[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_R }, + {.reg = KEYMAP_KEY_DOWN | KEY_R}, }; static const Key seq_s[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_S }, + {.reg = KEYMAP_KEY_DOWN | KEY_S}, }; static const Key seq_t[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_T }, + {.reg = KEYMAP_KEY_DOWN | KEY_T}, }; static const Key seq_u[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_U }, + {.reg = KEYMAP_KEY_DOWN | KEY_U}, }; static const Key seq_v[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_V }, + {.reg = KEYMAP_KEY_DOWN | KEY_V}, }; static const Key seq_w[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_W }, + {.reg = KEYMAP_KEY_DOWN | KEY_W}, }; static const Key seq_x[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_X }, + {.reg = KEYMAP_KEY_DOWN | KEY_X}, }; static const Key seq_y[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_Y }, + {.reg = KEYMAP_KEY_DOWN | KEY_Y}, }; static const Key seq_z[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_Z }, + {.reg = KEYMAP_KEY_DOWN | KEY_Z}, }; static const Key seq_curly_left[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_LEFTBRACE }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_LEFTBRACE}, }; static const Key seq_pipe[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_BACKSLASH }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_BACKSLASH}, }; static const Key seq_curly_right[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_RIGHTBRACE}, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_RIGHTBRACE}, }; static const Key seq_tilda[] = { - { .reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT }, - { .reg = KEYMAP_KEY_DOWN | KEY_GRAVE }, + {.reg = KEYMAP_KEY_DOWN | KEYMAP_MODIFIER_KEY | KEY_MOD_LSHIFT}, + {.reg = KEYMAP_KEY_DOWN | KEY_GRAVE}, }; static const Key seq_del[] = { - { .reg = KEYMAP_KEY_DOWN | KEY_BACKSPACE }, + {.reg = KEYMAP_KEY_DOWN | KEY_BACKSPACE}, }; -static const KeySequence unmapped = { - NULL, - 0 -}; +static const KeySequence unmapped = {NULL, 0}; -//define the keymap +// define the keymap const KeySequence ascii_keymap[] = { - unmapped, unmapped, unmapped, unmapped, unmapped, unmapped, unmapped, unmapped, //0 - 7 - KEYMAP_REGISTER(seq_backspace), - KEYMAP_REGISTER(seq_tab), - KEYMAP_REGISTER(seq_newline), - unmapped, unmapped, unmapped, unmapped, unmapped, - unmapped, unmapped, unmapped, unmapped, unmapped, unmapped, unmapped, unmapped, unmapped, unmapped, unmapped, unmapped, unmapped, unmapped, unmapped, unmapped, //16 - 31 - KEYMAP_REGISTER(seq_space), //32 space - KEYMAP_REGISTER(seq_exclamation_point), //33 ! - KEYMAP_REGISTER(seq_quote), //34 " - KEYMAP_REGISTER(seq_pound), //35 # - KEYMAP_REGISTER(seq_dollar), - KEYMAP_REGISTER(seq_percent), - KEYMAP_REGISTER(seq_amp), - KEYMAP_REGISTER(seq_apostrophe), - KEYMAP_REGISTER(seq_left_paren), - KEYMAP_REGISTER(seq_right_paren), - KEYMAP_REGISTER(seq_ast), - KEYMAP_REGISTER(seq_plus), - KEYMAP_REGISTER(seq_comma), - KEYMAP_REGISTER(seq_minus), - KEYMAP_REGISTER(seq_dot), - KEYMAP_REGISTER(seq_slash), - KEYMAP_REGISTER(seq_0), - KEYMAP_REGISTER(seq_1), - KEYMAP_REGISTER(seq_2), - KEYMAP_REGISTER(seq_3), - KEYMAP_REGISTER(seq_4), - KEYMAP_REGISTER(seq_5), - KEYMAP_REGISTER(seq_6), - KEYMAP_REGISTER(seq_7), - KEYMAP_REGISTER(seq_8), - KEYMAP_REGISTER(seq_9), - KEYMAP_REGISTER(seq_colon), - KEYMAP_REGISTER(seq_semicolon), - KEYMAP_REGISTER(seq_angle_left), - KEYMAP_REGISTER(seq_equal), - KEYMAP_REGISTER(seq_angle_right), - KEYMAP_REGISTER(seq_question), - KEYMAP_REGISTER(seq_at), - KEYMAP_REGISTER(seq_A), - KEYMAP_REGISTER(seq_B), - KEYMAP_REGISTER(seq_C), - KEYMAP_REGISTER(seq_D), - KEYMAP_REGISTER(seq_E), - KEYMAP_REGISTER(seq_F), - KEYMAP_REGISTER(seq_G), - KEYMAP_REGISTER(seq_H), - KEYMAP_REGISTER(seq_I), - KEYMAP_REGISTER(seq_J), - KEYMAP_REGISTER(seq_K), - KEYMAP_REGISTER(seq_L), - KEYMAP_REGISTER(seq_M), - KEYMAP_REGISTER(seq_N), - KEYMAP_REGISTER(seq_O), - KEYMAP_REGISTER(seq_P), - KEYMAP_REGISTER(seq_Q), - KEYMAP_REGISTER(seq_R), - KEYMAP_REGISTER(seq_S), - KEYMAP_REGISTER(seq_T), - KEYMAP_REGISTER(seq_U), - KEYMAP_REGISTER(seq_V), - KEYMAP_REGISTER(seq_W), - KEYMAP_REGISTER(seq_X), - KEYMAP_REGISTER(seq_Y), - KEYMAP_REGISTER(seq_Z), - KEYMAP_REGISTER(seq_brace_left), - KEYMAP_REGISTER(seq_backslash), - KEYMAP_REGISTER(seq_brace_right), - KEYMAP_REGISTER(seq_hat), - KEYMAP_REGISTER(seq_underscore), - KEYMAP_REGISTER(seq_grave), - KEYMAP_REGISTER(seq_a), - KEYMAP_REGISTER(seq_b), - KEYMAP_REGISTER(seq_c), - KEYMAP_REGISTER(seq_d), - KEYMAP_REGISTER(seq_e), - KEYMAP_REGISTER(seq_f), - KEYMAP_REGISTER(seq_g), - KEYMAP_REGISTER(seq_h), - KEYMAP_REGISTER(seq_i), - KEYMAP_REGISTER(seq_j), - KEYMAP_REGISTER(seq_k), - KEYMAP_REGISTER(seq_l), - KEYMAP_REGISTER(seq_m), - KEYMAP_REGISTER(seq_n), - KEYMAP_REGISTER(seq_o), - KEYMAP_REGISTER(seq_p), - KEYMAP_REGISTER(seq_q), - KEYMAP_REGISTER(seq_r), - KEYMAP_REGISTER(seq_s), - KEYMAP_REGISTER(seq_t), - KEYMAP_REGISTER(seq_u), - KEYMAP_REGISTER(seq_v), - KEYMAP_REGISTER(seq_w), - KEYMAP_REGISTER(seq_x), - KEYMAP_REGISTER(seq_y), - KEYMAP_REGISTER(seq_z), - KEYMAP_REGISTER(seq_curly_left), - KEYMAP_REGISTER(seq_pipe), - KEYMAP_REGISTER(seq_curly_right), - KEYMAP_REGISTER(seq_tilda), - KEYMAP_REGISTER(seq_del), + unmapped, + unmapped, + unmapped, + unmapped, + unmapped, + unmapped, + unmapped, + unmapped, // 0 - 7 + KEYMAP_REGISTER(seq_backspace), + KEYMAP_REGISTER(seq_tab), + KEYMAP_REGISTER(seq_newline), + unmapped, + unmapped, + unmapped, + unmapped, + unmapped, + unmapped, + unmapped, + unmapped, + unmapped, + unmapped, + unmapped, + unmapped, + unmapped, + unmapped, + unmapped, + unmapped, + unmapped, + unmapped, + unmapped, + unmapped, + unmapped, // 16 - 31 + KEYMAP_REGISTER(seq_space), // 32 space + KEYMAP_REGISTER(seq_exclamation_point), // 33 ! + KEYMAP_REGISTER(seq_quote), // 34 " + KEYMAP_REGISTER(seq_pound), // 35 # + KEYMAP_REGISTER(seq_dollar), + KEYMAP_REGISTER(seq_percent), + KEYMAP_REGISTER(seq_amp), + KEYMAP_REGISTER(seq_apostrophe), + KEYMAP_REGISTER(seq_left_paren), + KEYMAP_REGISTER(seq_right_paren), + KEYMAP_REGISTER(seq_ast), + KEYMAP_REGISTER(seq_plus), + KEYMAP_REGISTER(seq_comma), + KEYMAP_REGISTER(seq_minus), + KEYMAP_REGISTER(seq_dot), + KEYMAP_REGISTER(seq_slash), + KEYMAP_REGISTER(seq_0), + KEYMAP_REGISTER(seq_1), + KEYMAP_REGISTER(seq_2), + KEYMAP_REGISTER(seq_3), + KEYMAP_REGISTER(seq_4), + KEYMAP_REGISTER(seq_5), + KEYMAP_REGISTER(seq_6), + KEYMAP_REGISTER(seq_7), + KEYMAP_REGISTER(seq_8), + KEYMAP_REGISTER(seq_9), + KEYMAP_REGISTER(seq_colon), + KEYMAP_REGISTER(seq_semicolon), + KEYMAP_REGISTER(seq_angle_left), + KEYMAP_REGISTER(seq_equal), + KEYMAP_REGISTER(seq_angle_right), + KEYMAP_REGISTER(seq_question), + KEYMAP_REGISTER(seq_at), + KEYMAP_REGISTER(seq_A), + KEYMAP_REGISTER(seq_B), + KEYMAP_REGISTER(seq_C), + KEYMAP_REGISTER(seq_D), + KEYMAP_REGISTER(seq_E), + KEYMAP_REGISTER(seq_F), + KEYMAP_REGISTER(seq_G), + KEYMAP_REGISTER(seq_H), + KEYMAP_REGISTER(seq_I), + KEYMAP_REGISTER(seq_J), + KEYMAP_REGISTER(seq_K), + KEYMAP_REGISTER(seq_L), + KEYMAP_REGISTER(seq_M), + KEYMAP_REGISTER(seq_N), + KEYMAP_REGISTER(seq_O), + KEYMAP_REGISTER(seq_P), + KEYMAP_REGISTER(seq_Q), + KEYMAP_REGISTER(seq_R), + KEYMAP_REGISTER(seq_S), + KEYMAP_REGISTER(seq_T), + KEYMAP_REGISTER(seq_U), + KEYMAP_REGISTER(seq_V), + KEYMAP_REGISTER(seq_W), + KEYMAP_REGISTER(seq_X), + KEYMAP_REGISTER(seq_Y), + KEYMAP_REGISTER(seq_Z), + KEYMAP_REGISTER(seq_brace_left), + KEYMAP_REGISTER(seq_backslash), + KEYMAP_REGISTER(seq_brace_right), + KEYMAP_REGISTER(seq_hat), + KEYMAP_REGISTER(seq_underscore), + KEYMAP_REGISTER(seq_grave), + KEYMAP_REGISTER(seq_a), + KEYMAP_REGISTER(seq_b), + KEYMAP_REGISTER(seq_c), + KEYMAP_REGISTER(seq_d), + KEYMAP_REGISTER(seq_e), + KEYMAP_REGISTER(seq_f), + KEYMAP_REGISTER(seq_g), + KEYMAP_REGISTER(seq_h), + KEYMAP_REGISTER(seq_i), + KEYMAP_REGISTER(seq_j), + KEYMAP_REGISTER(seq_k), + KEYMAP_REGISTER(seq_l), + KEYMAP_REGISTER(seq_m), + KEYMAP_REGISTER(seq_n), + KEYMAP_REGISTER(seq_o), + KEYMAP_REGISTER(seq_p), + KEYMAP_REGISTER(seq_q), + KEYMAP_REGISTER(seq_r), + KEYMAP_REGISTER(seq_s), + KEYMAP_REGISTER(seq_t), + KEYMAP_REGISTER(seq_u), + KEYMAP_REGISTER(seq_v), + KEYMAP_REGISTER(seq_w), + KEYMAP_REGISTER(seq_x), + KEYMAP_REGISTER(seq_y), + KEYMAP_REGISTER(seq_z), + KEYMAP_REGISTER(seq_curly_left), + KEYMAP_REGISTER(seq_pipe), + KEYMAP_REGISTER(seq_curly_right), + KEYMAP_REGISTER(seq_tilda), + KEYMAP_REGISTER(seq_del), }; AsciiKeyMap asciiKeyMap(ascii_keymap, 128); \ No newline at end of file diff --git a/source/drivers/Button.cpp b/source/drivers/Button.cpp index 6fd49d35..9e26d940 100644 --- a/source/drivers/Button.cpp +++ b/source/drivers/Button.cpp @@ -22,57 +22,62 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "CodalConfig.h" #include "Button.h" -#include "Timer.h" -#include "EventModel.h" + +#include "CodalConfig.h" #include "CodalDmesg.h" +#include "EventModel.h" +#include "Timer.h" using namespace codal; /** - * Constructor. - * - * Create a software representation of a button. - * - * @param pin the physical pin on the device connected to this button. - * - * @param id the ID of the new Button object. - * - * @param eventConfiguration Configures the events that will be generated by this Button instance. - * Defaults to DEVICE_BUTTON_ALL_EVENTS. - * - * @param mode the configuration of internal pullups/pulldowns, as defined in the mbed PullMode class. PullNone by default. - * - */ -Button::Button(Pin &pin, uint16_t id, ButtonEventConfiguration eventConfiguration, ButtonPolarity polarity, PullMode mode) : _pin(pin), pullMode(mode) + * Constructor. + * + * Create a software representation of a button. + * + * @param pin the physical pin on the device connected to this button. + * + * @param id the ID of the new Button object. + * + * @param eventConfiguration Configures the events that will be generated by this Button instance. + * Defaults to DEVICE_BUTTON_ALL_EVENTS. + * + * @param mode the configuration of internal pullups/pulldowns, as defined in the mbed PullMode class. PullNone by + * default. + * + */ +Button::Button(Pin& pin, uint16_t id, ButtonEventConfiguration eventConfiguration, ButtonPolarity polarity, + PullMode mode) + : _pin(pin), pullMode(mode) { - this->id = id; + this->id = id; this->eventConfiguration = eventConfiguration; - this->downStartTime = 0; - this->sigma = 0; - this->polarity = polarity; + this->downStartTime = 0; + this->sigma = 0; + this->polarity = polarity; // For backward compatibility, always perform demand activation. this->isPressed(); } /** - * Changes the event configuration used by this button to the given ButtonEventConfiguration. - * - * All subsequent events generated by this button will then be informed by this configuraiton. - * - * @param config The new configuration for this button. Legal values are DEVICE_BUTTON_ALL_EVENTS or DEVICE_BUTTON_SIMPLE_EVENTS. - * - * Example: - * @code - * // Configure a button to generate all possible events. - * buttonA.setEventConfiguration(DEVICE_BUTTON_ALL_EVENTS); - * - * // Configure a button to suppress DEVICE_BUTTON_EVT_CLICK and DEVICE_BUTTON_EVT_LONG_CLICK events. - * buttonA.setEventConfiguration(DEVICE_BUTTON_SIMPLE_EVENTS); - * @endcode - */ + * Changes the event configuration used by this button to the given ButtonEventConfiguration. + * + * All subsequent events generated by this button will then be informed by this configuraiton. + * + * @param config The new configuration for this button. Legal values are DEVICE_BUTTON_ALL_EVENTS or + * DEVICE_BUTTON_SIMPLE_EVENTS. + * + * Example: + * @code + * // Configure a button to generate all possible events. + * buttonA.setEventConfiguration(DEVICE_BUTTON_ALL_EVENTS); + * + * // Configure a button to suppress DEVICE_BUTTON_EVT_CLICK and DEVICE_BUTTON_EVT_LONG_CLICK events. + * buttonA.setEventConfiguration(DEVICE_BUTTON_SIMPLE_EVENTS); + * @endcode + */ void Button::setEventConfiguration(ButtonEventConfiguration config) { this->eventConfiguration = config; @@ -94,15 +99,14 @@ int Button::buttonActive() } /** - * periodic callback from Device system timer. - * - * Check for state change for this button, and fires various events on a state change. - */ + * periodic callback from Device system timer. + * + * Check for state change for this button, and fires various events on a state change. + */ void Button::periodicCallback() { // If this button is disabled, do nothing. - if (!(status & DEVICE_COMPONENT_RUNNING)) - return; + if (!(status & DEVICE_COMPONENT_RUNNING)) return; // // If the pin is pulled low (touched), increment our culumative counter. @@ -110,76 +114,68 @@ void Button::periodicCallback() // This makes the output debounced for buttons, and desensitizes touch sensors // (particularly in environments where there is mains noise!) // - if(buttonActive()) - { - if (sigma < DEVICE_BUTTON_SIGMA_MAX) - sigma++; + if (buttonActive()) { + if (sigma < DEVICE_BUTTON_SIGMA_MAX) sigma++; } - else - { - if (sigma > DEVICE_BUTTON_SIGMA_MIN) - sigma--; + else { + if (sigma > DEVICE_BUTTON_SIGMA_MIN) sigma--; } // Check to see if we have off->on state change. - if(sigma > DEVICE_BUTTON_SIGMA_THRESH_HI && !(status & DEVICE_BUTTON_STATE)) - { + if (sigma > DEVICE_BUTTON_SIGMA_THRESH_HI && !(status & DEVICE_BUTTON_STATE)) { // Record we have a state change, and raise an event. status |= DEVICE_BUTTON_STATE; - Event evt(id,DEVICE_BUTTON_EVT_DOWN); + Event evt(id, DEVICE_BUTTON_EVT_DOWN); clickCount++; - //Record the time the button was pressed. + // Record the time the button was pressed. downStartTime = system_timer_current_time(); } // Check to see if we have on->off state change. - if(sigma < DEVICE_BUTTON_SIGMA_THRESH_LO && (status & DEVICE_BUTTON_STATE)) - { + if (sigma < DEVICE_BUTTON_SIGMA_THRESH_LO && (status & DEVICE_BUTTON_STATE)) { status &= ~DEVICE_BUTTON_STATE; status &= ~DEVICE_BUTTON_STATE_HOLD_TRIGGERED; - Event evt(id,DEVICE_BUTTON_EVT_UP); - - if (eventConfiguration == DEVICE_BUTTON_ALL_EVENTS) - { - //determine if this is a long click or a normal click and send event - if((system_timer_current_time() - downStartTime) >= DEVICE_BUTTON_LONG_CLICK_TIME) - Event evt(id,DEVICE_BUTTON_EVT_LONG_CLICK); - else - Event evt(id,DEVICE_BUTTON_EVT_CLICK); - } + Event evt(id, DEVICE_BUTTON_EVT_UP); + + if (eventConfiguration == DEVICE_BUTTON_ALL_EVENTS) { + // determine if this is a long click or a normal click and send event + if ((system_timer_current_time() - downStartTime) >= DEVICE_BUTTON_LONG_CLICK_TIME) + Event evt(id, DEVICE_BUTTON_EVT_LONG_CLICK); + else + Event evt(id, DEVICE_BUTTON_EVT_CLICK); + } } - //if button is pressed and the hold triggered event state is not triggered AND we are greater than the button debounce value - if((status & DEVICE_BUTTON_STATE) && !(status & DEVICE_BUTTON_STATE_HOLD_TRIGGERED) && (system_timer_current_time() - downStartTime) >= DEVICE_BUTTON_HOLD_TIME) - { - //set the hold triggered event flag + // if button is pressed and the hold triggered event state is not triggered AND we are greater than the button + // debounce value + if ((status & DEVICE_BUTTON_STATE) && !(status & DEVICE_BUTTON_STATE_HOLD_TRIGGERED) && + (system_timer_current_time() - downStartTime) >= DEVICE_BUTTON_HOLD_TIME) { + // set the hold triggered event flag status |= DEVICE_BUTTON_STATE_HOLD_TRIGGERED; - //fire hold event - Event evt(id,DEVICE_BUTTON_EVT_HOLD); + // fire hold event + Event evt(id, DEVICE_BUTTON_EVT_HOLD); } } /** - * Tests if this Button is currently pressed. - * - * @code - * if(buttonA.isPressed()) - * display.scroll("Pressed!"); - * @endcode - * - * @return 1 if this button is pressed, 0 otherwise. - */ + * Tests if this Button is currently pressed. + * + * @code + * if(buttonA.isPressed()) + * display.scroll("Pressed!"); + * @endcode + * + * @return 1 if this button is pressed, 0 otherwise. + */ int Button::isPressed() { - if (_pin.obj != this) - { - if (_pin.obj != NULL) - _pin.obj->releasePin(_pin); + if (_pin.obj != this) { + if (_pin.obj != NULL) _pin.obj->releasePin(_pin); _pin.obj = this; - _pin.setPolarity( polarity == ACTIVE_HIGH ? 1 : 0); + _pin.setPolarity(polarity == ACTIVE_HIGH ? 1 : 0); _pin.setPull(pullMode); this->status |= DEVICE_COMPONENT_STATUS_SYSTEM_TICK; } @@ -193,54 +189,48 @@ int Button::isPressed() * to allow it to be used by a different peripheral. * * @param pin the Pin to be released. - * @return DEVICE_OK on success, or DEVICE_NOT_IMPLEMENTED if unsupported, or DEVICE_INVALID_PARAMETER if the pin is not bound to this peripheral. + * @return DEVICE_OK on success, or DEVICE_NOT_IMPLEMENTED if unsupported, or DEVICE_INVALID_PARAMETER if the pin is not + * bound to this peripheral. */ -int Button::releasePin(Pin &pin) +int Button::releasePin(Pin& pin) { // We've been asked to disconnect from the given pin. // Stop requesting periodic callbacks from the scheduler. this->status &= ~DEVICE_COMPONENT_STATUS_SYSTEM_TICK; pin.obj = NULL; - if (deleteOnRelease) - delete this; + if (deleteOnRelease) delete this; return DEVICE_OK; } /** - * Destructor for Button, where we deregister this instance from the array of fiber components. - */ -Button::~Button() -{ -} + * Destructor for Button, where we deregister this instance from the array of fiber components. + */ +Button::~Button() {} /** * Puts the component in (or out of) sleep (low power) mode. */ int Button::setSleep(bool doSleep) { - if (doSleep) - { + if (doSleep) { status &= ~DEVICE_BUTTON_STATE; status &= ~DEVICE_BUTTON_STATE_HOLD_TRIGGERED; clickCount = 0; - sigma = 0; + sigma = 0; } - else - { - if ( isWakeOnActive()) - { - if ( buttonActive()) - { + else { + if (isWakeOnActive()) { + if (buttonActive()) { sigma = DEVICE_BUTTON_SIGMA_THRESH_LO + 1; status |= DEVICE_BUTTON_STATE; - Event evt(id,DEVICE_BUTTON_EVT_DOWN); - clickCount = 1; + Event evt(id, DEVICE_BUTTON_EVT_DOWN); + clickCount = 1; downStartTime = system_timer_current_time(); } } } - + return DEVICE_OK; } diff --git a/source/drivers/FXOS8700.cpp b/source/drivers/FXOS8700.cpp index 2b78906a..b041d641 100644 --- a/source/drivers/FXOS8700.cpp +++ b/source/drivers/FXOS8700.cpp @@ -29,12 +29,13 @@ DEALINGS IN THE SOFTWARE. * Also includes basic data caching and on demand activation. */ #include "FXOS8700.h" -#include "ErrorNo.h" -#include "Event.h" + +#include "Accelerometer.h" #include "CodalCompat.h" -#include "CodalFiber.h" #include "CodalDmesg.h" -#include "Accelerometer.h" +#include "CodalFiber.h" +#include "ErrorNo.h" +#include "Event.h" using namespace codal; @@ -42,38 +43,26 @@ using namespace codal; // Configuration table for available g force ranges. // Maps g -> XYZ_DATA_CFG bit [0..1] // -static const KeyValueTableEntry accelerometerRangeData[] = { - {2,0}, - {4,1}, - {8,2} -}; +static const KeyValueTableEntry accelerometerRangeData[] = {{2, 0}, {4, 1}, {8, 2}}; CREATE_KEY_VALUE_TABLE(accelerometerRange, accelerometerRangeData); // // Configuration table for available data update frequency. // maps microsecond period -> CTRL_REG1 data rate selection bits [3..5] // -static const KeyValueTableEntry accelerometerPeriodData[] = { - {2500,0x00}, - {5000,0x08}, - {10000,0x10}, - {20000,0x18}, - {80000,0x20}, - {160000,0x28}, - {320000,0x30}, - {1280000,0x38} -}; +static const KeyValueTableEntry accelerometerPeriodData[] = {{2500, 0x00}, {5000, 0x08}, {10000, 0x10}, + {20000, 0x18}, {80000, 0x20}, {160000, 0x28}, + {320000, 0x30}, {1280000, 0x38}}; CREATE_KEY_VALUE_TABLE(accelerometerPeriod, accelerometerPeriodData); - /** - * Configures the accelerometer for G range and sample rate defined - * in this object. The nearest values are chosen to those defined - * that are supported by the hardware. The instance variables are then - * updated to reflect reality. - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the accelerometer could not be configured. - */ + * Configures the accelerometer for G range and sample rate defined + * in this object. The nearest values are chosen to those defined + * that are supported by the hardware. The instance variables are then + * updated to reflect reality. + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the accelerometer could not be configured. + */ int FXOS8700::configure() { int result; @@ -81,16 +70,15 @@ int FXOS8700::configure() // First find the nearest sample rate to that specified. Accelerometer::samplePeriod = accelerometerPeriod.getKey(Accelerometer::samplePeriod * 2000) / 1000; - Accelerometer::sampleRange = accelerometerRange.getKey(Accelerometer::sampleRange); - Compass::samplePeriod = Accelerometer::samplePeriod; + Accelerometer::sampleRange = accelerometerRange.getKey(Accelerometer::sampleRange); + Compass::samplePeriod = Accelerometer::samplePeriod; // Now configure the accelerometer accordingly. // Firstly, disable the module (as some registers cannot be changed while its running). - value = 0x00; + value = 0x00; result = i2c.writeRegister(address, FXOS8700_CTRL_REG1, value); - if (result != 0) - { + if (result != 0) { DMESG("I2C ERROR: FXOS8700_CTRL_REG1"); return DEVICE_I2C_ERROR; } @@ -98,10 +86,9 @@ int FXOS8700::configure() // Enter hybrid mode (interleave accelerometer and magnetometer samples). // Also, select full oversampling on the magnetometer // TODO: Determine power / accuracy tradeoff here. - value = 0x1F; + value = 0x1F; result = i2c.writeRegister(address, FXOS8700_M_CTRL_REG1, value); - if (result != 0) - { + if (result != 0) { DMESG("I2C ERROR: FXOS8700_M_CTRL_REG1"); return DEVICE_I2C_ERROR; } @@ -109,60 +96,54 @@ int FXOS8700::configure() // Select the auto incremement mode, which allows a contiguous I2C block // read of both acceleromter and magnetometer data despite them being non-contguous // in memory... funky! - value = 0x20; + value = 0x20; result = i2c.writeRegister(address, FXOS8700_M_CTRL_REG2, value); - if (result != 0) - { + if (result != 0) { DMESG("I2C ERROR: FXOS8700_M_CTRL_REG2"); return DEVICE_I2C_ERROR; } // Configure Active LOW interrupt mode. - // Use OpenDrain configuation if we're on a shared IRQ line, PUSHPULL configuration otherwise. + // Use OpenDrain configuation if we're on a shared IRQ line, PUSHPULL configuration otherwise. #if CONFIG_ENABLED(DEVICE_I2C_IRQ_SHARED) value = 0x01; #else value = 0x00; #endif result = i2c.writeRegister(address, FXOS8700_CTRL_REG3, value); - if (result != 0) - { + if (result != 0) { DMESG("I2C ERROR: FXOS8700_CTRL_REG3"); return DEVICE_I2C_ERROR; } // Enable a data ready interrupt. - value = 0x01; + value = 0x01; result = i2c.writeRegister(address, FXOS8700_CTRL_REG4, value); - if (result != 0) - { + if (result != 0) { DMESG("I2C ERROR: FXOS8700_CTRL_REG4"); return DEVICE_I2C_ERROR; } // Route the data ready interrupt to INT1 pin. - value = 0x01; + value = 0x01; result = i2c.writeRegister(address, FXOS8700_CTRL_REG5, value); - if (result != 0) - { + if (result != 0) { DMESG("I2C ERROR: FXOS8700_CTRL_REG5"); return DEVICE_I2C_ERROR; } // Configure acceleromter g range. - value = accelerometerRange.get(Accelerometer::sampleRange); + value = accelerometerRange.get(Accelerometer::sampleRange); result = i2c.writeRegister(address, FXOS8700_XYZ_DATA_CFG, value); - if (result != 0) - { + if (result != 0) { DMESG("I2C ERROR: FXOS8700_XYZ_DATA_CFG"); return DEVICE_I2C_ERROR; } // Configure sample rate and re-enable the sensor. - value = accelerometerPeriod.get(Accelerometer::samplePeriod * 1000) | 0x01; + value = accelerometerPeriod.get(Accelerometer::samplePeriod * 1000) | 0x01; result = i2c.writeRegister(address, FXOS8700_CTRL_REG1, value); - if (result != 0) - { + if (result != 0) { DMESG("I2C ERROR: FXOS8700_CTRL_REG1"); return DEVICE_I2C_ERROR; } @@ -171,15 +152,17 @@ int FXOS8700::configure() } /** - * Constructor. - * Create a software abstraction of an FXSO8700 combined accelerometer/magnetometer - * - * @param _i2c an instance of I2C used to communicate with the device. - * - * @param address the default I2C address of the accelerometer. Defaults to: FXS8700_DEFAULT_ADDR. - * + * Constructor. + * Create a software abstraction of an FXSO8700 combined accelerometer/magnetometer + * + * @param _i2c an instance of I2C used to communicate with the device. + * + * @param address the default I2C address of the accelerometer. Defaults to: FXS8700_DEFAULT_ADDR. + * */ -FXOS8700::FXOS8700(I2C &_i2c, Pin &_int1, CoordinateSpace &coordinateSpace, uint16_t address, uint16_t aid, uint16_t cid) : Accelerometer(coordinateSpace, aid), Compass(coordinateSpace, cid), i2c(_i2c), int1(_int1) +FXOS8700::FXOS8700(I2C& _i2c, Pin& _int1, CoordinateSpace& coordinateSpace, uint16_t address, uint16_t aid, + uint16_t cid) + : Accelerometer(coordinateSpace, aid), Compass(coordinateSpace, cid), i2c(_i2c), int1(_int1) { // Store our identifiers. this->address = address; @@ -193,61 +176,58 @@ FXOS8700::FXOS8700(I2C &_i2c, Pin &_int1, CoordinateSpace &coordinateSpace, uint * * @return true if the WHO_AM_I value is succesfully read. false otherwise. */ -int FXOS8700::isDetected(I2C &i2c, uint16_t address) +int FXOS8700::isDetected(I2C& i2c, uint16_t address) { return i2c.readRegister(address, FXOS8700_WHO_AM_I) == FXOS8700_WHOAMI_VAL; } /** - * Reads the sensor ata from the FXSO8700, and stores it in our buffer. - * This only happens if the device indicates that it has new data via int1. - * - * On first use, this member function will attempt to add this component to the - * list of fiber components in order to constantly update the values stored - * by this object. - * - * This lazy instantiation means that we do not - * obtain the overhead from non-chalantly adding this component to fiber components. - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the read request fails. - */ + * Reads the sensor ata from the FXSO8700, and stores it in our buffer. + * This only happens if the device indicates that it has new data via int1. + * + * On first use, this member function will attempt to add this component to the + * list of fiber components in order to constantly update the values stored + * by this object. + * + * This lazy instantiation means that we do not + * obtain the overhead from non-chalantly adding this component to fiber components. + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the read request fails. + */ int FXOS8700::requestUpdate() { // Ensure we're scheduled to update the data periodically Accelerometer::status |= DEVICE_COMPONENT_STATUS_IDLE_TICK; // Poll interrupt line from device (ACTIVE LOW) - if(int1.isActive()) - { + if (int1.isActive()) { uint8_t data[12]; FXOSRawSample sample; - uint8_t *lsb = (uint8_t *) &sample; - uint8_t *msb = lsb + 1; + uint8_t* lsb = (uint8_t*)&sample; + uint8_t* msb = lsb + 1; int result; #if CONFIG_ENABLED(DEVICE_I2C_IRQ_SHARED) // Determine if this device has all its data ready (we may be on a shared IRQ line) uint8_t status_reg = i2c.readRegister(address, FXOS8700_STATUS_REG); - if((status_reg & FXOS8700_STATUS_DATA_READY) != FXOS8700_STATUS_DATA_READY) - return DEVICE_OK; + if ((status_reg & FXOS8700_STATUS_DATA_READY) != FXOS8700_STATUS_DATA_READY) return DEVICE_OK; #endif // Read the combined accelerometer and magnetometer data. result = i2c.readRegister(address, FXOS8700_OUT_X_MSB, data, 12); - if (result !=0) - return DEVICE_I2C_ERROR; - + if (result != 0) return DEVICE_I2C_ERROR; + // read sensor data (and translate into signed little endian) - for (int i=0; i<12; i+=2) - { - *msb = data[i]; - *lsb = data[i+1]; + for (int i = 0; i < 12; i += 2) { + *msb = data[i]; + *lsb = data[i + 1]; msb += 2; lsb += 2; } - // scale the 14 bit accelerometer data (packed into 16 bits) into SI units (milli-g), and translate to ENU coordinate system + // scale the 14 bit accelerometer data (packed into 16 bits) into SI units (milli-g), and translate to ENU + // coordinate system Accelerometer::sampleENU.x = (-sample.ay * Accelerometer::sampleRange) / 32; Accelerometer::sampleENU.y = (sample.ax * Accelerometer::sampleRange) / 32; Accelerometer::sampleENU.z = (sample.az * Accelerometer::sampleRange) / 32; @@ -258,26 +238,23 @@ int FXOS8700::requestUpdate() Compass::sampleENU.z = FXOS8700_NORMALIZE_SAMPLE(sample.cz); Accelerometer::update(); - Compass::update(); + Compass::update(); } return DEVICE_OK; } /** - * A periodic callback invoked by the fiber scheduler idle thread. - * - * Internally calls updateSample(). - */ + * A periodic callback invoked by the fiber scheduler idle thread. + * + * Internally calls updateSample(). + */ void FXOS8700::idleCallback() { requestUpdate(); } /** - * Destructor for FXS8700, where we deregister from the array of fiber components. - */ -FXOS8700::~FXOS8700() -{ -} - + * Destructor for FXS8700, where we deregister from the array of fiber components. + */ +FXOS8700::~FXOS8700() {} diff --git a/source/drivers/GhostFAT.cpp b/source/drivers/GhostFAT.cpp index 54fd2598..d8b8411e 100644 --- a/source/drivers/GhostFAT.cpp +++ b/source/drivers/GhostFAT.cpp @@ -1,49 +1,48 @@ #include "GhostFAT.h" + #include "FAT.h" #if CONFIG_ENABLED(DEVICE_USB) #define UF2_DEFINE_HANDOVER 1 -#include "uf2format.h" - #include "CodalCompat.h" -#include "CodalDmesg.h" #include "CodalDevice.h" +#include "CodalDmesg.h" +#include "uf2format.h" #define NUM_FAT_BLOCKS 65000 #define SECTORS_PER_FAT FAT_SECTORS_PER_FAT(NUM_FAT_BLOCKS) -#define START_FAT0 FAT_START_FAT0(NUM_FAT_BLOCKS) -#define START_FAT1 FAT_START_FAT1(NUM_FAT_BLOCKS) -#define START_ROOTDIR FAT_START_ROOTDIR(NUM_FAT_BLOCKS) -#define START_CLUSTERS FAT_START_CLUSTERS(NUM_FAT_BLOCKS) +#define START_FAT0 FAT_START_FAT0(NUM_FAT_BLOCKS) +#define START_FAT1 FAT_START_FAT1(NUM_FAT_BLOCKS) +#define START_ROOTDIR FAT_START_ROOTDIR(NUM_FAT_BLOCKS) +#define START_CLUSTERS FAT_START_CLUSTERS(NUM_FAT_BLOCKS) #define LOG DMESG -namespace codal -{ +namespace codal { static const FAT_BootBlock BootBlock = { - {0xeb, 0x3c, 0x90}, // JumpInstruction - {'C', 'O', 'D', 'A', 'L', ' ', '0', '0'}, // OEMInfo - 512, // SectorSize - 1, // SectorsPerCluster - FAT_RESERVED_SECTORS, // ReservedSectors - 2, // FATCopies - (FAT_ROOT_DIR_SECTORS * 512 / 32), // RootDirectoryEntries - NUM_FAT_BLOCKS - 2, // TotalSectors16 - 0xF8, // MediaDescriptor - FAT_SECTORS_PER_FAT(NUM_FAT_BLOCKS), // SectorsPerFAT - 1, // SectorsPerTrack - 1, // Heads - 0, // HiddenSectors - 0, // TotalSectors32 - 0, // PhysicalDriveNum - 0, // Reserved - 0x29, // ExtendedBootSig - 0x00420042, // VolumeSerialNumber - "", // VolumeLabel - {'F', 'A', 'T', '1', '6', ' ', ' ', ' '}, // FilesystemIdentifier + {0xeb, 0x3c, 0x90}, // JumpInstruction + {'C', 'O', 'D', 'A', 'L', ' ', '0', '0'}, // OEMInfo + 512, // SectorSize + 1, // SectorsPerCluster + FAT_RESERVED_SECTORS, // ReservedSectors + 2, // FATCopies + (FAT_ROOT_DIR_SECTORS * 512 / 32), // RootDirectoryEntries + NUM_FAT_BLOCKS - 2, // TotalSectors16 + 0xF8, // MediaDescriptor + FAT_SECTORS_PER_FAT(NUM_FAT_BLOCKS), // SectorsPerFAT + 1, // SectorsPerTrack + 1, // Heads + 0, // HiddenSectors + 0, // TotalSectors32 + 0, // PhysicalDriveNum + 0, // Reserved + 0x29, // ExtendedBootSig + 0x00420042, // VolumeSerialNumber + "", // VolumeLabel + {'F', 'A', 'T', '1', '6', ' ', ' ', ' '}, // FilesystemIdentifier }; uint32_t GhostFAT::getCapacity() @@ -51,42 +50,37 @@ uint32_t GhostFAT::getCapacity() return NUM_FAT_BLOCKS; } -static int numClusters(GFATEntry *p) +static int numClusters(GFATEntry* p) { // at least one cluster! return (int)(p->size + 512) / 512; } -static int numDirEntries(GFATEntry *p) +static int numDirEntries(GFATEntry* p) { return 1 + (strlen(p->filename) + 1 + 12) / 13; } -static uint8_t fatChecksum(const char *name) +static uint8_t fatChecksum(const char* name) { uint8_t sum = 0; - for (int i = 0; i < 11; ++i) - sum = ((sum & 1) << 7) + (sum >> 1) + *name++; + for (int i = 0; i < 11; ++i) sum = ((sum & 1) << 7) + (sum >> 1) + *name++; return sum; } // note that ptr might be unaligned -static const char *copyVFatName(const char *ptr, void *dest, int len) +static const char* copyVFatName(const char* ptr, void* dest, int len) { - uint8_t *dst = (uint8_t *)dest; + uint8_t* dst = (uint8_t*)dest; - for (int i = 0; i < len; ++i) - { - if (ptr == NULL) - { + for (int i = 0; i < len; ++i) { + if (ptr == NULL) { *dst++ = 0xff; *dst++ = 0xff; } - else - { + else { char c = *ptr; - if (c && strchr("/?<>\\:*|^", c)) - c = '_'; + if (c && strchr("/?<>\\:*|^", c)) c = '_'; *dst++ = c; *dst++ = 0; if (*ptr) @@ -101,70 +95,57 @@ static const char *copyVFatName(const char *ptr, void *dest, int len) static int filechar(int c) { - if (!c) - return 0; - return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || - strchr("_-", c); + if (!c) return 0; + return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || strchr("_-", c); } -static void copyFsChars(char *dst, const char *src, int len) +static void copyFsChars(char* dst, const char* src, int len) { - for (int i = 0; i < len; ++i) - { - if (filechar(*src)) - { + for (int i = 0; i < len; ++i) { + if (filechar(*src)) { char c = *src++; - if ('a' <= c && c <= 'z') - c -= 32; + if ('a' <= c && c <= 'z') c -= 32; dst[i] = c; } - else - { - if (*src == '.') - src = ""; + else { + if (*src == '.') src = ""; if (*src == 0) dst[i] = ' '; else dst[i] = '_'; - while (*src && !filechar(*src)) - src++; + while (*src && !filechar(*src)) src++; } } } -void GhostFAT::readDirData(uint8_t *dest, int blkno, uint8_t dirid) +void GhostFAT::readDirData(uint8_t* dest, int blkno, uint8_t dirid) { - DirEntry *d = (DirEntry *)dest; - int idx = blkno * -16; - int id = 0; + DirEntry* d = (DirEntry*)dest; + int idx = blkno * -16; + int id = 0; - if (dirid == 0 && idx++ == 0) - { + if (dirid == 0 && idx++ == 0) { copyFsChars(d->name, volumeLabel(), 11); d->attrs = 0x28; d++; } - for (GFATEntry *e = files; e; e = e->next) - { - if (e->dirid != dirid) - continue; + for (GFATEntry* e = files; e; e = e->next) { + if (e->dirid != dirid) continue; id++; - if (idx >= 16) - break; + if (idx >= 16) break; char fatname[12]; copyFsChars(fatname, e->filename, 8); - const char *dot = strchr(e->filename, '.'); - if (!dot) - dot = "."; + const char* dot = strchr(e->filename, '.'); + if (!dot) dot = "."; copyFsChars(fatname + 8, dot + 1, 3); { char buf[10]; itoa(id, buf + 1); - buf[0] = '~'; + buf[0] = '~'; int idlen = strlen(buf); memcpy(fatname + 8 - idlen, buf, idlen); } @@ -175,35 +156,30 @@ void GhostFAT::readDirData(uint8_t *dest, int blkno, uint8_t dirid) // e->dirid); int numdirentries = numDirEntries(e); - for (int i = 0; i < numdirentries; ++i, ++idx) - { - if (0 <= idx && idx < 16) - { - if (i == numdirentries - 1) - { + for (int i = 0; i < numdirentries; ++i, ++idx) { + if (0 <= idx && idx < 16) { + if (i == numdirentries - 1) { memcpy(d->name, fatname, 11); - d->attrs = e->attrs; - d->size = e->size; + d->attrs = e->attrs; + d->size = e->size; d->startCluster = e->startCluster + 2; // timeToFat(e->mtime, &d->updateDate, &d->updateTime); // timeToFat(e->ctime, &d->createDate, &d->createTime); } - else - { - VFatEntry *f = (VFatEntry *)d; - int seq = numdirentries - i - 2; - f->seqno = seq + 1; // they start at 1 - if (i == 0) - f->seqno |= 0x40; - f->attrs = 0x0F; - f->type = 0x00; - f->checksum = fatChecksum(fatname); + else { + VFatEntry* f = (VFatEntry*)d; + int seq = numdirentries - i - 2; + f->seqno = seq + 1; // they start at 1 + if (i == 0) f->seqno |= 0x40; + f->attrs = 0x0F; + f->type = 0x00; + f->checksum = fatChecksum(fatname); f->startCluster = 0; - const char *ptr = e->filename + (13 * seq); - ptr = copyVFatName(ptr, f->name0, 5); - ptr = copyVFatName(ptr, f->name1, 6); - ptr = copyVFatName(ptr, f->name2, 2); + const char* ptr = e->filename + (13 * seq); + ptr = copyVFatName(ptr, f->name0, 5); + ptr = copyVFatName(ptr, f->name1, 6); + ptr = copyVFatName(ptr, f->name2, 2); } d++; } @@ -211,67 +187,55 @@ void GhostFAT::readDirData(uint8_t *dest, int blkno, uint8_t dirid) } } -#define WRITE_ENT(v) \ - do \ - { \ - if (skip++ >= 0) \ - *dest++ = v; \ - if (skip >= 256) \ - return; \ - cl++; \ +#define WRITE_ENT(v) \ + do { \ + if (skip++ >= 0) *dest++ = v; \ + if (skip >= 256) return; \ + cl++; \ } while (0) -void GhostFAT::buildBlock(uint32_t block_no, uint8_t *data) +void GhostFAT::buildBlock(uint32_t block_no, uint8_t* data) { memset(data, 0, 512); uint32_t sectionIdx = block_no; - if (block_no == 0) - { + if (block_no == 0) { memcpy(data, &BootBlock, sizeof(BootBlock)); - FAT_BootBlock *bb = (FAT_BootBlock *)data; + FAT_BootBlock* bb = (FAT_BootBlock*)data; copyFsChars(bb->VolumeLabel, volumeLabel(), 11); data[510] = 0x55; data[511] = 0xaa; } - else if (block_no < START_ROOTDIR) - { + else if (block_no < START_ROOTDIR) { sectionIdx -= START_FAT0; // logval("sidx", sectionIdx); - if (sectionIdx >= SECTORS_PER_FAT) - sectionIdx -= SECTORS_PER_FAT; + if (sectionIdx >= SECTORS_PER_FAT) sectionIdx -= SECTORS_PER_FAT; - int cl = 0; - int skip = -(sectionIdx * 256); - uint16_t *dest = (uint16_t *)data; + int cl = 0; + int skip = -(sectionIdx * 256); + uint16_t* dest = (uint16_t*)data; WRITE_ENT(0xfff0); WRITE_ENT(0xffff); - for (GFATEntry *p = files; p; p = p->next) - { + for (GFATEntry* p = files; p; p = p->next) { int n = numClusters(p) - 1; - for (int i = 0; i < n; i++) - WRITE_ENT(cl + 1); + for (int i = 0; i < n; i++) WRITE_ENT(cl + 1); WRITE_ENT(0xffff); } } - else if (block_no < START_CLUSTERS) - { + else if (block_no < START_CLUSTERS) { sectionIdx -= START_ROOTDIR; readDirData(data, sectionIdx, 0); } - else - { + else { sectionIdx -= START_CLUSTERS; - for (GFATEntry *p = files; p; p = p->next) - { - if (p->startCluster <= sectionIdx && (int)sectionIdx < p->startCluster + numClusters(p)) - { + for (GFATEntry* p = files; p; p = p->next) { + if (p->startCluster <= sectionIdx && (int)sectionIdx < p->startCluster + numClusters(p)) { sectionIdx -= p->startCluster; if (p->attrs & 0x10) readDirData(data, sectionIdx, (uint32_t)p->userdata); else - p->read(p, sectionIdx, (char *)data); + p->read(p, sectionIdx, (char*)data); break; } } @@ -282,10 +246,9 @@ void GhostFAT::readBlocks(int blockAddr, int numBlocks) { finalizeFiles(); - uint8_t *buf = new uint8_t[512]; + uint8_t* buf = new uint8_t[512]; - while (numBlocks--) - { + while (numBlocks--) { buildBlock(blockAddr, buf); writeBulk(buf, 512); blockAddr++; @@ -296,7 +259,6 @@ void GhostFAT::readBlocks(int blockAddr, int numBlocks) finishReadWrite(); } - void GhostFAT::writeBlocks(int blockAddr, int numBlocks) { #ifdef BOOTLOADER_START_ADDR @@ -304,25 +266,18 @@ void GhostFAT::writeBlocks(int blockAddr, int numBlocks) bool handoverSupported = false; const char *p0 = uf2_info(), *p = p0; - while (*p && *p != '\n') - p++; - while (p > p0) - { - if (*p == ' ') - break; - if (*p == 'O') - handoverSupported = true; + while (*p && *p != '\n') p++; + while (p > p0) { + if (*p == ' ') break; + if (*p == 'O') handoverSupported = true; p--; } - while (numBlocks--) - { + while (numBlocks--) { readBulk(buf, sizeof(buf)); - if (handoverSupported && is_uf2_block(buf)) - { - UF2_Block *b = (UF2_Block *)buf; - if (!(b->flags & UF2_FLAG_NOFLASH)) - { + if (handoverSupported && is_uf2_block(buf)) { + UF2_Block* b = (UF2_Block*)buf; + if (!(b->flags & UF2_FLAG_NOFLASH)) { check_uf2_handover(buf, numBlocks, in->ep & 0xf, out->ep & 0xf, cbwTag()); } } @@ -345,23 +300,19 @@ bool GhostFAT::filesFinalized() void GhostFAT::finalizeFiles() { - if (files == NULL || filesFinalized()) - return; + if (files == NULL || filesFinalized()) return; GFATEntry *regFiles = NULL, *dirs = NULL; - while (files) - { - GFATEntry *n = files->next; - if (files->attrs & 0x10) - { + while (files) { + GFATEntry* n = files->next; + if (files->attrs & 0x10) { files->next = dirs; - dirs = files; + dirs = files; } - else - { + else { files->next = regFiles; - regFiles = files; + regFiles = files; } files = n; } @@ -369,97 +320,85 @@ void GhostFAT::finalizeFiles() files = regFiles; int cl = 0; - for (GFATEntry *p = files; p; p = p->next) - { + for (GFATEntry* p = files; p; p = p->next) { p->startCluster = cl; cl += numClusters(p); - if (p->dirid) - { - for (GFATEntry *d = dirs; d; d = d->next) - { - if ((uint32_t)d->userdata == p->dirid) - { + if (p->dirid) { + for (GFATEntry* d = dirs; d; d = d->next) { + if ((uint32_t)d->userdata == p->dirid) { d->size += sizeof(DirEntry) * numDirEntries(p); break; } } } - if (p->next == NULL) - { + if (p->next == NULL) { p->next = dirs; - dirs = NULL; + dirs = NULL; } } } -GFATEntry *GhostFAT::addFile(GFATReadCallback read, void *userdata, const char *filename, - uint32_t size, uint8_t dirid) +GFATEntry* GhostFAT::addFile(GFATReadCallback read, void* userdata, const char* filename, uint32_t size, uint8_t dirid) { - if (filesFinalized()) - target_panic(DEVICE_USB_ERROR); + if (filesFinalized()) target_panic(DEVICE_USB_ERROR); - GFATEntry *f = (GFATEntry *)malloc(sizeof(GFATEntry) + strlen(filename) + 1); + GFATEntry* f = (GFATEntry*)malloc(sizeof(GFATEntry) + strlen(filename) + 1); memset(f, 0, sizeof(GFATEntry)); strcpy(f->filename, filename); - f->size = size; - f->read = read; - f->userdata = userdata; - f->dirid = dirid; - f->next = files; + f->size = size; + f->read = read; + f->userdata = userdata; + f->dirid = dirid; + f->next = files; f->startCluster = 0xffff; - files = f; + files = f; return f; } -static void readString(GFATEntry *ent, unsigned blockAddr, char *dst) +static void readString(GFATEntry* ent, unsigned blockAddr, char* dst) { blockAddr *= 512; - if (blockAddr >= ent->size) - return; - const char *f = (const char *)ent->userdata; - for (int i = 0; i < 512; ++i) - { + if (blockAddr >= ent->size) return; + const char* f = (const char*)ent->userdata; + for (int i = 0; i < 512; ++i) { dst[i] = *f; - if (*f) - f++; + if (*f) f++; } } -GFATEntry *GhostFAT::addStringFile(const char *file, const char *filename, uint8_t dirid) +GFATEntry* GhostFAT::addStringFile(const char* file, const char* filename, uint8_t dirid) { - return addFile(readString, (void *)file, filename, strlen(file), dirid); + return addFile(readString, (void*)file, filename, strlen(file), dirid); } -void GhostFAT::addDirectory(uint8_t id, const char *dirname) +void GhostFAT::addDirectory(uint8_t id, const char* dirname) { - GFATEntry *f = addFile(NULL, (void *)(uint32_t)id, dirname, 0); - f->attrs = 0x10; + GFATEntry* f = addFile(NULL, (void*)(uint32_t)id, dirname, 0); + f->attrs = 0x10; } -static void readCurrentUF2(GFATEntry *ent, unsigned blockAddr, char *dst) +static void readCurrentUF2(GFATEntry* ent, unsigned blockAddr, char* dst) { uint32_t addr = blockAddr * 256; - GhostFAT *th = (GhostFAT *)ent->userdata; - if (addr < th->internalFlashSize()) - { - UF2_Block *bl = (UF2_Block *)dst; + GhostFAT* th = (GhostFAT*)ent->userdata; + if (addr < th->internalFlashSize()) { + UF2_Block* bl = (UF2_Block*)dst; bl->magicStart0 = UF2_MAGIC_START0; bl->magicStart1 = UF2_MAGIC_START1; - bl->magicEnd = UF2_MAGIC_END; - bl->blockNo = blockAddr; - bl->numBlocks = th->internalFlashSize() / 256; - bl->targetAddr = addr; + bl->magicEnd = UF2_MAGIC_END; + bl->blockNo = blockAddr; + bl->numBlocks = th->internalFlashSize() / 256; + bl->targetAddr = addr; bl->payloadSize = 256; - memcpy(bl->data, (void *)addr, bl->payloadSize); + memcpy(bl->data, (void*)addr, bl->payloadSize); } } #if DEVICE_DMESG_BUFFER_SIZE > 0 -static void readDMesg(GFATEntry *ent, unsigned blockAddr, char *dst) +static void readDMesg(GFATEntry* ent, unsigned blockAddr, char* dst) { uint32_t addr = blockAddr * 512; - for (uint32_t i = 0; i < 512; ++i) - { + for (uint32_t i = 0; i < 512; ++i) { if (addr < codalLogStore.ptr) *dst++ = codalLogStore.buffer[addr++]; else @@ -478,6 +417,6 @@ void GhostFAT::addFiles() addFile(readDMesg, this, "dmesg.txt", DEVICE_DMESG_BUFFER_SIZE); #endif } -} +} // namespace codal #endif \ No newline at end of file diff --git a/source/drivers/HID.cpp b/source/drivers/HID.cpp index bd7c2724..331258f8 100644 --- a/source/drivers/HID.cpp +++ b/source/drivers/HID.cpp @@ -29,32 +29,32 @@ DEALINGS IN THE SOFTWARE. using namespace codal; static const char hidDescriptor[] = { - 0x06, 0x00, 0xFF, // usage page vendor #0 - 0x09, 0x01, // usage 1 - 0xA1, 0x01, // collection - application - 0x15, 0x00, // logical min 0 - 0x26, 0xFF, 0x00, // logical max 255 - 0x75, 8, // report size 8 - 0x95, 64, // report count 64 - 0x09, 0x01, // usage 1 - 0x81, 0x02, // input: data, variable, absolute - 0x95, 64, // report count 64 - 0x09, 0x01, // usage 1 - 0x91, 0x02, // output: data, variable, absolute - 0x95, 1, // report count 1 - 0x09, 0x01, // usage 1 - 0xB1, 0x02, // feature: data, variable, absolute - 0xC0, // end + 0x06, 0x00, 0xFF, // usage page vendor #0 + 0x09, 0x01, // usage 1 + 0xA1, 0x01, // collection - application + 0x15, 0x00, // logical min 0 + 0x26, 0xFF, 0x00, // logical max 255 + 0x75, 8, // report size 8 + 0x95, 64, // report count 64 + 0x09, 0x01, // usage 1 + 0x81, 0x02, // input: data, variable, absolute + 0x95, 64, // report count 64 + 0x09, 0x01, // usage 1 + 0x91, 0x02, // output: data, variable, absolute + 0x95, 1, // report count 1 + 0x09, 0x01, // usage 1 + 0xB1, 0x02, // feature: data, variable, absolute + 0xC0, // end }; static const HIDReportDescriptor reportDesc = { 9, - 0x21, // HID - 0x100, // hidbcd 1.00 - 0x00, // country code - 0x01, // num desc - 0x22, // report desc type - sizeof(hidDescriptor), // size of 0x22 + 0x21, // HID + 0x100, // hidbcd 1.00 + 0x00, // country code + 0x01, // num desc + 0x22, // report desc type + sizeof(hidDescriptor), // size of 0x22 }; static const InterfaceInfo ifaceInfo = { @@ -62,59 +62,53 @@ static const InterfaceInfo ifaceInfo = { sizeof(reportDesc), 1, { - 2, // numEndpoints - 0x03, /// class code - HID - 0x00, // subclass - 0x00, // protocol - 0x00, // - 0x00, // + 2, // numEndpoints + 0x03, /// class code - HID + 0x00, // subclass + 0x00, // protocol + 0x00, // + 0x00, // }, {USB_EP_TYPE_INTERRUPT, 1}, {USB_EP_TYPE_INTERRUPT, 1}, }; -USBHID::USBHID() : CodalUSBInterface() -{ -} +USBHID::USBHID() : CodalUSBInterface() {} -int USBHID::stdRequest(UsbEndpointIn &ctrl, USBSetup &setup) +int USBHID::stdRequest(UsbEndpointIn& ctrl, USBSetup& setup) { - if (setup.bRequest == USB_REQ_GET_DESCRIPTOR) - { - if (setup.wValueH == 0x21) - { + if (setup.bRequest == USB_REQ_GET_DESCRIPTOR) { + if (setup.wValueH == 0x21) { InterfaceDescriptor tmp; fillInterfaceInfo(&tmp); return ctrl.write(&tmp, sizeof(tmp)); } - else if (setup.wValueH == 0x22) - { + else if (setup.wValueH == 0x22) { return ctrl.write(hidDescriptor, sizeof(hidDescriptor)); } } return DEVICE_NOT_SUPPORTED; } -const InterfaceInfo *USBHID::getInterfaceInfo() +const InterfaceInfo* USBHID::getInterfaceInfo() { return &ifaceInfo; } -int USBHID::classRequest(UsbEndpointIn &ctrl, USBSetup &setup) +int USBHID::classRequest(UsbEndpointIn& ctrl, USBSetup& setup) { uint8_t buf[8] = {0}; - switch (setup.bRequest) - { - case HID_REQUEST_GET_PROTOCOL: - case HID_REQUEST_GET_IDLE: - case HID_REQUEST_GET_REPORT: - return ctrl.write(buf, sizeof(buf)); - - case HID_REQUEST_SET_IDLE: - case HID_REQUEST_SET_REPORT: - case HID_REQUEST_SET_PROTOCOL: - return ctrl.write(buf, 0); + switch (setup.bRequest) { + case HID_REQUEST_GET_PROTOCOL: + case HID_REQUEST_GET_IDLE: + case HID_REQUEST_GET_REPORT: + return ctrl.write(buf, sizeof(buf)); + + case HID_REQUEST_SET_IDLE: + case HID_REQUEST_SET_REPORT: + case HID_REQUEST_SET_PROTOCOL: + return ctrl.write(buf, 0); } return DEVICE_NOT_SUPPORTED; diff --git a/source/drivers/HIDJoystick.cpp b/source/drivers/HIDJoystick.cpp index 8a7e76c6..d1a2ca24 100644 --- a/source/drivers/HIDJoystick.cpp +++ b/source/drivers/HIDJoystick.cpp @@ -23,179 +23,172 @@ DEALINGS IN THE SOFTWARE. */ #include "HIDJoystick.h" + #include "HID.h" #if CONFIG_ENABLED(DEVICE_USB) using namespace codal; -//this descriptor must be stored in RAM +// this descriptor must be stored in RAM static char HIDJoystickDescriptor[] = { - 0x05, 0x01, // USAGE_PAGE (Generic Desktop) - 0x09, 0x05, // USAGE (Game Pad) - 0xa1, 0x01, // COLLECTION (Application) - 0x05, 0x02, // USAGE_PAGE (Simulation Controls) - 0x09, 0xbb, // USAGE (Throttle) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x25, 0x1f, // LOGICAL_MAXIMUM (31) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x01, // REPORT_COUNT (1) - 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x05, 0x02, // USAGE_PAGE (Simulation Controls) - 0x09, 0xb0, // USAGE (Rudder) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x25, 0x1f, // LOGICAL_MAXIMUM (31) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x01, // REPORT_COUNT (1) - 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x05, 0x01, // USAGE_PAGE (Generic Desktop) - 0xa1, 0x00, // COLLECTION (Physical) - 0x09, 0x30, // USAGE (X) - 0x09, 0x31, // USAGE (Y) - 0x09, 0x32, // USAGE (Z) - 0x09, 0x35, // USAGE (Rz) - 0x15, 0x81, // LOGICAL_MINIMUM (-127) - 0x25, 0x7f, // LOGICAL_MAXIMUM (127) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x04, // REPORT_COUNT (4) - 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x05, 0x09, // USAGE_PAGE (Button) - 0x19, 0x01, // USAGE_MINIMUM (Button 1) - 0x29, 0x10, // USAGE_MAXIMUM (Button 16) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x25, 0x01, // LOGICAL_MAXIMUM (1) - 0x75, 0x01, // REPORT_SIZE (1) - 0x95, 0x10, // REPORT_COUNT (16) - 0x81, 0x02, // INPUT (Data,Var,Abs) - 0xc0, // END_COLLECTION - 0xc0 // END_COLLECTION + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0x09, 0x05, // USAGE (Game Pad) + 0xa1, 0x01, // COLLECTION (Application) + 0x05, 0x02, // USAGE_PAGE (Simulation Controls) + 0x09, 0xbb, // USAGE (Throttle) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x1f, // LOGICAL_MAXIMUM (31) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x05, 0x02, // USAGE_PAGE (Simulation Controls) + 0x09, 0xb0, // USAGE (Rudder) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x1f, // LOGICAL_MAXIMUM (31) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x01, // REPORT_COUNT (1) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x05, 0x01, // USAGE_PAGE (Generic Desktop) + 0xa1, 0x00, // COLLECTION (Physical) + 0x09, 0x30, // USAGE (X) + 0x09, 0x31, // USAGE (Y) + 0x09, 0x32, // USAGE (Z) + 0x09, 0x35, // USAGE (Rz) + 0x15, 0x81, // LOGICAL_MINIMUM (-127) + 0x25, 0x7f, // LOGICAL_MAXIMUM (127) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x04, // REPORT_COUNT (4) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0x05, 0x09, // USAGE_PAGE (Button) + 0x19, 0x01, // USAGE_MINIMUM (Button 1) + 0x29, 0x10, // USAGE_MAXIMUM (Button 16) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x25, 0x01, // LOGICAL_MAXIMUM (1) + 0x75, 0x01, // REPORT_SIZE (1) + 0x95, 0x10, // REPORT_COUNT (16) + 0x81, 0x02, // INPUT (Data,Var,Abs) + 0xc0, // END_COLLECTION + 0xc0 // END_COLLECTION }; static const HIDReportDescriptor reportDesc = { - 9, - 0x21, // HID - 0x101, // hidbcd 1.01 - 0x00, // country code - 0x01, // num desc - 0x22, // report desc type - sizeof(HIDJoystickDescriptor), + 9, + 0x21, // HID + 0x101, // hidbcd 1.01 + 0x00, // country code + 0x01, // num desc + 0x22, // report desc type + sizeof(HIDJoystickDescriptor), }; static const InterfaceInfo ifaceInfo = { - &reportDesc, - sizeof(reportDesc), - 1, - { - 1, // numEndpoints - 0x03, /// class code - HID - 0x00, // subclass - none - 0x00, // protocol - none (there isn't a protocol defined for gamepad/joystick) - 0x00, // - 0x00, // - }, - {USB_EP_TYPE_INTERRUPT, 1}, - {USB_EP_TYPE_INTERRUPT, 1}, + &reportDesc, + sizeof(reportDesc), + 1, + { + 1, // numEndpoints + 0x03, /// class code - HID + 0x00, // subclass - none + 0x00, // protocol - none (there isn't a protocol defined for gamepad/joystick) + 0x00, // + 0x00, // + }, + {USB_EP_TYPE_INTERRUPT, 1}, + {USB_EP_TYPE_INTERRUPT, 1}, }; static HIDJoystickState joystickState = { - 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, }; -USBHIDJoystick::USBHIDJoystick() : USBHID() -{ - -} +USBHIDJoystick::USBHIDJoystick() : USBHID() {} -int USBHIDJoystick::stdRequest(UsbEndpointIn &ctrl, USBSetup &setup) +int USBHIDJoystick::stdRequest(UsbEndpointIn& ctrl, USBSetup& setup) { - if (setup.bRequest == USB_REQ_GET_DESCRIPTOR) - { - if (setup.wValueH == 0x21) - { - InterfaceDescriptor tmp; - fillInterfaceInfo(&tmp); - return ctrl.write(&tmp, sizeof(tmp)); - } - else if (setup.wValueH == 0x22) - { - return ctrl.write(HIDJoystickDescriptor, sizeof(HIDJoystickDescriptor)); - } - } - return DEVICE_NOT_SUPPORTED; + if (setup.bRequest == USB_REQ_GET_DESCRIPTOR) { + if (setup.wValueH == 0x21) { + InterfaceDescriptor tmp; + fillInterfaceInfo(&tmp); + return ctrl.write(&tmp, sizeof(tmp)); + } + else if (setup.wValueH == 0x22) { + return ctrl.write(HIDJoystickDescriptor, sizeof(HIDJoystickDescriptor)); + } + } + return DEVICE_NOT_SUPPORTED; } -const InterfaceInfo *USBHIDJoystick::getInterfaceInfo() +const InterfaceInfo* USBHIDJoystick::getInterfaceInfo() { - return &ifaceInfo; + return &ifaceInfo; } int USBHIDJoystick::buttonDown(uint8_t b) { - uint16_t btn = (1UL << b); - if( joystickState.buttons & btn ) - return DEVICE_OK; - else{ - joystickState.buttons |= btn; - return sendReport(); - } + uint16_t btn = (1UL << b); + if (joystickState.buttons & btn) + return DEVICE_OK; + else { + joystickState.buttons |= btn; + return sendReport(); + } } int USBHIDJoystick::buttonUp(uint8_t b) { - uint16_t btn = (1UL << b); - if( !(joystickState.buttons & btn) ) - return DEVICE_OK; - else{ - joystickState.buttons &= ~(btn); - return sendReport(); - } + uint16_t btn = (1UL << b); + if (!(joystickState.buttons & btn)) + return DEVICE_OK; + else { + joystickState.buttons &= ~(btn); + return sendReport(); + } } int USBHIDJoystick::move(int8_t num, int8_t x, int8_t y) { - switch(num){ - case 0: - joystickState.x0 = x; - joystickState.y0 = y; - break; - case 1: - joystickState.x1 = x; - joystickState.y1 = y; - break; - default: - return DEVICE_INVALID_PARAMETER; - break; - } - return sendReport(); + switch (num) { + case 0: + joystickState.x0 = x; + joystickState.y0 = y; + break; + case 1: + joystickState.x1 = x; + joystickState.y1 = y; + break; + default: + return DEVICE_INVALID_PARAMETER; + break; + } + return sendReport(); } int USBHIDJoystick::setThrottle(uint8_t num, uint8_t val) { - if(val > 31) - return DEVICE_INVALID_PARAMETER; - switch(num){ - case 0: - joystickState.throttle0 = val; - break; - case 1: - joystickState.throttle1 = val; - break; - default: - return DEVICE_INVALID_PARAMETER; - break; - } - return sendReport(); + if (val > 31) return DEVICE_INVALID_PARAMETER; + switch (num) { + case 0: + joystickState.throttle0 = val; + break; + case 1: + joystickState.throttle1 = val; + break; + default: + return DEVICE_INVALID_PARAMETER; + break; + } + return sendReport(); } int USBHIDJoystick::sendReport() { - if (!in) - return DEVICE_INVALID_STATE; + if (!in) return DEVICE_INVALID_STATE; - uint8_t report[sizeof(HIDJoystickState)]; - memcpy(report, &joystickState, sizeof(HIDJoystickState)); + uint8_t report[sizeof(HIDJoystickState)]; + memcpy(report, &joystickState, sizeof(HIDJoystickState)); - return in->write(report, sizeof(report)); + return in->write(report, sizeof(report)); } #endif diff --git a/source/drivers/HIDKeyboard.cpp b/source/drivers/HIDKeyboard.cpp index ef76249f..68434824 100644 --- a/source/drivers/HIDKeyboard.cpp +++ b/source/drivers/HIDKeyboard.cpp @@ -23,9 +23,10 @@ DEALINGS IN THE SOFTWARE. */ #include "HIDKeyboard.h" -#include "HID.h" + #include "AsciiKeyMap.h" #include "CodalDmesg.h" +#include "HID.h" #if CONFIG_ENABLED(DEVICE_USB) @@ -33,7 +34,7 @@ using namespace codal; #define HID_KEYBOARD_KEY_OFF 0x00 -//this descriptor must be stored in RAM +// this descriptor must be stored in RAM static char hidKeyboardDescriptor[] = { 0x05, 0x01, // Usage Page (Generic Desktop) 0x09, 0x06, // Usage (Keyboard) @@ -48,75 +49,84 @@ static char hidKeyboardDescriptor[] = { 0x95, 0x08, // Report Count (8) 0x81, 0x02, // Input (Data, Variable, Absolute) - 0x95, 0x01, // Report Count (1) - 0x75, 0x08, // Report Size (8) - 0x81, 0x01, // Input (Constant) reserved byte(1) - - 0x95, 0x05, // Report Count (5) - 0x75, 0x01, // Report Size (1) - 0x05, 0x08, // Usage Page (Page# for LEDs) - 0x19, 0x01, // Usage Minimum (1) - 0x29, 0x05, // Usage Maximum (5) - 0x91, 0x02, // Output (Data, Variable, Absolute), Led report - 0x95, 0x01, // Report Count (1) - 0x75, 0x03, // Report Size (3) - 0x91, 0x01, // Output (Data, Variable, Absolute), Led report padding - - 0x95, 0x06, // Report Count (6) - 0x75, 0x08, // Report Size (8) - 0x15, 0x00, // Logical Minimum (0) - 0x25, 0x65, // Logical Maximum (101) - 0x05, 0x07, // Usage Page (Key codes) - 0x19, 0x00, // Usage Minimum (0) - 0x29, 0x65, // Usage Maximum (101) - 0x81, 0x00, // Input (Data, Array) Key array(6 bytes) - - - 0x09, 0x05, // Usage (Vendor Defined) - 0x15, 0x00, // Logical Minimum (0) - 0x26, 0xFF, 0x00, // Logical Maximum (255) - 0x75, 0x08, // Report Count (2) - 0x95, 0x02, // Report Size (8 bit) - 0xB1, 0x02, // Feature (Data, Variable, Absolute) - - 0xC0, // End Collection (Application) - - 0x05, 0x0c, // Usage Page (Consumer Devices) - 0x09, 0x01, // Usage (Consumer Control) - 0xa1, 0x01, // Collection (Application) - 0x85, HID_KEYBOARD_REPORT_CONSUMER, // Report ID (2) - 0x15, 0x00, // Logical Minimum (0) - 0x25, 0x01, // Logical Maximum (1) - 0x75, 0x01, // Report Size (1) - 0x95, 0x10, // Report Count (16) - 0x09, 0xe2, // Usage (Mute) 0x01 - 0x09, 0xe9, // Usage (Volume Up) 0x02 - 0x09, 0xea, // Usage (Volume Down) 0x03 - 0x09, 0xcd, // Usage (Play/Pause) 0x04 - 0x09, 0xb7, // Usage (Stop) 0x05 - 0x09, 0xb6, // Usage (Scan Previous Track) 0x06 - 0x09, 0xb5, // Usage (Scan Next Track) 0x07 - 0x0a, 0x8a, 0x01, // Usage (Mail) 0x08 - 0x0a, 0x92, 0x01, // Usage (Calculator) 0x09 - 0x0a, 0x21, 0x02, // Usage (www search) 0x0a - 0x0a, 0x23, 0x02, // Usage (www home) 0x0b - 0x0a, 0x2a, 0x02, // Usage (www favorites) 0x0c - 0x0a, 0x27, 0x02, // Usage (www refresh) 0x0d - 0x0a, 0x26, 0x02, // Usage (www stop) 0x0e - 0x0a, 0x25, 0x02, // Usage (www forward) 0x0f - 0x0a, 0x24, 0x02, // Usage (www back) 0x10 - 0x81, 0x62, // Input (Data,Var,Abs,NPrf,Null) - 0xc0, // End Collection + 0x95, 0x01, // Report Count (1) + 0x75, 0x08, // Report Size (8) + 0x81, 0x01, // Input (Constant) reserved byte(1) + + 0x95, 0x05, // Report Count (5) + 0x75, 0x01, // Report Size (1) + 0x05, 0x08, // Usage Page (Page# for LEDs) + 0x19, 0x01, // Usage Minimum (1) + 0x29, 0x05, // Usage Maximum (5) + 0x91, 0x02, // Output (Data, Variable, Absolute), Led report + 0x95, 0x01, // Report Count (1) + 0x75, 0x03, // Report Size (3) + 0x91, 0x01, // Output (Data, Variable, Absolute), Led report padding + + 0x95, 0x06, // Report Count (6) + 0x75, 0x08, // Report Size (8) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x65, // Logical Maximum (101) + 0x05, 0x07, // Usage Page (Key codes) + 0x19, 0x00, // Usage Minimum (0) + 0x29, 0x65, // Usage Maximum (101) + 0x81, 0x00, // Input (Data, Array) Key array(6 bytes) + + 0x09, 0x05, // Usage (Vendor Defined) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, + 0x00, // Logical Maximum (255) + 0x75, 0x08, // Report Count (2) + 0x95, 0x02, // Report Size (8 bit) + 0xB1, 0x02, // Feature (Data, Variable, Absolute) + + 0xC0, // End Collection (Application) + + 0x05, 0x0c, // Usage Page (Consumer Devices) + 0x09, 0x01, // Usage (Consumer Control) + 0xa1, 0x01, // Collection (Application) + 0x85, HID_KEYBOARD_REPORT_CONSUMER, // Report ID (2) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x10, // Report Count (16) + 0x09, 0xe2, // Usage (Mute) 0x01 + 0x09, 0xe9, // Usage (Volume Up) 0x02 + 0x09, 0xea, // Usage (Volume Down) 0x03 + 0x09, 0xcd, // Usage (Play/Pause) 0x04 + 0x09, 0xb7, // Usage (Stop) 0x05 + 0x09, 0xb6, // Usage (Scan Previous Track) 0x06 + 0x09, 0xb5, // Usage (Scan Next Track) 0x07 + 0x0a, 0x8a, + 0x01, // Usage (Mail) 0x08 + 0x0a, 0x92, + 0x01, // Usage (Calculator) 0x09 + 0x0a, 0x21, + 0x02, // Usage (www search) 0x0a + 0x0a, 0x23, + 0x02, // Usage (www home) 0x0b + 0x0a, 0x2a, + 0x02, // Usage (www favorites) 0x0c + 0x0a, 0x27, + 0x02, // Usage (www refresh) 0x0d + 0x0a, 0x26, + 0x02, // Usage (www stop) 0x0e + 0x0a, 0x25, + 0x02, // Usage (www forward) 0x0f + 0x0a, 0x24, + 0x02, // Usage (www back) 0x10 + 0x81, 0x62, // Input (Data,Var,Abs,NPrf,Null) + 0xc0, // End Collection }; static const HIDReportDescriptor reportDesc = { 9, - 0x21, // HID - 0x101, // hidbcd 1.01 - 0x00, // country code - 0x01, // num desc - 0x22, // report desc type + 0x21, // HID + 0x101, // hidbcd 1.01 + 0x00, // country code + 0x01, // num desc + 0x22, // report desc type sizeof(hidKeyboardDescriptor), }; @@ -125,12 +135,12 @@ static const InterfaceInfo ifaceInfo = { sizeof(reportDesc), 1, { - 1, // numEndpoints - 0x03, /// class code - HID - 0x01, // subclass (boot interface) - 0x01, // protocol (keyboard) - 0x00, // - 0x00, // + 1, // numEndpoints + 0x03, /// class code - HID + 0x01, // subclass (boot interface) + 0x01, // protocol (keyboard) + 0x00, // + 0x00, // }, {USB_EP_TYPE_INTERRUPT, 1}, {USB_EP_TYPE_INTERRUPT, 1}, @@ -140,20 +150,19 @@ static KeyMap* currentMap = NULL; extern AsciiKeyMap asciiKeyMap; - /** - * initialises the report arrays for this USBHID instance. - */ + * initialises the report arrays for this USBHID instance. + */ void USBHIDKeyboard::initReports() { - reports[HID_KEYBOARD_REPORT_GENERIC].reportID = HID_KEYBOARD_REPORT_GENERIC; - reports[HID_KEYBOARD_REPORT_GENERIC].keyState = keyStateGeneric; - reports[HID_KEYBOARD_REPORT_GENERIC].reportSize = HID_KEYBOARD_KEYSTATE_SIZE_GENERIC; + reports[HID_KEYBOARD_REPORT_GENERIC].reportID = HID_KEYBOARD_REPORT_GENERIC; + reports[HID_KEYBOARD_REPORT_GENERIC].keyState = keyStateGeneric; + reports[HID_KEYBOARD_REPORT_GENERIC].reportSize = HID_KEYBOARD_KEYSTATE_SIZE_GENERIC; reports[HID_KEYBOARD_REPORT_GENERIC].keyPressedCount = 0; - reports[HID_KEYBOARD_REPORT_CONSUMER].reportID = HID_KEYBOARD_REPORT_CONSUMER; - reports[HID_KEYBOARD_REPORT_CONSUMER].keyState = keyStateConsumer; - reports[HID_KEYBOARD_REPORT_CONSUMER].reportSize = HID_KEYBOARD_KEYSTATE_SIZE_CONSUMER; + reports[HID_KEYBOARD_REPORT_CONSUMER].reportID = HID_KEYBOARD_REPORT_CONSUMER; + reports[HID_KEYBOARD_REPORT_CONSUMER].keyState = keyStateConsumer; + reports[HID_KEYBOARD_REPORT_CONSUMER].reportSize = HID_KEYBOARD_KEYSTATE_SIZE_CONSUMER; reports[HID_KEYBOARD_REPORT_CONSUMER].keyPressedCount = 0; memset(keyStateGeneric, 0, HID_KEYBOARD_KEYSTATE_SIZE_GENERIC); @@ -161,8 +170,8 @@ void USBHIDKeyboard::initReports() } /** - * Default constructor for a USBHIDKeyboard instance, sets the KeyMap to an ASCII default . - */ + * Default constructor for a USBHIDKeyboard instance, sets the KeyMap to an ASCII default . + */ USBHIDKeyboard::USBHIDKeyboard() { initReports(); @@ -170,10 +179,10 @@ USBHIDKeyboard::USBHIDKeyboard() } /** - * Constructor for a USBHIDKeyboard instance, sets the KeyMap to the given keymap. - * - * @param k The KeyMap to use. - */ + * Constructor for a USBHIDKeyboard instance, sets the KeyMap to the given keymap. + * + * @param k The KeyMap to use. + */ USBHIDKeyboard::USBHIDKeyboard(KeyMap& m) { initReports(); @@ -181,12 +190,12 @@ USBHIDKeyboard::USBHIDKeyboard(KeyMap& m) } /** - * Sets the KeyMap for this USBHIDKeyboard instance - * - * @param map The KeyMap to use. - * - * @return DEVICE_OK on success. - */ + * Sets the KeyMap for this USBHIDKeyboard instance + * + * @param map The KeyMap to use. + * + * @return DEVICE_OK on success. + */ int USBHIDKeyboard::setKeyMap(KeyMap& m) { currentMap = &m; @@ -194,17 +203,15 @@ int USBHIDKeyboard::setKeyMap(KeyMap& m) } /** - * Writes the given report out over USB. - * - * @param report A pointer to the report to copy to USB - */ + * Writes the given report out over USB. + * + * @param report A pointer to the report to copy to USB + */ int USBHIDKeyboard::updateReport(HIDKeyboardReport* report) { - if(report == NULL) - return DEVICE_INVALID_PARAMETER; + if (report == NULL) return DEVICE_INVALID_PARAMETER; - if (!in) - return DEVICE_INVALID_STATE; + if (!in) return DEVICE_INVALID_STATE; uint8_t reportBuf[report->reportSize + 1] = {report->reportID}; memcpy(reportBuf + 1, report->keyState, report->reportSize); @@ -212,34 +219,31 @@ int USBHIDKeyboard::updateReport(HIDKeyboardReport* report) return in->write(reportBuf, sizeof(reportBuf)); } - /** - * sets the media key buffer to the given Key, without affecting the state of other media keys. - * - * @param k a valid media key - * - * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if an incorrect key is passed. - */ + * sets the media key buffer to the given Key, without affecting the state of other media keys. + * + * @param k a valid media key + * + * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if an incorrect key is passed. + */ int USBHIDKeyboard::mediaKeyPress(Key k, KeyActionType action) { - int status = DEVICE_OK; - HIDKeyboardReport *report = &reports[HID_KEYBOARD_REPORT_CONSUMER]; + int status = DEVICE_OK; + HIDKeyboardReport* report = &reports[HID_KEYBOARD_REPORT_CONSUMER]; - uint16_t* keyState = (uint16_t *)report->keyState; + uint16_t* keyState = (uint16_t*)report->keyState; uint16_t currentModifier = *keyState; if (action == ReleaseKey) *keyState &= ~k.bit.code; else - *keyState |= k.bit.code; + *keyState |= k.bit.code; // update only when required. - if(*keyState != currentModifier) - status = updateReport(report); + if (*keyState != currentModifier) status = updateReport(report); - //we could not make the change. Revert - if(status != DEVICE_OK) - { + // we could not make the change. Revert + if (status != DEVICE_OK) { *keyState = currentModifier; return status; } @@ -248,19 +252,19 @@ int USBHIDKeyboard::mediaKeyPress(Key k, KeyActionType action) } /** - * sets the keyboard modifier buffer to the given Key, without affecting the state of other keys. - * - * @param k a valid modifier key - * - * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if an incorrect key is passed. - */ + * sets the keyboard modifier buffer to the given Key, without affecting the state of other keys. + * + * @param k a valid modifier key + * + * @return DEVICE_OK on success, DEVICE_INVALID_PARAMETER if an incorrect key is passed. + */ int USBHIDKeyboard::modifierKeyPress(Key k, KeyActionType action) { int status = DEVICE_OK; uint8_t currentModifier; - HIDKeyboardReport *report = &reports[HID_KEYBOARD_REPORT_GENERIC]; - currentModifier = *report->keyState; + HIDKeyboardReport* report = &reports[HID_KEYBOARD_REPORT_GENERIC]; + currentModifier = *report->keyState; if (action == ReleaseKey) *report->keyState &= ~k.bit.code; @@ -268,12 +272,10 @@ int USBHIDKeyboard::modifierKeyPress(Key k, KeyActionType action) *report->keyState = currentModifier | k.bit.code; // update only when required. - if(*report->keyState != currentModifier) - status = updateReport(report); + if (*report->keyState != currentModifier) status = updateReport(report); - //we could not make the change. Revert - if(status != DEVICE_OK) - { + // we could not make the change. Revert + if (status != DEVICE_OK) { *report->keyState = currentModifier; return status; } @@ -281,56 +283,49 @@ int USBHIDKeyboard::modifierKeyPress(Key k, KeyActionType action) return DEVICE_OK; } - /** - * sets one keyboard key buffer slot to the given Key. - * - * @param k a valid modifier key - * - * @return DEVICE_OK on success - */ + * sets one keyboard key buffer slot to the given Key. + * + * @param k a valid modifier key + * + * @return DEVICE_OK on success + */ int USBHIDKeyboard::standardKeyPress(Key k, KeyActionType action) { - int status = DEVICE_OK; - HIDKeyboardReport *report = &reports[HID_KEYBOARD_REPORT_GENERIC]; + int status = DEVICE_OK; + HIDKeyboardReport* report = &reports[HID_KEYBOARD_REPORT_GENERIC]; - if(report->keyPressedCount == 0 && action == ReleaseKey) - return DEVICE_INVALID_PARAMETER; + if (report->keyPressedCount == 0 && action == ReleaseKey) return DEVICE_INVALID_PARAMETER; - if(report->keyPressedCount == report->reportSize && action == PressKey) - return DEVICE_NO_RESOURCES; + if (report->keyPressedCount == report->reportSize && action == PressKey) return DEVICE_NO_RESOURCES; // firstly iterate through the array to determine if we are raising a key - int existingIndex = -1; + int existingIndex = -1; int firstSpareSlot = -1; - for(int i = HID_KEYBOARD_MODIFIER_OFFSET; i < report->reportSize; i++) - { + for (int i = HID_KEYBOARD_MODIFIER_OFFSET; i < report->reportSize; i++) { // we can break here, we don't need a spare slot, we are raising... - if(report->keyState[i] == k.bit.code) - { + if (report->keyState[i] == k.bit.code) { existingIndex = i; break; } - if(report->keyState[i] == HID_KEYBOARD_KEY_OFF && firstSpareSlot == -1) - firstSpareSlot = i; + if (report->keyState[i] == HID_KEYBOARD_KEY_OFF && firstSpareSlot == -1) firstSpareSlot = i; } // if found and correct action requested, perform action - if(existingIndex > -1 && action == ReleaseKey) + if (existingIndex > -1 && action == ReleaseKey) report->keyState[existingIndex] = HID_KEYBOARD_KEY_OFF; - else if(firstSpareSlot > -1 && action == PressKey) + else if (firstSpareSlot > -1 && action == PressKey) report->keyState[firstSpareSlot] = k.bit.code; status = updateReport(report); // update counts... - if(status == DEVICE_OK) - { - if(action == ReleaseKey) + if (status == DEVICE_OK) { + if (action == ReleaseKey) report->keyPressedCount--; - else if(action == PressKey) + else if (action == PressKey) report->keyPressedCount++; } else @@ -341,19 +336,19 @@ int USBHIDKeyboard::standardKeyPress(Key k, KeyActionType action) } /** - * Releases the given Key. - * - * @param k A valid Key - * - * @return DEVICE_OK on success. - */ + * Releases the given Key. + * + * @param k A valid Key + * + * @return DEVICE_OK on success. + */ int USBHIDKeyboard::keyUp(Key k) { int status = DEVICE_OK; - if(k.bit.isModifier) + if (k.bit.isModifier) status = modifierKeyPress(k, ReleaseKey); - else if(k.bit.isMedia) + else if (k.bit.isMedia) status = mediaKeyPress(k, ReleaseKey); else status = standardKeyPress(k, ReleaseKey); @@ -364,19 +359,19 @@ int USBHIDKeyboard::keyUp(Key k) } /** - * Press the given Key. - * - * @param k A valid Key - * - * @return DEVICE_OK on success. - */ + * Press the given Key. + * + * @param k A valid Key + * + * @return DEVICE_OK on success. + */ int USBHIDKeyboard::keyDown(Key k) { int status = DEVICE_OK; - if(k.bit.isModifier) + if (k.bit.isModifier) status = modifierKeyPress(k, PressKey); - else if(k.bit.isMedia) + else if (k.bit.isMedia) status = mediaKeyPress(k, PressKey); else status = standardKeyPress(k, PressKey); @@ -387,114 +382,108 @@ int USBHIDKeyboard::keyDown(Key k) } /** - * Releases the given Key. - * - * @param k A valid MediaKey - * - * @return DEVICE_OK on success. - */ + * Releases the given Key. + * + * @param k A valid MediaKey + * + * @return DEVICE_OK on success. + */ int USBHIDKeyboard::keyUp(MediaKey k) { return keyUp(currentMap->getMediaKey(k)); } /** - * Press the given Key. - * - * @param k A valid MediaKey - * - * @return DEVICE_OK on success. - */ + * Press the given Key. + * + * @param k A valid MediaKey + * + * @return DEVICE_OK on success. + */ int USBHIDKeyboard::keyDown(MediaKey k) { return keyDown(currentMap->getMediaKey(k)); } /** - * Releases the given Key. - * - * @param k A valid FunctionKey - * - * @return DEVICE_OK on success. - */ + * Releases the given Key. + * + * @param k A valid FunctionKey + * + * @return DEVICE_OK on success. + */ int USBHIDKeyboard::keyUp(FunctionKey k) { return keyUp(currentMap->getFunctionKey(k)); } /** - * Press the given Key. - * - * @param k A valid FunctionKey - * - * @return DEVICE_OK on success. - */ + * Press the given Key. + * + * @param k A valid FunctionKey + * + * @return DEVICE_OK on success. + */ int USBHIDKeyboard::keyDown(FunctionKey k) { return keyDown(currentMap->getFunctionKey(k)); } /** - * Release the key corresponding to the given character. - * - * @param c A valid character - * - * @return DEVICE_OK on success. - */ + * Release the key corresponding to the given character. + * + * @param c A valid character + * + * @return DEVICE_OK on success. + */ int USBHIDKeyboard::keyUp(uint16_t c) { - const KeySequence* seq = currentMap->mapCharacter(c); - int status = DEVICE_OK; + const KeySequence* seq = currentMap->mapCharacter(c); + int status = DEVICE_OK; - if(seq == NULL) - return DEVICE_INVALID_PARAMETER; + if (seq == NULL) return DEVICE_INVALID_PARAMETER; - for(int i = 0; i < seq->length; i++) - { - Key k = seq->seq[i]; + for (int i = 0; i < seq->length; i++) { + Key k = seq->seq[i]; status = keyUp(k); - if(status != DEVICE_OK) - break; + if (status != DEVICE_OK) break; } return status; } /** - * Press the key corresponding to the given character. - * - * @param c A valid character - * - * @return DEVICE_OK on success. - */ + * Press the key corresponding to the given character. + * + * @param c A valid character + * + * @return DEVICE_OK on success. + */ int USBHIDKeyboard::keyDown(uint16_t c) { - const KeySequence* seq = currentMap->mapCharacter(c); - int status = DEVICE_OK; + const KeySequence* seq = currentMap->mapCharacter(c); + int status = DEVICE_OK; - if(seq == NULL) - return DEVICE_INVALID_PARAMETER; + if (seq == NULL) return DEVICE_INVALID_PARAMETER; - for(int i = 0; i < seq->length; i++) - { - Key k = seq->seq[i]; + for (int i = 0; i < seq->length; i++) { + Key k = seq->seq[i]; status = keyDown(k); - if(status != DEVICE_OK) - break; + if (status != DEVICE_OK) break; } return status; } /** - * Presses and releases the given Key. - * - * @param k A valid Key - * - * @return DEVICE_OK on success. - */ + * Presses and releases the given Key. + * + * @param k A valid Key + * + * @return DEVICE_OK on success. + */ int USBHIDKeyboard::press(Key k) { keyDown(k); @@ -503,36 +492,36 @@ int USBHIDKeyboard::press(Key k) } /** - * Press and releases the given Key. - * - * @param k A valid MediaKey - * - * @return DEVICE_OK on success. - */ + * Press and releases the given Key. + * + * @param k A valid MediaKey + * + * @return DEVICE_OK on success. + */ int USBHIDKeyboard::press(MediaKey k) { return press(currentMap->getMediaKey(k)); } /** - * Press and releases the given Key. - * - * @param k A valid FunctionKey - * - * @return DEVICE_OK on success. - */ + * Press and releases the given Key. + * + * @param k A valid FunctionKey + * + * @return DEVICE_OK on success. + */ int USBHIDKeyboard::press(FunctionKey k) { return press(currentMap->getFunctionKey(k)); } /** - * Press and releases the Key corresponding to the given character. - * - * @param k A valid character - * - * @return DEVICE_OK on success. - */ + * Press and releases the Key corresponding to the given character. + * + * @param k A valid character + * + * @return DEVICE_OK on success. + */ int USBHIDKeyboard::press(uint16_t c) { int status = DEVICE_OK; @@ -545,22 +534,21 @@ int USBHIDKeyboard::press(uint16_t c) } /** - * Releases ALL keys on the keyboard (including Media keys) - * - * @return DEVICE_OK on success. - */ + * Releases ALL keys on the keyboard (including Media keys) + * + * @return DEVICE_OK on success. + */ int USBHIDKeyboard::flush() { int status = DEVICE_OK; - HIDKeyboardReport *report = &reports[HID_KEYBOARD_REPORT_GENERIC]; + HIDKeyboardReport* report = &reports[HID_KEYBOARD_REPORT_GENERIC]; memset(report->keyState, 0, report->reportSize); status = updateReport(report); report->keyPressedCount = 0; - if(status != DEVICE_OK) - return status; + if (status != DEVICE_OK) return status; report = &reports[HID_KEYBOARD_REPORT_CONSUMER]; memset(report->keyState, 0, report->reportSize); @@ -568,37 +556,33 @@ int USBHIDKeyboard::flush() report->keyPressedCount = 0; - return status; } /** - * Type a sequence of keys - * - * @param seq A valid pointer to a KeySequence containing multiple keys. See ASCIIKeyMap.cpp for example usage. - * - * @return DEVICE_OK on success. - */ -int USBHIDKeyboard::type(const KeySequence *seq) + * Type a sequence of keys + * + * @param seq A valid pointer to a KeySequence containing multiple keys. See ASCIIKeyMap.cpp for example usage. + * + * @return DEVICE_OK on success. + */ +int USBHIDKeyboard::type(const KeySequence* seq) { - if(seq == NULL) - return DEVICE_INVALID_PARAMETER; + if (seq == NULL) return DEVICE_INVALID_PARAMETER; - //send each keystroke in the sequence - for(int i = 0; i < seq->length; i++) - { + // send each keystroke in the sequence + for (int i = 0; i < seq->length; i++) { Key k = seq->seq[i]; - if(k.bit.allKeysUp) - flush(); + if (k.bit.allKeysUp) flush(); - if(k.bit.isKeyDown) + if (k.bit.isKeyDown) keyDown(k); else keyUp(k); } - //all keys up is implicit at the end of each sequence + // all keys up is implicit at the end of each sequence flush(); fiber_sleep(HID_KEYBOARD_DELAY_DEFAULT); @@ -606,61 +590,55 @@ int USBHIDKeyboard::type(const KeySequence *seq) } /** - * Type a sequence of characters - * - * @param s A valid pointer to a char array - * - * @param len The length of s. - * - * @return DEVICE_OK on success. - */ + * Type a sequence of characters + * + * @param s A valid pointer to a char array + * + * @param len The length of s. + * + * @return DEVICE_OK on success. + */ int USBHIDKeyboard::type(const char* s, uint32_t len) { int status; - for(uint32_t i = 0; i < len; i++) - { - if((status = type(currentMap->mapCharacter(s[i]))) != DEVICE_OK) - return status; + for (uint32_t i = 0; i < len; i++) { + if ((status = type(currentMap->mapCharacter(s[i]))) != DEVICE_OK) return status; } return DEVICE_OK; } /** - * Type a sequence of characters - * - * @param s A ManagedString instance containing the characters to type. - * - * @return DEVICE_OK on success. - */ + * Type a sequence of characters + * + * @param s A ManagedString instance containing the characters to type. + * + * @return DEVICE_OK on success. + */ int USBHIDKeyboard::type(ManagedString s) { return type(s.toCharArray(), s.length()); } -int USBHIDKeyboard::stdRequest(UsbEndpointIn &ctrl, USBSetup &setup) +int USBHIDKeyboard::stdRequest(UsbEndpointIn& ctrl, USBSetup& setup) { - if (setup.bRequest == USB_REQ_GET_DESCRIPTOR) - { - if (setup.wValueH == 0x21) - { + if (setup.bRequest == USB_REQ_GET_DESCRIPTOR) { + if (setup.wValueH == 0x21) { InterfaceDescriptor tmp; fillInterfaceInfo(&tmp); return ctrl.write(&tmp, sizeof(tmp)); } - else if (setup.wValueH == 0x22) - { + else if (setup.wValueH == 0x22) { return ctrl.write(hidKeyboardDescriptor, sizeof(hidKeyboardDescriptor)); } } return DEVICE_NOT_SUPPORTED; } -const InterfaceInfo *USBHIDKeyboard::getInterfaceInfo() +const InterfaceInfo* USBHIDKeyboard::getInterfaceInfo() { return &ifaceInfo; } - #endif \ No newline at end of file diff --git a/source/drivers/HIDMouse.cpp b/source/drivers/HIDMouse.cpp index bf454d4e..9464f29d 100644 --- a/source/drivers/HIDMouse.cpp +++ b/source/drivers/HIDMouse.cpp @@ -23,148 +23,140 @@ DEALINGS IN THE SOFTWARE. */ #include "HIDMouse.h" + #include "HID.h" #if CONFIG_ENABLED(DEVICE_USB) using namespace codal; -//this descriptor must be stored in RAM +// this descriptor must be stored in RAM static char hidMouseDescriptor[] = { - 0x05, 0x01, //Usage Page: Generic Desktop Controls - 0x09, 0x02, //Usage: Mouse (2) - 0xA1, 0x01, //Collection: Application - 0x09, 0x01, //Usage: Pointer (1) - 0xA1, 0x00, //Collection: Physical - 0x05, 0x09, //Usage Page: Button (9) - 0x19, 0x01, //Usage Minimum: Button 1 - 0x29, 0x03, //Usage Maximum: Button 3 - 0x15, 0x00, //Logical Minimum: 0 - 0x25, 0x01, //Logical Maximum: 1 - 0x95, 0x03, //Report Count: 3 - 0x75, 0x01, //Report Size: 1 - 0x81, 0x02, //Input: Data (2) - 0x95, 0x01, //Report Count: 1 - 0x75, 0x05, //Report Size: 5 - 0x81, 0x01, //Input: Constant (1) - 0x05, 0x01, //Usage Page: Generic Desktop Controls - 0x09, 0x30, //Usage: X - 0x09, 0x31, //Usage: Y - 0x09, 0x38, //Usage: Wheel - 0x15, 0x81, //Logical Minimum: -127 - 0x25, 0x7f, //Logical Maximum: 127 - 0x75, 0x08, //Report Size: 8 - 0x95, 0x03, //Report Count: 3 - 0x81, 0x06, //Input: Data (6) - 0xC0, //End collection - 0xC0 //End collection + 0x05, 0x01, // Usage Page: Generic Desktop Controls + 0x09, 0x02, // Usage: Mouse (2) + 0xA1, 0x01, // Collection: Application + 0x09, 0x01, // Usage: Pointer (1) + 0xA1, 0x00, // Collection: Physical + 0x05, 0x09, // Usage Page: Button (9) + 0x19, 0x01, // Usage Minimum: Button 1 + 0x29, 0x03, // Usage Maximum: Button 3 + 0x15, 0x00, // Logical Minimum: 0 + 0x25, 0x01, // Logical Maximum: 1 + 0x95, 0x03, // Report Count: 3 + 0x75, 0x01, // Report Size: 1 + 0x81, 0x02, // Input: Data (2) + 0x95, 0x01, // Report Count: 1 + 0x75, 0x05, // Report Size: 5 + 0x81, 0x01, // Input: Constant (1) + 0x05, 0x01, // Usage Page: Generic Desktop Controls + 0x09, 0x30, // Usage: X + 0x09, 0x31, // Usage: Y + 0x09, 0x38, // Usage: Wheel + 0x15, 0x81, // Logical Minimum: -127 + 0x25, 0x7f, // Logical Maximum: 127 + 0x75, 0x08, // Report Size: 8 + 0x95, 0x03, // Report Count: 3 + 0x81, 0x06, // Input: Data (6) + 0xC0, // End collection + 0xC0 // End collection }; static const HIDReportDescriptor reportDesc = { - 9, - 0x21, // HID - 0x101, // hidbcd 1.01 - 0x00, // country code - 0x01, // num desc - 0x22, // report desc type - sizeof(hidMouseDescriptor), + 9, + 0x21, // HID + 0x101, // hidbcd 1.01 + 0x00, // country code + 0x01, // num desc + 0x22, // report desc type + sizeof(hidMouseDescriptor), }; static const InterfaceInfo ifaceInfo = { - &reportDesc, - sizeof(reportDesc), - 1, - { - 1, // numEndpoints - 0x03, /// class code - HID - 0x01, // subclass (boot interface) - 0x02, // protocol (Mouse) - 0x00, // - 0x00, // - }, - {USB_EP_TYPE_INTERRUPT, 1}, - {USB_EP_TYPE_INTERRUPT, 1}, + &reportDesc, + sizeof(reportDesc), + 1, + { + 1, // numEndpoints + 0x03, /// class code - HID + 0x01, // subclass (boot interface) + 0x02, // protocol (Mouse) + 0x00, // + 0x00, // + }, + {USB_EP_TYPE_INTERRUPT, 1}, + {USB_EP_TYPE_INTERRUPT, 1}, }; -static HIDMouseState mouseState = { - 0, 0, 0, 0, 0, 0, 0 -}; +static HIDMouseState mouseState = {0, 0, 0, 0, 0, 0, 0}; -USBHIDMouse::USBHIDMouse() : USBHID() -{ - -} +USBHIDMouse::USBHIDMouse() : USBHID() {} -int USBHIDMouse::stdRequest(UsbEndpointIn &ctrl, USBSetup &setup) +int USBHIDMouse::stdRequest(UsbEndpointIn& ctrl, USBSetup& setup) { - if (setup.bRequest == USB_REQ_GET_DESCRIPTOR) - { - if (setup.wValueH == 0x21) - { - InterfaceDescriptor tmp; - fillInterfaceInfo(&tmp); - return ctrl.write(&tmp, sizeof(tmp)); - } - else if (setup.wValueH == 0x22) - { - return ctrl.write(hidMouseDescriptor, sizeof(hidMouseDescriptor)); - } - } - return DEVICE_NOT_SUPPORTED; + if (setup.bRequest == USB_REQ_GET_DESCRIPTOR) { + if (setup.wValueH == 0x21) { + InterfaceDescriptor tmp; + fillInterfaceInfo(&tmp); + return ctrl.write(&tmp, sizeof(tmp)); + } + else if (setup.wValueH == 0x22) { + return ctrl.write(hidMouseDescriptor, sizeof(hidMouseDescriptor)); + } + } + return DEVICE_NOT_SUPPORTED; } -const InterfaceInfo *USBHIDMouse::getInterfaceInfo() +const InterfaceInfo* USBHIDMouse::getInterfaceInfo() { - return &ifaceInfo; + return &ifaceInfo; } int USBHIDMouse::buttonDown(USBHIDMouseButton b) { - if(mouseState.buttons.reg & b) - return DEVICE_OK; - else{ - mouseState.buttons.reg |= b; - return sendReport(); - } + if (mouseState.buttons.reg & b) + return DEVICE_OK; + else { + mouseState.buttons.reg |= b; + return sendReport(); + } } int USBHIDMouse::buttonUp(USBHIDMouseButton b) { - if( !(mouseState.buttons.reg & b) ) - return DEVICE_OK; - else{ - mouseState.buttons.reg &= ~(b); - return sendReport(); - } + if (!(mouseState.buttons.reg & b)) + return DEVICE_OK; + else { + mouseState.buttons.reg &= ~(b); + return sendReport(); + } } int USBHIDMouse::move(int8_t x, int8_t y) { - mouseState.xMovement = x; - mouseState.yMovement = y; - return sendReport(); + mouseState.xMovement = x; + mouseState.yMovement = y; + return sendReport(); } int USBHIDMouse::moveWheel(int8_t w) { - mouseState.wheelMovement = w; - return sendReport(); + mouseState.wheelMovement = w; + return sendReport(); } int USBHIDMouse::sendReport() { - if (!in) - return DEVICE_INVALID_STATE; + if (!in) return DEVICE_INVALID_STATE; - uint8_t report[sizeof(HIDMouseState)]; - memcpy(report, &mouseState, sizeof(HIDMouseState)); + uint8_t report[sizeof(HIDMouseState)]; + memcpy(report, &mouseState, sizeof(HIDMouseState)); - //movements are relative - mouseState.xMovement = 0; - mouseState.yMovement = 0; - mouseState.wheelMovement = 0; + // movements are relative + mouseState.xMovement = 0; + mouseState.yMovement = 0; + mouseState.wheelMovement = 0; - return in->write(report, sizeof(report)); + return in->write(report, sizeof(report)); } #endif diff --git a/source/drivers/ILI9341.cpp b/source/drivers/ILI9341.cpp index 0e66f52d..7c0af411 100644 --- a/source/drivers/ILI9341.cpp +++ b/source/drivers/ILI9341.cpp @@ -1,63 +1,63 @@ #include "ILI9341.h" -#include "CodalFiber.h" + #include "CodalDmesg.h" +#include "CodalFiber.h" -#define ILI9341_NOP 0x00 ///< No-op register -#define ILI9341_SWRESET 0x01 ///< Software reset register -#define ILI9341_RDDID 0x04 ///< Read display identification information -#define ILI9341_RDDST 0x09 ///< Read Display Status - -#define ILI9341_SLPIN 0x10 ///< Enter Sleep Mode -#define ILI9341_SLPOUT 0x11 ///< Sleep Out -#define ILI9341_PTLON 0x12 ///< Partial Mode ON -#define ILI9341_NORON 0x13 ///< Normal Display Mode ON - -#define ILI9341_RDMODE 0x0A ///< Read Display Power Mode -#define ILI9341_RDMADCTL 0x0B ///< Read Display MADCTL -#define ILI9341_RDPIXFMT 0x0C ///< Read Display Pixel Format -#define ILI9341_RDIMGFMT 0x0D ///< Read Display Image Format -#define ILI9341_RDSELFDIAG 0x0F ///< Read Display Self-Diagnostic Result - -#define ILI9341_INVOFF 0x20 ///< Display Inversion OFF -#define ILI9341_INVON 0x21 ///< Display Inversion ON -#define ILI9341_GAMMASET 0x26 ///< Gamma Set -#define ILI9341_DISPOFF 0x28 ///< Display OFF -#define ILI9341_DISPON 0x29 ///< Display ON - -#define ILI9341_CASET 0x2A ///< Column Address Set -#define ILI9341_PASET 0x2B ///< Page Address Set -#define ILI9341_RAMWR 0x2C ///< Memory Write -#define ILI9341_RAMRD 0x2E ///< Memory Read - -#define ILI9341_PTLAR 0x30 ///< Partial Area -#define ILI9341_MADCTL 0x36 ///< Memory Access Control -#define ILI9341_VSCRSADD 0x37 ///< Vertical Scrolling Start Address -#define ILI9341_PIXFMT 0x3A ///< COLMOD: Pixel Format Set - -#define ILI9341_FRMCTR1 0xB1 ///< Frame Rate Control (In Normal Mode/Full Colors) -#define ILI9341_FRMCTR2 0xB2 ///< Frame Rate Control (In Idle Mode/8 colors) -#define ILI9341_FRMCTR3 0xB3 ///< Frame Rate control (In Partial Mode/Full Colors) -#define ILI9341_INVCTR 0xB4 ///< Display Inversion Control -#define ILI9341_DFUNCTR 0xB6 ///< Display Function Control - -#define ILI9341_PWCTR1 0xC0 ///< Power Control 1 -#define ILI9341_PWCTR2 0xC1 ///< Power Control 2 -#define ILI9341_PWCTR3 0xC2 ///< Power Control 3 -#define ILI9341_PWCTR4 0xC3 ///< Power Control 4 -#define ILI9341_PWCTR5 0xC4 ///< Power Control 5 -#define ILI9341_VMCTR1 0xC5 ///< VCOM Control 1 -#define ILI9341_VMCTR2 0xC7 ///< VCOM Control 2 - -#define ILI9341_RDID1 0xDA ///< Read ID 1 -#define ILI9341_RDID2 0xDB ///< Read ID 2 -#define ILI9341_RDID3 0xDC ///< Read ID 3 -#define ILI9341_RDID4 0xDD ///< Read ID 4 - -#define ILI9341_GMCTRP1 0xE0 ///< Positive Gamma Correction -#define ILI9341_GMCTRN1 0xE1 ///< Negative Gamma Correction +#define ILI9341_NOP 0x00 ///< No-op register +#define ILI9341_SWRESET 0x01 ///< Software reset register +#define ILI9341_RDDID 0x04 ///< Read display identification information +#define ILI9341_RDDST 0x09 ///< Read Display Status + +#define ILI9341_SLPIN 0x10 ///< Enter Sleep Mode +#define ILI9341_SLPOUT 0x11 ///< Sleep Out +#define ILI9341_PTLON 0x12 ///< Partial Mode ON +#define ILI9341_NORON 0x13 ///< Normal Display Mode ON + +#define ILI9341_RDMODE 0x0A ///< Read Display Power Mode +#define ILI9341_RDMADCTL 0x0B ///< Read Display MADCTL +#define ILI9341_RDPIXFMT 0x0C ///< Read Display Pixel Format +#define ILI9341_RDIMGFMT 0x0D ///< Read Display Image Format +#define ILI9341_RDSELFDIAG 0x0F ///< Read Display Self-Diagnostic Result + +#define ILI9341_INVOFF 0x20 ///< Display Inversion OFF +#define ILI9341_INVON 0x21 ///< Display Inversion ON +#define ILI9341_GAMMASET 0x26 ///< Gamma Set +#define ILI9341_DISPOFF 0x28 ///< Display OFF +#define ILI9341_DISPON 0x29 ///< Display ON + +#define ILI9341_CASET 0x2A ///< Column Address Set +#define ILI9341_PASET 0x2B ///< Page Address Set +#define ILI9341_RAMWR 0x2C ///< Memory Write +#define ILI9341_RAMRD 0x2E ///< Memory Read + +#define ILI9341_PTLAR 0x30 ///< Partial Area +#define ILI9341_MADCTL 0x36 ///< Memory Access Control +#define ILI9341_VSCRSADD 0x37 ///< Vertical Scrolling Start Address +#define ILI9341_PIXFMT 0x3A ///< COLMOD: Pixel Format Set + +#define ILI9341_FRMCTR1 0xB1 ///< Frame Rate Control (In Normal Mode/Full Colors) +#define ILI9341_FRMCTR2 0xB2 ///< Frame Rate Control (In Idle Mode/8 colors) +#define ILI9341_FRMCTR3 0xB3 ///< Frame Rate control (In Partial Mode/Full Colors) +#define ILI9341_INVCTR 0xB4 ///< Display Inversion Control +#define ILI9341_DFUNCTR 0xB6 ///< Display Function Control + +#define ILI9341_PWCTR1 0xC0 ///< Power Control 1 +#define ILI9341_PWCTR2 0xC1 ///< Power Control 2 +#define ILI9341_PWCTR3 0xC2 ///< Power Control 3 +#define ILI9341_PWCTR4 0xC3 ///< Power Control 4 +#define ILI9341_PWCTR5 0xC4 ///< Power Control 5 +#define ILI9341_VMCTR1 0xC5 ///< VCOM Control 1 +#define ILI9341_VMCTR2 0xC7 ///< VCOM Control 2 + +#define ILI9341_RDID1 0xDA ///< Read ID 1 +#define ILI9341_RDID2 0xDB ///< Read ID 2 +#define ILI9341_RDID3 0xDC ///< Read ID 3 +#define ILI9341_RDID4 0xDD ///< Read ID 4 + +#define ILI9341_GMCTRP1 0xE0 ///< Positive Gamma Correction +#define ILI9341_GMCTRN1 0xE1 ///< Negative Gamma Correction //#define ILI9341_PWCTR6 0xFC - // clang-format off static const uint8_t initcmd[] = { @@ -145,10 +145,9 @@ static const uint8_t initcmd[] = { }; // clang-format on -namespace codal -{ +namespace codal { -ILI9341::ILI9341(ScreenIO &io, Pin &cs, Pin &dc) : ST7735(io, cs, dc) +ILI9341::ILI9341(ScreenIO& io, Pin& cs, Pin& dc) : ST7735(io, cs, dc) { double16 = true; } @@ -164,4 +163,4 @@ int ILI9341::init() return DEVICE_OK; } -} // namespace codal \ No newline at end of file +} // namespace codal \ No newline at end of file diff --git a/source/drivers/KeyValueStorage.cpp b/source/drivers/KeyValueStorage.cpp index d9cfb5e1..b68311a4 100644 --- a/source/drivers/KeyValueStorage.cpp +++ b/source/drivers/KeyValueStorage.cpp @@ -24,27 +24,27 @@ DEALINGS IN THE SOFTWARE. */ /** - * Class definition for the KeyValueStorage class. - * This allows reading and writing of FLASH memory. - */ + * Class definition for the KeyValueStorage class. + * This allows reading and writing of FLASH memory. + */ -#include "CodalConfig.h" #include "KeyValueStorage.h" + #include "CodalCompat.h" +#include "CodalConfig.h" using namespace codal; - /** - * Constructor. - * - * Creates an instance of KeyValueStorage which acts like a KeyValueStore - * that allows the retrieval, addition and deletion of KeyValuePairs. - * - * @param controller The non-volatile storage controller to use - * @param pageNumber The logical page number for this KeyValueStorage - * Optionally use negative number to count from end of address space. - */ + * Constructor. + * + * Creates an instance of KeyValueStorage which acts like a KeyValueStore + * that allows the retrieval, addition and deletion of KeyValuePairs. + * + * @param controller The non-volatile storage controller to use + * @param pageNumber The logical page number for this KeyValueStorage + * Optionally use negative number to count from end of address space. + */ KeyValueStorage::KeyValueStorage(NVMController& controller, int pageNumber) : controller(controller) { scratch = NULL; @@ -53,43 +53,40 @@ KeyValueStorage::KeyValueStorage(NVMController& controller, int pageNumber) : co if (pageNumber < 0) flashPagePtr = controller.getFlashEnd() - (controller.getPageSize() * pageNumber); else - flashPagePtr = controller.getFlashStart() + (controller.getPageSize() * pageNumber); + flashPagePtr = controller.getFlashStart() + (controller.getPageSize() * pageNumber); size(); } - /** - * Places a given key, and it's corresponding value into flash at the earliest - * available point. - * - * @param key the unique name that should be used as an identifier for the given data. - * The key is presumed to be null terminated. - * - * @param data a pointer to the beginning of the data to be persisted. - * - * @param dataSize the size of the data to be persisted - * - * @return DEVICE_OK on success, KEY_VALUE_INVALID_PARAMETER if the key or size is too large, - * KEY_VALUE_NO_RESOURCES if the storage page is full - */ -int KeyValueStorage::put(const char *key, uint8_t *data, int dataSize) + * Places a given key, and it's corresponding value into flash at the earliest + * available point. + * + * @param key the unique name that should be used as an identifier for the given data. + * The key is presumed to be null terminated. + * + * @param data a pointer to the beginning of the data to be persisted. + * + * @param dataSize the size of the data to be persisted + * + * @return DEVICE_OK on success, KEY_VALUE_INVALID_PARAMETER if the key or size is too large, + * KEY_VALUE_NO_RESOURCES if the storage page is full + */ +int KeyValueStorage::put(const char* key, uint8_t* data, int dataSize) { KeyValuePair pair; int keySize = strlen(key) + 1; - if(keySize > (int)sizeof(pair.key) || dataSize > (int)sizeof(pair.value) || dataSize < 0) + if (keySize > (int)sizeof(pair.key) || dataSize > (int)sizeof(pair.value) || dataSize < 0) return DEVICE_INVALID_PARAMETER; - KeyValuePair *currentValue = get(key); + KeyValuePair* currentValue = get(key); int upToDate = currentValue && (memcmp(currentValue->value, data, dataSize) == 0); - if(currentValue) - delete currentValue; + if (currentValue) delete currentValue; - if(upToDate) - return DEVICE_OK; + if (upToDate) return DEVICE_OK; memcpy(pair.key, key, keySize); memcpy(pair.value, data, dataSize); @@ -98,30 +95,27 @@ int KeyValueStorage::put(const char *key, uint8_t *data, int dataSize) int storeSize = size(); - //our KeyValueStore struct is always at 0 + // our KeyValueStore struct is always at 0 flashPointer += sizeof(KeyValueStore); int scratchPtr = sizeof(KeyValueStore) / 4; KeyValuePair storedPair = KeyValuePair(); - int found = 0; + int found = 0; scratchReset(); - //iterate through key value pairs in flash, writing them to the scratch page. - for(int i = 0; i < storeSize; i++) - { - controller.read((uint32_t *)&storedPair, flashPointer, sizeof(KeyValuePair)/4); + // iterate through key value pairs in flash, writing them to the scratch page. + for (int i = 0; i < storeSize; i++) { + controller.read((uint32_t*)&storedPair, flashPointer, sizeof(KeyValuePair) / 4); - //check if the keys match... - if(strcmp((char *)storedPair.key, (char *)pair.key) == 0) - { + // check if the keys match... + if (strcmp((char*)storedPair.key, (char*)pair.key) == 0) { found = 1; - //scratch our KeyValueStore struct so that it is preserved. + // scratch our KeyValueStore struct so that it is preserved. scratchKeyValueStore(KeyValueStore(KEY_VALUE_STORAGE_MAGIC, storeSize)); scratchKeyValuePair(pair, scratchPtr); } - else - { + else { scratchKeyValuePair(storedPair, scratchPtr); } @@ -129,87 +123,81 @@ int KeyValueStorage::put(const char *key, uint8_t *data, int dataSize) scratchPtr += sizeof(KeyValuePair) / 4; } - if(!found) - { - //if we haven't got a match for the key, check we can add a new KeyValuePair - if(storeSize == KEY_VALUE_STORAGE_MAX_PAIRS) - return DEVICE_NO_RESOURCES; + if (!found) { + // if we haven't got a match for the key, check we can add a new KeyValuePair + if (storeSize == KEY_VALUE_STORAGE_MAX_PAIRS) return DEVICE_NO_RESOURCES; storeSize += 1; - //scratch our updated values. + // scratch our updated values. scratchKeyValueStore(KeyValueStore(KEY_VALUE_STORAGE_MAGIC, storeSize)); scratchKeyValuePair(pair, scratchPtr); } - //erase our storage page + // erase our storage page controller.erase(flashPagePtr); - //copy from scratch to storage. + // copy from scratch to storage. controller.write(flashPagePtr, scratch, KEY_VALUE_STORAGE_SCRATCH_WORD_SIZE); return DEVICE_OK; } /** - * Places a given key, and it's corresponding value into flash at the earliest - * available point. - * - * @param key the unique name that should be used as an identifier for the given data. - * - * @param data a pointer to the beginning of the data to be persisted. - * - * @param dataSize the size of the data to be persisted - * - * @return DEVICE_OK on success, KEY_VALUE_INVALID_PARAMETER if the key or size is too large, - * KEY_VALUE_NO_RESOURCES if the storage page is full - */ + * Places a given key, and it's corresponding value into flash at the earliest + * available point. + * + * @param key the unique name that should be used as an identifier for the given data. + * + * @param data a pointer to the beginning of the data to be persisted. + * + * @param dataSize the size of the data to be persisted + * + * @return DEVICE_OK on success, KEY_VALUE_INVALID_PARAMETER if the key or size is too large, + * KEY_VALUE_NO_RESOURCES if the storage page is full + */ int KeyValueStorage::put(ManagedString key, uint8_t* data, int dataSize) { - return put((char *)key.toCharArray(), data, dataSize); + return put((char*)key.toCharArray(), data, dataSize); } /** - * Retreives a KeyValuePair identified by a given key. - * - * @param key the unique name used to identify a KeyValuePair in flash. - * - * @return a pointer to a heap allocated KeyValuePair struct, this pointer will be - * NULL if the key was not found in storage. - * - * @note it is up to the user to free memory after use. - */ + * Retreives a KeyValuePair identified by a given key. + * + * @param key the unique name used to identify a KeyValuePair in flash. + * + * @return a pointer to a heap allocated KeyValuePair struct, this pointer will be + * NULL if the key was not found in storage. + * + * @note it is up to the user to free memory after use. + */ KeyValuePair* KeyValueStorage::get(const char* key) { - //calculate our offsets for our storage page + // calculate our offsets for our storage page int storeSize = size(); - //we haven't got anything stored, so return... - if(storeSize == 0) - return NULL; + // we haven't got anything stored, so return... + if (storeSize == 0) return NULL; uint32_t flashPtr = this->flashPagePtr; - //our KeyValueStore struct is always at 0 + // our KeyValueStore struct is always at 0 flashPtr += sizeof(KeyValueStore); - KeyValuePair *pair = new KeyValuePair(); + KeyValuePair* pair = new KeyValuePair(); int i; - //iterate through flash until we have a match, or drop out. - for(i = 0; i < storeSize; i++) - { - controller.read((uint32_t *)pair, flashPtr, sizeof(KeyValuePair)/4); - if(strcmp(key,(char *)pair->key) == 0) - break; + // iterate through flash until we have a match, or drop out. + for (i = 0; i < storeSize; i++) { + controller.read((uint32_t*)pair, flashPtr, sizeof(KeyValuePair) / 4); + if (strcmp(key, (char*)pair->key) == 0) break; flashPtr += sizeof(KeyValuePair); } - //clean up - if(i == storeSize) - { + // clean up + if (i == storeSize) { delete pair; return NULL; } @@ -218,39 +206,38 @@ KeyValuePair* KeyValueStorage::get(const char* key) } /** - * Retreives a KeyValuePair identified by a given key. - * - * @param key the unique name used to identify a KeyValuePair in flash. - * - * @return a pointer to a heap allocated KeyValuePair struct, this pointer will be - * NULL if the key was not found in storage. - * - * @note it is up to the user to free memory after use. - */ + * Retreives a KeyValuePair identified by a given key. + * + * @param key the unique name used to identify a KeyValuePair in flash. + * + * @return a pointer to a heap allocated KeyValuePair struct, this pointer will be + * NULL if the key was not found in storage. + * + * @note it is up to the user to free memory after use. + */ KeyValuePair* KeyValueStorage::get(ManagedString key) { - return get((char *)key.toCharArray()); + return get((char*)key.toCharArray()); } /** - * Removes a KeyValuePair identified by a given key. - * - * @param key the unique name used to identify a KeyValuePair in flash. - * - * @return DEVICE_OK on success, or DEVICE_NO_DATA if the given key - * was not found in flash. - */ + * Removes a KeyValuePair identified by a given key. + * + * @param key the unique name used to identify a KeyValuePair in flash. + * + * @return DEVICE_OK on success, or DEVICE_NO_DATA if the given key + * was not found in flash. + */ int KeyValueStorage::remove(const char* key) { int storeSize = size(); - //if we have no data, we have nothing to do. - if(storeSize == 0) - return DEVICE_NO_DATA; + // if we have no data, we have nothing to do. + if (storeSize == 0) return DEVICE_NO_DATA; uint32_t flashPointer = this->flashPagePtr; - //our KeyValueStore struct is always at 0 + // our KeyValueStore struct is always at 0 flashPointer += sizeof(KeyValueStore); int scratchPointer = sizeof(KeyValueStore) / 4; @@ -263,21 +250,18 @@ int KeyValueStorage::remove(const char* key) // scratch the old size (it will be updated later if required). scratchKeyValueStore(KeyValueStore(KEY_VALUE_STORAGE_MAGIC, storeSize)); - //iterate through our flash copy pairs to scratch, unless there is a key patch - for(int i = 0; i < storeSize; i++) - { - controller.read((uint32_t *)&storedPair, flashPointer, sizeof(KeyValuePair)/4); + // iterate through our flash copy pairs to scratch, unless there is a key patch + for (int i = 0; i < storeSize; i++) { + controller.read((uint32_t*)&storedPair, flashPointer, sizeof(KeyValuePair) / 4); - //if we have a match, don't increment our scratchPointer - if(strcmp((char *)storedPair.key, (char *)key) == 0) - { + // if we have a match, don't increment our scratchPointer + if (strcmp((char*)storedPair.key, (char*)key) == 0) { found = 1; - //write our new KeyValueStore data + // write our new KeyValueStore data scratchKeyValueStore(KeyValueStore(KEY_VALUE_STORAGE_MAGIC, storeSize - 1)); } - else - { - //otherwise copy the KeyValuePair from our storage page. + else { + // otherwise copy the KeyValuePair from our storage page. scratchKeyValuePair(storedPair, scratchPointer); scratchPointer += sizeof(KeyValuePair) / 4; } @@ -285,56 +269,54 @@ int KeyValueStorage::remove(const char* key) flashPointer += sizeof(KeyValuePair); } - //if we haven't got a match, write our old KeyValueStore struct - if(!found) - { + // if we haven't got a match, write our old KeyValueStore struct + if (!found) { scratchKeyValueStore(KeyValueStore(KEY_VALUE_STORAGE_MAGIC, storeSize)); return DEVICE_NO_DATA; } - //copy scratch to our storage page + // copy scratch to our storage page controller.erase(flashPagePtr); controller.write(flashPagePtr, scratch, (sizeof(KeyValueStore) / 4) + (storeSize * (sizeof(KeyValuePair) / 4))); - + return DEVICE_OK; } /** - * Removes a KeyValuePair identified by a given key. - * - * @param key the unique name used to identify a KeyValuePair in flash. - * - * @return DEVICE_OK on success, or DEVICE_NO_DATA if the given key - * was not found in flash. - */ + * Removes a KeyValuePair identified by a given key. + * + * @param key the unique name used to identify a KeyValuePair in flash. + * + * @return DEVICE_OK on success, or DEVICE_NO_DATA if the given key + * was not found in flash. + */ int KeyValueStorage::remove(ManagedString key) { - return remove((char *)key.toCharArray()); + return remove((char*)key.toCharArray()); } /** - * The size of the flash based KeyValueStore. - * - * @return the number of entries in the key value store - */ + * The size of the flash based KeyValueStore. + * + * @return the number of entries in the key value store + */ int KeyValueStorage::size() { KeyValueStore store = KeyValueStore(); - //read our data! - controller.read((uint32_t *)&store, flashPagePtr, sizeof(KeyValueStore)/4); + // read our data! + controller.read((uint32_t*)&store, flashPagePtr, sizeof(KeyValueStore) / 4); - //if we haven't used flash before, we need to configure it - if(store.magic != KEY_VALUE_STORAGE_MAGIC) - { + // if we haven't used flash before, we need to configure it + if (store.magic != KEY_VALUE_STORAGE_MAGIC) { store.magic = KEY_VALUE_STORAGE_MAGIC; - store.size = 0; + store.size = 0; - //erase the scratch page and write our new KeyValueStore + // erase the scratch page and write our new KeyValueStore scratchReset(); scratchKeyValueStore(store); - //erase flash, and copy the scratch page over + // erase flash, and copy the scratch page over controller.erase(flashPagePtr); controller.write(flashPagePtr, scratch, KEY_VALUE_STORAGE_SCRATCH_WORD_SIZE); } @@ -357,32 +339,30 @@ int KeyValueStorage::wipe() */ void KeyValueStorage::scratchReset() { - if (scratch == NULL) - scratch = (uint32_t *)malloc(KEY_VALUE_STORAGE_SCRATCH_WORD_SIZE * 4); + if (scratch == NULL) scratch = (uint32_t*)malloc(KEY_VALUE_STORAGE_SCRATCH_WORD_SIZE * 4); memset(scratch, 0, KEY_VALUE_STORAGE_SCRATCH_WORD_SIZE * 4); } - /** - * Function for populating the scratch page with a KeyValueStore. - * - * @param store the KeyValueStore struct to write to the scratch page. - */ + * Function for populating the scratch page with a KeyValueStore. + * + * @param store the KeyValueStore struct to write to the scratch page. + */ void KeyValueStorage::scratchKeyValueStore(KeyValueStore store) { memcpy(this->scratch, &store, sizeof(KeyValueStore)); } /** - * Function for populating the scratch page with a KeyValuePair. - * - * @param pair the KeyValuePair struct to write to the scratch page. - * - * @param flashPointer the pointer in flash where this KeyValuePair resides. This pointer - * is used to determine the offset into the scratch page, where the KeyValuePair should - * be written. - */ + * Function for populating the scratch page with a KeyValuePair. + * + * @param pair the KeyValuePair struct to write to the scratch page. + * + * @param flashPointer the pointer in flash where this KeyValuePair resides. This pointer + * is used to determine the offset into the scratch page, where the KeyValuePair should + * be written. + */ void KeyValueStorage::scratchKeyValuePair(KeyValuePair pair, int scratchOffset) { memcpy(this->scratch + scratchOffset, &pair, sizeof(KeyValuePair)); diff --git a/source/drivers/LEDMatrix.cpp b/source/drivers/LEDMatrix.cpp index c58260f8..ec2b5d5b 100644 --- a/source/drivers/LEDMatrix.cpp +++ b/source/drivers/LEDMatrix.cpp @@ -23,13 +23,14 @@ DEALINGS IN THE SOFTWARE. */ /** - * Class definition for LEDMatrix. - * - * Represents an LED matrix array. - */ + * Class definition for LEDMatrix. + * + * Represents an LED matrix array. + */ #include "LEDMatrix.h" -#include "CodalFiber.h" + #include "CodalDmesg.h" +#include "CodalFiber.h" #include "ErrorNo.h" using namespace codal; @@ -37,54 +38,51 @@ using namespace codal; const int greyScaleTimings[LED_MATRIX_GREYSCALE_BIT_DEPTH] = {1, 23, 70, 163, 351, 726, 1476, 2976}; /** - * Constructor. - * - * Create a software representation an LED matrix. - * The display is initially blank. - * - * @param map The mapping information that relates pin inputs/outputs to physical screen coordinates. - * @param id The id the display should use when sending events on the MessageBus. Defaults to DEVICE_ID_DISPLAY. - */ -LEDMatrix::LEDMatrix(const MatrixMap &map, uint16_t id) : Display(map.width, map.height, id), matrixMap(map) + * Constructor. + * + * Create a software representation an LED matrix. + * The display is initially blank. + * + * @param map The mapping information that relates pin inputs/outputs to physical screen coordinates. + * @param id The id the display should use when sending events on the MessageBus. Defaults to DEVICE_ID_DISPLAY. + */ +LEDMatrix::LEDMatrix(const MatrixMap& map, uint16_t id) : Display(map.width, map.height, id), matrixMap(map) { - this->rotation = MATRIX_DISPLAY_ROTATION_0; + this->rotation = MATRIX_DISPLAY_ROTATION_0; this->greyscaleBitMsk = 0x01; - this->timingCount = 0; + this->timingCount = 0; this->setBrightness(LED_MATRIX_DEFAULT_BRIGHTNESS); - this->mode = DISPLAY_MODE_BLACK_AND_WHITE; + this->mode = DISPLAY_MODE_BLACK_AND_WHITE; this->strobeRow = 0; - if(EventModel::defaultEventBus) - EventModel::defaultEventBus->listen(id, LED_MATRIX_EVT_FRAME_TIMEOUT, this, &LEDMatrix::onTimeoutEvent, MESSAGE_BUS_LISTENER_IMMEDIATE); + if (EventModel::defaultEventBus) + EventModel::defaultEventBus->listen(id, LED_MATRIX_EVT_FRAME_TIMEOUT, this, &LEDMatrix::onTimeoutEvent, + MESSAGE_BUS_LISTENER_IMMEDIATE); this->status |= DEVICE_COMPONENT_STATUS_SYSTEM_TICK; this->status |= DEVICE_COMPONENT_RUNNING; } /** - * Internal frame update method, used to strobe the display. - * - * TODO: Write a more efficient, complementary variation of this method for the case where - * we have more rows than columns. - */ + * Internal frame update method, used to strobe the display. + * + * TODO: Write a more efficient, complementary variation of this method for the case where + * we have more rows than columns. + */ void LEDMatrix::periodicCallback() { - if(!(status & DEVICE_COMPONENT_RUNNING)) - return; + if (!(status & DEVICE_COMPONENT_RUNNING)) return; - if(mode == DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE) - { + if (mode == DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE) { renderWithLightSense(); return; } - if(mode == DISPLAY_MODE_BLACK_AND_WHITE) - render(); + if (mode == DISPLAY_MODE_BLACK_AND_WHITE) render(); - if(mode == DISPLAY_MODE_GREYSCALE) - { + if (mode == DISPLAY_MODE_GREYSCALE) { greyscaleBitMsk = 0x01; - timingCount = 0; + timingCount = 0; renderGreyscale(); } } @@ -103,8 +101,7 @@ void LEDMatrix::render() { // Simple optimisation. // If display is at zero brightness, there's nothing to do. - if(brightness == 0) - return; + if (brightness == 0) return; // Turn off the previous row matrixMap.rowPins[strobeRow]->setDigitalValue(0); @@ -112,36 +109,31 @@ void LEDMatrix::render() // Move on to the next row. strobeRow++; - if(strobeRow == matrixMap.rows) - strobeRow = 0; + if (strobeRow == matrixMap.rows) strobeRow = 0; // Calculate the bitpattern to write. - for (int i = 0; i < matrixMap.columns; i++) - { + for (int i = 0; i < matrixMap.columns; i++) { int index = (i * matrixMap.rows) + strobeRow; int x = matrixMap.map[index].x; int y = matrixMap.map[index].y; int t = x; - if(rotation == MATRIX_DISPLAY_ROTATION_90) - { - x = width - 1 - y; - y = t; + if (rotation == MATRIX_DISPLAY_ROTATION_90) { + x = width - 1 - y; + y = t; } - if(rotation == MATRIX_DISPLAY_ROTATION_180) - { - x = width - 1 - x; - y = height - 1 - y; + if (rotation == MATRIX_DISPLAY_ROTATION_180) { + x = width - 1 - x; + y = height - 1 - y; } - if(rotation == MATRIX_DISPLAY_ROTATION_270) - { - x = y; - y = height - 1 - t; + if (rotation == MATRIX_DISPLAY_ROTATION_270) { + x = y; + y = height - 1 - t; } - if (image.getBitmap()[y*width + x]) + if (image.getBitmap()[y * width + x]) matrixMap.columnPins[i]->setDigitalValue(0); else matrixMap.columnPins[i]->setDigitalValue(1); @@ -150,125 +142,121 @@ void LEDMatrix::render() // Turn off the previous row matrixMap.rowPins[strobeRow]->setDigitalValue(1); - //timer does not have enough resolution for brightness of 1. 23.53 us - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wtype-limits" - if(brightness <= LED_MATRIX_MAXIMUM_BRIGHTNESS && brightness > LED_MATRIX_MINIMUM_BRIGHTNESS) +// timer does not have enough resolution for brightness of 1. 23.53 us +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wtype-limits" + if (brightness <= LED_MATRIX_MAXIMUM_BRIGHTNESS && brightness > LED_MATRIX_MINIMUM_BRIGHTNESS) system_timer_event_after_us(frameTimeout, id, LED_MATRIX_EVT_FRAME_TIMEOUT); - #pragma GCC diagnostic pop +#pragma GCC diagnostic pop - //this will take around 23us to execute - if(brightness <= LED_MATRIX_MINIMUM_BRIGHTNESS) - renderFinish(); + // this will take around 23us to execute + if (brightness <= LED_MATRIX_MINIMUM_BRIGHTNESS) renderFinish(); } void LEDMatrix::renderWithLightSense() { - //reset the row counts and bit mask when we have hit the max. - if(strobeRow == matrixMap.rows + 1) - { + // reset the row counts and bit mask when we have hit the max. + if (strobeRow == matrixMap.rows + 1) { Event(id, LED_MATRIX_EVT_LIGHT_SENSE); strobeRow = 0; } - else - { + else { render(); } - } void LEDMatrix::renderGreyscale() { -/* - uint32_t row_data = 0x01 << (matrixMap.rowStart + strobeRow); - uint32_t col_data = 0; + /* + uint32_t row_data = 0x01 << (matrixMap.rowStart + strobeRow); + uint32_t col_data = 0; - // Calculate the bitpattern to write. - for (int i = 0; i < matrixMap.columns; i++) - { - int index = (i * matrixMap.rows) + strobeRow; - - int x = matrixMap.map[index].x; - int y = matrixMap.map[index].y; - int t = x; - - if(rotation == MATRIX_DISPLAY_ROTATION_90) + // Calculate the bitpattern to write. + for (int i = 0; i < matrixMap.columns; i++) { - x = width - 1 - y; - y = t; + int index = (i * matrixMap.rows) + strobeRow; + + int x = matrixMap.map[index].x; + int y = matrixMap.map[index].y; + int t = x; + + if(rotation == MATRIX_DISPLAY_ROTATION_90) + { + x = width - 1 - y; + y = t; + } + + if(rotation == MATRIX_DISPLAY_ROTATION_180) + { + x = width - 1 - x; + y = height - 1 - y; + } + + if(rotation == MATRIX_DISPLAY_ROTATION_270) + { + x = y; + y = height - 1 - t; + } + + if(min(image.getBitmap()[y * width + x],brightness) & greyscaleBitMsk) + col_data |= (1 << i); } - if(rotation == MATRIX_DISPLAY_ROTATION_180) - { - x = width - 1 - x; - y = height - 1 - y; - } + // Invert column bits (as we're sinking not sourcing power), and mask off any unused bits. + col_data = ~col_data << matrixMap.columnStart & col_mask; - if(rotation == MATRIX_DISPLAY_ROTATION_270) - { - x = y; - y = height - 1 - t; - } + // Write the new bit pattern + *LEDMatrix = col_data | row_data; - if(min(image.getBitmap()[y * width + x],brightness) & greyscaleBitMsk) - col_data |= (1 << i); - } - - // Invert column bits (as we're sinking not sourcing power), and mask off any unused bits. - col_data = ~col_data << matrixMap.columnStart & col_mask; - - // Write the new bit pattern - *LEDMatrix = col_data | row_data; - - if(timingCount > CODAL_DISPLAY_GREYSCALE_BIT_DEPTH-1) - return; + if(timingCount > CODAL_DISPLAY_GREYSCALE_BIT_DEPTH-1) + return; - greyscaleBitMsk <<= 1; + greyscaleBitMsk <<= 1; - if(timingCount < 3) - { - wait_us(greyScaleTimings[timingCount++]); - renderGreyscale(); - return; - } - renderTimer.attach_us(this,&LEDMatrix::renderGreyscale, greyScaleTimings[timingCount++]); -*/ + if(timingCount < 3) + { + wait_us(greyScaleTimings[timingCount++]); + renderGreyscale(); + return; + } + renderTimer.attach_us(this,&LEDMatrix::renderGreyscale, greyScaleTimings[timingCount++]); + */ } /** - * Configures the mode of the display. - * - * @param mode The mode to swap the display into. One of: DISPLAY_MODE_GREYSCALE, - * DISPLAY_MODE_BLACK_AND_WHITE, DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE - * - * @code - * display.setDisplayMode(DISPLAY_MODE_GREYSCALE); //per pixel brightness - * @endcode - */ + * Configures the mode of the display. + * + * @param mode The mode to swap the display into. One of: DISPLAY_MODE_GREYSCALE, + * DISPLAY_MODE_BLACK_AND_WHITE, DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE + * + * @code + * display.setDisplayMode(DISPLAY_MODE_GREYSCALE); //per pixel brightness + * @endcode + */ void LEDMatrix::setDisplayMode(DisplayMode mode) { this->mode = mode; } /** - * Retrieves the mode of the display. - * - * @return the current mode of the display - */ + * Retrieves the mode of the display. + * + * @return the current mode of the display + */ int LEDMatrix::getDisplayMode() { return this->mode; } /** - * Rotates the display to the given position. - * - * Axis aligned values only. - * - * @code - * display.rotateTo(MATRIX_DISPLAY_ROTATION_180); //rotates 180 degrees from original orientation - * @endcode - */ + * Rotates the display to the given position. + * + * Axis aligned values only. + * + * @code + * display.rotateTo(MATRIX_DISPLAY_ROTATION_180); //rotates 180 degrees from original orientation + * @endcode + */ void LEDMatrix::rotateTo(DisplayRotation rotation) { this->rotation = rotation; @@ -282,60 +270,59 @@ void LEDMatrix::rotateTo(DisplayRotation rotation) void LEDMatrix::setEnable(bool enableDisplay) { // If we're already in the correct state, then there's nothing to do. - if(((status & DEVICE_COMPONENT_RUNNING) && enableDisplay) || (!(status & DEVICE_COMPONENT_RUNNING) && !enableDisplay)) + if (((status & DEVICE_COMPONENT_RUNNING) && enableDisplay) || + (!(status & DEVICE_COMPONENT_RUNNING) && !enableDisplay)) return; // Turn off the currently live row row matrixMap.rowPins[strobeRow]->getDigitalValue(); - if (enableDisplay) - { + if (enableDisplay) { status |= DEVICE_COMPONENT_RUNNING; } - else - { + else { status &= ~DEVICE_COMPONENT_RUNNING; } } /** - * Enables the display, should only be called if the display is disabled. - * - * @code - * display.enable(); //Enables the display mechanics - * @endcode - * - * @note Only enables the display if the display is currently disabled. - */ + * Enables the display, should only be called if the display is disabled. + * + * @code + * display.enable(); //Enables the display mechanics + * @endcode + * + * @note Only enables the display if the display is currently disabled. + */ void LEDMatrix::enable() { setEnable(true); } /** - * Disables the display, which releases control of the GPIO pins used by the display, - * which are exposed on the edge connector. - * - * @code - * display.disable(); //disables the display - * @endcode - * - * @note Only disables the display if the display is currently enabled. - */ + * Disables the display, which releases control of the GPIO pins used by the display, + * which are exposed on the edge connector. + * + * @code + * display.disable(); //disables the display + * @endcode + * + * @note Only disables the display if the display is currently enabled. + */ void LEDMatrix::disable() { setEnable(false); } /** - * Clears the display of any remaining pixels. - * - * `display.image.clear()` can also be used! - * - * @code - * display.clear(); //clears the display - * @endcode - */ + * Clears the display of any remaining pixels. + * + * `display.image.clear()` can also be used! + * + * @code + * display.clear(); //clears the display + * @endcode + */ void LEDMatrix::clear() { image.clear(); @@ -352,8 +339,7 @@ int LEDMatrix::setBrightness(int b) { int result = Display::setBrightness(b); - if (result != DEVICE_OK) - return result; + if (result != DEVICE_OK) return result; // Precalculate the per frame "on" time for this brightness level. frameTimeout = (((int)brightness) * 1024 * SCHEDULER_TICK_PERIOD_US) / (255 * 1024); @@ -362,8 +348,8 @@ int LEDMatrix::setBrightness(int b) } /** - * Destructor for LEDMatrix, where we deregister this instance from the array of system components. - */ + * Destructor for LEDMatrix, where we deregister this instance from the array of system components. + */ LEDMatrix::~LEDMatrix() { this->status &= ~DEVICE_COMPONENT_STATUS_SYSTEM_TICK; diff --git a/source/drivers/LIS3DH.cpp b/source/drivers/LIS3DH.cpp index fb8eb6aa..47a82f9d 100644 --- a/source/drivers/LIS3DH.cpp +++ b/source/drivers/LIS3DH.cpp @@ -28,11 +28,12 @@ DEALINGS IN THE SOFTWARE. * Represents an implementation of the Freescale LIS3DH 3 axis accelerometer * Also includes basic data caching and on demand activation. */ -#include "CodalConfig.h" #include "LIS3DH.h" -#include "ErrorNo.h" + #include "CodalCompat.h" +#include "CodalConfig.h" #include "CodalFiber.h" +#include "ErrorNo.h" using namespace codal; @@ -40,12 +41,7 @@ using namespace codal; // Configuration table for available g force ranges. // Maps g -> LIS3DH_CTRL_REG4 [5..4] // -static const KeyValueTableEntry accelerometerRangeData[] = { - {2, 0}, - {4, 1}, - {8, 2}, - {16, 3} -}; +static const KeyValueTableEntry accelerometerRangeData[] = {{2, 0}, {4, 1}, {8, 2}, {16, 3}}; CREATE_KEY_VALUE_TABLE(accelerometerRange, accelerometerRangeData); // @@ -53,37 +49,31 @@ CREATE_KEY_VALUE_TABLE(accelerometerRange, accelerometerRangeData); // maps microsecond period -> LIS3DH_CTRL_REG1 data rate selection bits // static const KeyValueTableEntry accelerometerPeriodData[] = { - {2500, 0x70}, - {5000, 0x60}, - {10000, 0x50}, - {20000, 0x40}, - {40000, 0x30}, - {100000, 0x20}, - {1000000, 0x10} -}; + {2500, 0x70}, {5000, 0x60}, {10000, 0x50}, {20000, 0x40}, {40000, 0x30}, {100000, 0x20}, {1000000, 0x10}}; CREATE_KEY_VALUE_TABLE(accelerometerPeriod, accelerometerPeriodData); /** - * Constructor. - * Create a software abstraction of an accelerometer. - * - * @param _i2c an instance of DeviceI2C used to communicate with the onboard accelerometer. - * @param _int1 the pin connected to the LIS3DH IRQ line. - * @param coordinateSpace The orientation of the sensor. - * @param address the default I2C address of the accelerometer. Defaults to: LIS3DH_DEFAULT_ADDR. - * @param id the unique EventModel id of this component. Defaults to: DEVICE_ID_ACCELEROMETER - * - * @code - * DeviceI2C i2c = DeviceI2C(I2C_SDA0, I2C_SCL0); - * - * LIS3DH accelerometer = LIS3DH(i2c); - * @endcode + * Constructor. + * Create a software abstraction of an accelerometer. + * + * @param _i2c an instance of DeviceI2C used to communicate with the onboard accelerometer. + * @param _int1 the pin connected to the LIS3DH IRQ line. + * @param coordinateSpace The orientation of the sensor. + * @param address the default I2C address of the accelerometer. Defaults to: LIS3DH_DEFAULT_ADDR. + * @param id the unique EventModel id of this component. Defaults to: DEVICE_ID_ACCELEROMETER + * + * @code + * DeviceI2C i2c = DeviceI2C(I2C_SDA0, I2C_SCL0); + * + * LIS3DH accelerometer = LIS3DH(i2c); + * @endcode */ -LIS3DH::LIS3DH(I2C& _i2c, Pin &_int1, CoordinateSpace &coordinateSpace, uint16_t address, uint16_t id) : Accelerometer(coordinateSpace, id), i2c(_i2c), int1(_int1) +LIS3DH::LIS3DH(I2C& _i2c, Pin& _int1, CoordinateSpace& coordinateSpace, uint16_t address, uint16_t id) + : Accelerometer(coordinateSpace, id), i2c(_i2c), int1(_int1) { // Store our identifiers. - this->id = id; - this->status = 0; + this->id = id; + this->status = 0; this->address = address; // Configure and enable the accelerometer. @@ -91,13 +81,13 @@ LIS3DH::LIS3DH(I2C& _i2c, Pin &_int1, CoordinateSpace &coordinateSpace, uint16_t } /** - * Configures the accelerometer for G range and sample rate defined - * in this object. The nearest values are chosen to those defined - * that are supported by the hardware. The instance variables are then - * updated to reflect reality. - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the accelerometer could not be configured. - */ + * Configures the accelerometer for G range and sample rate defined + * in this object. The nearest values are chosen to those defined + * that are supported by the hardware. The instance variables are then + * updated to reflect reality. + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the accelerometer could not be configured. + */ int LIS3DH::configure() { int result; @@ -105,90 +95,82 @@ int LIS3DH::configure() // First find the nearest sample rate to that specified. samplePeriod = accelerometerPeriod.getKey(samplePeriod * 1000) / 1000; - sampleRange = accelerometerRange.getKey(sampleRange); + sampleRange = accelerometerRange.getKey(sampleRange); // Now configure the accelerometer accordingly. // Firstly, Configure for normal precision operation at the sample rate requested. - value = accelerometerPeriod.get(samplePeriod * 1000) | 0x07; + value = accelerometerPeriod.get(samplePeriod * 1000) | 0x07; result = i2c.writeRegister(address, LIS3DH_CTRL_REG1, value); - if (result != 0) - return DEVICE_I2C_ERROR; + if (result != 0) return DEVICE_I2C_ERROR; // Enable the INT1 interrupt pin when XYZ data is available. - value = 0x10; + value = 0x10; result = i2c.writeRegister(address, LIS3DH_CTRL_REG3, value); - if (result != 0) - return DEVICE_I2C_ERROR; + if (result != 0) return DEVICE_I2C_ERROR; // Configure for the selected g range. - value = accelerometerRange.get(sampleRange) << 4; - result = i2c.writeRegister(address, LIS3DH_CTRL_REG4, value); - if (result != 0) - return DEVICE_I2C_ERROR; + value = accelerometerRange.get(sampleRange) << 4; + result = i2c.writeRegister(address, LIS3DH_CTRL_REG4, value); + if (result != 0) return DEVICE_I2C_ERROR; // Configure for a latched interrupt request. - value = 0x08; + value = 0x08; result = i2c.writeRegister(address, LIS3DH_CTRL_REG5, value); - if (result != 0) - return DEVICE_I2C_ERROR; + if (result != 0) return DEVICE_I2C_ERROR; return DEVICE_OK; } - /** - * Attempts to read the 8 bit ID from the accelerometer, this can be used for - * validation purposes. - * - * @return the 8 bit ID returned by the accelerometer, or DEVICE_I2C_ERROR if the request fails. - * - * @code - * accelerometer.whoAmI(); - * @endcode - */ + * Attempts to read the 8 bit ID from the accelerometer, this can be used for + * validation purposes. + * + * @return the 8 bit ID returned by the accelerometer, or DEVICE_I2C_ERROR if the request fails. + * + * @code + * accelerometer.whoAmI(); + * @endcode + */ int LIS3DH::whoAmI() { uint8_t data; int result; result = i2c.readRegister(address, LIS3DH_WHOAMI, &data, 1); - if (result !=0) - return DEVICE_I2C_ERROR; + if (result != 0) return DEVICE_I2C_ERROR; return (int)data; } /** - * Reads the acceleration data from the accelerometer, and stores it in our buffer. - * This only happens if the accelerometer indicates that it has new data via int1. - * - * On first use, this member function will attempt to add this component to the - * list of fiber components in order to constantly update the values stored - * by this object. - * - * This technique is called lazy instantiation, and it means that we do not - * obtain the overhead from non-chalantly adding this component to fiber components. - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the read request fails. - */ + * Reads the acceleration data from the accelerometer, and stores it in our buffer. + * This only happens if the accelerometer indicates that it has new data via int1. + * + * On first use, this member function will attempt to add this component to the + * list of fiber components in order to constantly update the values stored + * by this object. + * + * This technique is called lazy instantiation, and it means that we do not + * obtain the overhead from non-chalantly adding this component to fiber components. + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the read request fails. + */ int LIS3DH::requestUpdate() { // Ensure we're scheduled to update the data periodically status |= DEVICE_COMPONENT_STATUS_IDLE_TICK; // Poll interrupt line from accelerometer. - if(int1.getDigitalValue() == 1) - { + if (int1.getDigitalValue() == 1) { int8_t data[6]; uint8_t src; int result; // read the XYZ data (16 bit) // n.b. we need to set the MSB bit to enable multibyte transfers from this device (WHY? Who Knows!) - result = i2c.readRegister(address, 0x80 | LIS3DH_OUT_X_L, (uint8_t *)data, 6); + result = i2c.readRegister(address, 0x80 | LIS3DH_OUT_X_L, (uint8_t*)data, 6); - if (result !=0) - return DEVICE_I2C_ERROR; + if (result != 0) return DEVICE_I2C_ERROR; target_wait_us(3); @@ -216,7 +198,7 @@ int LIS3DH::requestUpdate() sampleENU.x *= this->sampleRange; sampleENU.y *= this->sampleRange; sampleENU.z *= this->sampleRange; - + // Indicate that a new sample is available update(); } @@ -224,23 +206,20 @@ int LIS3DH::requestUpdate() return DEVICE_OK; }; - /** - * A periodic callback invoked by the fiber scheduler idle thread. - * - * Internally calls updateSample(). - */ + * A periodic callback invoked by the fiber scheduler idle thread. + * + * Internally calls updateSample(). + */ void LIS3DH::idleCallback() { requestUpdate(); } /** - * Destructor for LIS3DH, where we deregister from the array of fiber components. - */ -LIS3DH::~LIS3DH() -{ -} + * Destructor for LIS3DH, where we deregister from the array of fiber components. + */ +LIS3DH::~LIS3DH() {} int LIS3DH::setSleep(bool sleepMode) { diff --git a/source/drivers/LSM303Accelerometer.cpp b/source/drivers/LSM303Accelerometer.cpp index 872e93fc..149bfe7a 100644 --- a/source/drivers/LSM303Accelerometer.cpp +++ b/source/drivers/LSM303Accelerometer.cpp @@ -28,13 +28,14 @@ DEALINGS IN THE SOFTWARE. * Represents an implementation of the LSM303 3 axis accelerometer * Also includes basic data caching and on demand activation. */ +#include "LSM303Accelerometer.h" + +#include "CodalCompat.h" #include "CodalConfig.h" #include "CodalDmesg.h" -#include "LSM303Accelerometer.h" +#include "CodalFiber.h" #include "ErrorNo.h" #include "Event.h" -#include "CodalCompat.h" -#include "CodalFiber.h" using namespace codal; @@ -42,32 +43,18 @@ using namespace codal; // Configuration table for available g force ranges. // Maps g -> CTRL_REG4 full scale selection bits [4..5] // -static const KeyValueTableEntry accelerometerRangeData[] = { - {2, 0x00}, - {4, 0x10}, - {8, 0x20}, - {16, 0x30} -}; +static const KeyValueTableEntry accelerometerRangeData[] = {{2, 0x00}, {4, 0x10}, {8, 0x20}, {16, 0x30}}; CREATE_KEY_VALUE_TABLE(accelerometerRange, accelerometerRangeData); // // Configuration table for available data update frequency. // maps microsecond period -> CTRL_REG1 data rate selection bits [4..7] // -static const KeyValueTableEntry accelerometerPeriodData[] = { - {617, 0x80}, - {744, 0x90}, - {2500, 0x70}, - {5000, 0x60}, - {10000, 0x50}, - {20000, 0x40}, - {40000, 0x30}, - {100000, 0x20}, - {1000000, 0x10} -}; +static const KeyValueTableEntry accelerometerPeriodData[] = {{617, 0x80}, {744, 0x90}, {2500, 0x70}, + {5000, 0x60}, {10000, 0x50}, {20000, 0x40}, + {40000, 0x30}, {100000, 0x20}, {1000000, 0x10}}; CREATE_KEY_VALUE_TABLE(accelerometerPeriod, accelerometerPeriodData); - /** * Constructor. * Create a software abstraction of an accelerometer. @@ -76,10 +63,12 @@ CREATE_KEY_VALUE_TABLE(accelerometerPeriod, accelerometerPeriodData); * @param id The unique EventModel id of this component. Defaults to: DEVICE_ID_ACCELEROMETER * */ -LSM303Accelerometer::LSM303Accelerometer(I2C& _i2c, Pin &_int1, CoordinateSpace &coordinateSpace, uint16_t address, uint16_t id) : Accelerometer(coordinateSpace, id), i2c(_i2c), int1(_int1) +LSM303Accelerometer::LSM303Accelerometer(I2C& _i2c, Pin& _int1, CoordinateSpace& coordinateSpace, uint16_t address, + uint16_t id) + : Accelerometer(coordinateSpace, id), i2c(_i2c), int1(_int1) { // Store our identifiers. - this->status = 0; + this->status = 0; this->address = address; // Configure and enable the accelerometer. @@ -103,30 +92,31 @@ int LSM303Accelerometer::configure() // First find the nearest sample rate to that specified. samplePeriod = accelerometerPeriod.getKey(samplePeriod * 1000) / 1000; - sampleRange = accelerometerRange.getKey(sampleRange); + sampleRange = accelerometerRange.getKey(sampleRange); // Now configure the accelerometer accordingly. - // Place the device into normal (10 bit) mode, with all axes enabled at the nearest supported data rate to that requested. - result = i2c.writeRegister(address, LSM303_CTRL_REG1_A, status & LSM303_A_STATUS_ENABLED ? accelerometerPeriod.get(samplePeriod * 1000) | 0x07 : 0x00); - if (result != 0) - { + // Place the device into normal (10 bit) mode, with all axes enabled at the nearest supported data rate to that + // requested. + result = i2c.writeRegister( + address, LSM303_CTRL_REG1_A, + status & LSM303_A_STATUS_ENABLED ? accelerometerPeriod.get(samplePeriod * 1000) | 0x07 : 0x00); + if (result != 0) { DMESG("LSM303 INIT: ERROR WRITING LSM303_CTRL_REG1_A"); return DEVICE_I2C_ERROR; } // Enable the DRDY1 interrupt on INT1 pin. result = i2c.writeRegister(address, LSM303_CTRL_REG3_A, 0x10); - if (result != 0) - { + if (result != 0) { DMESG("LSM303 INIT: ERROR WRITING LSM303_CTRL_REG3_A"); return DEVICE_I2C_ERROR; } - // Select the g range to that requested, using little endian data format and disable self-test and high rate functions. + // Select the g range to that requested, using little endian data format and disable self-test and high rate + // functions. result = i2c.writeRegister(address, LSM303_CTRL_REG4_A, 0x80 | accelerometerRange.get(sampleRange)); - if (result != 0) - { + if (result != 0) { DMESG("LSM303 INIT: ERROR WRITING LSM303_CTRL_REG4_A"); return DEVICE_I2C_ERROR; } @@ -149,8 +139,7 @@ int LSM303Accelerometer::requestUpdate() { bool awaitSample = false; - if ((status & LSM303_A_STATUS_ENABLED) == 0x00) - { + if ((status & LSM303_A_STATUS_ENABLED) == 0x00) { // If we get here without being enabled, applicaiton code has requested // functionlity from this component. Perform on demand activation. status |= LSM303_A_STATUS_ENABLED; @@ -159,42 +148,38 @@ int LSM303Accelerometer::requestUpdate() // Ensure the first sample is accurate. awaitSample = true; - } + } // Poll interrupt line from device - do - { - if(int1.isActive()) - { + do { + if (int1.isActive()) { uint8_t data[6]; int result; - int16_t *x; - int16_t *y; - int16_t *z; + int16_t* x; + int16_t* y; + int16_t* z; - #if CONFIG_ENABLED(DEVICE_I2C_IRQ_SHARED) +#if CONFIG_ENABLED(DEVICE_I2C_IRQ_SHARED) // Determine if this device has all its data ready (we may be on a shared IRQ line) uint8_t status_reg = i2c.readRegister(address, LSM303_STATUS_REG_A); - if((status_reg & LSM303_A_STATUS_DATA_READY) != LSM303_A_STATUS_DATA_READY) - { + if ((status_reg & LSM303_A_STATUS_DATA_READY) != LSM303_A_STATUS_DATA_READY) { if (awaitSample) continue; else return DEVICE_OK; } - #endif +#endif // Read the combined accelerometer and magnetometer data. - result = i2c.readRegister(address, LSM303_OUT_X_L_A | 0x80, data, 6); + result = i2c.readRegister(address, LSM303_OUT_X_L_A | 0x80, data, 6); awaitSample = false; - if (result !=0) - return DEVICE_I2C_ERROR; + if (result != 0) return DEVICE_I2C_ERROR; // Read in each reading as a 16 bit little endian value, and scale to 10 bits. - x = ((int16_t *) &data[0]); - y = ((int16_t *) &data[2]); - z = ((int16_t *) &data[4]); + x = ((int16_t*)&data[0]); + y = ((int16_t*)&data[2]); + z = ((int16_t*)&data[4]); *x = *x / 32; *y = *y / 32; @@ -203,7 +188,7 @@ int LSM303Accelerometer::requestUpdate() // Scale into millig (approx) and align to ENU coordinate system sampleENU.x = -((int)(*y)) * sampleRange; sampleENU.y = -((int)(*x)) * sampleRange; - sampleENU.z = ((int)(*z)) * sampleRange; + sampleENU.z = ((int)(*z)) * sampleRange; // indicate that new data is available. update(); @@ -214,10 +199,10 @@ int LSM303Accelerometer::requestUpdate() } /** - * A periodic callback invoked by the fiber scheduler idle thread. - * - * Internally calls updateSample(). - */ + * A periodic callback invoked by the fiber scheduler idle thread. + * + * Internally calls updateSample(). + */ void LSM303Accelerometer::idleCallback() { requestUpdate(); @@ -228,30 +213,27 @@ void LSM303Accelerometer::idleCallback() */ int LSM303Accelerometer::setSleep(bool doSleep) { - if (doSleep && (status & LSM303_A_STATUS_ENABLED)) - { + if (doSleep && (status & LSM303_A_STATUS_ENABLED)) { status &= ~DEVICE_COMPONENT_STATUS_IDLE_TICK; status |= LSM303_A_STATUS_SLEEPING; status &= ~LSM303_A_STATUS_ENABLED; configure(); } - - if (!doSleep && (status & LSM303_A_STATUS_SLEEPING)) - { + + if (!doSleep && (status & LSM303_A_STATUS_SLEEPING)) { status |= DEVICE_COMPONENT_STATUS_IDLE_TICK; status &= ~LSM303_A_STATUS_SLEEPING; } - + return DEVICE_OK; } - /** * Attempts to read the 8 bit WHO_AM_I value from the accelerometer * * @return true if the WHO_AM_I value is succesfully read. false otherwise. */ -int LSM303Accelerometer::isDetected(I2C &i2c, uint16_t address) +int LSM303Accelerometer::isDetected(I2C& i2c, uint16_t address) { return i2c.readRegister(address, LSM303_WHO_AM_I_A) == LSM303_A_WHOAMI_VAL; } @@ -259,7 +241,4 @@ int LSM303Accelerometer::isDetected(I2C &i2c, uint16_t address) /** * Destructor. */ -LSM303Accelerometer::~LSM303Accelerometer() -{ -} - +LSM303Accelerometer::~LSM303Accelerometer() {} diff --git a/source/drivers/LSM303Magnetometer.cpp b/source/drivers/LSM303Magnetometer.cpp index 82137dae..d515b503 100644 --- a/source/drivers/LSM303Magnetometer.cpp +++ b/source/drivers/LSM303Magnetometer.cpp @@ -27,13 +27,14 @@ DEALINGS IN THE SOFTWARE. * * Represents an implementation of the ST LSM303 3 axis magnetometer */ -#include "CodalConfig.h" +#include "LSM303Magnetometer.h" + #include "CodalComponent.h" +#include "CodalConfig.h" #include "CodalDmesg.h" #include "CodalUtil.h" -#include "CoordinateSystem.h" -#include "LSM303Magnetometer.h" #include "Compass.h" +#include "CoordinateSystem.h" #include "ErrorNo.h" #include "Event.h" @@ -44,16 +45,15 @@ using namespace codal; // maps microsecond period -> LSM303_CFG_REG_A_M data rate selection bits [2..3] // static const KeyValueTableEntry magnetometerPeriodData[] = { - {10000, 0x0C}, // 100 Hz - {20000, 0x08}, // 50 Hz - {50000, 0x04}, // 20 Hz - {100000, 0x00} // 10 Hz + {10000, 0x0C}, // 100 Hz + {20000, 0x08}, // 50 Hz + {50000, 0x04}, // 20 Hz + {100000, 0x00} // 10 Hz }; CREATE_KEY_VALUE_TABLE(magnetometerPeriod, magnetometerPeriodData); - /** - * Configures the compass for the sample rate defined in this object. + * Configures the compass for the sample rate defined in this object. * The nearest values are chosen to those defined * that are supported by the hardware. The instance variables are then * updated to reflect reality. @@ -68,25 +68,23 @@ int LSM303Magnetometer::configure() // First find the nearest sample rate to that specified. samplePeriod = magnetometerPeriod.getKey(samplePeriod * 1000) / 1000; - // Now configure the magnetometer for the requested sample rate, low power continuous mode with temperature compensation disabled + // Now configure the magnetometer for the requested sample rate, low power continuous mode with temperature + // compensation disabled value = magnetometerPeriod.get(samplePeriod * 1000); // Configure the component as enabled or disabled as appropriate. - if (!(status & LSM303_M_STATUS_ENABLED)) - value |= 0x03; + if (!(status & LSM303_M_STATUS_ENABLED)) value |= 0x03; result = i2c.writeRegister(address, LSM303_CFG_REG_A_M, value); - if (result != DEVICE_OK) - { + if (result != DEVICE_OK) { DMESG("LSM303 INIT: ERROR WRITING LSM303_CFG_REG_A_M"); return DEVICE_I2C_ERROR; } // Enable Data Ready interrupt, with buffering of data to avoid race conditions. - value = status & LSM303_M_STATUS_ENABLED ? 0x01 : 0x00; + value = status & LSM303_M_STATUS_ENABLED ? 0x01 : 0x00; result = i2c.writeRegister(address, LSM303_CFG_REG_C_M, value); - if (result != DEVICE_OK) - { + if (result != DEVICE_OK) { DMESG("LSM303 INIT: ERROR WRITING LSM303_CFG_REG_C_M"); return DEVICE_I2C_ERROR; } @@ -95,15 +93,17 @@ int LSM303Magnetometer::configure() } /** - * Constructor. - * Create a software abstraction of an FXSO8700 combined magnetometer/magnetometer - * - * @param _i2c an instance of I2C used to communicate with the device. - * - * @param address the default I2C address of the magnetometer. Defaults to: FXS8700_DEFAULT_ADDR. - * + * Constructor. + * Create a software abstraction of an FXSO8700 combined magnetometer/magnetometer + * + * @param _i2c an instance of I2C used to communicate with the device. + * + * @param address the default I2C address of the magnetometer. Defaults to: FXS8700_DEFAULT_ADDR. + * */ -LSM303Magnetometer::LSM303Magnetometer(I2C &_i2c, Pin &_int1, CoordinateSpace &coordinateSpace, uint16_t address, uint16_t id) : Compass(coordinateSpace, id), i2c(_i2c), int1(_int1) +LSM303Magnetometer::LSM303Magnetometer(I2C& _i2c, Pin& _int1, CoordinateSpace& coordinateSpace, uint16_t address, + uint16_t id) + : Compass(coordinateSpace, id), i2c(_i2c), int1(_int1) { // Store our identifiers. this->address = address; @@ -112,7 +112,6 @@ LSM303Magnetometer::LSM303Magnetometer(I2C &_i2c, Pin &_int1, CoordinateSpace &c configure(); } - /** * Poll to see if new data is available from the hardware. If so, update it. * n.b. it is not necessary to explicitly call this funciton to update data @@ -128,8 +127,7 @@ int LSM303Magnetometer::requestUpdate() { bool awaitSample = false; - if ((status & LSM303_M_STATUS_ENABLED) == 0x00) - { + if ((status & LSM303_M_STATUS_ENABLED) == 0x00) { // If we get here without being enabled, applicaiton code has requested // functionlity from this component. Perform on demand activation. status |= LSM303_M_STATUS_ENABLED; @@ -138,41 +136,38 @@ int LSM303Magnetometer::requestUpdate() // Ensure the first sample is accurate. awaitSample = true; - } + } - // Poll interrupt line from device - do{ - if(int1.isActive()) - { + // Poll interrupt line from device + do { + if (int1.isActive()) { uint8_t data[6]; int result; - int16_t *x; - int16_t *y; - int16_t *z; + int16_t* x; + int16_t* y; + int16_t* z; - #if CONFIG_ENABLED(DEVICE_I2C_IRQ_SHARED) +#if CONFIG_ENABLED(DEVICE_I2C_IRQ_SHARED) // Determine if this device has all its data ready (we may be on a shared IRQ line) uint8_t status_reg = i2c.readRegister(address, LSM303_STATUS_REG_M); - if((status_reg & LSM303_M_STATUS_DATA_READY) != LSM303_M_STATUS_DATA_READY) - { + if ((status_reg & LSM303_M_STATUS_DATA_READY) != LSM303_M_STATUS_DATA_READY) { if (awaitSample) continue; else return DEVICE_OK; } - #endif +#endif // Read the combined accelerometer and magnetometer data. - result = i2c.readRegister(address, LSM303_OUTX_L_REG_M | 0x80, data, 6); + result = i2c.readRegister(address, LSM303_OUTX_L_REG_M | 0x80, data, 6); awaitSample = false; - if (result !=0) - return DEVICE_I2C_ERROR; + if (result != 0) return DEVICE_I2C_ERROR; // Read in each reading as a 16 bit little endian value, and scale to 10 bits. - x = ((int16_t *) &data[0]); - y = ((int16_t *) &data[2]); - z = ((int16_t *) &data[4]); + x = ((int16_t*)&data[0]); + y = ((int16_t*)&data[2]); + z = ((int16_t*)&data[4]); // Align to ENU coordinate system sampleENU.x = LSM303_M_NORMALIZE_SAMPLE(-((int)(*y))); @@ -187,12 +182,11 @@ int LSM303Magnetometer::requestUpdate() return DEVICE_OK; } - /** - * A periodic callback invoked by the fiber scheduler idle thread. - * - * Internally calls updateSample(). - */ + * A periodic callback invoked by the fiber scheduler idle thread. + * + * Internally calls updateSample(). + */ void LSM303Magnetometer::idleCallback() { requestUpdate(); @@ -203,20 +197,18 @@ void LSM303Magnetometer::idleCallback() */ int LSM303Magnetometer::setSleep(bool doSleep) { - if (doSleep && (status & LSM303_M_STATUS_ENABLED)) - { + if (doSleep && (status & LSM303_M_STATUS_ENABLED)) { status &= ~DEVICE_COMPONENT_STATUS_IDLE_TICK; status |= LSM303_M_STATUS_SLEEPING; status &= ~LSM303_M_STATUS_ENABLED; configure(); } - - if (!doSleep && (status & LSM303_M_STATUS_SLEEPING)) - { + + if (!doSleep && (status & LSM303_M_STATUS_SLEEPING)) { status |= DEVICE_COMPONENT_STATUS_IDLE_TICK; status &= ~LSM303_M_STATUS_SLEEPING; } - + return DEVICE_OK; } @@ -225,15 +217,12 @@ int LSM303Magnetometer::setSleep(bool doSleep) * * @return true if the WHO_AM_I value is succesfully read. false otherwise. */ -int LSM303Magnetometer::isDetected(I2C &i2c, uint16_t address) +int LSM303Magnetometer::isDetected(I2C& i2c, uint16_t address) { return i2c.readRegister(address, LSM303_WHO_AM_I_M) == LSM303_M_WHOAMI_VAL; } /** - * Destructor for FXS8700, where we deregister from the array of fiber components. - */ -LSM303Magnetometer::~LSM303Magnetometer() -{ -} - + * Destructor for FXS8700, where we deregister from the array of fiber components. + */ +LSM303Magnetometer::~LSM303Magnetometer() {} diff --git a/source/drivers/LinearAnalogSensor.cpp b/source/drivers/LinearAnalogSensor.cpp index 0b3a96e4..b329c9f5 100644 --- a/source/drivers/LinearAnalogSensor.cpp +++ b/source/drivers/LinearAnalogSensor.cpp @@ -23,8 +23,9 @@ DEALINGS IN THE SOFTWARE. */ /** - * Class definition for a normalised, non-linear analog sensor, that takes the general form of a logarithmic response to a sensed value, in a potential divider. - * Implements a base class for such a sensor, using the Steinhart-Hart equation to delineate a result. + * Class definition for a normalised, non-linear analog sensor, that takes the general form of a logarithmic response to + * a sensed value, in a potential divider. Implements a base class for such a sensor, using the Steinhart-Hart equation + * to delineate a result. */ #include "LinearAnalogSensor.h" @@ -44,10 +45,12 @@ using namespace codal; * @param outputCeiling The maximum level in the output range. Default: 1023. * */ -LinearAnalogSensor::LinearAnalogSensor(Pin &pin, uint16_t id, uint16_t inputFloor, uint16_t inputCeiling, float outputFloor, float outputCeiling) : AnalogSensor(pin, id) +LinearAnalogSensor::LinearAnalogSensor(Pin& pin, uint16_t id, uint16_t inputFloor, uint16_t inputCeiling, + float outputFloor, float outputCeiling) + : AnalogSensor(pin, id) { - this->inputFloor = inputFloor; - this->outputFloor = outputFloor; + this->inputFloor = inputFloor; + this->outputFloor = outputFloor; this->conversionFactor = (outputCeiling - outputFloor) / ((float)(inputCeiling - inputFloor)); } @@ -61,18 +64,17 @@ void LinearAnalogSensor::updateSample() float sensorReading; float value; - sensorReading = (float) (this->readValue() - this->inputFloor); + sensorReading = (float)(this->readValue() - this->inputFloor); value = this->outputFloor + sensorReading * this->conversionFactor; - // If this is the first reading performed, take it a a baseline. Otherwise, perform a decay average to smooth out the data. - if (!(this->status & ANALOG_SENSOR_INITIALISED)) - { + // If this is the first reading performed, take it a a baseline. Otherwise, perform a decay average to smooth out + // the data. + if (!(this->status & ANALOG_SENSOR_INITIALISED)) { this->sensorValue = value; - this->status |= ANALOG_SENSOR_INITIALISED; + this->status |= ANALOG_SENSOR_INITIALISED; } - else - { + else { this->sensorValue = (this->sensorValue * (1.0f - this->sensitivity)) + (value * this->sensitivity); } diff --git a/source/drivers/MAG3110.cpp b/source/drivers/MAG3110.cpp index a8628476..9e0d292c 100644 --- a/source/drivers/MAG3110.cpp +++ b/source/drivers/MAG3110.cpp @@ -24,39 +24,39 @@ DEALINGS IN THE SOFTWARE. */ /** - * Class definition for a MAG3110 Compass. - * - * Represents an implementation of the Freescale MAG3110 I2C Magnetmometer. - * Also includes basic caching, calibration and on demand activation. - */ -#include "CodalConfig.h" + * Class definition for a MAG3110 Compass. + * + * Represents an implementation of the Freescale MAG3110 I2C Magnetmometer. + * Also includes basic caching, calibration and on demand activation. + */ #include "MAG3110.h" + +#include "CodalConfig.h" +#include "CodalFiber.h" #include "ErrorNo.h" #include "I2C.h" -#include "CodalFiber.h" using namespace codal; /** - * Constructor. - * Create a software representation of an e-compass. - * - * @param _i2c an instance of codal::I2C, which the compass is accessible from. - * @param int1 The codal::Pin connected to the MAG3110 interrupt line. - * @param _accelerometer an instance of codal::Accelerometer, used for tilt compensation. - * @param coordinateSpace The 3D coordinate space transform to use with this sensor. - * @param address the address of the MAG3110 device on the i2c bus. Defaults to MAG3110_DEFAULT_ADDR. - * @param id the ID of the new MAG3110 object. Defaults to MAG3110_DEFAULT_ADDR. - * - * @code - * MAG3110 compass(i2c, accelerometer, coordinateSpace); - * @endcode - */ - -MAG3110::MAG3110(I2C& _i2c, Pin& int1, Accelerometer& _accelerometer, CoordinateSpace &coordinateSpace, uint16_t address, uint16_t id) : - Compass(_accelerometer, coordinateSpace, id), - int1(int1), - i2c(_i2c) + * Constructor. + * Create a software representation of an e-compass. + * + * @param _i2c an instance of codal::I2C, which the compass is accessible from. + * @param int1 The codal::Pin connected to the MAG3110 interrupt line. + * @param _accelerometer an instance of codal::Accelerometer, used for tilt compensation. + * @param coordinateSpace The 3D coordinate space transform to use with this sensor. + * @param address the address of the MAG3110 device on the i2c bus. Defaults to MAG3110_DEFAULT_ADDR. + * @param id the ID of the new MAG3110 object. Defaults to MAG3110_DEFAULT_ADDR. + * + * @code + * MAG3110 compass(i2c, accelerometer, coordinateSpace); + * @endcode + */ + +MAG3110::MAG3110(I2C& _i2c, Pin& int1, Accelerometer& _accelerometer, CoordinateSpace& coordinateSpace, + uint16_t address, uint16_t id) + : Compass(_accelerometer, coordinateSpace, id), int1(int1), i2c(_i2c) { this->address = address; @@ -74,112 +74,102 @@ int MAG3110::whoAmI() int result; result = i2c.readRegister(address, MAG_WHOAMI, &data, 1); - if (result != DEVICE_OK) - return DEVICE_I2C_ERROR; + if (result != DEVICE_OK) return DEVICE_I2C_ERROR; return (int)data; } /** - * Updates the local sample, only if the compass indicates that - * data is stale. - * - * @note Can be used to trigger manual updates, if the device is running without a scheduler. - * Also called internally by all get[X,Y,Z]() member functions. - */ + * Updates the local sample, only if the compass indicates that + * data is stale. + * + * @note Can be used to trigger manual updates, if the device is running without a scheduler. + * Also called internally by all get[X,Y,Z]() member functions. + */ int MAG3110::requestUpdate() { - if(!(status & DEVICE_COMPONENT_STATUS_IDLE_TICK)) - status |= DEVICE_COMPONENT_STATUS_IDLE_TICK; + if (!(status & DEVICE_COMPONENT_STATUS_IDLE_TICK)) status |= DEVICE_COMPONENT_STATUS_IDLE_TICK; // Poll interrupt line from compass (Active HI). // Interrupt is cleared on data read of MAG_OUT_X_MSB. - if(int1.getDigitalValue()) - { + if (int1.getDigitalValue()) { uint8_t data[6]; int16_t s; - uint8_t *lsb = (uint8_t *) &s; - uint8_t *msb = lsb + 1; + uint8_t* lsb = (uint8_t*)&s; + uint8_t* msb = lsb + 1; int result; // Read the combined magnetometer and magnetometer data. result = i2c.readRegister(address, MAG_OUT_X_MSB, data, 6); - if (result !=0) - return DEVICE_I2C_ERROR; - - // Scale the 14 bit data (packed into 16 bits) into SI units (milli-g) and translate into signed little endian, and align to ENU coordinate system - *msb = data[0]; - *lsb = data[1]; - sampleENU.y = MAG3110_NORMALIZE_SAMPLE(s); + if (result != 0) return DEVICE_I2C_ERROR; + + // Scale the 14 bit data (packed into 16 bits) into SI units (milli-g) and translate into signed little endian, + // and align to ENU coordinate system + *msb = data[0]; + *lsb = data[1]; + sampleENU.y = MAG3110_NORMALIZE_SAMPLE(s); - *msb = data[2]; - *lsb = data[3]; - sampleENU.x = -MAG3110_NORMALIZE_SAMPLE(s); + *msb = data[2]; + *lsb = data[3]; + sampleENU.x = -MAG3110_NORMALIZE_SAMPLE(s); - *msb = data[4]; - *lsb = data[5]; - sampleENU.z = -MAG3110_NORMALIZE_SAMPLE(s); + *msb = data[4]; + *lsb = data[5]; + sampleENU.z = -MAG3110_NORMALIZE_SAMPLE(s); // Inform the higher level driver that raw data has been updated. update(); - } return DEVICE_OK; } /** - * Periodic callback from the idle thread. - * - * Calls updateSample(). - */ + * Periodic callback from the idle thread. + * + * Calls updateSample(). + */ void MAG3110::idleCallback() { requestUpdate(); } /** - * Configures the compass for the sample rate defined in this object. - * The nearest values are chosen to those defined that are supported by the hardware. - * The instance variables are then updated to reflect reality. - * - * @return DEVICE_OK or DEVICE_I2C_ERROR if the magnetometer could not be configured. - */ + * Configures the compass for the sample rate defined in this object. + * The nearest values are chosen to those defined that are supported by the hardware. + * The instance variables are then updated to reflect reality. + * + * @return DEVICE_OK or DEVICE_I2C_ERROR if the magnetometer could not be configured. + */ int MAG3110::configure() { - const MAG3110SampleRateConfig *actualSampleRate; + const MAG3110SampleRateConfig* actualSampleRate; int result; // First, take the device offline, so it can be configured. - result = i2c.writeRegister(this->address,MAG_CTRL_REG1, 0x00); - if (result != DEVICE_OK) - return DEVICE_I2C_ERROR; + result = i2c.writeRegister(this->address, MAG_CTRL_REG1, 0x00); + if (result != DEVICE_OK) return DEVICE_I2C_ERROR; // Wait for the part to enter standby mode... - while(1) - { + while (1) { // Read the status of the part... // If we can't communicate with it over I2C, pass on the error. uint8_t d = 0; - result = i2c.readRegister(this->address, MAG_SYSMOD, &d, 1); - if (result == DEVICE_I2C_ERROR) - return DEVICE_I2C_ERROR; + result = i2c.readRegister(this->address, MAG_SYSMOD, &d, 1); + if (result == DEVICE_I2C_ERROR) return DEVICE_I2C_ERROR; // if the part in in standby, we're good to carry on. - if(result == 0) - break; + if (result == 0) break; // Perform a power efficient sleep... - fiber_sleep(100); + fiber_sleep(100); } // Find the nearest sample rate to that specified. - actualSampleRate = &MAG3110SampleRate[MAG3110_SAMPLE_RATES-1]; - for (int i=MAG3110_SAMPLE_RATES-1; i>=0; i--) - { - if(MAG3110SampleRate[i].sample_period < this->samplePeriod * 1000) - break; + actualSampleRate = &MAG3110SampleRate[MAG3110_SAMPLE_RATES - 1]; + for (int i = MAG3110_SAMPLE_RATES - 1; i >= 0; i--) { + if (MAG3110SampleRate[i].sample_period < this->samplePeriod * 1000) break; actualSampleRate = &MAG3110SampleRate[i]; } @@ -189,28 +179,25 @@ int MAG3110::configure() // Enable automatic reset after each sample; result = i2c.writeRegister(this->address, MAG_CTRL_REG2, 0xA0); - if (result != DEVICE_OK) - return DEVICE_I2C_ERROR; - + if (result != DEVICE_OK) return DEVICE_I2C_ERROR; // Bring the device online, with the requested sample frequency. result = i2c.writeRegister(this->address, MAG_CTRL_REG1, actualSampleRate->ctrl_reg1 | 0x01); - if (result != DEVICE_OK) - return DEVICE_I2C_ERROR; + if (result != DEVICE_OK) return DEVICE_I2C_ERROR; return DEVICE_OK; } const MAG3110SampleRateConfig MAG3110SampleRate[MAG3110_SAMPLE_RATES] = { - {12500, 0x00}, // 80 Hz - {25000, 0x20}, // 40 Hz - {50000, 0x40}, // 20 Hz - {100000, 0x60}, // 10 hz - {200000, 0x80}, // 5 hz - {400000, 0x88}, // 2.5 hz - {800000, 0x90}, // 1.25 hz - {1600000, 0xb0}, // 0.63 hz - {3200000, 0xd0}, // 0.31 hz - {6400000, 0xf0}, // 0.16 hz - {12800000, 0xf8} // 0.08 hz + {12500, 0x00}, // 80 Hz + {25000, 0x20}, // 40 Hz + {50000, 0x40}, // 20 Hz + {100000, 0x60}, // 10 hz + {200000, 0x80}, // 5 hz + {400000, 0x88}, // 2.5 hz + {800000, 0x90}, // 1.25 hz + {1600000, 0xb0}, // 0.63 hz + {3200000, 0xd0}, // 0.31 hz + {6400000, 0xf0}, // 0.16 hz + {12800000, 0xf8} // 0.08 hz }; diff --git a/source/drivers/MMA8653.cpp b/source/drivers/MMA8653.cpp index c1647c16..d82162d3 100644 --- a/source/drivers/MMA8653.cpp +++ b/source/drivers/MMA8653.cpp @@ -29,117 +29,108 @@ DEALINGS IN THE SOFTWARE. * Represents an implementation of the Freescale MMA8653 3 axis accelerometer * Also includes basic data caching and on demand activation. */ -#include "CodalConfig.h" -#include "CodalComponent.h" #include "MMA8653.h" + +#include "CodalComponent.h" +#include "CodalConfig.h" #include "ErrorNo.h" using namespace codal; /** - * Configures the accelerometer for G range and sample rate defined - * in this object. The nearest values are chosen to those defined - * that are supported by the hardware. The instance variables are then - * updated to reflect reality. - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the accelerometer could not be configured. - */ + * Configures the accelerometer for G range and sample rate defined + * in this object. The nearest values are chosen to those defined + * that are supported by the hardware. The instance variables are then + * updated to reflect reality. + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the accelerometer could not be configured. + */ int MMA8653::configure() { - const MMA8653SampleRangeConfig *actualSampleRange; - const MMA8653SampleRateConfig *actualSampleRate; + const MMA8653SampleRangeConfig* actualSampleRange; + const MMA8653SampleRateConfig* actualSampleRate; int result; // First find the nearest sample rate to that specified. - actualSampleRate = &MMA8653SampleRate[MMA8653_SAMPLE_RATES-1]; - for (int i=MMA8653_SAMPLE_RATES-1; i>=0; i--) - { - if(MMA8653SampleRate[i].sample_period < this->samplePeriod * 1000) - break; + actualSampleRate = &MMA8653SampleRate[MMA8653_SAMPLE_RATES - 1]; + for (int i = MMA8653_SAMPLE_RATES - 1; i >= 0; i--) { + if (MMA8653SampleRate[i].sample_period < this->samplePeriod * 1000) break; actualSampleRate = &MMA8653SampleRate[i]; } // Now find the nearest sample range to that specified. - actualSampleRange = &MMA8653SampleRange[MMA8653_SAMPLE_RANGES-1]; - for (int i=MMA8653_SAMPLE_RANGES-1; i>=0; i--) - { - if(MMA8653SampleRange[i].sample_range < this->sampleRange) - break; + actualSampleRange = &MMA8653SampleRange[MMA8653_SAMPLE_RANGES - 1]; + for (int i = MMA8653_SAMPLE_RANGES - 1; i >= 0; i--) { + if (MMA8653SampleRange[i].sample_range < this->sampleRange) break; actualSampleRange = &MMA8653SampleRange[i]; } // OK, we have the correct data. Update our local state. this->samplePeriod = actualSampleRate->sample_period / 1000; - this->sampleRange = actualSampleRange->sample_range; + this->sampleRange = actualSampleRange->sample_range; // Now configure the accelerometer accordingly. // First place the device into standby mode, so it can be configured. result = i2c.writeRegister(this->address, MMA8653_CTRL_REG1, 0x00); - if (result != DEVICE_OK) - return DEVICE_I2C_ERROR; + if (result != DEVICE_OK) return DEVICE_I2C_ERROR; // Enable high precisiosn mode. This consumes a bit more power, but still only 184 uA! result = i2c.writeRegister(this->address, MMA8653_CTRL_REG2, 0x10); - if (result != DEVICE_OK) - return DEVICE_I2C_ERROR; + if (result != DEVICE_OK) return DEVICE_I2C_ERROR; // Enable the INT1 interrupt pin. result = i2c.writeRegister(this->address, MMA8653_CTRL_REG4, 0x01); - if (result != DEVICE_OK) - return DEVICE_I2C_ERROR; + if (result != DEVICE_OK) return DEVICE_I2C_ERROR; // Select the DATA_READY event source to be routed to INT1 result = i2c.writeRegister(this->address, MMA8653_CTRL_REG5, 0x01); - if (result != DEVICE_OK) - return DEVICE_I2C_ERROR; + if (result != DEVICE_OK) return DEVICE_I2C_ERROR; // Configure for the selected g range. result = i2c.writeRegister(this->address, MMA8653_XYZ_DATA_CFG, actualSampleRange->xyz_data_cfg); - if (result != DEVICE_OK) - return DEVICE_I2C_ERROR; + if (result != DEVICE_OK) return DEVICE_I2C_ERROR; // Bring the device back online, with 10bit wide samples at the requested frequency. result = i2c.writeRegister(this->address, MMA8653_CTRL_REG1, actualSampleRate->ctrl_reg1 | 0x01); - if (result != DEVICE_OK) - return DEVICE_I2C_ERROR; + if (result != DEVICE_OK) return DEVICE_I2C_ERROR; return DEVICE_OK; } /** - * Constructor. - * Create a software abstraction of an accelerometer. - * - * @param _i2c an instance of codal::I2C used to communicate with the accelerometer. - * - * @param address the default I2C address of the accelerometer. Defaults to: MMA8653_DEFAULT_ADDR. - * - * @param id the unique EventModel id of this component. Defaults to: DEVICE_ID_ACCELEROMETER - * - * @code - * MMA8653 accelerometer = MMA8653(i2c); - * @endcode + * Constructor. + * Create a software abstraction of an accelerometer. + * + * @param _i2c an instance of codal::I2C used to communicate with the accelerometer. + * + * @param address the default I2C address of the accelerometer. Defaults to: MMA8653_DEFAULT_ADDR. + * + * @param id the unique EventModel id of this component. Defaults to: DEVICE_ID_ACCELEROMETER + * + * @code + * MMA8653 accelerometer = MMA8653(i2c); + * @endcode */ -MMA8653::MMA8653(I2C& _i2c, Pin& int1, CoordinateSpace& cspace, uint16_t address, uint16_t id) : Accelerometer(cspace, id), int1(int1), i2c(_i2c) +MMA8653::MMA8653(I2C& _i2c, Pin& int1, CoordinateSpace& cspace, uint16_t address, uint16_t id) + : Accelerometer(cspace, id), int1(int1), i2c(_i2c) { this->address = address; // Configure and enable the accelerometer. - if (configure() == DEVICE_OK) - status |= (DEVICE_COMPONENT_RUNNING); + if (configure() == DEVICE_OK) status |= (DEVICE_COMPONENT_RUNNING); } /** - * Attempts to read the 8 bit ID from the accelerometer, this can be used for - * validation purposes. - * - * @return the 8 bit ID returned by the accelerometer, or DEVICE_I2C_ERROR if the request fails. - * - * @code - * accelerometer.whoAmI(); - * @endcode - */ + * Attempts to read the 8 bit ID from the accelerometer, this can be used for + * validation purposes. + * + * @return the 8 bit ID returned by the accelerometer, or DEVICE_I2C_ERROR if the request fails. + * + * @code + * accelerometer.whoAmI(); + * @endcode + */ int MMA8653::whoAmI() { uint8_t data; @@ -147,41 +138,37 @@ int MMA8653::whoAmI() result = i2c.readRegister(this->address, MMA8653_WHOAMI, &data, 1); - if (result != DEVICE_OK) - return DEVICE_I2C_ERROR; + if (result != DEVICE_OK) return DEVICE_I2C_ERROR; return (int)data; } /** - * Reads the acceleration data from the accelerometer, and stores it in our buffer. - * This only happens if the accelerometer indicates that it has new data via int1. - * - * On first use, this member function will attempt to add this component to the - * list of fiber components in order to constantly update the values stored - * by this object. - * - * This technique is called lazy instantiation, and it means that we do not - * obtain the overhead from non-chalantly adding this component to fiber components. - * - * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the read request fails. - */ + * Reads the acceleration data from the accelerometer, and stores it in our buffer. + * This only happens if the accelerometer indicates that it has new data via int1. + * + * On first use, this member function will attempt to add this component to the + * list of fiber components in order to constantly update the values stored + * by this object. + * + * This technique is called lazy instantiation, and it means that we do not + * obtain the overhead from non-chalantly adding this component to fiber components. + * + * @return DEVICE_OK on success, DEVICE_I2C_ERROR if the read request fails. + */ int MMA8653::requestUpdate() { - if(!(status & DEVICE_COMPONENT_STATUS_IDLE_TICK)) - status |= DEVICE_COMPONENT_STATUS_IDLE_TICK; + if (!(status & DEVICE_COMPONENT_STATUS_IDLE_TICK)) status |= DEVICE_COMPONENT_STATUS_IDLE_TICK; // Poll interrupt line from accelerometer. // n.b. Default is Active LO. Interrupt is cleared in data read. - if(!int1.getDigitalValue()) - { + if (!int1.getDigitalValue()) { Sample3D s; int8_t data[6]; int result; - result = i2c.readRegister(this->address, MMA8653_OUT_X_MSB, (uint8_t *)data, 6); - if (result != DEVICE_OK) - return DEVICE_I2C_ERROR; + result = i2c.readRegister(this->address, MMA8653_OUT_X_MSB, (uint8_t*)data, 6); + if (result != DEVICE_OK) return DEVICE_I2C_ERROR; // read MSB values... sampleENU.x = data[0]; @@ -212,10 +199,10 @@ int MMA8653::requestUpdate() }; /** - * A periodic callback invoked by the fiber scheduler idle thread. - * - * Internally calls updateSample(). - */ + * A periodic callback invoked by the fiber scheduler idle thread. + * + * Internally calls updateSample(). + */ void MMA8653::idleCallback() { requestUpdate(); @@ -229,20 +216,8 @@ int MMA8653::setSleep(bool sleepMode) return configure(); } +const MMA8653SampleRangeConfig MMA8653SampleRange[MMA8653_SAMPLE_RANGES] = {{2, 0}, {4, 1}, {8, 2}}; -const MMA8653SampleRangeConfig MMA8653SampleRange[MMA8653_SAMPLE_RANGES] = { - {2, 0}, - {4, 1}, - {8, 2} -}; - -const MMA8653SampleRateConfig MMA8653SampleRate[MMA8653_SAMPLE_RATES] = { - {1250, 0x00}, - {2500, 0x08}, - {5000, 0x10}, - {10000, 0x18}, - {20000, 0x20}, - {80000, 0x28}, - {160000, 0x30}, - {640000, 0x38} -}; +const MMA8653SampleRateConfig MMA8653SampleRate[MMA8653_SAMPLE_RATES] = {{1250, 0x00}, {2500, 0x08}, {5000, 0x10}, + {10000, 0x18}, {20000, 0x20}, {80000, 0x28}, + {160000, 0x30}, {640000, 0x38}}; diff --git a/source/drivers/MPU6050.cpp b/source/drivers/MPU6050.cpp index 81be9716..4f5dd42a 100644 --- a/source/drivers/MPU6050.cpp +++ b/source/drivers/MPU6050.cpp @@ -1,24 +1,24 @@ -#include "CodalConfig.h" #include "MPU6050.h" -#include "ErrorNo.h" -#include "CodalCompat.h" -#include "CodalFiber.h" +#include "CodalCompat.h" +#include "CodalConfig.h" #include "CodalDmesg.h" +#include "CodalFiber.h" +#include "ErrorNo.h" using namespace codal; - -MPU6050::MPU6050(I2C& _i2c, Pin &_int1, CoordinateSpace &coordinateSpace, uint16_t address, uint16_t id) : Accelerometer(coordinateSpace, id), i2c(_i2c), int1(_int1) +MPU6050::MPU6050(I2C& _i2c, Pin& _int1, CoordinateSpace& coordinateSpace, uint16_t address, uint16_t id) + : Accelerometer(coordinateSpace, id), i2c(_i2c), int1(_int1) { // Store our identifiers. - this->id = id; - this->status = 0; - this->address = address<<1; + this->id = id; + this->status = 0; + this->address = address << 1; // Update our internal state for 50Hz at +/- 2g (50Hz has a period af 20ms). this->samplePeriod = 20; - this->sampleRange = 2; + this->sampleRange = 2; // Configure and enable the accelerometer. configure(); @@ -28,13 +28,15 @@ int MPU6050::configure() { i2c.writeRegister(address, 0x6B, 0x80); fiber_sleep(20); - i2c.writeRegister(address, 0x6B, 0x00); /* PWR_MGMT_1 -- SLEEP 0; CYCLE 0; TEMP_DIS 0; CLKSEL 3 (PLL with Z Gyro reference) */ - i2c.writeRegister(address, 0x1A, 0x01); /* CONFIG -- EXT_SYNC_SET 0 (disable input pin for data sync) ; default DLPF_CFG = 0 => ACC bandwidth = 260Hz GYRO bandwidth = 256Hz) */ - i2c.writeRegister(address, 0x1B, 0x18); /* GYRO_CONFIG -- FS_SEL = 3: Full scale set to 2000 deg/sec */ + i2c.writeRegister(address, 0x6B, + 0x00); /* PWR_MGMT_1 -- SLEEP 0; CYCLE 0; TEMP_DIS 0; CLKSEL 3 (PLL with Z Gyro reference) */ + i2c.writeRegister(address, 0x1A, 0x01); /* CONFIG -- EXT_SYNC_SET 0 (disable input pin for data sync) ; + default DLPF_CFG = 0 => ACC bandwidth = 260Hz GYRO bandwidth = 256Hz) */ + i2c.writeRegister(address, 0x1B, 0x18); /* GYRO_CONFIG -- FS_SEL = 3: Full scale set to 2000 deg/sec */ i2c.writeRegister(address, 0x19, 32); - i2c.writeRegister(address, 0x37, 0x30); // enable interrupt latch; also enable clear of pin by any read - i2c.writeRegister(address, 0x38, 0x01); // enable raw data interrupt + i2c.writeRegister(address, 0x37, 0x30); // enable interrupt latch; also enable clear of pin by any read + i2c.writeRegister(address, 0x38, 0x01); // enable raw data interrupt DMESG("MPU6050 init %x", whoAmI()); return DEVICE_OK; @@ -46,10 +48,9 @@ int MPU6050::whoAmI() int result; // the default whoami should return 0x68 result = i2c.readRegister(address, MPU6050_WHOAMI, &data, 1); - if (result !=0) - return 0xffff; + if (result != 0) return 0xffff; - return (data>>1) & 0x3f; + return (data >> 1) & 0x3f; } int MPU6050::requestUpdate() @@ -59,11 +60,10 @@ int MPU6050::requestUpdate() status |= DEVICE_COMPONENT_STATUS_IDLE_TICK; - if(int1.getDigitalValue() == 1) { - result = i2c.readRegister(address, 0x3B, (uint8_t *) i2cData, 14); + if (int1.getDigitalValue() == 1) { + result = i2c.readRegister(address, 0x3B, (uint8_t*)i2cData, 14); - if (result != 0) - return DEVICE_I2C_ERROR; + if (result != 0) return DEVICE_I2C_ERROR; sample.x = ((i2cData[0] << 8) | i2cData[1]); sample.y = ((i2cData[2] << 8) | i2cData[3]); @@ -74,7 +74,7 @@ int MPU6050::requestUpdate() gyro.z = (((i2cData[12] << 8) | i2cData[13])); int16_t t = (((i2cData[6] << 8) | i2cData[7])); - temp = t * 10 / 34 + 3653; + temp = t * 10 / 34 + 3653; sample.x /= 16; sample.y /= 16; diff --git a/source/drivers/MessageBus.cpp b/source/drivers/MessageBus.cpp index 8d0fa5df..b15c19df 100644 --- a/source/drivers/MessageBus.cpp +++ b/source/drivers/MessageBus.cpp @@ -23,33 +23,34 @@ DEALINGS IN THE SOFTWARE. */ /** - * Class definition for the MessageBus. - * - * The MessageBus is the common mechanism to deliver asynchronous events on the - * Device platform. It serves a number of purposes: - * - * 1) It provides an eventing abstraction that is independent of the underlying substrate. - * - * 2) It provides a mechanism to decouple user code from trusted system code - * i.e. the basis of a message passing nano kernel. - * - * 3) It allows a common high level eventing abstraction across a range of hardware types.e.g. buttons, BLE... - * - * 4) It provides a mechanim for extensibility - new devices added via I/O pins can have OO based - * drivers and communicate via the message bus with minima impact on user level languages. - * - * 5) It allows for the possiblility of event / data aggregation, which in turn can save energy. - * - * It has the following design principles: - * - * 1) Maintain a low RAM footprint where possible - * - * 2) Make few assumptions about the underlying platform, but allow optimizations where possible. - */ -#include "CodalConfig.h" + * Class definition for the MessageBus. + * + * The MessageBus is the common mechanism to deliver asynchronous events on the + * Device platform. It serves a number of purposes: + * + * 1) It provides an eventing abstraction that is independent of the underlying substrate. + * + * 2) It provides a mechanism to decouple user code from trusted system code + * i.e. the basis of a message passing nano kernel. + * + * 3) It allows a common high level eventing abstraction across a range of hardware types.e.g. buttons, BLE... + * + * 4) It provides a mechanim for extensibility - new devices added via I/O pins can have OO based + * drivers and communicate via the message bus with minima impact on user level languages. + * + * 5) It allows for the possiblility of event / data aggregation, which in turn can save energy. + * + * It has the following design principles: + * + * 1) Maintain a low RAM footprint where possible + * + * 2) Make few assumptions about the underlying platform, but allow optimizations where possible. + */ #include "MessageBus.h" -#include "CodalFiber.h" + +#include "CodalConfig.h" #include "CodalDmesg.h" +#include "CodalFiber.h" #include "ErrorNo.h" #include "NotifyEvents.h" #include "codal_target_hal.h" @@ -59,50 +60,46 @@ using namespace codal; static uint16_t userNotifyId = DEVICE_NOTIFY_USER_EVENT_BASE; /** - * Default constructor. - * - * Adds itself as a fiber component, and also configures itself to be the - * default EventModel if defaultEventBus is NULL. - */ + * Default constructor. + * + * Adds itself as a fiber component, and also configures itself to be the + * default EventModel if defaultEventBus is NULL. + */ MessageBus::MessageBus() { - this->listeners = NULL; + this->listeners = NULL; this->evt_queue_head = NULL; this->evt_queue_tail = NULL; - this->queueLength = 0; + this->queueLength = 0; // ANY listeners for scheduler events MUST be immediate, or else they will not be registered. listen(DEVICE_ID_SCHEDULER, DEVICE_SCHEDULER_EVT_IDLE, this, &MessageBus::idle, MESSAGE_BUS_LISTENER_IMMEDIATE); - if(EventModel::defaultEventBus == NULL) - EventModel::defaultEventBus = this; + if (EventModel::defaultEventBus == NULL) EventModel::defaultEventBus = this; } /** - * Invokes a callback on a given Listener - * - * Internal wrapper function, used to enable - * parameterised callbacks through the fiber scheduler. - */ + * Invokes a callback on a given Listener + * + * Internal wrapper function, used to enable + * parameterised callbacks through the fiber scheduler. + */ REAL_TIME_FUNC -void async_callback(void *param) +void async_callback(void* param) { - Listener *listener = (Listener *)param; + Listener* listener = (Listener*)param; // OK, now we need to decide how to behave depending on our configuration. // If this a fiber f already active within this listener then check our // configuration to determine the correct course of action. // - if (listener->flags & MESSAGE_BUS_LISTENER_BUSY) - { + if (listener->flags & MESSAGE_BUS_LISTENER_BUSY) { // Drop this event, if that's how we've been configured. - if (listener->flags & MESSAGE_BUS_LISTENER_DROP_IF_BUSY) - return; + if (listener->flags & MESSAGE_BUS_LISTENER_DROP_IF_BUSY) return; // Queue this event up for later, if that's how we've been configured. - if (listener->flags & MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY) - { + if (listener->flags & MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY) { listener->queue(listener->evt); return; } @@ -114,11 +111,9 @@ void async_callback(void *param) // Record that we have a fiber going into this listener... listener->flags |= MESSAGE_BUS_LISTENER_BUSY; - while (1) - { + while (1) { // Firstly, check for a method callback into an object. - if (listener->flags & MESSAGE_BUS_LISTENER_METHOD) - listener->cb_method->fire(listener->evt); + if (listener->flags & MESSAGE_BUS_LISTENER_METHOD) listener->cb_method->fire(listener->evt); // Now a parameterised C function else if (listener->flags & MESSAGE_BUS_LISTENER_PARAMETERISED) @@ -128,17 +123,16 @@ void async_callback(void *param) else listener->cb(listener->evt); - // If there are more events to process, dequeue the next one and process it. - if ((listener->flags & MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY) && listener->evt_queue) - { - EventQueueItem *item = listener->evt_queue; + if ((listener->flags & MESSAGE_BUS_LISTENER_QUEUE_IF_BUSY) && listener->evt_queue) { + EventQueueItem* item = listener->evt_queue; - listener->evt = item->evt; + listener->evt = item->evt; listener->evt_queue = listener->evt_queue->next; delete item; - // We spin the scheduler here, to preven any particular event handler from continuously holding onto resources. + // We spin the scheduler here, to preven any particular event handler from continuously holding onto + // resources. schedule(); } else @@ -150,17 +144,17 @@ void async_callback(void *param) } /** - * Queue the given event for processing at a later time. - * Add the given event at the tail of our queue. - * - * @param The event to queue. - */ + * Queue the given event for processing at a later time. + * Add the given event at the tail of our queue. + * + * @param The event to queue. + */ REAL_TIME_FUNC -void MessageBus::queueEvent(Event &evt) +void MessageBus::queueEvent(Event& evt) { int processingComplete; - EventQueueItem *prev = evt_queue_tail; + EventQueueItem* prev = evt_queue_tail; // Now process all handler regsitered as URGENT. // These pre-empt the queue, and are useful for fast, high priority services. @@ -168,14 +162,12 @@ void MessageBus::queueEvent(Event &evt) // If we've already processed all event handlers, we're all done. // No need to queue the event. - if (processingComplete) - return; + if (processingComplete) return; // If we need to queue, but there is no space, then there's nothg we can do. - if (queueLength >= MESSAGE_BUS_LISTENER_MAX_QUEUE_DEPTH) - { + if (queueLength >= MESSAGE_BUS_LISTENER_MAX_QUEUE_DEPTH) { // Note that this can lead to strange lockups, where we await an event that never arrives. - //DMESG("evt %d/%d: overflow!", evt.source, evt.value); + // DMESG("evt %d/%d: overflow!", evt.source, evt.value); return; } @@ -183,24 +175,21 @@ void MessageBus::queueEvent(Event &evt) // We queue this event at the tail of the queue at the point where we entered queueEvent() // This is important as the processing above *may* have generated further events, and // we want to maintain ordering of events. - EventQueueItem *item = new EventQueueItem(evt); + EventQueueItem* item = new EventQueueItem(evt); // The queue was empty when we entered this function, so queue our event at the start of the queue. target_disable_irq(); - if (prev == NULL) - { - item->next = evt_queue_head; + if (prev == NULL) { + item->next = evt_queue_head; evt_queue_head = item; } - else - { + else { item->next = prev->next; prev->next = item; } - if (item->next == NULL) - evt_queue_tail = item; + if (item->next == NULL) evt_queue_tail = item; queueLength++; @@ -208,39 +197,36 @@ void MessageBus::queueEvent(Event &evt) } /** - * Extract the next event from the front of the event queue (if present). - * - * @return a pointer to the EventQueueItem that is at the head of the list. - */ + * Extract the next event from the front of the event queue (if present). + * + * @return a pointer to the EventQueueItem that is at the head of the list. + */ REAL_TIME_FUNC EventQueueItem* MessageBus::dequeueEvent() { - EventQueueItem *item = NULL; + EventQueueItem* item = NULL; target_disable_irq(); - if (evt_queue_head != NULL) - { - item = evt_queue_head; + if (evt_queue_head != NULL) { + item = evt_queue_head; evt_queue_head = item->next; - if (evt_queue_head == NULL) - evt_queue_tail = NULL; + if (evt_queue_head == NULL) evt_queue_tail = NULL; queueLength--; } target_enable_irq(); - return item; } /** - * Cleanup any Listeners marked for deletion from the list. - * - * @return The number of listeners removed from the list. - */ + * Cleanup any Listeners marked for deletion from the list. + * + * @return The number of listeners removed from the list. + */ int MessageBus::deleteMarkedListeners() { Listener *l, *p; @@ -250,18 +236,16 @@ int MessageBus::deleteMarkedListeners() p = NULL; // Walk this list of event handlers. Delete any that match the given listener. - while (l != NULL) - { - if ((l->flags & MESSAGE_BUS_LISTENER_DELETING) && !(l->flags & MESSAGE_BUS_LISTENER_BUSY)) - { + while (l != NULL) { + if ((l->flags & MESSAGE_BUS_LISTENER_DELETING) && !(l->flags & MESSAGE_BUS_LISTENER_BUSY)) { if (p == NULL) listeners = l->next; else p->next = l->next; // delete the listener. - Listener *t = l; - l = l->next; + Listener* t = l; + l = l->next; delete t; removed++; @@ -277,21 +261,21 @@ int MessageBus::deleteMarkedListeners() } /** - * Periodic callback from Device. - * - * Process at least one event from the event queue, if it is not empty. - * We then continue processing events until something appears on the runqueue. - */ + * Periodic callback from Device. + * + * Process at least one event from the event queue, if it is not empty. + * We then continue processing events until something appears on the runqueue. + */ void MessageBus::idle(Event) { // Clear out any listeners marked for deletion this->deleteMarkedListeners(); - EventQueueItem *item = this->dequeueEvent(); + EventQueueItem* item = this->dequeueEvent(); - // Whilst there are events to process and we have no useful other work to do, pull them off the queue and process them. - while (item) - { + // Whilst there are events to process and we have no useful other work to do, pull them off the queue and process + // them. + while (item) { // send the event to all standard event listeners. this->process(item->evt); @@ -301,8 +285,7 @@ void MessageBus::idle(Event) // If we have created some useful work to do, we stop processing. // This helps to minimise the number of blocked fibers we create at any point in time, therefore // also reducing the RAM footprint. - if(!scheduler_runqueue_empty()) - break; + if (!scheduler_runqueue_empty()) break; // Pull the next event to process, if there is one. item = this->dequeueEvent(); @@ -310,25 +293,25 @@ void MessageBus::idle(Event) } /** - * Queues the given event to be sent to all registered recipients. - * - * @param evt The event to send. - * - * @code - * MessageBus bus; - * - * // Creates and sends the Event using bus. - * Event evt(DEVICE_ID_BUTTON_A, DEVICE_BUTTON_EVT_CLICK); - * - * // Creates the Event, but delays the sending of that event. - * Event evt1(DEVICE_ID_BUTTON_A, DEVICE_BUTTON_EVT_CLICK, CREATE_ONLY); - * - * bus.send(evt1); - * - * // This has the same effect! - * evt1.fire() - * @endcode - */ + * Queues the given event to be sent to all registered recipients. + * + * @param evt The event to send. + * + * @code + * MessageBus bus; + * + * // Creates and sends the Event using bus. + * Event evt(DEVICE_ID_BUTTON_A, DEVICE_BUTTON_EVT_CLICK); + * + * // Creates the Event, but delays the sending of that event. + * Event evt1(DEVICE_ID_BUTTON_A, DEVICE_BUTTON_EVT_CLICK, CREATE_ONLY); + * + * bus.send(evt1); + * + * // This has the same effect! + * evt1.fire() + * @endcode + */ REAL_TIME_FUNC int MessageBus::send(Event evt) { @@ -340,32 +323,30 @@ int MessageBus::send(Event evt) } /** - * Internal function, used to deliver the given event to all relevant recipients. - * Normally, this is called once an event has been removed from the event queue. - * - * @param evt The event to send. - * - * @param urgent The type of listeners to process (optional). If set to true, only listeners defined as urgent and non-blocking will be processed - * otherwise, all other (standard) listeners will be processed. Defaults to false. - * - * @return 1 if all matching listeners were processed, 0 if further processing is required. - * - * @note It is recommended that all external code uses the send() function instead of this function, - * or the constructors provided by Event. - */ + * Internal function, used to deliver the given event to all relevant recipients. + * Normally, this is called once an event has been removed from the event queue. + * + * @param evt The event to send. + * + * @param urgent The type of listeners to process (optional). If set to true, only listeners defined as urgent and + * non-blocking will be processed otherwise, all other (standard) listeners will be processed. Defaults to false. + * + * @return 1 if all matching listeners were processed, 0 if further processing is required. + * + * @note It is recommended that all external code uses the send() function instead of this function, + * or the constructors provided by Event. + */ REAL_TIME_FUNC -int MessageBus::process(Event &evt, bool urgent) +int MessageBus::process(Event& evt, bool urgent) { - Listener *l; + Listener* l; int complete = 1; bool listenerUrgent; l = listeners; - while (l != NULL) - { - if((l->id == evt.source || l->id == DEVICE_ID_ANY) && (l->value == evt.value || l->value == DEVICE_EVT_ANY)) - { + while (l != NULL) { + if ((l->id == evt.source || l->id == DEVICE_ID_ANY) && (l->value == evt.value || l->value == DEVICE_EVT_ANY)) { // If we're running under the fiber scheduler, then derive the THREADING_MODE for the callback based on the // metadata in the listener itself. if (fiber_scheduler_running()) @@ -374,8 +355,7 @@ int MessageBus::process(Event &evt, bool urgent) listenerUrgent = true; // If we should process this event hander in this pass, then activate the listener. - if(listenerUrgent == urgent && !(l->flags & MESSAGE_BUS_LISTENER_DELETING)) - { + if (listenerUrgent == urgent && !(l->flags & MESSAGE_BUS_LISTENER_DELETING)) { l->evt = evt; // OK, if this handler has regisitered itself as non-blocking, we just execute it directly... @@ -395,27 +375,26 @@ int MessageBus::process(Event &evt, bool urgent) l = l->next; } - //Serial.println("EXIT"); - //while (!(UCSR0A & _BV(TXC0))); + // Serial.println("EXIT"); + // while (!(UCSR0A & _BV(TXC0))); return complete; } /** - * Add the given Listener to the list of event handlers, unconditionally. - * - * @param listener The Listener to add. - * - * @return DEVICE_OK if the listener is valid, DEVICE_INVALID_PARAMETER otherwise. - */ -int MessageBus::add(Listener *newListener) + * Add the given Listener to the list of event handlers, unconditionally. + * + * @param listener The Listener to add. + * + * @return DEVICE_OK if the listener is valid, DEVICE_INVALID_PARAMETER otherwise. + */ +int MessageBus::add(Listener* newListener) { Listener *l, *p; int methodCallback; - //handler can't be NULL! - if (newListener == NULL) - return DEVICE_INVALID_PARAMETER; + // handler can't be NULL! + if (newListener == NULL) return DEVICE_INVALID_PARAMETER; l = listeners; @@ -424,17 +403,16 @@ int MessageBus::add(Listener *newListener) // We always check the ID, VALUE and CB_METHOD fields. // If we have a callback to a method, check the cb_method class. Otherwise, the cb function point is sufficient. - while (l != NULL) - { + while (l != NULL) { methodCallback = (newListener->flags & MESSAGE_BUS_LISTENER_METHOD) && (l->flags & MESSAGE_BUS_LISTENER_METHOD); - if (l->id == newListener->id && l->value == newListener->value && (methodCallback ? *l->cb_method == *newListener->cb_method : l->cb == newListener->cb) && newListener->cb_arg == l->cb_arg) - { + if (l->id == newListener->id && l->value == newListener->value && + (methodCallback ? *l->cb_method == *newListener->cb_method : l->cb == newListener->cb) && + newListener->cb_arg == l->cb_arg) { // We have a perfect match for this event listener already registered. // If it's marked for deletion, we simply resurrect the listener, and we're done. // Either way, we return an error code, as the *new* listener should be released... - if(l->flags & MESSAGE_BUS_LISTENER_DELETING) - l->flags &= ~MESSAGE_BUS_LISTENER_DELETING; + if (l->flags & MESSAGE_BUS_LISTENER_DELETING) l->flags &= ~MESSAGE_BUS_LISTENER_DELETING; return DEVICE_NOT_SUPPORTED; } @@ -444,8 +422,7 @@ int MessageBus::add(Listener *newListener) // We have a valid, new event handler. Add it to the list. // if listeners is null - we can automatically add this listener to the list at the beginning... - if (listeners == NULL) - { + if (listeners == NULL) { listeners = newListener; Event(DEVICE_ID_MESSAGE_BUS_LISTENER, newListener->id); @@ -460,32 +437,28 @@ int MessageBus::add(Listener *newListener) p = listeners; l = listeners; - while (l != NULL && l->id < newListener->id) - { + while (l != NULL && l->id < newListener->id) { p = l; l = l->next; } - while (l != NULL && l->id == newListener->id && l->value < newListener->value) - { + while (l != NULL && l->id == newListener->id && l->value < newListener->value) { p = l; l = l->next; } - //add at front of list - if (p == listeners && (newListener->id < p->id || (p->id == newListener->id && p->value > newListener->value))) - { + // add at front of list + if (p == listeners && (newListener->id < p->id || (p->id == newListener->id && p->value > newListener->value))) { newListener->next = p; - //this new listener is now the front! + // this new listener is now the front! listeners = newListener; } - //add after p - else - { + // add after p + else { newListener->next = p->next; - p->next = newListener; + p->next = newListener; } Event(DEVICE_ID_MESSAGE_BUS_LISTENER, newListener->id); @@ -493,36 +466,31 @@ int MessageBus::add(Listener *newListener) } /** - * Remove the given Listener from the list of event handlers. - * - * @param listener The Listener to remove. - * - * @return DEVICE_OK if the listener is valid, DEVICE_INVALID_PARAMETER otherwise. - */ -int MessageBus::remove(Listener *listener) + * Remove the given Listener from the list of event handlers. + * + * @param listener The Listener to remove. + * + * @return DEVICE_OK if the listener is valid, DEVICE_INVALID_PARAMETER otherwise. + */ +int MessageBus::remove(Listener* listener) { - Listener *l; + Listener* l; int removed = 0; - //handler can't be NULL! - if (listener == NULL) - return DEVICE_INVALID_PARAMETER; + // handler can't be NULL! + if (listener == NULL) return DEVICE_INVALID_PARAMETER; l = listeners; // Walk this list of event handlers. Delete any that match the given listener. - while (l != NULL) - { - if ((listener->flags & MESSAGE_BUS_LISTENER_METHOD) == (l->flags & MESSAGE_BUS_LISTENER_METHOD)) - { - if(((listener->flags & MESSAGE_BUS_LISTENER_METHOD) && (*l->cb_method == *listener->cb_method)) || - ((!(listener->flags & MESSAGE_BUS_LISTENER_METHOD) && l->cb == listener->cb))) - { - if ((listener->id == DEVICE_ID_ANY || listener->id == l->id) && (listener->value == DEVICE_EVT_ANY || listener->value == l->value)) - { + while (l != NULL) { + if ((listener->flags & MESSAGE_BUS_LISTENER_METHOD) == (l->flags & MESSAGE_BUS_LISTENER_METHOD)) { + if (((listener->flags & MESSAGE_BUS_LISTENER_METHOD) && (*l->cb_method == *listener->cb_method)) || + ((!(listener->flags & MESSAGE_BUS_LISTENER_METHOD) && l->cb == listener->cb))) { + if ((listener->id == DEVICE_ID_ANY || listener->id == l->id) && + (listener->value == DEVICE_EVT_ANY || listener->value == l->value)) { // If notification of deletion has been requested, invoke the listener deletion callback. - if (listener_deletion_callback) - listener_deletion_callback(l); + if (listener_deletion_callback) listener_deletion_callback(l); // Found a match. mark this to be removed from the list. l->flags |= MESSAGE_BUS_LISTENER_DELETING; @@ -541,20 +509,18 @@ int MessageBus::remove(Listener *listener) } /** - * Returns the Listener with the given position in our list. - * - * @param n The position in the list to return. - * - * @return the Listener at postion n in the list, or NULL if the position is invalid. - */ + * Returns the Listener with the given position in our list. + * + * @param n The position in the list to return. + * + * @return the Listener at postion n in the list, or NULL if the position is invalid. + */ Listener* MessageBus::elementAt(int n) { - Listener *l = listeners; + Listener* l = listeners; - while (n > 0) - { - if (l == NULL) - return NULL; + while (n > 0) { + if (l == NULL) return NULL; n--; l = l->next; @@ -573,11 +539,11 @@ uint16_t allocateNotifyEvent() return userNotifyId++; } -} +} // namespace codal /** - * Destructor for MessageBus, where we deregister this instance from the array of fiber components. - */ + * Destructor for MessageBus, where we deregister this instance from the array of fiber components. + */ MessageBus::~MessageBus() { ignore(DEVICE_ID_SCHEDULER, DEVICE_EVT_ANY, this, &MessageBus::idle); diff --git a/source/drivers/MultiButton.cpp b/source/drivers/MultiButton.cpp index d8ba27f2..8e06d6b2 100644 --- a/source/drivers/MultiButton.cpp +++ b/source/drivers/MultiButton.cpp @@ -23,14 +23,15 @@ DEALINGS IN THE SOFTWARE. */ /** - * Class definition for a MultiButton. - * - * Represents a virtual button, capable of reacting to simultaneous presses of two - * other buttons. - */ -#include "CodalConfig.h" + * Class definition for a MultiButton. + * + * Represents a virtual button, capable of reacting to simultaneous presses of two + * other buttons. + */ #include "MultiButton.h" +#include "CodalConfig.h" + using namespace codal; /** @@ -51,103 +52,96 @@ using namespace codal; */ MultiButton::MultiButton(uint16_t button1, uint16_t button2, uint16_t id) { - this->id = id; - this->button1 = button1; - this->button2 = button2; + this->id = id; + this->button1 = button1; + this->button2 = button2; this->eventConfiguration = DEVICE_BUTTON_SIMPLE_EVENTS; - if (EventModel::defaultEventBus) - { - EventModel::defaultEventBus->listen(button1, DEVICE_EVT_ANY, this, &MultiButton::onButtonEvent, MESSAGE_BUS_LISTENER_IMMEDIATE); - EventModel::defaultEventBus->listen(button2, DEVICE_EVT_ANY, this, &MultiButton::onButtonEvent, MESSAGE_BUS_LISTENER_IMMEDIATE); + if (EventModel::defaultEventBus) { + EventModel::defaultEventBus->listen(button1, DEVICE_EVT_ANY, this, &MultiButton::onButtonEvent, + MESSAGE_BUS_LISTENER_IMMEDIATE); + EventModel::defaultEventBus->listen(button2, DEVICE_EVT_ANY, this, &MultiButton::onButtonEvent, + MESSAGE_BUS_LISTENER_IMMEDIATE); } } /** - * Retrieves the button id for the alternate button id given. - * - * @param b the id of the button whose state we would like to retrieve. - * - * @return the other sub button id. - */ + * Retrieves the button id for the alternate button id given. + * + * @param b the id of the button whose state we would like to retrieve. + * + * @return the other sub button id. + */ uint16_t MultiButton::otherSubButton(uint16_t b) { return (b == button1 ? button2 : button1); } /** - * Determines if the given button id is marked as pressed. - * - * @param button the id of the button whose state we would like to retrieve. - * - * @return 1 if pressed, 0 if not. - */ + * Determines if the given button id is marked as pressed. + * + * @param button the id of the button whose state we would like to retrieve. + * + * @return 1 if pressed, 0 if not. + */ int MultiButton::isSubButtonPressed(uint16_t button) { - if (button == button1) - return status & MULTI_BUTTON_STATE_1; + if (button == button1) return status & MULTI_BUTTON_STATE_1; - if (button == button2) - return status & MULTI_BUTTON_STATE_2; + if (button == button2) return status & MULTI_BUTTON_STATE_2; return 0; } /** - * Determines if the given button id is marked as held. - * - * @param button the id of the button whose state we would like to retrieve. - * - * @return 1 if held, 0 if not. - */ + * Determines if the given button id is marked as held. + * + * @param button the id of the button whose state we would like to retrieve. + * + * @return 1 if held, 0 if not. + */ int MultiButton::isSubButtonHeld(uint16_t button) { - if (button == button1) - return status & MULTI_BUTTON_HOLD_TRIGGERED_1; + if (button == button1) return status & MULTI_BUTTON_HOLD_TRIGGERED_1; - if (button == button2) - return status & MULTI_BUTTON_HOLD_TRIGGERED_2; + if (button == button2) return status & MULTI_BUTTON_HOLD_TRIGGERED_2; return 0; } /** - * Determines if the given button id is marked as supressed. - * - * @param button the id of the button whose state we would like to retrieve. - * - * @return 1 if supressed, 0 if not. - */ + * Determines if the given button id is marked as supressed. + * + * @param button the id of the button whose state we would like to retrieve. + * + * @return 1 if supressed, 0 if not. + */ int MultiButton::isSubButtonSupressed(uint16_t button) { - if (button == button1) - return status & MULTI_BUTTON_SUPRESSED_1; + if (button == button1) return status & MULTI_BUTTON_SUPRESSED_1; - if (button == button2) - return status & MULTI_BUTTON_SUPRESSED_2; + if (button == button2) return status & MULTI_BUTTON_SUPRESSED_2; return 0; } /** - * Configures the button pressed state for the given button id. - * - * @param button the id of the button whose state requires updating. - * - * @param value the value to set for this buttons state. (Transformed into a logical 0 or 1). - */ + * Configures the button pressed state for the given button id. + * + * @param button the id of the button whose state requires updating. + * + * @param value the value to set for this buttons state. (Transformed into a logical 0 or 1). + */ void MultiButton::setButtonState(uint16_t button, int value) { - if (button == button1) - { + if (button == button1) { if (value) status |= MULTI_BUTTON_STATE_1; else status &= ~MULTI_BUTTON_STATE_1; } - if (button == button2) - { + if (button == button2) { if (value) status |= MULTI_BUTTON_STATE_2; else @@ -156,24 +150,22 @@ void MultiButton::setButtonState(uint16_t button, int value) } /** - * Configures the button held state for the given button id. - * - * @param button the id of the button whose state requires updating. - * - * @param value the value to set for this buttons state. (Transformed into a logical 0 or 1). - */ + * Configures the button held state for the given button id. + * + * @param button the id of the button whose state requires updating. + * + * @param value the value to set for this buttons state. (Transformed into a logical 0 or 1). + */ void MultiButton::setHoldState(uint16_t button, int value) { - if (button == button1) - { + if (button == button1) { if (value) status |= MULTI_BUTTON_HOLD_TRIGGERED_1; else status &= ~MULTI_BUTTON_HOLD_TRIGGERED_1; } - if (button == button2) - { + if (button == button2) { if (value) status |= MULTI_BUTTON_HOLD_TRIGGERED_2; else @@ -182,24 +174,22 @@ void MultiButton::setHoldState(uint16_t button, int value) } /** - * Configures the button suppressed state for the given button id. - * - * @param button the id of the button whose state requires updating. - * - * @param value the value to set for this buttons state. (Transformed into a logical 0 or 1). - */ + * Configures the button suppressed state for the given button id. + * + * @param button the id of the button whose state requires updating. + * + * @param value the value to set for this buttons state. (Transformed into a logical 0 or 1). + */ void MultiButton::setSupressedState(uint16_t button, int value) { - if (button == button1) - { + if (button == button1) { if (value) status |= MULTI_BUTTON_SUPRESSED_1; else status &= ~MULTI_BUTTON_SUPRESSED_1; } - if (button == button2) - { + if (button == button2) { if (value) status |= MULTI_BUTTON_SUPRESSED_2; else @@ -211,7 +201,8 @@ void MultiButton::setSupressedState(uint16_t button, int value) * Changes the event configuration of this button to the given ButtonEventConfiguration. * All subsequent events generated by this button will then be informed by this configuration. * - * @param config The new configuration for this button. Legal values are DEVICE_BUTTON_ALL_EVENTS or DEVICE_BUTTON_SIMPLE_EVENTS. + * @param config The new configuration for this button. Legal values are DEVICE_BUTTON_ALL_EVENTS or + * DEVICE_BUTTON_SIMPLE_EVENTS. * * @code * // Configure a button to generate all possible events. @@ -227,38 +218,34 @@ void MultiButton::setEventConfiguration(ButtonEventConfiguration config) } /** - * A member function that is invoked when any event is detected from the two - * button IDs this MultiButton instance was constructed with. - * - * @param evt the event received from the default EventModel. - */ + * A member function that is invoked when any event is detected from the two + * button IDs this MultiButton instance was constructed with. + * + * @param evt the event received from the default EventModel. + */ void MultiButton::onButtonEvent(Event evt) { - int button = evt.source; + int button = evt.source; int otherButton = otherSubButton(button); - switch(evt.value) - { + switch (evt.value) { case DEVICE_BUTTON_EVT_DOWN: setButtonState(button, 1); - if(isSubButtonPressed(otherButton)) - { + if (isSubButtonPressed(otherButton)) { Event e(id, DEVICE_BUTTON_EVT_DOWN); clickCount++; } - break; + break; case DEVICE_BUTTON_EVT_HOLD: setHoldState(button, 1); - if(isSubButtonHeld(otherButton)) - Event e(id, DEVICE_BUTTON_EVT_HOLD); + if (isSubButtonHeld(otherButton)) Event e(id, DEVICE_BUTTON_EVT_HOLD); - break; + break; case DEVICE_BUTTON_EVT_UP: - if(isSubButtonPressed(otherButton)) - { + if (isSubButtonPressed(otherButton)) { Event e(id, DEVICE_BUTTON_EVT_UP); if (isSubButtonHeld(button) && isSubButtonHeld(otherButton)) @@ -268,8 +255,7 @@ void MultiButton::onButtonEvent(Event evt) setSupressedState(otherButton, 1); } - else if (!isSubButtonSupressed(button) && eventConfiguration == DEVICE_BUTTON_ALL_EVENTS) - { + else if (!isSubButtonSupressed(button) && eventConfiguration == DEVICE_BUTTON_ALL_EVENTS) { if (isSubButtonHeld(button)) Event e(button, DEVICE_BUTTON_EVT_LONG_CLICK); else @@ -280,22 +266,20 @@ void MultiButton::onButtonEvent(Event evt) setHoldState(button, 0); setSupressedState(button, 0); - break; - + break; } } - /** - * Tests if this MultiButton instance is virtually pressed. - * - * @return 1 if both physical buttons are pressed simultaneously. - * - * @code - * if(buttonAB.isPressed()) - * display.scroll("Pressed!"); - * @endcode - */ + * Tests if this MultiButton instance is virtually pressed. + * + * @return 1 if both physical buttons are pressed simultaneously. + * + * @code + * if(buttonAB.isPressed()) + * display.scroll("Pressed!"); + * @endcode + */ int MultiButton::isPressed() { return ((status & MULTI_BUTTON_STATE_1) && (status & MULTI_BUTTON_STATE_2)); diff --git a/source/drivers/NonLinearAnalogSensor.cpp b/source/drivers/NonLinearAnalogSensor.cpp index ab0c17d8..cf4850c7 100644 --- a/source/drivers/NonLinearAnalogSensor.cpp +++ b/source/drivers/NonLinearAnalogSensor.cpp @@ -23,8 +23,9 @@ DEALINGS IN THE SOFTWARE. */ /** - * Class definition for a normalised, non-linear analog sensor, that takes the general form of a logarithmic response to a sensed value, in a potential divider. - * Implements a base class for such a sensor, using the Steinhart-Hart equation to delineate a result. + * Class definition for a normalised, non-linear analog sensor, that takes the general form of a logarithmic response to + * a sensed value, in a potential divider. Implements a base class for such a sensor, using the Steinhart-Hart equation + * to delineate a result. */ #include "NonLinearAnalogSensor.h" @@ -43,13 +44,15 @@ using namespace codal; * @param seriesResistor The value (in ohms) of the resistor in series with the sensor. * @param zeroOffset Optional zero offset applied to all SI units (e.g. 273.15 for temperature sensing in C vs Kelvin). */ -NonLinearAnalogSensor::NonLinearAnalogSensor(Pin &pin, uint16_t id, float nominalValue, float nominalReading, float beta, float seriesResistor, float zeroOffset) : AnalogSensor(pin, id) +NonLinearAnalogSensor::NonLinearAnalogSensor(Pin& pin, uint16_t id, float nominalValue, float nominalReading, + float beta, float seriesResistor, float zeroOffset) + : AnalogSensor(pin, id) { - this->nominalValue = nominalValue; + this->nominalValue = nominalValue; this->nominalReading = nominalReading; - this->beta = beta; + this->beta = beta; this->seriesResistor = seriesResistor; - this->zeroOffset = zeroOffset; + this->zeroOffset = zeroOffset; } /** @@ -63,17 +66,19 @@ void NonLinearAnalogSensor::updateSample() float value; sensorReading = (((1023.0f) * this->seriesResistor) / this->readValue()) - this->seriesResistor; - value = (1.0f / ((log(sensorReading / this->nominalReading) / this->beta) + (1.0f / (this->nominalValue + this->zeroOffset)))) - this->zeroOffset; + value = (1.0f / ((log(sensorReading / this->nominalReading) / this->beta) + + (1.0f / (this->nominalValue + this->zeroOffset)))) - + this->zeroOffset; - // If this is the first reading performed, take it a a baseline. Otherwise, perform a decay average to smooth out the data. - if (!(status & ANALOG_SENSOR_INITIALISED)) - { + // If this is the first reading performed, take it a a baseline. Otherwise, perform a decay average to smooth out + // the data. + if (!(status & ANALOG_SENSOR_INITIALISED)) { this->sensorValue = value; - this->status |= ANALOG_SENSOR_INITIALISED; + this->status |= ANALOG_SENSOR_INITIALISED; } - else - { - this->sensorValue = ((this->sensorValue * (1023 - this->sensitivity)) + ((uint16_t)value * this->sensitivity)) >> 10; + else { + this->sensorValue = + ((this->sensorValue * (1023 - this->sensitivity)) + ((uint16_t)value * this->sensitivity)) >> 10; } checkThresholding(); diff --git a/source/drivers/PearsonHash.cpp b/source/drivers/PearsonHash.cpp index f77ceb0e..5d91b054 100644 --- a/source/drivers/PearsonHash.cpp +++ b/source/drivers/PearsonHash.cpp @@ -3,24 +3,18 @@ using namespace codal; const unsigned char hashTable[256] = { - 251, 175, 119, 215, 81, 14, 79, 191, 103, 49, 181, 143, 186, 157, 0, - 232, 31, 32, 55, 60, 152, 58, 17, 237, 174, 70, 160, 144, 220, 90, 57, - 223, 59, 3, 18, 140, 111, 166, 203, 196, 134, 243, 124, 95, 222, 179, - 197, 65, 180, 48, 36, 15, 107, 46, 233, 130, 165, 30, 123, 161, 209, 23, - 97, 16, 40, 91, 219, 61, 100, 10, 210, 109, 250, 127, 22, 138, 29, 108, - 244, 67, 207, 9, 178, 204, 74, 98, 126, 249, 167, 116, 34, 77, 193, - 200, 121, 5, 20, 113, 71, 35, 128, 13, 182, 94, 25, 226, 227, 199, 75, - 27, 41, 245, 230, 224, 43, 225, 177, 26, 155, 150, 212, 142, 218, 115, - 241, 73, 88, 105, 39, 114, 62, 255, 192, 201, 145, 214, 168, 158, 221, - 148, 154, 122, 12, 84, 82, 163, 44, 139, 228, 236, 205, 242, 217, 11, - 187, 146, 159, 64, 86, 239, 195, 42, 106, 198, 118, 112, 184, 172, 87, - 2, 173, 117, 176, 229, 247, 253, 137, 185, 99, 164, 102, 147, 45, 66, - 231, 52, 141, 211, 194, 206, 246, 238, 56, 110, 78, 248, 63, 240, 189, - 93, 92, 51, 53, 183, 19, 171, 72, 50, 33, 104, 101, 69, 8, 252, 83, 120, - 76, 135, 85, 54, 202, 125, 188, 213, 96, 235, 136, 208, 162, 129, 190, - 132, 156, 38, 47, 1, 7, 254, 24, 4, 216, 131, 89, 21, 28, 133, 37, 153, - 149, 80, 170, 68, 6, 169, 234, 151 -}; + 251, 175, 119, 215, 81, 14, 79, 191, 103, 49, 181, 143, 186, 157, 0, 232, 31, 32, 55, 60, 152, 58, + 17, 237, 174, 70, 160, 144, 220, 90, 57, 223, 59, 3, 18, 140, 111, 166, 203, 196, 134, 243, 124, 95, + 222, 179, 197, 65, 180, 48, 36, 15, 107, 46, 233, 130, 165, 30, 123, 161, 209, 23, 97, 16, 40, 91, + 219, 61, 100, 10, 210, 109, 250, 127, 22, 138, 29, 108, 244, 67, 207, 9, 178, 204, 74, 98, 126, 249, + 167, 116, 34, 77, 193, 200, 121, 5, 20, 113, 71, 35, 128, 13, 182, 94, 25, 226, 227, 199, 75, 27, + 41, 245, 230, 224, 43, 225, 177, 26, 155, 150, 212, 142, 218, 115, 241, 73, 88, 105, 39, 114, 62, 255, + 192, 201, 145, 214, 168, 158, 221, 148, 154, 122, 12, 84, 82, 163, 44, 139, 228, 236, 205, 242, 217, 11, + 187, 146, 159, 64, 86, 239, 195, 42, 106, 198, 118, 112, 184, 172, 87, 2, 173, 117, 176, 229, 247, 253, + 137, 185, 99, 164, 102, 147, 45, 66, 231, 52, 141, 211, 194, 206, 246, 238, 56, 110, 78, 248, 63, 240, + 189, 93, 92, 51, 53, 183, 19, 171, 72, 50, 33, 104, 101, 69, 8, 252, 83, 120, 76, 135, 85, 54, + 202, 125, 188, 213, 96, 235, 136, 208, 162, 129, 190, 132, 156, 38, 47, 1, 7, 254, 24, 4, 216, 131, + 89, 21, 28, 133, 37, 153, 149, 80, 170, 68, 6, 169, 234, 151}; // REF: https://en.wikipedia.org/wiki/Pearson_hashing inline unsigned char eightBitHash(const char* s) @@ -34,15 +28,14 @@ uint32_t PearsonHash::hashN(ManagedString s, uint8_t byteCount) { unsigned char hash; uint32_t length = s.length() + 1; - char *buffer = (char *)malloc(length); + char* buffer = (char*)malloc(length); memcpy(buffer, s.toCharArray(), length); uint32_t res = 0; - uint32_t i = 0; + uint32_t i = 0; - while (i < byteCount) - { + while (i < byteCount) { hash = eightBitHash(buffer); res |= (hash << (i * 8)); buffer[0] = (buffer[0] + 1) % 255; @@ -61,10 +54,10 @@ uint8_t PearsonHash::hash8(ManagedString s) uint16_t PearsonHash::hash16(ManagedString s) { - return (uint16_t)hashN(s,2); + return (uint16_t)hashN(s, 2); } uint32_t PearsonHash::hash32(ManagedString s) { - return (uint32_t)hashN(s,4); + return (uint32_t)hashN(s, 4); } \ No newline at end of file diff --git a/source/drivers/PulseIn.cpp b/source/drivers/PulseIn.cpp index 8eae3ed2..f65ceee7 100644 --- a/source/drivers/PulseIn.cpp +++ b/source/drivers/PulseIn.cpp @@ -23,8 +23,9 @@ DEALINGS IN THE SOFTWARE. */ #include "PulseIn.h" -#include "Timer.h" + #include "CodalDmesg.h" +#include "Timer.h" using namespace codal; @@ -32,38 +33,38 @@ bool PulseIn::timeoutGeneratorStarted = false; /** * Creates a new instance of a synchronous pulse detector ont he given pin. - * + * * @param pin The pin to observe for pulse events * @return the period of the next pulse in microseconds, or XXX if the given timeout expires. */ -PulseIn::PulseIn(Pin &p) : pin(p) +PulseIn::PulseIn(Pin& p) : pin(p) { lastPeriod = 0; - lastEdge = 0; - enabled = false; + lastEdge = 0; + enabled = false; lock.wait(); } /** * Synchronously await a pulse, and return the period of the pulse. - * + * * @param timeout The maximum amount of time to wait for a pulse, in microseconds. Set to zero to wait indefinitely. * @return The period of the next pulse, in microseconds, or DEVICE_CANCELLED if the timeout passes. */ -int -PulseIn::awaitPulse(int timeout) +int PulseIn::awaitPulse(int timeout) { // perform lazy initialisation of our dependencies - if (!enabled) - { + if (!enabled) { // Configure the requested pin to supply pulse events. pin.eventOn(DEVICE_PIN_EVENT_ON_PULSE); - EventModel::defaultEventBus->listen(pin.id, pin.getPolarity() ? DEVICE_PIN_EVT_PULSE_HI : DEVICE_PIN_EVT_PULSE_LO, this, &PulseIn::onPulse, MESSAGE_BUS_LISTENER_IMMEDIATE); - EventModel::defaultEventBus->listen(DEVICE_ID_PULSE_IN, DEVICE_EVT_PULSE_IN_TIMEOUT, this, &PulseIn::onTimeout, MESSAGE_BUS_LISTENER_IMMEDIATE); + EventModel::defaultEventBus->listen(pin.id, + pin.getPolarity() ? DEVICE_PIN_EVT_PULSE_HI : DEVICE_PIN_EVT_PULSE_LO, this, + &PulseIn::onPulse, MESSAGE_BUS_LISTENER_IMMEDIATE); + EventModel::defaultEventBus->listen(DEVICE_ID_PULSE_IN, DEVICE_EVT_PULSE_IN_TIMEOUT, this, &PulseIn::onTimeout, + MESSAGE_BUS_LISTENER_IMMEDIATE); - if (!timeoutGeneratorStarted) - { + if (!timeoutGeneratorStarted) { system_timer_event_every_us(10000, DEVICE_ID_PULSE_IN, DEVICE_EVT_PULSE_IN_TIMEOUT); timeoutGeneratorStarted = true; } @@ -75,7 +76,7 @@ PulseIn::awaitPulse(int timeout) this->timeout = system_timer_current_time_us() + timeout; else this->timeout = 0; - + lastPeriod = 0; lock.wait(); @@ -83,18 +84,17 @@ PulseIn::awaitPulse(int timeout) if (lastPeriod != 0) return lastPeriod; else - return DEVICE_CANCELLED; + return DEVICE_CANCELLED; } /** * Event handler called when a pulse is detected. */ -void -PulseIn::onPulse(Event e) +void PulseIn::onPulse(Event e) { - timeout = 0; - lastPeriod = (uint32_t) e.timestamp; - + timeout = 0; + lastPeriod = (uint32_t)e.timestamp; + // Wake any blocked fibers and reset the lock. lock.notifyAll(); lock.wait(); @@ -103,12 +103,10 @@ PulseIn::onPulse(Event e) /** * Event handler called when a timeout event is generated. */ -void -PulseIn::onTimeout(Event e) +void PulseIn::onTimeout(Event e) { - if (timeout && system_timer_current_time_us() > timeout) - { - timeout = 0; + if (timeout && system_timer_current_time_us() > timeout) { + timeout = 0; lastPeriod = 0; // Wake any blocked fibers and reset the lock. @@ -123,29 +121,29 @@ PulseIn::onTimeout(Event e) * to allow it to be used by a different peripheral. * * @param pin the Pin to be released. - * @return DEVICE_OK on success, or DEVICE_NOT_IMPLEMENTED if unsupported, or DEVICE_INVALID_PARAMETER if the pin is not bound to this peripheral. + * @return DEVICE_OK on success, or DEVICE_NOT_IMPLEMENTED if unsupported, or DEVICE_INVALID_PARAMETER if the pin is not + * bound to this peripheral. */ -int PulseIn::releasePin(Pin &pin) +int PulseIn::releasePin(Pin& pin) { // We've been asked to disconnect from the given pin. // As we do nothing else, simply disable ourselves. disable(); - if (deleteOnRelease) - delete this; + if (deleteOnRelease) delete this; return DEVICE_OK; } void PulseIn::disable() { - if (enabled) - { + if (enabled) { enabled = false; - EventModel::defaultEventBus->ignore(pin.id, pin.getPolarity() ? DEVICE_PIN_EVT_PULSE_HI : DEVICE_PIN_EVT_PULSE_LO, this, &PulseIn::onPulse); + EventModel::defaultEventBus->ignore( + pin.id, pin.getPolarity() ? DEVICE_PIN_EVT_PULSE_HI : DEVICE_PIN_EVT_PULSE_LO, this, &PulseIn::onPulse); EventModel::defaultEventBus->ignore(DEVICE_ID_PULSE_IN, DEVICE_EVT_PULSE_IN_TIMEOUT, this, &PulseIn::onTimeout); - //pin.eventOn(DEVICE_PIN_EVENT_NONE); - timeout = 0; + // pin.eventOn(DEVICE_PIN_EVENT_NONE); + timeout = 0; lastPeriod = 0; lock.notifyAll(); } diff --git a/source/drivers/ST7735.cpp b/source/drivers/ST7735.cpp index fb6ec386..09223323 100644 --- a/source/drivers/ST7735.cpp +++ b/source/drivers/ST7735.cpp @@ -1,40 +1,40 @@ #include "ST7735.h" -#include "CodalFiber.h" + #include "CodalDmesg.h" +#include "CodalFiber.h" #define SWAP 0 -#define assert(cond) \ - if (!(cond)) \ - target_panic(909) +#define assert(cond) \ + if (!(cond)) target_panic(909) -#define ST7735_NOP 0x00 +#define ST7735_NOP 0x00 #define ST7735_SWRESET 0x01 -#define ST7735_RDDID 0x04 -#define ST7735_RDDST 0x09 +#define ST7735_RDDID 0x04 +#define ST7735_RDDST 0x09 -#define ST7735_SLPIN 0x10 +#define ST7735_SLPIN 0x10 #define ST7735_SLPOUT 0x11 -#define ST7735_PTLON 0x12 -#define ST7735_NORON 0x13 +#define ST7735_PTLON 0x12 +#define ST7735_NORON 0x13 -#define ST7735_INVOFF 0x20 -#define ST7735_INVON 0x21 +#define ST7735_INVOFF 0x20 +#define ST7735_INVON 0x21 #define ST7735_DISPOFF 0x28 -#define ST7735_DISPON 0x29 -#define ST7735_CASET 0x2A -#define ST7735_RASET 0x2B -#define ST7735_RAMWR 0x2C -#define ST7735_RAMRD 0x2E +#define ST7735_DISPON 0x29 +#define ST7735_CASET 0x2A +#define ST7735_RASET 0x2B +#define ST7735_RAMWR 0x2C +#define ST7735_RAMRD 0x2E -#define ST7735_PTLAR 0x30 +#define ST7735_PTLAR 0x30 #define ST7735_COLMOD 0x3A #define ST7735_MADCTL 0x36 #define ST7735_FRMCTR1 0xB1 #define ST7735_FRMCTR2 0xB2 #define ST7735_FRMCTR3 0xB3 -#define ST7735_INVCTR 0xB4 +#define ST7735_INVCTR 0xB4 #define ST7735_DISSET5 0xB6 #define ST7735_PWCTR1 0xC0 @@ -54,20 +54,19 @@ #define ST7735_GMCTRP1 0xE0 #define ST7735_GMCTRN1 0xE1 -#define MADCTL_MY 0x80 -#define MADCTL_MX 0x40 -#define MADCTL_MV 0x20 -#define MADCTL_ML 0x10 +#define MADCTL_MY 0x80 +#define MADCTL_MX 0x40 +#define MADCTL_MV 0x20 +#define MADCTL_ML 0x10 #define MADCTL_RGB 0x00 #define MADCTL_BGR 0x08 -#define MADCTL_MH 0x04 +#define MADCTL_MH 0x04 -namespace codal -{ +namespace codal { -ST7735::ST7735(ScreenIO &io, Pin &cs, Pin &dc) : io(io), cs(&cs), dc(&dc), work(NULL) +ST7735::ST7735(ScreenIO& io, Pin& cs, Pin& dc) : io(io), cs(&cs), dc(&dc), work(NULL) { - double16 = false; + double16 = false; inSleepMode = false; } @@ -136,14 +135,13 @@ static const uint8_t initCmds[] = { #define DATABUFSIZE 500 #endif -struct ST7735WorkBuffer -{ +struct ST7735WorkBuffer { unsigned width; unsigned height; uint8_t dataBuf[DATABUFSIZE]; - const uint8_t *srcPtr; + const uint8_t* srcPtr; unsigned x; - uint32_t *paletteTable; + uint32_t* paletteTable; unsigned srcLeft; bool inProgress; uint32_t expPalette[256]; @@ -152,30 +150,25 @@ struct ST7735WorkBuffer void ST7735::sendBytes(unsigned num) { assert(num > 0); - if (num > work->srcLeft) - num = work->srcLeft; + if (num > work->srcLeft) num = work->srcLeft; work->srcLeft -= num; - if (double16) - { - uint32_t *dst = (uint32_t *)work->dataBuf; - while (num--) - { + if (double16) { + uint32_t* dst = (uint32_t*)work->dataBuf; + while (num--) { uint8_t v = *work->srcPtr++; - *dst++ = work->expPalette[v & 0xf]; - *dst++ = work->expPalette[v >> 4]; + *dst++ = work->expPalette[v & 0xf]; + *dst++ = work->expPalette[v >> 4]; } - startTransfer((uint8_t *)dst - work->dataBuf); + startTransfer((uint8_t*)dst - work->dataBuf); } - else - { - uint8_t *dst = work->dataBuf; - while (num--) - { + else { + uint8_t* dst = work->dataBuf; + while (num--) { uint32_t v = work->expPalette[*work->srcPtr++]; - *dst++ = v; - *dst++ = v >> 8; - *dst++ = v >> 16; + *dst++ = v; + *dst++ = v >> 8; + *dst++ = v >> 16; } startTransfer(dst - work->dataBuf); } @@ -183,59 +176,54 @@ void ST7735::sendBytes(unsigned num) void ST7735::sendWords(unsigned numBytes) { - if (numBytes > work->srcLeft) - numBytes = work->srcLeft & ~3; + if (numBytes > work->srcLeft) numBytes = work->srcLeft & ~3; assert(numBytes > 0); work->srcLeft -= numBytes; - uint32_t numWords = numBytes >> 2; - const uint32_t *src = (const uint32_t *)work->srcPtr; - uint32_t *tbl = work->expPalette; - uint32_t *dst = (uint32_t *)work->dataBuf; + uint32_t numWords = numBytes >> 2; + const uint32_t* src = (const uint32_t*)work->srcPtr; + uint32_t* tbl = work->expPalette; + uint32_t* dst = (uint32_t*)work->dataBuf; if (double16) - while (numWords--) - { + while (numWords--) { uint32_t v = *src++; - *dst++ = tbl[0xf & (v >> 0)]; - *dst++ = tbl[0xf & (v >> 4)]; - *dst++ = tbl[0xf & (v >> 8)]; - *dst++ = tbl[0xf & (v >> 12)]; - *dst++ = tbl[0xf & (v >> 16)]; - *dst++ = tbl[0xf & (v >> 20)]; - *dst++ = tbl[0xf & (v >> 24)]; - *dst++ = tbl[0xf & (v >> 28)]; + *dst++ = tbl[0xf & (v >> 0)]; + *dst++ = tbl[0xf & (v >> 4)]; + *dst++ = tbl[0xf & (v >> 8)]; + *dst++ = tbl[0xf & (v >> 12)]; + *dst++ = tbl[0xf & (v >> 16)]; + *dst++ = tbl[0xf & (v >> 20)]; + *dst++ = tbl[0xf & (v >> 24)]; + *dst++ = tbl[0xf & (v >> 28)]; } else - while (numWords--) - { + while (numWords--) { uint32_t s = *src++; uint32_t o = tbl[s & 0xff]; uint32_t v = tbl[(s >> 8) & 0xff]; - *dst++ = o | (v << 24); - o = tbl[(s >> 16) & 0xff]; - *dst++ = (v >> 8) | (o << 16); - v = tbl[s >> 24]; - *dst++ = (o >> 16) | (v << 8); + *dst++ = o | (v << 24); + o = tbl[(s >> 16) & 0xff]; + *dst++ = (v >> 8) | (o << 16); + v = tbl[s >> 24]; + *dst++ = (o >> 16) | (v << 8); } - work->srcPtr = (uint8_t *)src; - startTransfer((uint8_t *)dst - work->dataBuf); + work->srcPtr = (uint8_t*)src; + startTransfer((uint8_t*)dst - work->dataBuf); } -void ST7735::sendColorsStep(ST7735 *st) +void ST7735::sendColorsStep(ST7735* st) { - ST7735WorkBuffer *work = st->work; + ST7735WorkBuffer* work = st->work; - if (work->paletteTable) - { - auto palette = work->paletteTable; + if (work->paletteTable) { + auto palette = work->paletteTable; work->paletteTable = NULL; memset(work->dataBuf, 0, sizeof(work->dataBuf)); - uint8_t *base = work->dataBuf; - for (int i = 0; i < 16; ++i) - { - base[i] = (palette[i] >> 18) & 0x3f; - base[i + 32] = (palette[i] >> 10) & 0x3f; + uint8_t* base = work->dataBuf; + for (int i = 0; i < 16; ++i) { + base[i] = (palette[i] >> 18) & 0x3f; + base[i + 32] = (palette[i] >> 10) & 0x3f; base[i + 32 + 64] = (palette[i] >> 2) & 0x3f; } st->startRAMWR(0x2D); @@ -243,41 +231,33 @@ void ST7735::sendColorsStep(ST7735 *st) st->endCS(); } - if (work->x == 0) - { + if (work->x == 0) { st->startRAMWR(); work->x++; } - if (st->double16 && work->srcLeft == 0 && work->x++ < (work->width << 1)) - { + if (st->double16 && work->srcLeft == 0 && work->x++ < (work->width << 1)) { work->srcLeft = (work->height + 1) >> 1; - if ((work->x & 1) == 0) - { + if ((work->x & 1) == 0) { work->srcPtr -= work->srcLeft; } } // with the current image format in PXT the sendBytes cases never happen unsigned align = (unsigned)work->srcPtr & 3; - if (work->srcLeft && align) - { + if (work->srcLeft && align) { st->sendBytes(4 - align); } - else if (work->srcLeft < 4) - { - if (work->srcLeft == 0) - { + else if (work->srcLeft < 4) { + if (work->srcLeft == 0) { st->endCS(); Event(DEVICE_ID_DISPLAY, 100); } - else - { + else { st->sendBytes(work->srcLeft); } } - else - { + else { if (st->double16) st->sendWords(sizeof(work->dataBuf) / 8); else @@ -292,8 +272,7 @@ void ST7735::startTransfer(unsigned size) void ST7735::startRAMWR(int cmd) { - if (cmd == 0) - cmd = ST7735_RAMWR; + if (cmd == 0) cmd = ST7735_RAMWR; cmdBuf[0] = cmd; sendCmd(cmdBuf, 1); @@ -311,24 +290,20 @@ void ST7735::sendDone(Event) void ST7735::waitForSendDone() { - if (work && work->inProgress) - fiber_wait_for_event(DEVICE_ID_DISPLAY, 101); + if (work && work->inProgress) fiber_wait_for_event(DEVICE_ID_DISPLAY, 101); } int ST7735::setSleep(bool sleepMode) { - if (sleepMode == this->inSleepMode) - return DEVICE_OK; + if (sleepMode == this->inSleepMode) return DEVICE_OK; - if (sleepMode) - { - uint8_t cmd = ST7735_SLPIN; + if (sleepMode) { + uint8_t cmd = ST7735_SLPIN; this->inSleepMode = true; waitForSendDone(); sendCmd(&cmd, 1); } - else - { + else { uint8_t cmd = ST7735_SLPOUT; sendCmd(&cmd, 1); fiber_sleep(120); @@ -340,37 +315,32 @@ int ST7735::setSleep(bool sleepMode) #define ENC16(r, g, b) (((r << 3) | (g >> 3)) & 0xff) | (((b | (g << 5)) & 0xff) << 8) -int ST7735::sendIndexedImage(const uint8_t *src, unsigned width, unsigned height, uint32_t *palette) +int ST7735::sendIndexedImage(const uint8_t* src, unsigned width, unsigned height, uint32_t* palette) { - if (!work) - { + if (!work) { work = new ST7735WorkBuffer; memset(work, 0, sizeof(*work)); if (double16) - for (int i = 0; i < 16; ++i) - { - uint16_t e = ENC16(i, i, i); + for (int i = 0; i < 16; ++i) { + uint16_t e = ENC16(i, i, i); work->expPalette[i] = e | (e << 16); } else - for (int i = 0; i < 256; ++i) - work->expPalette[i] = 0x1011 * (i & 0xf) | (0x110100 * (i >> 4)); + for (int i = 0; i < 256; ++i) work->expPalette[i] = 0x1011 * (i & 0xf) | (0x110100 * (i >> 4)); EventModel::defaultEventBus->listen(DEVICE_ID_DISPLAY, 100, this, &ST7735::sendDone); } - if (work->inProgress || inSleepMode) - return DEVICE_BUSY; + if (work->inProgress || inSleepMode) return DEVICE_BUSY; work->paletteTable = palette; work->inProgress = true; - work->srcPtr = src; - work->width = width; - work->height = height; - work->srcLeft = (height + 1) >> 1; + work->srcPtr = src; + work->width = width; + work->height = height; + work->srcLeft = (height + 1) >> 1; // when not scaling up, we don't care about where lines end - if (!double16) - work->srcLeft *= width; + if (!double16) work->srcLeft *= width; work->x = 0; sendColorsStep(this); @@ -379,11 +349,10 @@ int ST7735::sendIndexedImage(const uint8_t *src, unsigned width, unsigned height } // we don't modify *buf, but it cannot be in flash, so no const as a hint -void ST7735::sendCmd(uint8_t *buf, int len) +void ST7735::sendCmd(uint8_t* buf, int len) { // make sure cmd isn't on stack - if (buf != cmdBuf) - memcpy(cmdBuf, buf, len); + if (buf != cmdBuf) memcpy(cmdBuf, buf, len); buf = cmdBuf; setCommand(); beginCS(); @@ -391,24 +360,21 @@ void ST7735::sendCmd(uint8_t *buf, int len) setData(); len--; buf++; - if (len > 0) - io.send(buf, len); + if (len > 0) io.send(buf, len); endCS(); } -void ST7735::sendCmdSeq(const uint8_t *buf) +void ST7735::sendCmdSeq(const uint8_t* buf) { - while (*buf) - { + while (*buf) { cmdBuf[0] = *buf++; - int v = *buf++; - int len = v & ~DELAY; + int v = *buf++; + int len = v & ~DELAY; // note that we have to copy to RAM memcpy(cmdBuf + 1, buf, len); sendCmd(cmdBuf, len + 1); buf += len; - if (v & DELAY) - { + if (v & DELAY) { fiber_sleep(*buf++); } } @@ -416,8 +382,8 @@ void ST7735::sendCmdSeq(const uint8_t *buf) void ST7735::setAddrWindow(int x, int y, int w, int h) { - int x2 = x + w - 1; - int y2 = y + h - 1; + int x2 = x + w - 1; + int y2 = y + h - 1; uint8_t cmd0[] = {ST7735_RASET, (uint8_t)(x >> 8), (uint8_t)x, (uint8_t)(x2 >> 8), (uint8_t)x2}; uint8_t cmd1[] = {ST7735_CASET, (uint8_t)(y >> 8), (uint8_t)y, (uint8_t)(y2 >> 8), (uint8_t)y2}; sendCmd(cmd1, sizeof(cmd1)); @@ -429,7 +395,7 @@ int ST7735::init() endCS(); setData(); - fiber_sleep(10); // TODO check if delay needed + fiber_sleep(10); // TODO check if delay needed sendCmdSeq(initCmds); return DEVICE_OK; @@ -438,12 +404,9 @@ int ST7735::init() void ST7735::configure(uint8_t madctl, uint32_t frmctr1) { uint8_t cmd0[] = {ST7735_MADCTL, madctl}; - uint8_t cmd1[] = {ST7735_FRMCTR1, (uint8_t)(frmctr1 >> 16), (uint8_t)(frmctr1 >> 8), - (uint8_t)frmctr1}; - if (madctl != 0xff) - sendCmd(cmd0, sizeof(cmd0)); - if (frmctr1 != 0xffffff) - sendCmd(cmd1, cmd1[3] == 0xff ? 3 : 4); + uint8_t cmd1[] = {ST7735_FRMCTR1, (uint8_t)(frmctr1 >> 16), (uint8_t)(frmctr1 >> 8), (uint8_t)frmctr1}; + if (madctl != 0xff) sendCmd(cmd0, sizeof(cmd0)); + if (frmctr1 != 0xffffff) sendCmd(cmd1, cmd1[3] == 0xff ? 3 : 4); } -} // namespace codal \ No newline at end of file +} // namespace codal \ No newline at end of file diff --git a/source/drivers/ScreenIO.cpp b/source/drivers/ScreenIO.cpp index ddda0d90..a94e76d9 100644 --- a/source/drivers/ScreenIO.cpp +++ b/source/drivers/ScreenIO.cpp @@ -1,19 +1,17 @@ #include "SPIScreenIO.h" -namespace codal -{ +namespace codal { -SPIScreenIO::SPIScreenIO(SPI &spi) : spi(spi) {} +SPIScreenIO::SPIScreenIO(SPI& spi) : spi(spi) {} -void SPIScreenIO::send(const void *txBuffer, uint32_t txSize) +void SPIScreenIO::send(const void* txBuffer, uint32_t txSize) { - spi.transfer((const uint8_t *)txBuffer, txSize, NULL, 0); + spi.transfer((const uint8_t*)txBuffer, txSize, NULL, 0); } -void SPIScreenIO::startSend(const void *txBuffer, uint32_t txSize, PVoidCallback doneHandler, - void *handlerArg) +void SPIScreenIO::startSend(const void* txBuffer, uint32_t txSize, PVoidCallback doneHandler, void* handlerArg) { - spi.startTransfer((const uint8_t *)txBuffer, txSize, NULL, 0, doneHandler, handlerArg); + spi.startTransfer((const uint8_t*)txBuffer, txSize, NULL, 0, doneHandler, handlerArg); } -} // namespace codal \ No newline at end of file +} // namespace codal \ No newline at end of file diff --git a/source/drivers/StandardSPIFlash.cpp b/source/drivers/StandardSPIFlash.cpp index cee21175..f956eb7d 100644 --- a/source/drivers/StandardSPIFlash.cpp +++ b/source/drivers/StandardSPIFlash.cpp @@ -27,12 +27,10 @@ DEALINGS IN THE SOFTWARE. using namespace codal; //#define check(cond) if(!(cond)) return DEVICE_INVALID_PARAMETER -#define check(cond) \ - if (!(cond)) \ - target_panic(909) +#define check(cond) \ + if (!(cond)) target_panic(909) -StandardSPIFlash::StandardSPIFlash(SPI &spi, Pin &ssel, int numPages) - : _numPages(numPages), spi(spi), ssel(ssel) +StandardSPIFlash::StandardSPIFlash(SPI& spi, Pin& ssel, int numPages) : _numPages(numPages), spi(spi), ssel(ssel) { ssel.setDigitalValue(1); } @@ -45,14 +43,13 @@ void StandardSPIFlash::setCommand(uint8_t command, int addr) cmdBuf[3] = addr >> 0; } -int StandardSPIFlash::sendCommand(uint8_t command, int addr, void *resp, int respSize) +int StandardSPIFlash::sendCommand(uint8_t command, int addr, void* resp, int respSize) { setCommand(command, addr); ssel.setDigitalValue(0); int r = spi.transfer(cmdBuf, addr == -1 ? 1 : 4, NULL, 0); - if (r == DEVICE_OK) - r = spi.transfer(NULL, 0, (uint8_t *)resp, respSize); + if (r == DEVICE_OK) r = spi.transfer(NULL, 0, (uint8_t*)resp, respSize); ssel.setDigitalValue(1); return r; @@ -65,13 +62,10 @@ void StandardSPIFlash::writeEnable() int StandardSPIFlash::waitBusy(int waitMS) { - do - { + do { int r = sendCommand(0x05, -1, &status, 1); - if (r < 0) - return r; - if (waitMS) - fiber_sleep(waitMS); + if (r < 0) return r; + if (waitMS) fiber_sleep(waitMS); } while (status & 0x01); return DEVICE_OK; @@ -82,14 +76,14 @@ int StandardSPIFlash::numPages() return _numPages; } -int StandardSPIFlash::readBytes(uint32_t addr, void *buffer, uint32_t len) +int StandardSPIFlash::readBytes(uint32_t addr, void* buffer, uint32_t len) { check(addr + len <= _numPages * SPIFLASH_PAGE_SIZE); check(addr <= _numPages * SPIFLASH_PAGE_SIZE); return sendCommand(0x03, addr, buffer, len); } -int StandardSPIFlash::writeBytes(uint32_t addr, const void *buffer, uint32_t len) +int StandardSPIFlash::writeBytes(uint32_t addr, const void* buffer, uint32_t len) { check(len <= SPIFLASH_PAGE_SIZE); check(addr / SPIFLASH_PAGE_SIZE == (addr + len - 1) / SPIFLASH_PAGE_SIZE); @@ -101,11 +95,9 @@ int StandardSPIFlash::writeBytes(uint32_t addr, const void *buffer, uint32_t len ssel.setDigitalValue(0); for (uint32_t i = 0; i < 4; ++i) - if (spi.write(cmdBuf[i]) < 0) - goto fail; + if (spi.write(cmdBuf[i]) < 0) goto fail; for (uint32_t i = 0; i < len; ++i) - if (spi.write(((const uint8_t *)buffer)[i]) < 0) - goto fail; + if (spi.write(((const uint8_t*)buffer)[i]) < 0) goto fail; ssel.setDigitalValue(1); // the typical write time is under 1ms, so we don't bother with fiber_sleep() @@ -120,8 +112,7 @@ int StandardSPIFlash::eraseCore(uint8_t cmd, uint32_t addr) { writeEnable(); int r = sendCommand(cmd, addr); - if (r < 0) - return r; + if (r < 0) return r; return waitBusy(10); } @@ -141,5 +132,5 @@ int StandardSPIFlash::eraseBigRow(uint32_t addr) int StandardSPIFlash::eraseChip() { - return eraseCore(0xC7, -1); // or 0x60 + return eraseCore(0xC7, -1); // or 0x60 } diff --git a/source/drivers/TouchButton.cpp b/source/drivers/TouchButton.cpp index b8d7542e..cf7fbf84 100644 --- a/source/drivers/TouchButton.cpp +++ b/source/drivers/TouchButton.cpp @@ -28,10 +28,11 @@ DEALINGS IN THE SOFTWARE. * Represents a single, software controlled capacitative touch button on the device. */ -#include "CodalConfig.h" #include "TouchButton.h" -#include "Timer.h" + +#include "CodalConfig.h" #include "EventModel.h" +#include "Timer.h" using namespace codal; @@ -43,17 +44,17 @@ using namespace codal; * @param pin The physical pin on the device to sense. * @param sensor The touch sensor driver for this touch sensitive pin. */ -TouchButton::TouchButton(Pin &pin, TouchSensor &sensor, int threshold) : Button(pin, pin.id, DEVICE_BUTTON_ALL_EVENTS, ACTIVE_LOW, PullMode::None), touchSensor(sensor) +TouchButton::TouchButton(Pin& pin, TouchSensor& sensor, int threshold) + : Button(pin, pin.id, DEVICE_BUTTON_ALL_EVENTS, ACTIVE_LOW, PullMode::None), touchSensor(sensor) { // Disable periodic events. These will come from our TouchSensor. this->threshold = threshold; - this->reading = 0; + this->reading = 0; this->buttonActive(); // Perform a calibraiton if necessary - if (threshold < 0) - calibrate(); + if (threshold < 0) calibrate(); } /** @@ -63,14 +64,12 @@ TouchButton::TouchButton(Pin &pin, TouchSensor &sensor, int threshold) : Button( int TouchButton::buttonActive() { // register ourselves with the sensor if necessary - if (!(status & TOUCH_BUTTON_RUNNING)) - { + if (!(status & TOUCH_BUTTON_RUNNING)) { touchSensor.addTouchButton(this); status |= TOUCH_BUTTON_RUNNING; } - if (status & TOUCH_BUTTON_CALIBRATING) - return 0; + if (status & TOUCH_BUTTON_CALIBRATING) return 0; return reading >= threshold; } @@ -83,7 +82,7 @@ void TouchButton::calibrate() // indicate that we're entering a calibration phase. // We reuse the threshold variable to track calibration progress, just to save a little memory. this->reading = TOUCH_BUTTON_CALIBRATION_PERIOD; - threshold = 0; + threshold = 0; status |= TOUCH_BUTTON_CALIBRATING; } @@ -100,7 +99,7 @@ void TouchButton::setThreshold(int threshold) /** * Determine the threshold currently in use by the TouchButton - * + * * @return the current threshold value */ int TouchButton::getThreshold() @@ -151,24 +150,23 @@ int TouchButton::getValue() */ void TouchButton::setValue(int reading) { - if (status & TOUCH_BUTTON_CALIBRATING) - { + if (status & TOUCH_BUTTON_CALIBRATING) { // if this is the first reading, take it as our best estimate - if (threshold == 0) - this->threshold = reading; + if (threshold == 0) this->threshold = reading; // Record the highest value measured. This is our baseline. this->threshold = max(this->threshold, reading); #ifdef TOUCH_BUTTON_DECAY_AVERAGE - this->threshold = ((this->threshold * (100-TOUCH_BUTTON_DECAY_AVERAGE)) / 100) + ((reading * TOUCH_BUTTON_DECAY_AVERAGE) / 100); + this->threshold = ((this->threshold * (100 - TOUCH_BUTTON_DECAY_AVERAGE)) / 100) + + ((reading * TOUCH_BUTTON_DECAY_AVERAGE) / 100); #endif this->reading--; // We've completed calibration, return to normal mode of operation. - if (this->reading == 0) - { - this->threshold += ((this->threshold * TOUCH_BUTTON_SENSITIVITY) / 100) + TOUCH_BUTTON_CALIBRATION_LINEAR_OFFSET; + if (this->reading == 0) { + this->threshold += + ((this->threshold * TOUCH_BUTTON_SENSITIVITY) / 100) + TOUCH_BUTTON_CALIBRATION_LINEAR_OFFSET; status &= ~TOUCH_BUTTON_CALIBRATING; } @@ -178,7 +176,8 @@ void TouchButton::setValue(int reading) // Otherewise we're not calibrating, so simply record the result. this->reading = reading; #ifdef TOUCH_BUTTON_DECAY_AVERAGE - this->reading = ((this->reading * (100-TOUCH_BUTTON_DECAY_AVERAGE)) / 100) + ((reading * TOUCH_BUTTON_DECAY_AVERAGE) / 100); + this->reading = + ((this->reading * (100 - TOUCH_BUTTON_DECAY_AVERAGE)) / 100) + ((reading * TOUCH_BUTTON_DECAY_AVERAGE) / 100); #endif } @@ -189,7 +188,7 @@ void TouchButton::setValue(int reading) * * @param pin the Pin to be released */ -int TouchButton::releasePin(Pin &pin) +int TouchButton::releasePin(Pin& pin) { Button::releasePin(pin); touchSensor.removeTouchButton(this); @@ -199,8 +198,8 @@ int TouchButton::releasePin(Pin &pin) } /** - * Destructor for TouchButton, where we deregister this touch button with our sensor... - */ + * Destructor for TouchButton, where we deregister this touch button with our sensor... + */ TouchButton::~TouchButton() { touchSensor.removeTouchButton(this); diff --git a/source/drivers/TouchSensor.cpp b/source/drivers/TouchSensor.cpp index 48f33733..e1a204b8 100644 --- a/source/drivers/TouchSensor.cpp +++ b/source/drivers/TouchSensor.cpp @@ -23,14 +23,14 @@ DEALINGS IN THE SOFTWARE. */ #include "TouchSensor.h" -#include "Event.h" + #include "CodalFiber.h" +#include "Event.h" #include "Timer.h" #include "codal_target_hal.h" using namespace codal; - /** * Default Constructor. * @@ -41,7 +41,7 @@ using namespace codal; */ TouchSensor::TouchSensor(uint16_t id) : drivePin(*(Pin*)NULL) { - this->id = id; + this->id = id; this->numberOfButtons = 0; } @@ -53,21 +53,21 @@ TouchSensor::TouchSensor(uint16_t id) : drivePin(*(Pin*)NULL) * @param pin The physical pin on the device that drives the capacitative sensing. * @id The ID of this component, defaults to DEVICE_ID_TOUCH_SENSOR */ -TouchSensor::TouchSensor(Pin &pin, uint16_t id) : drivePin(pin) +TouchSensor::TouchSensor(Pin& pin, uint16_t id) : drivePin(pin) { - this->id = id; + this->id = id; this->numberOfButtons = 0; // Initialise output drive low (to drain any residual charge before sampling begins). drivePin.setDigitalValue(0); // Clear list off attached buttons. - for (int i=0; ilisten(id, TOUCH_SENSOR_UPDATE_NEEDED, this, &TouchSensor::onSampleEvent, MESSAGE_BUS_LISTENER_IMMEDIATE); + if (EventModel::defaultEventBus) + EventModel::defaultEventBus->listen(id, TOUCH_SENSOR_UPDATE_NEEDED, this, &TouchSensor::onSampleEvent, + MESSAGE_BUS_LISTENER_IMMEDIATE); // Generate an event every TOUCH_SENSOR_SAMPLE_PERIOD milliseconds. system_timer_event_every_us(TOUCH_SENSOR_SAMPLE_PERIOD * 1000, id, TOUCH_SENSOR_UPDATE_NEEDED); @@ -76,16 +76,14 @@ TouchSensor::TouchSensor(Pin &pin, uint16_t id) : drivePin(pin) /** * Begin touch sensing on the given button */ -int TouchSensor::addTouchButton(TouchButton *button) +int TouchSensor::addTouchButton(TouchButton* button) { // if our limit of buttons is reached, then there's nothing more to do. - if (numberOfButtons == TOUCH_SENSOR_MAX_BUTTONS) - return DEVICE_NO_RESOURCES; + if (numberOfButtons == TOUCH_SENSOR_MAX_BUTTONS) return DEVICE_NO_RESOURCES; // Protect against duplicate buttons from being added. - for (int i=0; i_pin.drainPin(); buttons[i]->active = true; } @@ -141,16 +136,12 @@ void TouchSensor::onSampleEvent(Event) // raise the drive pin, and start testing the receiver pins... drivePin.setDigitalValue(1); - while(1) - { + while (1) { activeSensors = 0; - for (int i=0; iactive) - { - if(buttons[i]->getPinValue() == 1 || cycles >= (buttons[i]->threshold)) - { + for (int i = 0; i < numberOfButtons; i++) { + if (buttons[i]->active) { + if (buttons[i]->getPinValue() == 1 || cycles >= (buttons[i]->threshold)) { buttons[i]->active = false; buttons[i]->setValue(cycles); } @@ -160,8 +151,7 @@ void TouchSensor::onSampleEvent(Event) cycles += numberOfButtons; - if (activeSensors == 0 || cycles > TOUCH_SENSE_SAMPLE_MAX) - break; + if (activeSensors == 0 || cycles > TOUCH_SENSE_SAMPLE_MAX) break; } drivePin.setDigitalValue(0); @@ -172,6 +162,6 @@ void TouchSensor::onSampleEvent(Event) */ TouchSensor::~TouchSensor() { - if(EventModel::defaultEventBus) + if (EventModel::defaultEventBus) EventModel::defaultEventBus->ignore(id, TOUCH_SENSOR_UPDATE_NEEDED, this, &TouchSensor::onSampleEvent); } diff --git a/source/drivers/USBMSC.cpp b/source/drivers/USBMSC.cpp index 4b333121..8b5f7ed9 100644 --- a/source/drivers/USBMSC.cpp +++ b/source/drivers/USBMSC.cpp @@ -63,21 +63,20 @@ DEALINGS IN THE SOFTWARE. #define STRICT 0 -#define DEVICE_MSC_EVT_START_READ 1 +#define DEVICE_MSC_EVT_START_READ 1 #define DEVICE_MSC_EVT_START_WRITE 2 -#include "USBMassStorageClass.h" #include "EventModel.h" +#include "USBMassStorageClass.h" #define CPU_TO_LE32(x) (x) #define le32_to_cpu(x) (x) -#define SCSI_SET_SENSE(Key, Acode, Aqual) \ - do \ - { \ - state->SenseData.SenseKey = (Key); \ - state->SenseData.AdditionalSenseCode = (Acode); \ - state->SenseData.AdditionalSenseQualifier = (Aqual); \ +#define SCSI_SET_SENSE(Key, Acode, Aqual) \ + do { \ + state->SenseData.SenseKey = (Key); \ + state->SenseData.AdditionalSenseCode = (Acode); \ + state->SenseData.AdditionalSenseQualifier = (Aqual); \ } while (0) static inline uint32_t CPU_TO_BE32(uint32_t v) @@ -85,94 +84,86 @@ static inline uint32_t CPU_TO_BE32(uint32_t v) return (v << 24) | ((v & 0xff00) << 8) | ((v & 0xff0000) >> 8) | (v >> 24); } -static inline uint16_t read16(uint8_t *p) +static inline uint16_t read16(uint8_t* p) { return (p[0] << 8) | p[1]; } -static inline uint16_t read32(uint8_t *p) +static inline uint16_t read32(uint8_t* p) { return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; } -namespace codal -{ -struct MSCState -{ +namespace codal { +struct MSCState { MS_CommandBlockWrapper_t CommandBlock; MS_CommandStatusWrapper_t CommandStatus; SCSI_Request_Sense_Response_t SenseData; }; -} +} // namespace codal using namespace codal; static const InterfaceInfo ifaceInfo = { - NULL, // No supplemental descriptor - 0, // ditto - 2, // two endpoints + NULL, // No supplemental descriptor + 0, // ditto + 2, // two endpoints { - 2, // numEndpoints - 0x08, // class code - mass storage - 0x06, // subclass - SCSI transparent command set - 80, // protocol code - bulk only transport - 0x00, // iface string - 0x00, // alt setting + 2, // numEndpoints + 0x08, // class code - mass storage + 0x06, // subclass - SCSI transparent command set + 80, // protocol code - bulk only transport + 0x00, // iface string + 0x00, // alt setting }, {USB_EP_TYPE_BULK, 0}, {USB_EP_TYPE_BULK, 0}, }; -int USBMSC::classRequest(UsbEndpointIn &ctrl, USBSetup &setup) +int USBMSC::classRequest(UsbEndpointIn& ctrl, USBSetup& setup) { uint8_t tmp; - switch (setup.bRequest) - { - case MS_REQ_MassStorageReset: - LOG("MSC reset"); - in->reset(); - out->reset(); - ctrl.write(&tmp, 0); - disableIRQ = false; - out->enableIRQ(); - return DEVICE_OK; - case MS_REQ_GetMaxLUN: - LOG("get max lun"); - tmp = totalLUNs() - 1; - ctrl.write(&tmp, 1); - return DEVICE_OK; + switch (setup.bRequest) { + case MS_REQ_MassStorageReset: + LOG("MSC reset"); + in->reset(); + out->reset(); + ctrl.write(&tmp, 0); + disableIRQ = false; + out->enableIRQ(); + return DEVICE_OK; + case MS_REQ_GetMaxLUN: + LOG("get max lun"); + tmp = totalLUNs() - 1; + ctrl.write(&tmp, 1); + return DEVICE_OK; } return DEVICE_NOT_SUPPORTED; } -const InterfaceInfo *USBMSC::getInterfaceInfo() +const InterfaceInfo* USBMSC::getInterfaceInfo() { return &ifaceInfo; } int USBMSC::endpointRequest() { - if (disableIRQ) - return DEVICE_OK; + if (disableIRQ) return DEVICE_OK; int len = out->read(&state->CommandBlock, sizeof(state->CommandBlock)); - if (len == 0) - return DEVICE_OK; + if (len == 0) return DEVICE_OK; - if (len != sizeof(state->CommandBlock)) - { + if (len != sizeof(state->CommandBlock)) { DMESG("MSC: read cmd len=%d", len); goto stall; } - if ((state->CommandBlock.Signature != CPU_TO_LE32(MS_CBW_SIGNATURE)) || - (state->CommandBlock.LUN >= totalLUNs()) || (state->CommandBlock.Flags & 0x1F) || - (state->CommandBlock.SCSICommandLength == 0) || - (state->CommandBlock.SCSICommandLength > 16)) - { + if ((state->CommandBlock.Signature != CPU_TO_LE32(MS_CBW_SIGNATURE)) || (state->CommandBlock.LUN >= totalLUNs()) || + (state->CommandBlock.Flags & 0x1F) || (state->CommandBlock.SCSICommandLength == 0) || + (state->CommandBlock.SCSICommandLength > 16)) { DMESG("MSC: read cmd invalid; cmdlen=%d", state->CommandBlock.SCSICommandLength); goto stall; } @@ -189,33 +180,29 @@ USBMSC::USBMSC() : CodalUSBInterface() { state = new MSCState(); memset(state, 0, sizeof(*state)); - state->SenseData.ResponseCode = 0x70; + state->SenseData.ResponseCode = 0x70; state->SenseData.AdditionalLength = 0x0A; - failed = false; - listen = false; - disableIRQ = false; + failed = false; + listen = false; + disableIRQ = false; } int USBMSC::sendResponse(bool ok) { - if (ok) - { - SCSI_SET_SENSE(SCSI_SENSE_KEY_GOOD, SCSI_ASENSE_NO_ADDITIONAL_INFORMATION, - SCSI_ASENSEQ_NO_QUALIFIER); + if (ok) { + SCSI_SET_SENSE(SCSI_SENSE_KEY_GOOD, SCSI_ASENSE_NO_ADDITIONAL_INFORMATION, SCSI_ASENSEQ_NO_QUALIFIER); } - else - { + else { LOG("response failed: sense key %x", state->SenseData.SenseKey); } - state->CommandStatus.Status = ok ? MS_SCSI_COMMAND_Pass : MS_SCSI_COMMAND_Fail; - state->CommandStatus.Signature = CPU_TO_LE32(MS_CSW_SIGNATURE); - state->CommandStatus.Tag = state->CommandBlock.Tag; + state->CommandStatus.Status = ok ? MS_SCSI_COMMAND_Pass : MS_SCSI_COMMAND_Fail; + state->CommandStatus.Signature = CPU_TO_LE32(MS_CSW_SIGNATURE); + state->CommandStatus.Tag = state->CommandBlock.Tag; state->CommandStatus.DataTransferResidue = state->CommandBlock.DataTransferLength; #if STRICT - if (!ok && (le32_to_cpu(state->CommandStatus.DataTransferResidue))) - { + if (!ok && (le32_to_cpu(state->CommandStatus.DataTransferResidue))) { if (state->CommandBlock.Flags & MS_COMMAND_DIR_DATA_IN) in->stall(); else @@ -224,8 +211,7 @@ int USBMSC::sendResponse(bool ok) } #endif - if (!writePadded(&state->CommandStatus, sizeof(state->CommandStatus))) - return -1; + if (!writePadded(&state->CommandStatus, sizeof(state->CommandStatus))) return -1; return 0; } @@ -233,70 +219,65 @@ int USBMSC::handeSCSICommand() { bool ok = false; - //LOG("SCSI CMD %x %x:%x", state->CommandBlock.SCSICommandData[0], - // state->CommandBlock.SCSICommandData[1], state->CommandBlock.SCSICommandData[2]); + // LOG("SCSI CMD %x %x:%x", state->CommandBlock.SCSICommandData[0], + // state->CommandBlock.SCSICommandData[1], state->CommandBlock.SCSICommandData[2]); /* Run the appropriate SCSI command hander function based on the passed command */ - switch (state->CommandBlock.SCSICommandData[0]) - { - case SCSI_CMD_INQUIRY: - ok = cmdInquiry(); - break; - case SCSI_CMD_REQUEST_SENSE: - ok = cmdRequest_Sense(); - break; - case SCSI_CMD_READ_CAPACITY_10: - ok = cmdRead_Capacity_10(); - break; - case SCSI_CMD_SEND_DIAGNOSTIC: - ok = cmdSend_Diagnostic(); - break; - case SCSI_CMD_WRITE_10: - cmdReadWrite_10(false); - return 0; // sends response by itself - case SCSI_CMD_READ_10: - cmdReadWrite_10(true); - return 0; // ditto - case SCSI_CMD_MODE_SENSE_6: - ok = cmdModeSense(false); - break; - case SCSI_CMD_MODE_SENSE_10: - ok = cmdModeSense(true); - break; - case SCSI_CMD_READ_FORMAT_CAPACITY: - ok = cmdReadFormatCapacity(); - break; - case SCSI_CMD_START_STOP_UNIT: - case SCSI_CMD_TEST_UNIT_READY: - case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: - case SCSI_CMD_VERIFY_10: - /* These commands should just succeed, no handling required */ - ok = true; - state->CommandBlock.DataTransferLength = 0; - break; - default: - /* Update the SENSE key to reflect the invalid command */ - SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_ASENSE_INVALID_COMMAND, - SCSI_ASENSEQ_NO_QUALIFIER); - break; + switch (state->CommandBlock.SCSICommandData[0]) { + case SCSI_CMD_INQUIRY: + ok = cmdInquiry(); + break; + case SCSI_CMD_REQUEST_SENSE: + ok = cmdRequest_Sense(); + break; + case SCSI_CMD_READ_CAPACITY_10: + ok = cmdRead_Capacity_10(); + break; + case SCSI_CMD_SEND_DIAGNOSTIC: + ok = cmdSend_Diagnostic(); + break; + case SCSI_CMD_WRITE_10: + cmdReadWrite_10(false); + return 0; // sends response by itself + case SCSI_CMD_READ_10: + cmdReadWrite_10(true); + return 0; // ditto + case SCSI_CMD_MODE_SENSE_6: + ok = cmdModeSense(false); + break; + case SCSI_CMD_MODE_SENSE_10: + ok = cmdModeSense(true); + break; + case SCSI_CMD_READ_FORMAT_CAPACITY: + ok = cmdReadFormatCapacity(); + break; + case SCSI_CMD_START_STOP_UNIT: + case SCSI_CMD_TEST_UNIT_READY: + case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: + case SCSI_CMD_VERIFY_10: + /* These commands should just succeed, no handling required */ + ok = true; + state->CommandBlock.DataTransferLength = 0; + break; + default: + /* Update the SENSE key to reflect the invalid command */ + SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_ASENSE_INVALID_COMMAND, SCSI_ASENSEQ_NO_QUALIFIER); + break; } return sendResponse(ok); } -void USBMSC::readBulk(void *ptr, int dataSize) +void USBMSC::readBulk(void* ptr, int dataSize) { usb_assert(dataSize % 64 == 0); - if (failed) - { + if (failed) { memset(ptr, 0, dataSize); return; } - for (int i = 0; i < dataSize;) - { - int len = out->read((uint8_t *)ptr + i, dataSize - i); - if (len < 0) - { + for (int i = 0; i < dataSize;) { + int len = out->read((uint8_t*)ptr + i, dataSize - i); + if (len < 0) { fail(); return; } @@ -307,42 +288,35 @@ void USBMSC::readBulk(void *ptr, int dataSize) void USBMSC::fail() { - failed = true; + failed = true; disableIRQ = false; out->enableIRQ(); } -void USBMSC::writeBulk(const void *ptr, int dataSize) +void USBMSC::writeBulk(const void* ptr, int dataSize) { usb_assert(dataSize % 64 == 0); - if (failed) - return; + if (failed) return; state->CommandBlock.DataTransferLength -= dataSize; - in->flags |= USB_EP_FLAG_NO_AUTO_ZLP; // disable AUTO-ZLP - if (in->write(ptr, dataSize) < 0) - fail(); + in->flags |= USB_EP_FLAG_NO_AUTO_ZLP; // disable AUTO-ZLP + if (in->write(ptr, dataSize) < 0) fail(); } -bool USBMSC::writePadded(const void *ptr, int dataSize, int allocSize) +bool USBMSC::writePadded(const void* ptr, int dataSize, int allocSize) { - if (allocSize == -1) - allocSize = dataSize; + if (allocSize == -1) allocSize = dataSize; - in->flags &= ~USB_EP_FLAG_NO_AUTO_ZLP; // enable AUTO-ZLP + in->flags &= ~USB_EP_FLAG_NO_AUTO_ZLP; // enable AUTO-ZLP - if (dataSize >= allocSize) - { - if (in->write(ptr, allocSize) < 0) - return false; + if (dataSize >= allocSize) { + if (in->write(ptr, allocSize) < 0) return false; dataSize = allocSize; } - else - { + else { uint8_t tmp[allocSize]; memset(tmp, 0, allocSize); memcpy(tmp, ptr, dataSize); - if (in->write(tmp, allocSize) < 0) - return false; + if (in->write(tmp, allocSize) < 0) return false; } state->CommandBlock.DataTransferLength -= dataSize; @@ -357,9 +331,9 @@ bool USBMSC::cmdInquiry() memset(&InquiryData, 0, sizeof(InquiryData)); - InquiryData.Removable = true; + InquiryData.Removable = true; InquiryData.ResponseDataFormat = 2; - InquiryData.AdditionalLength = 0x1F; + InquiryData.AdditionalLength = 0x1F; //.VendorID = "LUFA", //.ProductID = "Dataflash Disk", @@ -367,12 +341,9 @@ bool USBMSC::cmdInquiry() #if STRICT /* Only the standard INQUIRY data is supported, check if any optional INQUIRY bits set */ - if ((state->CommandBlock.SCSICommandData[1] & ((1 << 0) | (1 << 1))) || - state->CommandBlock.SCSICommandData[2]) - { + if ((state->CommandBlock.SCSICommandData[1] & ((1 << 0) | (1 << 1))) || state->CommandBlock.SCSICommandData[2]) { /* Optional but unsupported bits set - update the SENSE key and fail the request */ - SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_ASENSE_INVALID_FIELD_IN_CDB, - SCSI_ASENSEQ_NO_QUALIFIER); + SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_ASENSE_INVALID_FIELD_IN_CDB, SCSI_ASENSEQ_NO_QUALIFIER); return false; } @@ -389,7 +360,7 @@ bool USBMSC::cmdRequest_Sense() bool USBMSC::cmdRead_Capacity_10() { - uint32_t info[] = {CPU_TO_BE32(getCapacity() - 1), // final address + uint32_t info[] = {CPU_TO_BE32(getCapacity() - 1), // final address CPU_TO_BE32(512)}; return writePadded(&info, sizeof(info)); @@ -398,21 +369,17 @@ bool USBMSC::cmdRead_Capacity_10() bool USBMSC::cmdSend_Diagnostic() { /* Check to see if the SELF TEST bit is not set */ - if (!(state->CommandBlock.SCSICommandData[1] & (1 << 2))) - { + if (!(state->CommandBlock.SCSICommandData[1] & (1 << 2))) { /* Only self-test supported - update SENSE key and fail the command */ - SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_ASENSE_INVALID_FIELD_IN_CDB, - SCSI_ASENSEQ_NO_QUALIFIER); + SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_ASENSE_INVALID_FIELD_IN_CDB, SCSI_ASENSEQ_NO_QUALIFIER); return false; } /* Check to see if all attached Dataflash ICs are functional */ - if (!storageOK()) - { + if (!storageOK()) { /* Update SENSE key with a hardware error condition and return command fail */ - SCSI_SET_SENSE(SCSI_SENSE_KEY_HARDWARE_ERROR, SCSI_ASENSE_NO_ADDITIONAL_INFORMATION, - SCSI_ASENSEQ_NO_QUALIFIER); + SCSI_SET_SENSE(SCSI_SENSE_KEY_HARDWARE_ERROR, SCSI_ASENSE_NO_ADDITIONAL_INFORMATION, SCSI_ASENSEQ_NO_QUALIFIER); return false; } @@ -425,8 +392,8 @@ bool USBMSC::cmdSend_Diagnostic() void USBMSC::finishReadWrite() { - bool ok = !failed; - failed = false; + bool ok = !failed; + failed = false; disableIRQ = false; out->enableIRQ(); sendResponse(ok); @@ -435,37 +402,31 @@ void USBMSC::finishReadWrite() void USBMSC::cmdReadWrite_10(bool isRead) { /* Check if the disk is write protected or not */ - if (!isRead && isReadOnly()) - { + if (!isRead && isReadOnly()) { /* Block address is invalid, update SENSE key and return command fail */ - SCSI_SET_SENSE(SCSI_SENSE_KEY_DATA_PROTECT, SCSI_ASENSE_WRITE_PROTECTED, - SCSI_ASENSEQ_NO_QUALIFIER); + SCSI_SET_SENSE(SCSI_SENSE_KEY_DATA_PROTECT, SCSI_ASENSE_WRITE_PROTECTED, SCSI_ASENSEQ_NO_QUALIFIER); sendResponse(false); return; } - blockAddr = read32(&state->CommandBlock.SCSICommandData[2]); + blockAddr = read32(&state->CommandBlock.SCSICommandData[2]); blockCount = read16(&state->CommandBlock.SCSICommandData[7]); /* Check if the block address is outside the maximum allowable value for the LUN */ - if (blockAddr >= getCapacity()) - { + if (blockAddr >= getCapacity()) { /* Block address is invalid, update SENSE key and return command fail */ - SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST, - SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE, SCSI_ASENSEQ_NO_QUALIFIER); + SCSI_SET_SENSE(SCSI_SENSE_KEY_ILLEGAL_REQUEST, SCSI_ASENSE_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE, + SCSI_ASENSEQ_NO_QUALIFIER); sendResponse(false); return; } failed = false; - if (!listen) - { + if (!listen) { listen = true; - EventModel::defaultEventBus->listen(DEVICE_ID_MSC, DEVICE_MSC_EVT_START_READ, this, - &USBMSC::readHandler); - EventModel::defaultEventBus->listen(DEVICE_ID_MSC, DEVICE_MSC_EVT_START_WRITE, this, - &USBMSC::writeHandler); + EventModel::defaultEventBus->listen(DEVICE_ID_MSC, DEVICE_MSC_EVT_START_READ, this, &USBMSC::readHandler); + EventModel::defaultEventBus->listen(DEVICE_ID_MSC, DEVICE_MSC_EVT_START_WRITE, this, &USBMSC::writeHandler); } out->disableIRQ(); @@ -487,13 +448,11 @@ void USBMSC::writeHandler(Event) bool USBMSC::cmdModeSense(bool is10) { uint8_t ro = isReadOnly() ? 0x80 : 0x00; - if (is10) - { + if (is10) { uint8_t resp[] = {0, 0, 0, ro, 0, 0, 0, 0}; return writePadded(resp, sizeof(resp)); } - else - { + else { uint8_t resp[] = {0, 0, ro, 0}; return writePadded(resp, sizeof(resp)); } @@ -501,16 +460,16 @@ bool USBMSC::cmdModeSense(bool is10) bool USBMSC::cmdReadFormatCapacity() { - uint32_t cap = getCapacity(); + uint32_t cap = getCapacity(); uint8_t buf[12] = {0, 0, 0, - 8, // length + 8, // length (uint8_t)(cap >> 24), (uint8_t)(cap >> 16), (uint8_t)(cap >> 8), (uint8_t)(cap >> 0), - 2, // Descriptor Code: Formatted Media + 2, // Descriptor Code: Formatted Media 0, (512 >> 8), 0}; diff --git a/source/streams/DataStream.cpp b/source/streams/DataStream.cpp index 91539487..b54f4f02 100644 --- a/source/streams/DataStream.cpp +++ b/source/streams/DataStream.cpp @@ -23,29 +23,26 @@ DEALINGS IN THE SOFTWARE. */ #include "DataStream.h" + #include "CodalComponent.h" -#include "ManagedBuffer.h" -#include "Event.h" #include "CodalFiber.h" #include "ErrorNo.h" +#include "Event.h" +#include "ManagedBuffer.h" using namespace codal; /** -* Default implementation of DataSource and DataSink classes. -*/ + * Default implementation of DataSource and DataSink classes. + */ ManagedBuffer DataSource::pull() { - return ManagedBuffer(); + return ManagedBuffer(); } -void DataSource::connect(DataSink& ) -{ -} +void DataSource::connect(DataSink&) {} -void DataSource::disconnect() -{ -} +void DataSource::disconnect() {} int DataSource::getFormat() { @@ -57,41 +54,41 @@ int DataSource::setFormat(int format) return DEVICE_NOT_SUPPORTED; } -float DataSource::getSampleRate() { +float DataSource::getSampleRate() +{ return DATASTREAM_SAMPLE_RATE_UNKNOWN; } -float DataSource::requestSampleRate(float sampleRate) { +float DataSource::requestSampleRate(float sampleRate) +{ // Just consume this by default, we don't _have_ to honour requests for specific rates. return DATASTREAM_SAMPLE_RATE_UNKNOWN; } int DataSink::pullRequest() { - return DEVICE_NOT_SUPPORTED; + return DEVICE_NOT_SUPPORTED; } -DataStream::DataStream(DataSource &upstream) +DataStream::DataStream(DataSource& upstream) { this->pullRequestEventCode = 0; - this->isBlocking = true; - this->hasPending = false; - this->missedBuffers = CODAL_DATASTREAM_HIGH_WATER_MARK; - this->downstreamReturn = DEVICE_OK; - this->flowEventCode = 0; + this->isBlocking = true; + this->hasPending = false; + this->missedBuffers = CODAL_DATASTREAM_HIGH_WATER_MARK; + this->downstreamReturn = DEVICE_OK; + this->flowEventCode = 0; this->downStream = NULL; - this->upStream = &upstream; + this->upStream = &upstream; } -DataStream::~DataStream() -{ -} +DataStream::~DataStream() {} -uint16_t DataStream::emitFlowEvents( uint16_t id ) +uint16_t DataStream::emitFlowEvents(uint16_t id) { - if( this->flowEventCode == 0 ) { - if( id == 0 ) + if (this->flowEventCode == 0) { + if (id == 0) this->flowEventCode = allocateNotifyEvent(); else this->flowEventCode = id; @@ -101,8 +98,7 @@ uint16_t DataStream::emitFlowEvents( uint16_t id ) bool DataStream::isReadOnly() { - if( this->hasPending ) - return this->nextBuffer.isReadOnly(); + if (this->hasPending) return this->nextBuffer.isReadOnly(); return true; } @@ -111,9 +107,9 @@ bool DataStream::isFlowing() return this->missedBuffers < CODAL_DATASTREAM_HIGH_WATER_MARK; } -void DataStream::connect(DataSink &sink) +void DataStream::connect(DataSink& sink) { - this->downStream = &sink; + this->downStream = &sink; this->upStream->connect(*this); } @@ -129,7 +125,7 @@ int DataStream::getFormat() void DataStream::disconnect() { - this->downStream = NULL; + this->downStream = NULL; } void DataStream::setBlocking(bool isBlocking) @@ -137,36 +133,33 @@ void DataStream::setBlocking(bool isBlocking) this->isBlocking = isBlocking; // If this is the first time async mode has been used on this stream, allocate the necessary resources. - if (!this->isBlocking && this->pullRequestEventCode == 0) - { + if (!this->isBlocking && this->pullRequestEventCode == 0) { this->pullRequestEventCode = allocateNotifyEvent(); - if(EventModel::defaultEventBus) - EventModel::defaultEventBus->listen(DEVICE_ID_NOTIFY, this->pullRequestEventCode, this, &DataStream::onDeferredPullRequest); + if (EventModel::defaultEventBus) + EventModel::defaultEventBus->listen(DEVICE_ID_NOTIFY, this->pullRequestEventCode, this, + &DataStream::onDeferredPullRequest); } } ManagedBuffer DataStream::pull() { // 1, as we will normally be at '1' waiting buffer here if we're in-sync with the source - if( this->missedBuffers > 1 ) - Event evt( DEVICE_ID_NOTIFY, this->flowEventCode ); - + if (this->missedBuffers > 1) Event evt(DEVICE_ID_NOTIFY, this->flowEventCode); + this->missedBuffers = 0; // Are we running in sync (blocking) mode? - if( this->isBlocking ) - return this->upStream->pull(); - + if (this->isBlocking) return this->upStream->pull(); + this->hasPending = false; - return ManagedBuffer( this->nextBuffer ); // Deep copy! + return ManagedBuffer(this->nextBuffer); // Deep copy! } void DataStream::onDeferredPullRequest(Event) { - this->downstreamReturn = DEVICE_OK; // The default state + this->downstreamReturn = DEVICE_OK; // The default state - if (downStream != NULL) - this->downstreamReturn = downStream->pullRequest(); + if (downStream != NULL) this->downstreamReturn = downStream->pullRequest(); } bool DataStream::canPull(int size) @@ -178,39 +171,37 @@ bool DataStream::canPull(int size) int DataStream::pullRequest() { // _Technically_ not a missed buffer... yet. But we can only check later. - if( this->missedBuffers < CODAL_DATASTREAM_HIGH_WATER_MARK ) - if( ++this->missedBuffers == CODAL_DATASTREAM_HIGH_WATER_MARK ) - if( this->flowEventCode != 0 ) - Event evt( DEVICE_ID_NOTIFY, this->flowEventCode ); + if (this->missedBuffers < CODAL_DATASTREAM_HIGH_WATER_MARK) + if (++this->missedBuffers == CODAL_DATASTREAM_HIGH_WATER_MARK) + if (this->flowEventCode != 0) Event evt(DEVICE_ID_NOTIFY, this->flowEventCode); // Are we running in async (non-blocking) mode? - if( !this->isBlocking ) { - if( this->hasPending && this->downstreamReturn != DEVICE_OK ) { - Event evt( DEVICE_ID_NOTIFY, this->pullRequestEventCode ); + if (!this->isBlocking) { + if (this->hasPending && this->downstreamReturn != DEVICE_OK) { + Event evt(DEVICE_ID_NOTIFY, this->pullRequestEventCode); return this->downstreamReturn; } this->nextBuffer = this->upStream->pull(); this->hasPending = true; - Event evt( DEVICE_ID_NOTIFY, this->pullRequestEventCode ); + Event evt(DEVICE_ID_NOTIFY, this->pullRequestEventCode); return this->downstreamReturn; } - if( this->downStream != NULL ) - return this->downStream->pullRequest(); + if (this->downStream != NULL) return this->downStream->pullRequest(); return DEVICE_BUSY; } -float DataStream::getSampleRate() { - if( this->upStream != NULL ) - return this->upStream->getSampleRate(); +float DataStream::getSampleRate() +{ + if (this->upStream != NULL) return this->upStream->getSampleRate(); return DATASTREAM_SAMPLE_RATE_UNKNOWN; } -float DataStream::requestSampleRate(float sampleRate) { - if( this->upStream != NULL ) - return this->upStream->requestSampleRate( sampleRate ); +float DataStream::requestSampleRate(float sampleRate) +{ + if (this->upStream != NULL) return this->upStream->requestSampleRate(sampleRate); return DATASTREAM_SAMPLE_RATE_UNKNOWN; } \ No newline at end of file diff --git a/source/streams/EffectFilter.cpp b/source/streams/EffectFilter.cpp index 5e81ddb4..3df76193 100644 --- a/source/streams/EffectFilter.cpp +++ b/source/streams/EffectFilter.cpp @@ -1,25 +1,24 @@ #include "EffectFilter.h" -#include "ManagedBuffer.h" + +#include "CodalDmesg.h" #include "DataStream.h" +#include "ManagedBuffer.h" #include "StreamNormalizer.h" -#include "CodalDmesg.h" using namespace codal; -EffectFilter::EffectFilter(DataSource &source, bool deepCopy) : upStream( source ) +EffectFilter::EffectFilter(DataSource& source, bool deepCopy) : upStream(source) { this->downStream = NULL; - this->deepCopy = deepCopy; - source.connect( *this ); + this->deepCopy = deepCopy; + source.connect(*this); } -EffectFilter::~EffectFilter() -{ -} +EffectFilter::~EffectFilter() {} ManagedBuffer EffectFilter::pull() { - ManagedBuffer input = this->upStream.pull(); + ManagedBuffer input = this->upStream.pull(); ManagedBuffer output = (deepCopy || input.isReadOnly()) ? ManagedBuffer(input.length()) : input; applyEffect(input, output, this->upStream.getFormat()); @@ -28,12 +27,11 @@ ManagedBuffer EffectFilter::pull() int EffectFilter::pullRequest() { - if( this->downStream != NULL ) - return this->downStream->pullRequest(); + if (this->downStream != NULL) return this->downStream->pullRequest(); return DEVICE_BUSY; } -void EffectFilter::connect(DataSink &sink) +void EffectFilter::connect(DataSink& sink) { this->downStream = &sink; } @@ -53,9 +51,9 @@ int EffectFilter::getFormat() return this->upStream.getFormat(); } -int EffectFilter::setFormat( int format ) +int EffectFilter::setFormat(int format) { - return this->upStream.setFormat( format ); + return this->upStream.setFormat(format); } float EffectFilter::getSampleRate() @@ -65,7 +63,7 @@ float EffectFilter::getSampleRate() float EffectFilter::requestSampleRate(float sampleRate) { - return this->upStream.requestSampleRate( sampleRate ); + return this->upStream.requestSampleRate(sampleRate); } /** @@ -73,14 +71,14 @@ float EffectFilter::requestSampleRate(float sampleRate) * * @param deepCopy Set to true to copy incoming data into a freshly allocated buffer, or false to change data in place. */ -void EffectFilter::setDeepCopy( bool deepCopy ) +void EffectFilter::setDeepCopy(bool deepCopy) { this->deepCopy = deepCopy; } /** * Default effect - a simple pass through filter. - * + * * @param inputBuffer the buffer containing data to process. * @param outputBuffer the buffer in which to store the filtered data. n.b. MAY be the same memory as the input buffer. * @param format the format of the data (word size and signed/unsigned representation) diff --git a/source/streams/FIFOStream.cpp b/source/streams/FIFOStream.cpp index 7f10ae6d..591a521a 100644 --- a/source/streams/FIFOStream.cpp +++ b/source/streams/FIFOStream.cpp @@ -1,23 +1,23 @@ #include "FIFOStream.h" -#include "ErrorNo.h" + +#include "CodalDmesg.h" #include "DataStream.h" +#include "ErrorNo.h" #include "ManagedBuffer.h" -#include "CodalDmesg.h" #include "MessageBus.h" using namespace codal; -FIFOStream::FIFOStream( DataSource &source ) : upStream( source ) +FIFOStream::FIFOStream(DataSource& source) : upStream(source) { - this->bufferCount = 0; + this->bufferCount = 0; this->bufferLength = 0; - + this->downStream = NULL; - source.connect( *this ); + source.connect(*this); - this->allowInput = false; + this->allowInput = false; this->allowOutput = false; - } FIFOStream::~FIFOStream() @@ -32,20 +32,17 @@ bool FIFOStream::canPull() ManagedBuffer FIFOStream::pull() { - if( (this->bufferLength > 0) && this->allowOutput ) - { + if ((this->bufferLength > 0) && this->allowOutput) { ManagedBuffer out = buffer[0]; - for (int i = 0; i < FIFO_MAXIMUM_BUFFERS-1; i++) - buffer[i] = buffer[i + 1]; + for (int i = 0; i < FIFO_MAXIMUM_BUFFERS - 1; i++) buffer[i] = buffer[i + 1]; - buffer[FIFO_MAXIMUM_BUFFERS-1] = ManagedBuffer(); + buffer[FIFO_MAXIMUM_BUFFERS - 1] = ManagedBuffer(); this->bufferLength -= out.length(); this->bufferCount--; - if (this->bufferCount > 0 && downStream != NULL) - downStream->pullRequest(); + if (this->bufferCount > 0 && downStream != NULL) downStream->pullRequest(); return out; } @@ -58,41 +55,34 @@ int FIFOStream::length() return this->bufferLength; } -bool FIFOStream::isFull() { +bool FIFOStream::isFull() +{ return this->bufferCount < FIFO_MAXIMUM_BUFFERS; } void FIFOStream::dumpState() { - DMESG( - "TapeDeck { bufferCount = %d/%d, bufferLength = %dB }", - this->bufferCount, - FIFO_MAXIMUM_BUFFERS, - this->bufferLength - ); + DMESG("TapeDeck { bufferCount = %d/%d, bufferLength = %dB }", this->bufferCount, FIFO_MAXIMUM_BUFFERS, + this->bufferLength); } int FIFOStream::pullRequest() { - if( this->bufferCount >= FIFO_MAXIMUM_BUFFERS ) - return DEVICE_NO_RESOURCES; + if (this->bufferCount >= FIFO_MAXIMUM_BUFFERS) return DEVICE_NO_RESOURCES; ManagedBuffer inBuffer = this->upStream.pull(); - if( this->allowInput && inBuffer.length() > 0 ) - { - this->buffer[ this->bufferCount++ ] = inBuffer; + if (this->allowInput && inBuffer.length() > 0) { + this->buffer[this->bufferCount++] = inBuffer; this->bufferLength += inBuffer.length(); } - if (bufferCount > 0 && this->allowOutput && downStream != NULL) - return downStream->pullRequest(); + if (bufferCount > 0 && this->allowOutput && downStream != NULL) return downStream->pullRequest(); - if( this->bufferCount >= FIFO_MAXIMUM_BUFFERS ) - return DEVICE_BUSY; + if (this->bufferCount >= FIFO_MAXIMUM_BUFFERS) return DEVICE_BUSY; return DEVICE_OK; } -void FIFOStream::connect( DataSink &sink ) +void FIFOStream::connect(DataSink& sink) { this->downStream = &sink; } @@ -112,26 +102,24 @@ int FIFOStream::getFormat() return this->upStream.getFormat(); } -int FIFOStream::setFormat( int format ) +int FIFOStream::setFormat(int format) { - return this->upStream.setFormat( format ); + return this->upStream.setFormat(format); } -void FIFOStream::setInputEnable( bool state ) +void FIFOStream::setInputEnable(bool state) { this->allowInput = state; } -void FIFOStream::setOutputEnable( bool state ) +void FIFOStream::setOutputEnable(bool state) { bool enabling = false; - DMESG("FIFO:setOutputEnable %d", state ); + DMESG("FIFO:setOutputEnable %d", state); - if (this->allowOutput == false && state) - enabling = true; + if (this->allowOutput == false && state) enabling = true; this->allowOutput = state; - + // If we've just been enabled and have data to send, issue a pullrequest to ensure our downstream is aware of this - if (enabling && bufferCount > 0 && downStream != NULL) - downStream->pullRequest(); + if (enabling && bufferCount > 0 && downStream != NULL) downStream->pullRequest(); } \ No newline at end of file diff --git a/source/streams/LevelDetector.cpp b/source/streams/LevelDetector.cpp index 02e6cbf1..893efbf9 100644 --- a/source/streams/LevelDetector.cpp +++ b/source/streams/LevelDetector.cpp @@ -22,28 +22,31 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include "LevelDetector.h" + +#include "CodalCompat.h" #include "CodalConfig.h" +#include "CodalDmesg.h" +#include "ErrorNo.h" #include "Event.h" -#include "CodalCompat.h" #include "Timer.h" -#include "LevelDetector.h" -#include "ErrorNo.h" -#include "CodalDmesg.h" using namespace codal; -LevelDetector::LevelDetector(DataSource &source, int highThreshold, int lowThreshold, uint16_t id, bool connectImmediately) : upstream(source) +LevelDetector::LevelDetector(DataSource& source, int highThreshold, int lowThreshold, uint16_t id, + bool connectImmediately) + : upstream(source) { - this->id = id; - this->level = 0; - this->sigma = 0; + this->id = id; + this->level = 0; + this->sigma = 0; this->windowPosition = 0; - this->windowSize = LEVEL_DETECTOR_DEFAULT_WINDOW_SIZE; - this->lowThreshold = lowThreshold; - this->highThreshold = highThreshold; + this->windowSize = LEVEL_DETECTOR_DEFAULT_WINDOW_SIZE; + this->lowThreshold = lowThreshold; + this->highThreshold = highThreshold; this->status |= LEVEL_DETECTOR_INITIALISED; this->activated = false; - if(connectImmediately){ + if (connectImmediately) { upstream.connect(*this); } } @@ -53,49 +56,46 @@ LevelDetector::LevelDetector(DataSource &source, int highThreshold, int lowThres */ int LevelDetector::pullRequest() { - if( this->timeout - system_timer_current_time() > CODAL_STREAM_IDLE_TIMEOUT_MS && !activated ) { + if (this->timeout - system_timer_current_time() > CODAL_STREAM_IDLE_TIMEOUT_MS && !activated) { return DEVICE_BUSY; } ManagedBuffer b = upstream.pull(); - int16_t *data = (int16_t *) &b[0]; + int16_t* data = (int16_t*)&b[0]; int samples = b.length() / 2; - for (int i=0; i < samples; i++) - { - if(upstream.getFormat() == DATASTREAM_FORMAT_8BIT_SIGNED){ - sigma += abs((int8_t) *data); + for (int i = 0; i < samples; i++) { + if (upstream.getFormat() == DATASTREAM_FORMAT_8BIT_SIGNED) { + sigma += abs((int8_t)*data); } else sigma += abs(*data); windowPosition++; - if (windowPosition == windowSize) - { + if (windowPosition == windowSize) { level = sigma / windowSize; - sigma = 0; + sigma = 0; windowPosition = 0; - // If 8 bit - then multiply by 8 to upscale result. High 8 bit ~20, High 16 bit ~150 so roughly 8 times higher - if(upstream.getFormat() == DATASTREAM_FORMAT_8BIT_SIGNED){ - level = level*8; + // If 8 bit - then multiply by 8 to upscale result. High 8 bit ~20, High 16 bit ~150 so roughly 8 times + // higher + if (upstream.getFormat() == DATASTREAM_FORMAT_8BIT_SIGNED) { + level = level * 8; } - if ((!(status & LEVEL_DETECTOR_HIGH_THRESHOLD_PASSED)) && level > highThreshold) - { + if ((!(status & LEVEL_DETECTOR_HIGH_THRESHOLD_PASSED)) && level > highThreshold) { Event(id, LEVEL_THRESHOLD_HIGH); - status |= LEVEL_DETECTOR_HIGH_THRESHOLD_PASSED; + status |= LEVEL_DETECTOR_HIGH_THRESHOLD_PASSED; status &= ~LEVEL_DETECTOR_LOW_THRESHOLD_PASSED; } - if ((!(status & LEVEL_DETECTOR_LOW_THRESHOLD_PASSED)) && level < lowThreshold) - { + if ((!(status & LEVEL_DETECTOR_LOW_THRESHOLD_PASSED)) && level < lowThreshold) { Event(id, LEVEL_THRESHOLD_LOW); - status |= LEVEL_DETECTOR_LOW_THRESHOLD_PASSED; + status |= LEVEL_DETECTOR_LOW_THRESHOLD_PASSED; status &= ~LEVEL_DETECTOR_HIGH_THRESHOLD_PASSED; } } @@ -113,18 +113,16 @@ int LevelDetector::pullRequest() */ int LevelDetector::getValue() { - if( !this->upstream.isConnected() ) - this->upstream.connect( *this ); + if (!this->upstream.isConnected()) this->upstream.connect(*this); this->timeout = system_timer_current_time() + CODAL_STREAM_IDLE_TIMEOUT_MS; - target_wait( 100 ); + target_wait(100); return level; } -void LevelDetector::activateForEvents( bool state ) +void LevelDetector::activateForEvents(bool state) { this->activated = state; - if( this->activated && !upstream.isConnected() ) - upstream.connect(*this); + if (this->activated && !upstream.isConnected()) upstream.connect(*this); } /** @@ -137,8 +135,7 @@ void LevelDetector::activateForEvents( bool state ) int LevelDetector::setLowThreshold(int value) { // Protect against churn if the same threshold is set repeatedly. - if (lowThreshold == value) - return DEVICE_OK; + if (lowThreshold == value) return DEVICE_OK; // We need to update our threshold lowThreshold = value; @@ -147,8 +144,7 @@ int LevelDetector::setLowThreshold(int value) status &= ~LEVEL_DETECTOR_LOW_THRESHOLD_PASSED; // If a HIGH threshold has been set, ensure it's above the LOW threshold. - if (highThreshold < lowThreshold) - setHighThreshold(lowThreshold+1); + if (highThreshold < lowThreshold) setHighThreshold(lowThreshold + 1); return DEVICE_OK; } @@ -163,8 +159,7 @@ int LevelDetector::setLowThreshold(int value) int LevelDetector::setHighThreshold(int value) { // Protect against churn if the same threshold is set repeatedly. - if (highThreshold == value) - return DEVICE_OK; + if (highThreshold == value) return DEVICE_OK; // We need to update our threshold highThreshold = value; @@ -173,8 +168,7 @@ int LevelDetector::setHighThreshold(int value) status &= ~LEVEL_DETECTOR_HIGH_THRESHOLD_PASSED; // If a HIGH threshold has been set, ensure it's above the LOW threshold. - if (lowThreshold > highThreshold) - setLowThreshold(highThreshold - 1); + if (lowThreshold > highThreshold) setLowThreshold(highThreshold - 1); return DEVICE_OK; } @@ -200,9 +194,9 @@ int LevelDetector::getHighThreshold() } /** - * Set the window size to the given value. The window size defines the number of samples used to determine a sound level. - * The higher the value, the more accurate the result will be. The lower the value, the more responsive the result will be. - * Adjust this value to suit the requirements of your applicaiton. + * Set the window size to the given value. The window size defines the number of samples used to determine a sound + * level. The higher the value, the more accurate the result will be. The lower the value, the more responsive the + * result will be. Adjust this value to suit the requirements of your applicaiton. * * @param size The size of the window to use (number of samples). * @@ -210,8 +204,7 @@ int LevelDetector::getHighThreshold() */ int LevelDetector::setWindowSize(int size) { - if (size <= 0) - return DEVICE_INVALID_PARAMETER; + if (size <= 0) return DEVICE_INVALID_PARAMETER; this->windowSize = size; return DEVICE_OK; @@ -220,6 +213,4 @@ int LevelDetector::setWindowSize(int size) /** * Destructor. */ -LevelDetector::~LevelDetector() -{ -} +LevelDetector::~LevelDetector() {} diff --git a/source/streams/LevelDetectorSPL.cpp b/source/streams/LevelDetectorSPL.cpp index 39032716..5cca20f0 100644 --- a/source/streams/LevelDetectorSPL.cpp +++ b/source/streams/LevelDetectorSPL.cpp @@ -22,80 +22,83 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include "LevelDetectorSPL.h" + +#include "CodalAssert.h" +#include "CodalCompat.h" #include "CodalConfig.h" +#include "ErrorNo.h" #include "Event.h" -#include "CodalCompat.h" -#include "Timer.h" #include "LevelDetector.h" -#include "LevelDetectorSPL.h" -#include "ErrorNo.h" #include "StreamNormalizer.h" -#include "CodalAssert.h" +#include "Timer.h" using namespace codal; -LevelDetectorSPL::LevelDetectorSPL(DataSource &source, float highThreshold, float lowThreshold, float gain, float minValue, uint16_t id, bool activateImmediately) : upstream(source), resourceLock(0) +LevelDetectorSPL::LevelDetectorSPL(DataSource& source, float highThreshold, float lowThreshold, float gain, + float minValue, uint16_t id, bool activateImmediately) + : upstream(source), resourceLock(0) { - this->id = id; - this->level = 0; - this->windowSize = LEVEL_DETECTOR_SPL_DEFAULT_WINDOW_SIZE; - this->lowThreshold = lowThreshold; + this->id = id; + this->level = 0; + this->windowSize = LEVEL_DETECTOR_SPL_DEFAULT_WINDOW_SIZE; + this->lowThreshold = lowThreshold; this->highThreshold = highThreshold; - this->minValue = minValue; - this->gain = gain; + this->minValue = minValue; + this->gain = gain; this->status |= LEVEL_DETECTOR_SPL_INITIALISED; this->unit = LEVEL_DETECTOR_SPL_DB; - enabled = true; - if(activateImmediately){ + enabled = true; + if (activateImmediately) { upstream.connect(*this); this->activated = true; } - else{ + else { this->activated = false; } this->quietBlockCount = 0; this->noisyBlockCount = 0; - this->inNoisyBlock = false; - this->maxRms = 0; + this->inNoisyBlock = false; + this->maxRms = 0; this->bufferCount = 0; - this->timeout = 0; + this->timeout = 0; } int LevelDetectorSPL::pullRequest() { // If we're not manually activated, not held active by a timeout, and we have no-one waiting on our data, bail. - if( !activated && !(system_timer_current_time() - this->timeout < CODAL_STREAM_IDLE_TIMEOUT_MS) && resourceLock.getWaitCount() == 0 ) { + if (!activated && !(system_timer_current_time() - this->timeout < CODAL_STREAM_IDLE_TIMEOUT_MS) && + resourceLock.getWaitCount() == 0) { this->bufferCount = 0; return DEVICE_BUSY; } ManagedBuffer b = upstream.pull(); - uint8_t *data = &b[0]; - - int format = upstream.getFormat(); - int skip = 1; + uint8_t* data = &b[0]; + + int format = upstream.getFormat(); + int skip = 1; float multiplier = 256; - windowSize = 256; + windowSize = 256; - if (format == DATASTREAM_FORMAT_16BIT_SIGNED || format == DATASTREAM_FORMAT_UNKNOWN){ - skip = 2; + if (format == DATASTREAM_FORMAT_16BIT_SIGNED || format == DATASTREAM_FORMAT_UNKNOWN) { + skip = 2; multiplier = 1; windowSize = 128; } - else if (format == DATASTREAM_FORMAT_32BIT_SIGNED){ - skip = 4; + else if (format == DATASTREAM_FORMAT_32BIT_SIGNED) { + skip = 4; windowSize = 64; - multiplier = (1/65536); + multiplier = (1 / 65536); } int samples = b.length() / skip; - while(samples){ + while (samples) { // ensure we use at least windowSize number of samples (128) - if(samples < windowSize) - break; + if (samples < windowSize) break; uint8_t *ptr, *end; @@ -105,14 +108,14 @@ int LevelDetectorSPL::pullRequest() float pref = 0.00002; /******************************* - * GET MAX VALUE - ******************************/ + * GET MAX VALUE + ******************************/ int16_t maxVal = 0; int16_t minVal = 32766; int32_t v; ptr = data; while (ptr < end) { - v = (int32_t) StreamNormalizer::readSample[format](ptr); + v = (int32_t)StreamNormalizer::readSample[format](ptr); if (v > maxVal) maxVal = v; if (v < minVal) minVal = v; ptr += skip; @@ -120,24 +123,24 @@ int LevelDetectorSPL::pullRequest() maxVal = (maxVal - minVal) / 2; /******************************* - * GET RMS AMPLITUDE FOR CLAP DETECTION - ******************************/ + * GET RMS AMPLITUDE FOR CLAP DETECTION + ******************************/ int sumSquares = 0; - int count = 0; - ptr = data; + int count = 0; + ptr = data; while (ptr < end) { count++; - v = (int32_t) StreamNormalizer::readSample[format](ptr) - minVal; // need to sub minVal to avoid overflow + v = (int32_t)StreamNormalizer::readSample[format](ptr) - minVal; // need to sub minVal to avoid overflow sumSquares += v * v; ptr += skip; } float rms = sqrt(sumSquares / count); /******************************* - * CALCULATE SPL - ******************************/ - float conv = ((float) maxVal * multiplier) / ((1 << 15) - 1) * gain; - conv = 20 * log10(conv / pref); + * CALCULATE SPL + ******************************/ + float conv = ((float)maxVal * multiplier) / ((1 << 15) - 1) * gain; + conv = 20 * log10(conv / pref); if (conv < minValue) level = minValue; @@ -150,62 +153,52 @@ int LevelDetectorSPL::pullRequest() data += windowSize; /******************************* - * EMIT EVENTS - ******************************/ + * EMIT EVENTS + ******************************/ - if( this->bufferCount < LEVEL_DETECTOR_SPL_MIN_BUFFERS ) { - this->bufferCount++; // Here to prevent this endlessly increasing + if (this->bufferCount < LEVEL_DETECTOR_SPL_MIN_BUFFERS) { + this->bufferCount++; // Here to prevent this endlessly increasing return DEVICE_OK; } - if( this->resourceLock.getWaitCount() > 0 ) - this->resourceLock.notifyAll(); + if (this->resourceLock.getWaitCount() > 0) this->resourceLock.notifyAll(); // HIGH THRESHOLD - if ((!(status & LEVEL_DETECTOR_SPL_HIGH_THRESHOLD_PASSED)) && level > highThreshold) - { + if ((!(status & LEVEL_DETECTOR_SPL_HIGH_THRESHOLD_PASSED)) && level > highThreshold) { Event(id, LEVEL_THRESHOLD_HIGH); - status |= LEVEL_DETECTOR_SPL_HIGH_THRESHOLD_PASSED; + status |= LEVEL_DETECTOR_SPL_HIGH_THRESHOLD_PASSED; status &= ~LEVEL_DETECTOR_SPL_LOW_THRESHOLD_PASSED; } // LOW THRESHOLD - else if ((!(status & LEVEL_DETECTOR_SPL_LOW_THRESHOLD_PASSED)) && level < lowThreshold) - { + else if ((!(status & LEVEL_DETECTOR_SPL_LOW_THRESHOLD_PASSED)) && level < lowThreshold) { Event(id, LEVEL_THRESHOLD_LOW); - status |= LEVEL_DETECTOR_SPL_LOW_THRESHOLD_PASSED; + status |= LEVEL_DETECTOR_SPL_LOW_THRESHOLD_PASSED; status &= ~LEVEL_DETECTOR_SPL_HIGH_THRESHOLD_PASSED; } // CLAP DETECTION HANDLING if (this->inNoisyBlock && rms > this->maxRms) this->maxRms = rms; - if ( - ( // if start of clap - !this->inNoisyBlock && - rms > LEVEL_DETECTOR_SPL_BEGIN_POSS_CLAP_RMS && - this->quietBlockCount >= LEVEL_DETECTOR_SPL_CLAP_MIN_QUIET_BLOCKS - ) || - ( // or if continuing a clap - this->inNoisyBlock && - rms > LEVEL_DETECTOR_SPL_CLAP_OVER_RMS - )) { + if (( // if start of clap + !this->inNoisyBlock && rms > LEVEL_DETECTOR_SPL_BEGIN_POSS_CLAP_RMS && + this->quietBlockCount >= LEVEL_DETECTOR_SPL_CLAP_MIN_QUIET_BLOCKS) || + ( // or if continuing a clap + this->inNoisyBlock && rms > LEVEL_DETECTOR_SPL_CLAP_OVER_RMS)) { // noisy block - if (!this->inNoisyBlock) - this->maxRms = rms; + if (!this->inNoisyBlock) this->maxRms = rms; this->quietBlockCount = 0; this->noisyBlockCount += 1; this->inNoisyBlock = true; - - } else { + } + else { // quiet block - if ( // if not too long, not too short, and loud enough - this->noisyBlockCount <= LEVEL_DETECTOR_SPL_CLAP_MAX_LOUD_BLOCKS && - this->noisyBlockCount >= LEVEL_DETECTOR_SPL_CLAP_MIN_LOUD_BLOCKS && - this->maxRms >= LEVEL_DETECTOR_SPL_MIN_IN_CLAP_RMS - ) { + if ( // if not too long, not too short, and loud enough + this->noisyBlockCount <= LEVEL_DETECTOR_SPL_CLAP_MAX_LOUD_BLOCKS && + this->noisyBlockCount >= LEVEL_DETECTOR_SPL_CLAP_MIN_LOUD_BLOCKS && + this->maxRms >= LEVEL_DETECTOR_SPL_MIN_IN_CLAP_RMS) { Event(id, LEVEL_DETECTOR_SPL_CLAP); } - this->inNoisyBlock = false; + this->inNoisyBlock = false; this->noisyBlockCount = 0; this->quietBlockCount += 1; this->maxRms = 0; @@ -215,41 +208,38 @@ int LevelDetectorSPL::pullRequest() return DEVICE_OK; } -float LevelDetectorSPL::getValue( int scale ) +float LevelDetectorSPL::getValue(int scale) { - if( !this->upstream.isConnected() ) - this->upstream.connect( *this ); + if (!this->upstream.isConnected()) this->upstream.connect(*this); // Lock the resource, THEN bump the timout, so we get consistent on-time - if( this->bufferCount < LEVEL_DETECTOR_SPL_MIN_BUFFERS ) - resourceLock.wait(); + if (this->bufferCount < LEVEL_DETECTOR_SPL_MIN_BUFFERS) resourceLock.wait(); this->timeout = system_timer_current_time(); - return splToUnit( this->level, scale ); + return splToUnit(this->level, scale); } -void LevelDetectorSPL::activateForEvents( bool state ) +void LevelDetectorSPL::activateForEvents(bool state) { this->activated = state; - if( this->activated && !this->upstream.isConnected() ) { - this->upstream.connect( *this ); + if (this->activated && !this->upstream.isConnected()) { + this->upstream.connect(*this); } } -void LevelDetectorSPL::disable(){ +void LevelDetectorSPL::disable() +{ enabled = false; } - int LevelDetectorSPL::setLowThreshold(float value) { // Convert specified unit into db if necessary value = unitToSpl(value); // Protect against churn if the same threshold is set repeatedly. - if (lowThreshold == value) - return DEVICE_OK; + if (lowThreshold == value) return DEVICE_OK; // We need to update our threshold lowThreshold = value; @@ -258,8 +248,7 @@ int LevelDetectorSPL::setLowThreshold(float value) status &= ~LEVEL_DETECTOR_SPL_LOW_THRESHOLD_PASSED; // If a HIGH threshold has been set, ensure it's above the LOW threshold. - if (highThreshold < lowThreshold) - setHighThreshold(lowThreshold+1); + if (highThreshold < lowThreshold) setHighThreshold(lowThreshold + 1); return DEVICE_OK; } @@ -270,8 +259,7 @@ int LevelDetectorSPL::setHighThreshold(float value) value = unitToSpl(value); // Protect against churn if the same threshold is set repeatedly. - if (highThreshold == value) - return DEVICE_OK; + if (highThreshold == value) return DEVICE_OK; // We need to update our threshold highThreshold = value; @@ -280,8 +268,7 @@ int LevelDetectorSPL::setHighThreshold(float value) status &= ~LEVEL_DETECTOR_SPL_HIGH_THRESHOLD_PASSED; // If a HIGH threshold has been set, ensure it's above the LOW threshold. - if (lowThreshold > highThreshold) - setLowThreshold(highThreshold - 1); + if (lowThreshold > highThreshold) setLowThreshold(highThreshold - 1); return DEVICE_OK; } @@ -298,8 +285,7 @@ float LevelDetectorSPL::getHighThreshold() int LevelDetectorSPL::setWindowSize(int size) { - if (size <= 0) - return DEVICE_INVALID_PARAMETER; + if (size <= 0) return DEVICE_INVALID_PARAMETER; this->windowSize = size; return DEVICE_OK; @@ -313,8 +299,7 @@ int LevelDetectorSPL::setGain(float gain) int LevelDetectorSPL::setUnit(int unit) { - if (unit == LEVEL_DETECTOR_SPL_DB || unit == LEVEL_DETECTOR_SPL_8BIT) - { + if (unit == LEVEL_DETECTOR_SPL_DB || unit == LEVEL_DETECTOR_SPL_8BIT) { this->unit = unit; return DEVICE_OK; } @@ -322,27 +307,22 @@ int LevelDetectorSPL::setUnit(int unit) return DEVICE_INVALID_PARAMETER; } - float LevelDetectorSPL::splToUnit(float level, int queryUnit) { queryUnit = queryUnit == -1 ? unit : queryUnit; - if (queryUnit == LEVEL_DETECTOR_SPL_8BIT) - { + if (queryUnit == LEVEL_DETECTOR_SPL_8BIT) { level = (level - LEVEL_DETECTOR_SPL_8BIT_000_POINT) * LEVEL_DETECTOR_SPL_8BIT_CONVERSION; // Ensure the result is clamped into the expected range. - if (level < 0.0f) - level = 0.0f; + if (level < 0.0f) level = 0.0f; - if (level > 255.0f) - level = 255.0f; + if (level > 255.0f) level = 255.0f; } return level; } - float LevelDetectorSPL::unitToSpl(float level, int queryUnit) { queryUnit = queryUnit == -1 ? unit : queryUnit; @@ -353,6 +333,4 @@ float LevelDetectorSPL::unitToSpl(float level, int queryUnit) return level; } -LevelDetectorSPL::~LevelDetectorSPL() -{ -} +LevelDetectorSPL::~LevelDetectorSPL() {} diff --git a/source/streams/LowPassFilter.cpp b/source/streams/LowPassFilter.cpp index b9d83c5b..aefef965 100644 --- a/source/streams/LowPassFilter.cpp +++ b/source/streams/LowPassFilter.cpp @@ -1,45 +1,42 @@ #include "LowPassFilter.h" + #include "CodalDmesg.h" using namespace codal; -LowPassFilter::LowPassFilter( DataSource &source, float beta, bool deepCopy) : EffectFilter( source, deepCopy ) +LowPassFilter::LowPassFilter(DataSource& source, float beta, bool deepCopy) : EffectFilter(source, deepCopy) { this->lpf_value = 1.0; setBeta(beta); } -LowPassFilter::~LowPassFilter() -{ -} +LowPassFilter::~LowPassFilter() {} /** * Apply a simple low pass filter on the give buffer of data. * Y(n) = (1-ß)*Y(n-1) + (ß*X(n))) = Y(n-1) - (ß*(Y(n-1)-X(n))); - * + * * @param inputBuffer the buffer containing data to process. * @param outputBuffer the buffer in which to store the filtered data. n.b. MAY be the same memory as the input buffer. * @param format the format of the data (word size and signed/unsigned representation) */ void LowPassFilter::applyEffect(ManagedBuffer inputBuffer, ManagedBuffer outputBuffer, int format) { - if( inputBuffer.length() < 1 ) - return; - + if (inputBuffer.length() < 1) return; + int bytesPerSample = DATASTREAM_FORMAT_BYTES_PER_SAMPLE(format); - int sampleCount = inputBuffer.length() / bytesPerSample; - uint8_t *in = inputBuffer.getBytes(); - uint8_t *out = outputBuffer.getBytes(); + int sampleCount = inputBuffer.length() / bytesPerSample; + uint8_t* in = inputBuffer.getBytes(); + uint8_t* out = outputBuffer.getBytes(); - for( int i=0; ilpf_beta = beta; } \ No newline at end of file diff --git a/source/streams/MemorySource.cpp b/source/streams/MemorySource.cpp index 36a437f0..74bd58e1 100644 --- a/source/streams/MemorySource.cpp +++ b/source/streams/MemorySource.cpp @@ -23,6 +23,7 @@ DEALINGS IN THE SOFTWARE. */ #include "MemorySource.h" + #include "CodalDmesg.h" using namespace codal; @@ -39,19 +40,19 @@ MemorySource::MemorySource() : output(*this) this->setFormat(DATASTREAM_FORMAT_8BIT_UNSIGNED); this->setBufferSize(MEMORY_SOURCE_DEFAULT_MAX_BUFFER); lock.wait(); -} +} /* - * Allow out downstream component to register itself with us - */ -void MemorySource::connect(DataSink &sink) + * Allow out downstream component to register itself with us + */ +void MemorySource::connect(DataSink& sink) { this->downstream = &sink; } /** * Determines if this source is connected to a downstream component - * + * * @return true If a downstream is connected * @return false If a downstream is not connected */ @@ -63,8 +64,7 @@ bool MemorySource::isConnected() /** * Determine the data format of the buffers streamed out of this component. */ -int -MemorySource::getFormat() +int MemorySource::getFormat() { return outputFormat; } @@ -73,8 +73,7 @@ MemorySource::getFormat() * Defines the data format of the buffers streamed out of this component. * @param format the format to use, one of */ -int -MemorySource::setFormat(int format) +int MemorySource::setFormat(int format) { outputFormat = format; return DEVICE_OK; @@ -84,8 +83,7 @@ MemorySource::setFormat(int format) * Determine the maximum size of the buffers streamed out of this component. * @return The maximum size of this component's output buffers, in bytes. */ -int -MemorySource::getBufferSize() +int MemorySource::getBufferSize() { return outputBufferSize; } @@ -94,8 +92,7 @@ MemorySource::getBufferSize() * Defines the maximum size of the buffers streamed out of this component. * @param size the size of this component's output buffers, in bytes. */ -int -MemorySource::setBufferSize(int size) +int MemorySource::setBufferSize(int size) { outputBufferSize = size; return DEVICE_OK; @@ -107,7 +104,7 @@ MemorySource::setBufferSize(int size) ManagedBuffer MemorySource::pull() { // Calculate the amount of data we can transfer. - int l = min(bytesToSend, outputBufferSize); + int l = min(bytesToSend, outputBufferSize); buffer = ManagedBuffer(l); memcpy(&buffer[0], in, l); @@ -116,25 +113,20 @@ ManagedBuffer MemorySource::pull() in += l; // If we've consumed the input buffer, see if we need to reload it - if (bytesToSend == 0) - { - if (count > 0) - count--; + if (bytesToSend == 0) { + if (count > 0) count--; - if (count != 0) - { + if (count != 0) { bytesToSend = length; - in = data; + in = data; } } // If we still have data to send, indicate this to our downstream component - if (bytesToSend > 0) - downstream->pullRequest(); - + if (bytesToSend > 0) downstream->pullRequest(); + // If we have completed playback and blockingbehaviour was requested, wake the fiber that is blocked waiting. - if (bytesToSend == 0 && count == 0 && blockingPlayout) - lock.notify(); + if (bytesToSend == 0 && count == 0 && blockingPlayout) lock.notify(); return buffer; } @@ -143,17 +135,19 @@ ManagedBuffer MemorySource::pull() * Perform a non-blocking playout of the data buffer. Returns when all the data has been queued. * @param data pointer to memory location to playout * @param length number of samples in the buffer. Assumes a sample size as defined by setFormat(). - * @param count if set, playback the buffer the given number of times. Defaults to 1. Set to a negative number to loop forever. + * @param count if set, playback the buffer the given number of times. Defaults to 1. Set to a negative number to loop + * forever. */ -void MemorySource::playAsync(const void *data, int length, int count) +void MemorySource::playAsync(const void* data, int length, int count) { _play(data, length, count, false); -} +} /** * Perform a non-blocking playout of the data buffer. Returns when all the data has been queued. * @param b the buffer to playout - * @param count if set, playback the buffer the given number of times. Defaults to 1. Set to a negative number to loop forever. + * @param count if set, playback the buffer the given number of times. Defaults to 1. Set to a negative number to loop + * forever. */ void MemorySource::playAsync(ManagedBuffer b, int count) { @@ -164,35 +158,35 @@ void MemorySource::playAsync(ManagedBuffer b, int count) * Perform a blocking playout of the data buffer. Returns when all the data has been queued. * @param data pointer to memory location to playout * @param length number of samples in the buffer. Assumes a sample size as defined by setFormat(). - * @param count if set, playback the buffer the given number of times. Defaults to 1. Set to a negative number to loop forever. + * @param count if set, playback the buffer the given number of times. Defaults to 1. Set to a negative number to loop + * forever. */ -void MemorySource::play(const void *data, int length, int count) +void MemorySource::play(const void* data, int length, int count) { _play(data, length, count, true); -} +} /** * Perform a blocking playout of the data buffer. Returns when all the data has been queued. * @param b the buffer to playout - * @param count if set, playback the buffer the given number of times. Defaults to 1. Set to a negative number to loop forever. + * @param count if set, playback the buffer the given number of times. Defaults to 1. Set to a negative number to loop + * forever. */ void MemorySource::play(ManagedBuffer b, int count) { this->play(&b[0], b.length(), count); } -void MemorySource::_play(const void *data, int length, int count, bool mode) +void MemorySource::_play(const void* data, int length, int count, bool mode) { - if (downstream == NULL || length <= 0 || count == 0) - return; + if (downstream == NULL || length <= 0 || count == 0) return; - this->data = this->in = (uint8_t *)data; - this->length =this->bytesToSend = length; - this->count = count; - this->blockingPlayout = mode; + this->data = this->in = (uint8_t*)data; + this->length = this->bytesToSend = length; + this->count = count; + this->blockingPlayout = mode; downstream->pullRequest(); - if (this->blockingPlayout) - lock.wait(); + if (this->blockingPlayout) lock.wait(); } \ No newline at end of file diff --git a/source/streams/Mixer.cpp b/source/streams/Mixer.cpp index cf35fe75..906af24a 100644 --- a/source/streams/Mixer.cpp +++ b/source/streams/Mixer.cpp @@ -23,63 +23,63 @@ DEALINGS IN THE SOFTWARE. */ #include "Mixer.h" -#include "ErrorNo.h" + #include "CodalDmesg.h" +#include "ErrorNo.h" using namespace codal; Mixer::Mixer() { - channels = NULL; + channels = NULL; downStream = NULL; } Mixer::~Mixer() { - while (channels) - { - auto n = channels; + while (channels) { + auto n = channels; channels = n->next; n->stream->disconnect(); delete n; } } -MixerChannel *Mixer::addChannel(DataStream &stream) +MixerChannel* Mixer::addChannel(DataStream& stream) { - auto c = new MixerChannel(); - c->stream = &stream; - c->next = channels; - c->volume = 1024; + auto c = new MixerChannel(); + c->stream = &stream; + c->next = channels; + c->volume = 1024; c->isSigned = true; - channels = c; + channels = c; stream.connect(*this); return c; } -ManagedBuffer Mixer::pull() { - if (!channels) - return ManagedBuffer(512); +ManagedBuffer Mixer::pull() +{ + if (!channels) return ManagedBuffer(512); ManagedBuffer sum; - MixerChannel *next; + MixerChannel* next; for (auto ch = channels; ch; ch = next) { - next = ch->next; // save next in case the current channel gets deleted - bool isSigned = ch->isSigned; - int vol = ch->volume; + next = ch->next; // save next in case the current channel gets deleted + bool isSigned = ch->isSigned; + int vol = ch->volume; ManagedBuffer data = ch->stream->pull(); if (sum.length() < data.length()) { ManagedBuffer newsum(data.length()); newsum.writeBuffer(0, sum); sum = newsum; } - auto d = (int16_t*)&data[0]; - auto s = (int16_t*)&sum[0]; + auto d = (int16_t*)&data[0]; + auto s = (int16_t*)&sum[0]; auto len = data.length() >> 1; while (len--) { int v = isSigned ? *d : *(uint16_t*)d - 512; - v = ((v * vol) + (*s << 10)) >> 10; + v = ((v * vol) + (*s << 10)) >> 10; if (v < -512) v = -512; if (v > 511) v = 511; *s = v; @@ -88,11 +88,10 @@ ManagedBuffer Mixer::pull() { } } - auto s = (int16_t*)&sum[0]; + auto s = (int16_t*)&sum[0]; auto len = sum.length() >> 1; - while (len--) - *s++ += 512; - + while (len--) *s++ += 512; + return sum; } @@ -101,12 +100,11 @@ int Mixer::pullRequest() // we might call it too much if we have more than one channel, but we // assume the downStream is only going to call pull() as much as it needs // and not more - if (downStream) - downStream->pullRequest(); + if (downStream) downStream->pullRequest(); return DEVICE_OK; } -void Mixer::connect(DataSink &sink) +void Mixer::connect(DataSink& sink) { this->downStream = &sink; } diff --git a/source/streams/StreamFlowTrigger.cpp b/source/streams/StreamFlowTrigger.cpp index a6191163..4c290db0 100644 --- a/source/streams/StreamFlowTrigger.cpp +++ b/source/streams/StreamFlowTrigger.cpp @@ -1,15 +1,16 @@ #include "StreamFlowTrigger.h" -#include "ManagedBuffer.h" -#include "DataStream.h" + #include "CodalDmesg.h" +#include "DataStream.h" +#include "ManagedBuffer.h" using namespace codal; -StreamFlowTrigger::StreamFlowTrigger( DataSource &source ) : upStream( source ) +StreamFlowTrigger::StreamFlowTrigger(DataSource& source) : upStream(source) { this->eventHandler = NULL; - this->downStream = NULL; - source.connect( *this ); + this->downStream = NULL; + source.connect(*this); } StreamFlowTrigger::~StreamFlowTrigger() @@ -17,27 +18,26 @@ StreamFlowTrigger::~StreamFlowTrigger() // NOP } -void StreamFlowTrigger::setDataHandler( void (*handler)(int) ) +void StreamFlowTrigger::setDataHandler(void (*handler)(int)) { this->eventHandler = handler; } ManagedBuffer StreamFlowTrigger::pull() { - (*this->eventHandler)( TRIGGER_PULL ); + (*this->eventHandler)(TRIGGER_PULL); return this->upStream.pull(); } int StreamFlowTrigger::pullRequest() { - (*this->eventHandler)( TRIGGER_REQUEST ); - if( this->downStream != NULL ) - return this->downStream->pullRequest(); - + (*this->eventHandler)(TRIGGER_REQUEST); + if (this->downStream != NULL) return this->downStream->pullRequest(); + return DEVICE_BUSY; } -void StreamFlowTrigger::connect( DataSink &sink ) +void StreamFlowTrigger::connect(DataSink& sink) { this->downStream = &sink; } @@ -57,7 +57,7 @@ int StreamFlowTrigger::getFormat() return this->upStream.getFormat(); } -int StreamFlowTrigger::setFormat( int format ) +int StreamFlowTrigger::setFormat(int format) { - return this->upStream.setFormat( format ); + return this->upStream.setFormat(format); } \ No newline at end of file diff --git a/source/streams/StreamNormalizer.cpp b/source/streams/StreamNormalizer.cpp index 9b8a04b8..87b13e78 100644 --- a/source/streams/StreamNormalizer.cpp +++ b/source/streams/StreamNormalizer.cpp @@ -23,98 +23,103 @@ DEALINGS IN THE SOFTWARE. */ #include "StreamNormalizer.h" -#include "ErrorNo.h" + #include "CodalDmesg.h" +#include "ErrorNo.h" using namespace codal; -static int read_sample_1(uint8_t *ptr) +static int read_sample_1(uint8_t* ptr) { - return (int) *ptr; + return (int)*ptr; } -static int read_sample_2(uint8_t *ptr) +static int read_sample_2(uint8_t* ptr) { - int8_t *p = (int8_t *) ptr; - return (int) *p; + int8_t* p = (int8_t*)ptr; + return (int)*p; } -static int read_sample_3(uint8_t *ptr) +static int read_sample_3(uint8_t* ptr) { - uint16_t *p = (uint16_t *) ptr; - return (int) *p; + uint16_t* p = (uint16_t*)ptr; + return (int)*p; } -static int read_sample_4(uint8_t *ptr) +static int read_sample_4(uint8_t* ptr) { - int16_t *p = (int16_t *) ptr; - return (int) *p; + int16_t* p = (int16_t*)ptr; + return (int)*p; } -static int read_sample_5(uint8_t *ptr) +static int read_sample_5(uint8_t* ptr) { - uint32_t *p = (uint32_t *) ptr; - return (int) (*p >> 8); + uint32_t* p = (uint32_t*)ptr; + return (int)(*p >> 8); } -static int read_sample_6(uint8_t *ptr) +static int read_sample_6(uint8_t* ptr) { - int32_t *p = (int32_t *) ptr; - return (int) (*p >> 8); + int32_t* p = (int32_t*)ptr; + return (int)(*p >> 8); } -static int read_sample_7(uint8_t *ptr) +static int read_sample_7(uint8_t* ptr) { - uint32_t *p = (uint32_t *) ptr; - return (int) *p; + uint32_t* p = (uint32_t*)ptr; + return (int)*p; } -static int read_sample_8(uint8_t *ptr) +static int read_sample_8(uint8_t* ptr) { - int32_t *p = (int32_t *) ptr; - return (int) *p; + int32_t* p = (int32_t*)ptr; + return (int)*p; } -static void write_sample_1(uint8_t *ptr, int value) +static void write_sample_1(uint8_t* ptr, int value) { - *ptr = (uint8_t) value; + *ptr = (uint8_t)value; } -static void write_sample_2(uint8_t *ptr, int value) +static void write_sample_2(uint8_t* ptr, int value) { - *ptr = (int8_t) value; + *ptr = (int8_t)value; } -static void write_sample_3(uint8_t *ptr, int value) +static void write_sample_3(uint8_t* ptr, int value) { - *(uint16_t *)ptr = (uint16_t) value; + *(uint16_t*)ptr = (uint16_t)value; } -static void write_sample_4(uint8_t *ptr, int value) +static void write_sample_4(uint8_t* ptr, int value) { - *(int16_t *)ptr = (int16_t) value; + *(int16_t*)ptr = (int16_t)value; } -static void write_sample_5_6(uint8_t *ptr, int value) +static void write_sample_5_6(uint8_t* ptr, int value) { - *ptr = value & 0xFF; - *(ptr+1) = (value>>8) & 0xFF; - *(ptr+2) = (value>>16) & 0xFF; + *ptr = value & 0xFF; + *(ptr + 1) = (value >> 8) & 0xFF; + *(ptr + 2) = (value >> 16) & 0xFF; } -static void write_sample_7(uint8_t *ptr, int value) +static void write_sample_7(uint8_t* ptr, int value) { - *(uint32_t *)ptr = (uint32_t) value; + *(uint32_t*)ptr = (uint32_t)value; } -static void write_sample_8(uint8_t *ptr, int value) +static void write_sample_8(uint8_t* ptr, int value) { - *(int32_t *)ptr = (int32_t) value; + *(int32_t*)ptr = (int32_t)value; } // Lookup table to optimse parsing of input stream. -SampleReadFn StreamNormalizer::readSample[] = {read_sample_1, read_sample_1, read_sample_2, read_sample_3, read_sample_4, read_sample_5, read_sample_6, read_sample_7, read_sample_8}; -SampleWriteFn StreamNormalizer::writeSample[] = {write_sample_1, write_sample_1, write_sample_2, write_sample_3, write_sample_4, write_sample_5_6, write_sample_5_6, write_sample_7, write_sample_8}; +SampleReadFn StreamNormalizer::readSample[] = {read_sample_1, read_sample_1, read_sample_2, + read_sample_3, read_sample_4, read_sample_5, + read_sample_6, read_sample_7, read_sample_8}; +SampleWriteFn StreamNormalizer::writeSample[] = {write_sample_1, write_sample_1, write_sample_2, + write_sample_3, write_sample_4, write_sample_5_6, + write_sample_5_6, write_sample_7, write_sample_8}; /** * Creates a component capable of translating one data representation format into another @@ -123,18 +128,20 @@ SampleWriteFn StreamNormalizer::writeSample[] = {write_sample_1, write_sample_1, * @param gain The gain to apply to each sample (default: 1.0) * @param normalize Derive a zero offset for the input stream, and subtract from each sample (default: false) * @param format The format to convert the input stream into - * @param stabilisation the maximum change of zero-offset permitted between subsequent buffers before output is initiated. Set to zero to disable (default) + * @param stabilisation the maximum change of zero-offset permitted between subsequent buffers before output is + * initiated. Set to zero to disable (default) */ -StreamNormalizer::StreamNormalizer(DataSource &source, float gain, bool normalize, int format, int stabilisation) : upstream(source), output(*this) +StreamNormalizer::StreamNormalizer(DataSource& source, float gain, bool normalize, int format, int stabilisation) + : upstream(source), output(*this) { setFormat(format); setGain(gain); setNormalize(normalize); setOrMask(0); this->zeroOffsetValid = false; - this->zeroOffset = 0; - this->stabilisation = stabilisation; - this->outputEnabled = normalize && stabilisation ? false : true; + this->zeroOffset = 0; + this->stabilisation = stabilisation; + this->outputEnabled = normalize && stabilisation ? false : true; // Register with our upstream component source.connect(*this); @@ -145,58 +152,55 @@ StreamNormalizer::StreamNormalizer(DataSource &source, float gain, bool normaliz */ ManagedBuffer StreamNormalizer::pull() { - int samples; // Number of samples in the input buffer. - int s; // The sample being processed, encpasulated inside a 32 bit number. - uint8_t *data; // Input buffer read pointer. - uint8_t *result; // Output buffer write pointer. - int inputFormat; // The format of the input buffer. - int bytesPerSampleIn; // number of bit per sample of the input buffer. - int bytesPerSampleOut; // number of bit per sample of the input buffer. - int z = 0; // normalized zero point calculated from this buffer. - int zo = (int) zeroOffset; // Snapshot of our previously calculate zero point. - ManagedBuffer buffer; // The buffer being processed. - + int samples; // Number of samples in the input buffer. + int s; // The sample being processed, encpasulated inside a 32 bit number. + uint8_t* data; // Input buffer read pointer. + uint8_t* result; // Output buffer write pointer. + int inputFormat; // The format of the input buffer. + int bytesPerSampleIn; // number of bit per sample of the input buffer. + int bytesPerSampleOut; // number of bit per sample of the input buffer. + int z = 0; // normalized zero point calculated from this buffer. + int zo = (int)zeroOffset; // Snapshot of our previously calculate zero point. + ManagedBuffer buffer; // The buffer being processed. + // Determine the input format. inputFormat = upstream.getFormat(); // If no output format has been selected, infer it from our upstream component. - if (outputFormat == DATASTREAM_FORMAT_UNKNOWN) - outputFormat = inputFormat; + if (outputFormat == DATASTREAM_FORMAT_UNKNOWN) outputFormat = inputFormat; // Deterine the sample size of out input and output formats. - bytesPerSampleIn = DATASTREAM_FORMAT_BYTES_PER_SAMPLE(inputFormat); + bytesPerSampleIn = DATASTREAM_FORMAT_BYTES_PER_SAMPLE(inputFormat); bytesPerSampleOut = DATASTREAM_FORMAT_BYTES_PER_SAMPLE(outputFormat); // Acquire the buffer to be processed. ManagedBuffer inputBuffer = upstream.pull(); - samples = inputBuffer.length() / bytesPerSampleIn; + samples = inputBuffer.length() / bytesPerSampleIn; // Use in place processing where possible, but allocate a new buffer when needed. if (DATASTREAM_FORMAT_BYTES_PER_SAMPLE(inputFormat) == DATASTREAM_FORMAT_BYTES_PER_SAMPLE(outputFormat)) buffer = inputBuffer; else buffer = ManagedBuffer(samples * bytesPerSampleOut); - + // Initialise input an doutput buffer pointers. - data = &inputBuffer[0]; + data = &inputBuffer[0]; result = &buffer[0]; // Iterate over the input samples and apply gain, normalization and output formatting. - for (int i=0; i < samples; i++) - { + for (int i = 0; i < samples; i++) { // read an input sample, account for the appropriate encoding. s = readSample[inputFormat](data); data += bytesPerSampleIn; // Calculate and apply normalization, if configured. - if (normalize) - { + if (normalize) { z += s; s = s - zo; } // Apply configured gain, and mask if any. - s = (int) ((float)s * gain); + s = (int)((float)s * gain); s |= orMask; // Write out the sample. @@ -205,15 +209,13 @@ ManagedBuffer StreamNormalizer::pull() } // Store the average sample value as an inferred zero point for the next buffer. - if (normalize) - { + if (normalize) { float calculatedZeroOffset = (float)z / (float)samples; - zeroOffset = zeroOffsetValid ? zeroOffset*0.5 + calculatedZeroOffset*0.5 : calculatedZeroOffset; + zeroOffset = zeroOffsetValid ? zeroOffset * 0.5 + calculatedZeroOffset * 0.5 : calculatedZeroOffset; zeroOffsetValid = true; - if (stabilisation == 0 || abs((int)zeroOffset - zo) < stabilisation) - outputEnabled = true; + if (stabilisation == 0 || abs((int)zeroOffset - zo) < stabilisation) outputEnabled = true; } // Ensure output buffer is the correct size; @@ -256,8 +258,7 @@ bool StreamNormalizer::getNormalize() */ int StreamNormalizer::getFormat() { - if (outputFormat == DATASTREAM_FORMAT_UNKNOWN) - outputFormat = upstream.getFormat(); + if (outputFormat == DATASTREAM_FORMAT_UNKNOWN) outputFormat = upstream.getFormat(); return outputFormat; } @@ -268,8 +269,7 @@ int StreamNormalizer::getFormat() */ int StreamNormalizer::setFormat(int format) { - if (format < DATASTREAM_FORMAT_UNKNOWN || format > DATASTREAM_FORMAT_32BIT_SIGNED) - return DEVICE_INVALID_PARAMETER; + if (format < DATASTREAM_FORMAT_UNKNOWN || format > DATASTREAM_FORMAT_32BIT_SIGNED) return DEVICE_INVALID_PARAMETER; outputFormat = format; return DEVICE_OK; @@ -311,20 +311,20 @@ int StreamNormalizer::setOrMask(uint32_t mask) /** * Destructor. */ -StreamNormalizer::~StreamNormalizer() -{ -} +StreamNormalizer::~StreamNormalizer() {} -float StreamNormalizer::getSampleRate() { +float StreamNormalizer::getSampleRate() +{ return this->upstream.getSampleRate(); } -float StreamNormalizer::requestSampleRate(float sampleRate) { - return this->upstream.requestSampleRate( sampleRate ); +float StreamNormalizer::requestSampleRate(float sampleRate) +{ + return this->upstream.requestSampleRate(sampleRate); } bool StreamNormalizer::isConnected() { - //return this->output.isConnected(); + // return this->output.isConnected(); return false; } \ No newline at end of file diff --git a/source/streams/StreamRecording.cpp b/source/streams/StreamRecording.cpp index 3e34a6c6..30ade18d 100644 --- a/source/streams/StreamRecording.cpp +++ b/source/streams/StreamRecording.cpp @@ -1,24 +1,25 @@ #include "StreamRecording.h" -#include "ErrorNo.h" + +#include "CodalDmesg.h" #include "DataStream.h" +#include "ErrorNo.h" #include "ManagedBuffer.h" #include "MessageBus.h" -#include "CodalDmesg.h" using namespace codal; -StreamRecording::StreamRecording( DataSource &source, uint32_t maxLength ) : upStream( source ) -{ - this->state = REC_STATE_STOPPED; - this->bufferChain = NULL; - this->lastBuffer = NULL; - this->readHead = NULL; - this->maxBufferLenth = maxLength; +StreamRecording::StreamRecording(DataSource& source, uint32_t maxLength) : upStream(source) +{ + this->state = REC_STATE_STOPPED; + this->bufferChain = NULL; + this->lastBuffer = NULL; + this->readHead = NULL; + this->maxBufferLenth = maxLength; this->totalBufferLength = 0; - this->lastUpstreamRate = DATASTREAM_SAMPLE_RATE_UNKNOWN; + this->lastUpstreamRate = DATASTREAM_SAMPLE_RATE_UNKNOWN; this->downStream = NULL; - upStream.connect( *this ); + upStream.connect(*this); } StreamRecording::~StreamRecording() @@ -34,22 +35,20 @@ bool StreamRecording::canPull() ManagedBuffer StreamRecording::pull() { // Are we playing back? - if( this->state != REC_STATE_PLAYING ) - return ManagedBuffer(); - + if (this->state != REC_STATE_PLAYING) return ManagedBuffer(); + // Do we have data to send? - if( this->readHead == NULL ) { + if (this->readHead == NULL) { stop(); return ManagedBuffer(); } - + // Grab the next block and move the r/w head ManagedBuffer out = this->readHead->buffer; - this->readHead = this->readHead->next; + this->readHead = this->readHead->next; // Prod the downstream that we're good to go - if( downStream != NULL ) - downStream->pullRequest(); + if (downStream != NULL) downStream->pullRequest(); // Return the block return out; @@ -60,69 +59,68 @@ int StreamRecording::length() return this->totalBufferLength; } -float StreamRecording::duration( unsigned int sampleRate ) +float StreamRecording::duration(unsigned int sampleRate) { - return ((float)this->length() / DATASTREAM_FORMAT_BYTES_PER_SAMPLE((float)this->getFormat()) ) / (float)sampleRate; + return ((float)this->length() / DATASTREAM_FORMAT_BYTES_PER_SAMPLE((float)this->getFormat())) / (float)sampleRate; } -bool StreamRecording::isFull() { +bool StreamRecording::isFull() +{ return this->totalBufferLength >= this->maxBufferLenth; } void StreamRecording::printChain() { - #if CONFIG_ENABLED(DMESG_SERIAL_DEBUG) && CONFIG_ENABLED(DMESG_AUDIO_DEBUG) - DMESGN( "START -> " ); - StreamRecording_Buffer * node = this->bufferChain; - while( node != NULL ) { - DMESGN( "%x -> ", (int)(node->buffer.getBytes()) ); - codal_dmesg_flush(); - node = node->next; - } - DMESG( "END (%d hz)", (int)this->lastUpstreamRate ); - #endif +#if CONFIG_ENABLED(DMESG_SERIAL_DEBUG) && CONFIG_ENABLED(DMESG_AUDIO_DEBUG) + DMESGN("START -> "); + StreamRecording_Buffer* node = this->bufferChain; + while (node != NULL) { + DMESGN("%x -> ", (int)(node->buffer.getBytes())); + codal_dmesg_flush(); + node = node->next; + } + DMESG("END (%d hz)", (int)this->lastUpstreamRate); +#endif } int StreamRecording::pullRequest() { // Are we recording? - if( this->state != REC_STATE_RECORDING ) - return DEVICE_BUSY; + if (this->state != REC_STATE_RECORDING) return DEVICE_BUSY; - ManagedBuffer data = this->upStream.pull(); + ManagedBuffer data = this->upStream.pull(); this->lastUpstreamRate = this->upStream.getSampleRate(); // Are we getting empty buffers (probably because we're out of RAM!) - if( data == ManagedBuffer() || data.length() <= 1 ) { + if (data == ManagedBuffer() || data.length() <= 1) { return DEVICE_OK; } // Can we record any more? - if( !isFull() ) - { - StreamRecording_Buffer * block = new StreamRecording_Buffer( data ); - if( block == NULL ) - return DEVICE_NO_RESOURCES; + if (!isFull()) { + StreamRecording_Buffer* block = new StreamRecording_Buffer(data); + if (block == NULL) return DEVICE_NO_RESOURCES; block->next = NULL; // Are we initialising stuff? If so, hook the front of the chain up too... - if( this->lastBuffer == NULL ) { + if (this->lastBuffer == NULL) { this->bufferChain = block; - } else + } + else this->lastBuffer->next = block; - + this->lastBuffer = block; - + this->totalBufferLength += this->lastBuffer->buffer.length(); - + return DEVICE_OK; } - + this->stop(); return DEVICE_NO_RESOURCES; } -void StreamRecording::connect( DataSink &sink ) +void StreamRecording::connect(DataSink& sink) { this->downStream = &sink; } @@ -142,17 +140,16 @@ int StreamRecording::getFormat() return this->upStream.getFormat(); } -int StreamRecording::setFormat( int format ) +int StreamRecording::setFormat(int format) { - return this->upStream.setFormat( format ); + return this->upStream.setFormat(format); } bool StreamRecording::recordAsync() { // Duplicate check from within erase(), but here for safety in case of later code edits... - if( this->state != REC_STATE_STOPPED ) - this->stop(); - + if (this->state != REC_STATE_STOPPED) this->stop(); + erase(); bool changed = this->state != REC_STATE_RECORDING; @@ -165,39 +162,35 @@ bool StreamRecording::recordAsync() void StreamRecording::record() { recordAsync(); - while( isRecording() ) - fiber_sleep(5); + while (isRecording()) fiber_sleep(5); printChain(); } void StreamRecording::erase() { - if( this->state != REC_STATE_STOPPED ) - this->stop(); - + if (this->state != REC_STATE_STOPPED) this->stop(); + // Run down the chain, freeing as we go - StreamRecording_Buffer * node = this->bufferChain; - while( node != NULL ) { - StreamRecording_Buffer * next = node->next; + StreamRecording_Buffer* node = this->bufferChain; + while (node != NULL) { + StreamRecording_Buffer* next = node->next; delete node; node = next; } this->totalBufferLength = 0; - this->lastBuffer = NULL; - this->readHead = NULL; - this->bufferChain = NULL; - this->lastUpstreamRate = DATASTREAM_SAMPLE_RATE_UNKNOWN; + this->lastBuffer = NULL; + this->readHead = NULL; + this->bufferChain = NULL; + this->lastUpstreamRate = DATASTREAM_SAMPLE_RATE_UNKNOWN; } bool StreamRecording::playAsync() { - if( this->state != REC_STATE_STOPPED ) - this->stop(); + if (this->state != REC_STATE_STOPPED) this->stop(); bool changed = this->state != REC_STATE_PLAYING; - + this->state = REC_STATE_PLAYING; - if( this->downStream != NULL ) - this->downStream->pullRequest(); + if (this->downStream != NULL) this->downStream->pullRequest(); return changed; } @@ -205,16 +198,15 @@ bool StreamRecording::playAsync() void StreamRecording::play() { playAsync(); - while( isPlaying() ) - fiber_sleep(5); + while (isPlaying()) fiber_sleep(5); } bool StreamRecording::stop() { bool changed = this->state != REC_STATE_STOPPED; - this->state = REC_STATE_STOPPED; - this->readHead = this->bufferChain; // Snap to the start + this->state = REC_STATE_STOPPED; + this->readHead = this->bufferChain; // Snap to the start return changed; } @@ -239,8 +231,7 @@ bool StreamRecording::isStopped() float StreamRecording::getSampleRate() { - if( this->lastUpstreamRate == DATASTREAM_SAMPLE_RATE_UNKNOWN ) - return this->upStream.getSampleRate(); - + if (this->lastUpstreamRate == DATASTREAM_SAMPLE_RATE_UNKNOWN) return this->upStream.getSampleRate(); + return this->lastUpstreamRate; } \ No newline at end of file diff --git a/source/streams/StreamSplitter.cpp b/source/streams/StreamSplitter.cpp index 400b3dac..d8cb5697 100644 --- a/source/streams/StreamSplitter.cpp +++ b/source/streams/StreamSplitter.cpp @@ -22,23 +22,24 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -#include "CodalConfig.h" #include "StreamSplitter.h" -#include "StreamNormalizer.h" + +#include "CodalConfig.h" +#include "CodalDmesg.h" #include "ErrorNo.h" #include "Event.h" -#include "CodalDmesg.h" +#include "StreamNormalizer.h" using namespace codal; -SplitterChannel::SplitterChannel( StreamSplitter * parent, DataSink * output = NULL ) +SplitterChannel::SplitterChannel(StreamSplitter* parent, DataSink* output = NULL) { - this->sampleRate = DATASTREAM_SAMPLE_RATE_UNKNOWN; - this->parent = parent; - this->output = output; + this->sampleRate = DATASTREAM_SAMPLE_RATE_UNKNOWN; + this->parent = parent; + this->output = output; this->pullAttempts = 0; - this->sentBuffers = 0; - this->inUnderflow = 0; + this->sentBuffers = 0; + this->inUnderflow = 0; } SplitterChannel::~SplitterChannel() @@ -46,50 +47,53 @@ SplitterChannel::~SplitterChannel() // } -int SplitterChannel::pullRequest() { +int SplitterChannel::pullRequest() +{ this->pullAttempts++; - if( output != NULL ) - return output->pullRequest(); + if (output != NULL) return output->pullRequest(); return DEVICE_BUSY; } -ManagedBuffer SplitterChannel::resample( ManagedBuffer _in, uint8_t * buffer, int length ) { - +ManagedBuffer SplitterChannel::resample(ManagedBuffer _in, uint8_t* buffer, int length) +{ // Going the long way around - drop any extra samples... - float inRate = parent->upstream.getSampleRate(); + float inRate = parent->upstream.getSampleRate(); float outRate = sampleRate; - int inFmt = parent->upstream.getFormat(); - int bytesPerSample = DATASTREAM_FORMAT_BYTES_PER_SAMPLE( inFmt ); - int totalSamples = _in.length() / bytesPerSample; + int inFmt = parent->upstream.getFormat(); + int bytesPerSample = DATASTREAM_FORMAT_BYTES_PER_SAMPLE(inFmt); + int totalSamples = _in.length() / bytesPerSample; // Integer estimate the number of sample drops required - int byteDeficit = (int)inRate - (int)outRate; + int byteDeficit = (int)inRate - (int)outRate; int packetsPerSec = (int)inRate / totalSamples; int dropPerPacket = byteDeficit / packetsPerSec; int samplesPerOut = totalSamples - dropPerPacket; // If we're not supplied an external buffer, make our own... - uint8_t * output = buffer; - if( output == NULL ) { - output = (uint8_t *)malloc( samplesPerOut * bytesPerSample ); + uint8_t* output = buffer; + if (output == NULL) { + output = (uint8_t*)malloc(samplesPerOut * bytesPerSample); length = samplesPerOut * bytesPerSample; - } else { + } + else { if (length > samplesPerOut * bytesPerSample) { length = samplesPerOut * bytesPerSample; } - } + } int oversample_offset = 0; - int oversample_step = (totalSamples * CONFIG_SPLITTER_OVERSAMPLE_STEP) / samplesPerOut; - - uint8_t *inPtr = &_in[0]; - uint8_t *outPtr = output; - while( outPtr - output < length ) - { - int a = StreamNormalizer::readSample[inFmt]( inPtr + ((int)(oversample_offset / CONFIG_SPLITTER_OVERSAMPLE_STEP) * bytesPerSample) ); - int b = StreamNormalizer::readSample[inFmt]( inPtr + (((int)(oversample_offset / CONFIG_SPLITTER_OVERSAMPLE_STEP) + 1) * bytesPerSample) ); - int s = a + ((int)((b - a)/CONFIG_SPLITTER_OVERSAMPLE_STEP) * (oversample_offset % CONFIG_SPLITTER_OVERSAMPLE_STEP)); + int oversample_step = (totalSamples * CONFIG_SPLITTER_OVERSAMPLE_STEP) / samplesPerOut; + + uint8_t* inPtr = &_in[0]; + uint8_t* outPtr = output; + while (outPtr - output < length) { + int a = StreamNormalizer::readSample[inFmt]( + inPtr + ((int)(oversample_offset / CONFIG_SPLITTER_OVERSAMPLE_STEP) * bytesPerSample)); + int b = StreamNormalizer::readSample[inFmt]( + inPtr + (((int)(oversample_offset / CONFIG_SPLITTER_OVERSAMPLE_STEP) + 1) * bytesPerSample)); + int s = a + ((int)((b - a) / CONFIG_SPLITTER_OVERSAMPLE_STEP) * + (oversample_offset % CONFIG_SPLITTER_OVERSAMPLE_STEP)); oversample_offset += oversample_step; @@ -97,28 +101,28 @@ ManagedBuffer SplitterChannel::resample( ManagedBuffer _in, uint8_t * buffer, in outPtr += bytesPerSample; } - ManagedBuffer result = ManagedBuffer( output, length ); + ManagedBuffer result = ManagedBuffer(output, length); // Did we create this memory? If so, free it again. - if( buffer == NULL ) - free( output ); + if (buffer == NULL) free(output); return result; } -uint8_t * SplitterChannel::pullInto( uint8_t * rawBuffer, int length ) +uint8_t* SplitterChannel::pullInto(uint8_t* rawBuffer, int length) { this->pullAttempts = 0; this->sentBuffers++; ManagedBuffer inData = parent->getBuffer(); // Shortcuts - we can't fabricate samples, so just pass on what we can if we don't know or can't keep up. - if( this->sampleRate == DATASTREAM_SAMPLE_RATE_UNKNOWN || this->sampleRate >= this->parent->upstream.getSampleRate() ) { - inData.readBytes( rawBuffer, 0, min(inData.length(), length) ); + if (this->sampleRate == DATASTREAM_SAMPLE_RATE_UNKNOWN || + this->sampleRate >= this->parent->upstream.getSampleRate()) { + inData.readBytes(rawBuffer, 0, min(inData.length(), length)); return rawBuffer + min(inData.length(), length); } - ManagedBuffer result = this->resample( inData, rawBuffer, length ); + ManagedBuffer result = this->resample(inData, rawBuffer, length); return rawBuffer + result.length(); } @@ -129,16 +133,17 @@ ManagedBuffer SplitterChannel::pull() ManagedBuffer inData = parent->getBuffer(); // Shortcuts - we can't fabricate samples, so just pass on what we can if we don't know or can't keep up. - if( this->sampleRate == DATASTREAM_SAMPLE_RATE_UNKNOWN || this->sampleRate >= this->parent->upstream.getSampleRate() ) + if (this->sampleRate == DATASTREAM_SAMPLE_RATE_UNKNOWN || + this->sampleRate >= this->parent->upstream.getSampleRate()) return inData; - - return this->resample( inData ); // Autocreate the output buffer + + return this->resample(inData); // Autocreate the output buffer } -void SplitterChannel::connect(DataSink &sink) +void SplitterChannel::connect(DataSink& sink) { output = &sink; - Event e( parent->id, SPLITTER_CHANNEL_CONNECT ); + Event e(parent->id, SPLITTER_CHANNEL_CONNECT); } bool SplitterChannel::isConnected() @@ -149,7 +154,7 @@ bool SplitterChannel::isConnected() void SplitterChannel::disconnect() { output = NULL; - Event e( parent->id, SPLITTER_CHANNEL_DISCONNECT ); + Event e(parent->id, SPLITTER_CHANNEL_DISCONNECT); } int SplitterChannel::getFormat() @@ -159,56 +164,48 @@ int SplitterChannel::getFormat() int SplitterChannel::setFormat(int format) { - return parent->upstream.setFormat( format ); + return parent->upstream.setFormat(format); } float SplitterChannel::getSampleRate() { - if( sampleRate != DATASTREAM_SAMPLE_RATE_UNKNOWN ) - return sampleRate; + if (sampleRate != DATASTREAM_SAMPLE_RATE_UNKNOWN) return sampleRate; return parent->upstream.getSampleRate(); } -float SplitterChannel::requestSampleRate( float sampleRate ) +float SplitterChannel::requestSampleRate(float sampleRate) { this->sampleRate = sampleRate; // Do we need to request a higher rate upstream? - if( parent->upstream.getSampleRate() < sampleRate ) { - + if (parent->upstream.getSampleRate() < sampleRate) { // Request it, and if we got less that we expected, report that rate - if( parent->upstream.requestSampleRate( sampleRate ) < sampleRate ) - return parent->upstream.getSampleRate(); + if (parent->upstream.requestSampleRate(sampleRate) < sampleRate) return parent->upstream.getSampleRate(); } // Otherwise, report our own rate (we're matching or altering it ourselves) return sampleRate; } - - - - /** * Creates a component that distributes a single upstream datasource to many downstream datasinks * * @param source a DataSource to receive data from */ -StreamSplitter::StreamSplitter(DataSource &source, uint16_t id) : upstream(source) +StreamSplitter::StreamSplitter(DataSource& source, uint16_t id) : upstream(source) { - this->id = id; - this->channels = 0; + this->id = id; + this->channels = 0; this->activeChannels = 0; - this->isActive = false; + this->isActive = false; // init array to NULL. - for (int i = 0; i < CONFIG_MAX_CHANNELS; i++) - outputChannels[i] = NULL; - + for (int i = 0; i < CONFIG_MAX_CHANNELS; i++) outputChannels[i] = NULL; + upstream.connect(*this); this->__cycle = 0; - //this->status |= DEVICE_COMPONENT_STATUS_SYSTEM_TICK; + // this->status |= DEVICE_COMPONENT_STATUS_SYSTEM_TICK; } StreamSplitter::~StreamSplitter() @@ -218,9 +215,8 @@ StreamSplitter::~StreamSplitter() ManagedBuffer StreamSplitter::getBuffer() { - if( lastBuffer == ManagedBuffer() ) - lastBuffer = upstream.pull(); - + if (lastBuffer == ManagedBuffer()) lastBuffer = upstream.pull(); + return lastBuffer; } @@ -232,54 +228,51 @@ int StreamSplitter::pullRequest() activeChannels = 0; // For each downstream channel that exists in array outputChannels - make a pullRequest - for (int i = 0; i < CONFIG_MAX_CHANNELS; i++) - { + for (int i = 0; i < CONFIG_MAX_CHANNELS; i++) { if (outputChannels[i] != NULL) { - if( outputChannels[i]->pullRequest() == DEVICE_OK ) { + if (outputChannels[i]->pullRequest() == DEVICE_OK) { activeChannels++; - if( !isActive ) - Event e( id, SPLITTER_ACTIVATE ); + if (!isActive) Event e(id, SPLITTER_ACTIVATE); isActive = true; } } } - - if( activeChannels == 0 && isActive ) { - Event e( id, SPLITTER_DEACTIVATE ); + + if (activeChannels == 0 && isActive) { + Event e(id, SPLITTER_DEACTIVATE); isActive = false; } lastBuffer = ManagedBuffer(); - Event e( id, SPLITTER_TICK ); + Event e(id, SPLITTER_TICK); return DEVICE_BUSY; } - -SplitterChannel * StreamSplitter::createChannel() +SplitterChannel* StreamSplitter::createChannel() { int placed = -1; - for (int i = 0; i < CONFIG_MAX_CHANNELS; i++) - { + for (int i = 0; i < CONFIG_MAX_CHANNELS; i++) { // Add downstream as one of the splitters datasinks that will be served - if (outputChannels[i] == NULL){ - outputChannels[i] = new SplitterChannel( this, NULL ); - placed = i; + if (outputChannels[i] == NULL) { + outputChannels[i] = new SplitterChannel(this, NULL); + placed = i; break; } } - if(placed != -1) { + if (placed != -1) { channels++; return outputChannels[placed]; } - + return NULL; } -bool StreamSplitter::destroyChannel( SplitterChannel * channel ) { - for( int i=0; ioutput == output ) { +SplitterChannel* StreamSplitter::getChannel(DataSink* output) +{ + for (int i = 0; i < CONFIG_MAX_CHANNELS; i++) { + if (outputChannels[i] != NULL) { + if (outputChannels[i]->output == output) { return outputChannels[i]; } } diff --git a/source/streams/Synthesizer.cpp b/source/streams/Synthesizer.cpp index 6497287e..60460536 100644 --- a/source/streams/Synthesizer.cpp +++ b/source/streams/Synthesizer.cpp @@ -23,6 +23,7 @@ DEALINGS IN THE SOFTWARE. */ #include "Synthesizer.h" + #include "CodalFiber.h" #include "ErrorNo.h" @@ -51,66 +52,98 @@ static const uint16_t loudnessCompensation[] = { }; #endif -static const uint16_t sineTone[] = {0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,3,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,11,11,12,13,13,14,15,16,16,17,18,19,20,21,22,22,23,24,25,26,27,28,29,30,32,33,34,35,36,37,38,40,41,42,43,45,46,47,49,50,51,53,54,56,57,58,60,61,63,64,66,68,69,71,72,74,76,77,79,81,82,84,86,87,89,91,93,95,96,98,100,102,104,106,108,110,112,114,116,118,120,122,124,126,128,130,132,134,136,138,141,143,145,147,149,152,154,156,158,161,163,165,167,170,172,175,177,179,182,184,187,189,191,194,196,199,201,204,206,209,211,214,216,219,222,224,227,229,232,235,237,240,243,245,248,251,253,256,259,262,264,267,270,273,275,278,281,284,287,289,292,295,298,301,304,307,309,312,315,318,321,324,327,330,333,336,339,342,345,348,351,354,357,360,363,366,369,372,375,378,381,384,387,390,393,396,399,402,405,408,411,414,417,420,424,427,430,433,436,439,442,445,448,452,455,458,461,464,467,470,473,477,480,483,486,489,492,495,498,502,505,508,511,514,517,520,524,527,530,533,536,539,542,545,549,552,555,558,561,564,567,570,574,577,580,583,586,589,592,595,598,602,605,608,611,614,617,620,623,626,629,632,635,638,641,644,647,650,653,656,659,662,665,668,671,674,677,680,683,686,689,692,695,698,701,704,707,710,713,715,718,721,724,727,730,733,735,738,741,744,747,749,752,755,758,760,763,766,769,771,774,777,779,782,785,787,790,793,795,798,800,803,806,808,811,813,816,818,821,823,826,828,831,833,835,838,840,843,845,847,850,852,855,857,859,861,864,866,868,870,873,875,877,879,881,884,886,888,890,892,894,896,898,900,902,904,906,908,910,912,914,916,918,920,922,924,926,927,929,931,933,935,936,938,940,941,943,945,946,948,950,951,953,954,956,958,959,961,962,964,965,966,968,969,971,972,973,975,976,977,979,980,981,982,984,985,986,987,988,989,990,992,993,994,995,996,997,998,999,1000,1000,1001,1002,1003,1004,1005,1006,1006,1007,1008,1009,1009,1010,1011,1011,1012,1013,1013,1014,1014,1015,1015,1016,1016,1017,1017,1018,1018,1019,1019,1019,1020,1020,1020,1021,1021,1021,1021,1022,1022,1022,1022,1022,1022,1022,1022,1022,1022,1023,1022}; - -uint16_t Synthesizer::SineTone(void *arg, int position) { +static const uint16_t sineTone[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, + 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 11, 11, 12, 13, + 13, 14, 15, 16, 16, 17, 18, 19, 20, 21, 22, 22, 23, 24, 25, 26, 27, 28, 29, + 30, 32, 33, 34, 35, 36, 37, 38, 40, 41, 42, 43, 45, 46, 47, 49, 50, 51, 53, + 54, 56, 57, 58, 60, 61, 63, 64, 66, 68, 69, 71, 72, 74, 76, 77, 79, 81, 82, + 84, 86, 87, 89, 91, 93, 95, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, + 120, 122, 124, 126, 128, 130, 132, 134, 136, 138, 141, 143, 145, 147, 149, 152, 154, 156, 158, + 161, 163, 165, 167, 170, 172, 175, 177, 179, 182, 184, 187, 189, 191, 194, 196, 199, 201, 204, + 206, 209, 211, 214, 216, 219, 222, 224, 227, 229, 232, 235, 237, 240, 243, 245, 248, 251, 253, + 256, 259, 262, 264, 267, 270, 273, 275, 278, 281, 284, 287, 289, 292, 295, 298, 301, 304, 307, + 309, 312, 315, 318, 321, 324, 327, 330, 333, 336, 339, 342, 345, 348, 351, 354, 357, 360, 363, + 366, 369, 372, 375, 378, 381, 384, 387, 390, 393, 396, 399, 402, 405, 408, 411, 414, 417, 420, + 424, 427, 430, 433, 436, 439, 442, 445, 448, 452, 455, 458, 461, 464, 467, 470, 473, 477, 480, + 483, 486, 489, 492, 495, 498, 502, 505, 508, 511, 514, 517, 520, 524, 527, 530, 533, 536, 539, + 542, 545, 549, 552, 555, 558, 561, 564, 567, 570, 574, 577, 580, 583, 586, 589, 592, 595, 598, + 602, 605, 608, 611, 614, 617, 620, 623, 626, 629, 632, 635, 638, 641, 644, 647, 650, 653, 656, + 659, 662, 665, 668, 671, 674, 677, 680, 683, 686, 689, 692, 695, 698, 701, 704, 707, 710, 713, + 715, 718, 721, 724, 727, 730, 733, 735, 738, 741, 744, 747, 749, 752, 755, 758, 760, 763, 766, + 769, 771, 774, 777, 779, 782, 785, 787, 790, 793, 795, 798, 800, 803, 806, 808, 811, 813, 816, + 818, 821, 823, 826, 828, 831, 833, 835, 838, 840, 843, 845, 847, 850, 852, 855, 857, 859, 861, + 864, 866, 868, 870, 873, 875, 877, 879, 881, 884, 886, 888, 890, 892, 894, 896, 898, 900, 902, + 904, 906, 908, 910, 912, 914, 916, 918, 920, 922, 924, 926, 927, 929, 931, 933, 935, 936, 938, + 940, 941, 943, 945, 946, 948, 950, 951, 953, 954, 956, 958, 959, 961, 962, 964, 965, 966, 968, + 969, 971, 972, 973, 975, 976, 977, 979, 980, 981, 982, 984, 985, 986, 987, 988, 989, 990, 992, + 993, 994, 995, 996, 997, 998, 999, 1000, 1000, 1001, 1002, 1003, 1004, 1005, 1006, 1006, 1007, 1008, 1009, + 1009, 1010, 1011, 1011, 1012, 1013, 1013, 1014, 1014, 1015, 1015, 1016, 1016, 1017, 1017, 1018, 1018, 1019, 1019, + 1019, 1020, 1020, 1020, 1021, 1021, 1021, 1021, 1022, 1022, 1022, 1022, 1022, 1022, 1022, 1022, 1022, 1022, 1023, + 1022}; + +uint16_t Synthesizer::SineTone(void* arg, int position) +{ int off = TONE_WIDTH - position; - if (off < TONE_WIDTH / 2) - position = off; + if (off < TONE_WIDTH / 2) position = off; return sineTone[position]; } -uint16_t Synthesizer::SawtoothTone(void *arg, int position) { +uint16_t Synthesizer::SawtoothTone(void* arg, int position) +{ return position; } -uint16_t Synthesizer::TriangleTone(void *arg, int position) { +uint16_t Synthesizer::TriangleTone(void* arg, int position) +{ return position < 512 ? position * 2 : (1023 - position) * 2; } -uint16_t Synthesizer::NoiseTone(void *arg, int position) { +uint16_t Synthesizer::NoiseTone(void* arg, int position) +{ // deterministic, semi-random noise uint32_t mult = (uint32_t)arg; - if (mult == 0) - mult = 7919; + if (mult == 0) mult = 7919; return (position * mult) & 1023; } -uint16_t Synthesizer::SquareWaveTone(void *arg, int position) { +uint16_t Synthesizer::SquareWaveTone(void* arg, int position) +{ return position < 512 ? 1023 : 0; } -uint16_t Synthesizer::SquareWaveToneExt(void *arg, int position) { +uint16_t Synthesizer::SquareWaveToneExt(void* arg, int position) +{ uint32_t duty = (uint32_t)arg; return (uint32_t)position <= duty ? 1023 : 0; } -uint16_t Synthesizer::CustomTone(void *arg, int position) { - if (position < 0 || position >= 1024) - return 0; +uint16_t Synthesizer::CustomTone(void* arg, int position) +{ + if (position < 0 || position >= 1024) return 0; return ((uint16_t*)arg)[position]; } /* * Simple internal helper funtion that creates a fiber within the givien Synthesizer to handle playback */ -static void begin_playback(void *data) +static void begin_playback(void* data) { ((Synthesizer*)data)->generate(-1); } /** - * Class definition for a Synthesizer. - * A Synthesizer generates a tone waveform based on a number of overlapping waveforms. - */ + * Class definition for a Synthesizer. + * A Synthesizer generates a tone waveform based on a number of overlapping waveforms. + */ Synthesizer::Synthesizer(int sampleRate, bool isSigned) : output(*this) { - this->isSigned = isSigned; - this->bufferSize = 512; + this->isSigned = isSigned; + this->bufferSize = 512; this->samplePeriodNs = 1000000000 / sampleRate; this->setVolume(1024); - this->active = false; - this->synchronous = false; + this->active = false; + this->synchronous = false; this->bytesWritten = 0; this->setTone(Synthesizer::TriangleTone); this->position = 0; @@ -122,18 +155,16 @@ Synthesizer::Synthesizer(int sampleRate, bool isSigned) : output(*this) */ void Synthesizer::idleCallback() { - if (bytesWritten && !synchronous && !active && output.canPull(bytesWritten)) - { + if (bytesWritten && !synchronous && !active && output.canPull(bytesWritten)) { buffer.truncate(bytesWritten); output.pullRequest(); bytesWritten = 0; } } - /** - * Define the central frequency of this synthesizer - */ + * Define the central frequency of this synthesizer + */ int Synthesizer::setFrequency(float frequency) { return setFrequency(frequency, 0); @@ -148,25 +179,23 @@ int Synthesizer::setFrequency(float frequency) int Synthesizer::setFrequency(float frequency, int period, int envelopeStart, int envelopeEnd) { // If another fiber is already actively using this resource, we can't service this request. - if (synchronous) - return DEVICE_BUSY; + if (synchronous) return DEVICE_BUSY; // record our new intended frequency. - newPeriodNs = frequency == 0.0 ? 0 : (uint32_t) (1000000000.0f / frequency); + newPeriodNs = frequency == 0.0 ? 0 : (uint32_t)(1000000000.0f / frequency); - if (period == 0) - { + if (period == 0) { // We've been asked to play a new tone in the background. - // If a tone is already playing in the background, we only need to update frequency (already done above). Otherwise also launch a playout fiber. - if(!active) - { + // If a tone is already playing in the background, we only need to update frequency (already done above). + // Otherwise also launch a playout fiber. + if (!active) { active = true; create_fiber(begin_playback, this); } } - else - { - // We've been asked to playout a new note synchronously. Record the period of playback, and start creation of the sample content. + else { + // We've been asked to playout a new note synchronously. Record the period of playback, and start creation of + // the sample content. synchronous = true; generate(1000 * period, envelopeStart, envelopeEnd); synchronous = false; @@ -179,9 +208,7 @@ int Synthesizer::setFrequency(float frequency, int period, int envelopeStart, in * Destructor. * Removes all resources held by the instance. */ -Synthesizer::~Synthesizer() -{ -} +Synthesizer::~Synthesizer() {} /** * Creates the next audio buffer, and attmepts to queue this on the output stream. @@ -190,33 +217,30 @@ void Synthesizer::generate(int playoutTimeUs, int envelopeStart, int envelopeEnd { int periodNs = newPeriodNs; - int toneDelta; // the number of samples within our tone print that we increment for each playout sample. - int toneSigma; // the fraction of samples within our tone print (*1000) that we increment for each playout sample. + int toneDelta; // the number of samples within our tone print that we increment for each playout sample. + int toneSigma; // the fraction of samples within our tone print (*1000) that we increment for each playout sample. - float toneRate = periodNs == 0 ? 0 : ((float)samplePeriodNs * (float) TONE_WIDTH) / (float) periodNs; - toneDelta = (int) toneRate; - toneSigma = (int) ((toneRate - (float)toneDelta) * 1000.0f); + float toneRate = periodNs == 0 ? 0 : ((float)samplePeriodNs * (float)TONE_WIDTH) / (float)periodNs; + toneDelta = (int)toneRate; + toneSigma = (int)((toneRate - (float)toneDelta) * 1000.0f); - int sigma = 0; + int sigma = 0; int playoutSamples = determineSampleCount(playoutTimeUs); - int localAmplitude = (amplitude * envelopeStart) << 10; + int localAmplitude = (amplitude * envelopeStart) << 10; int localAmplitudeDelta = ((envelopeEnd - envelopeStart) << 20) / playoutSamples; - while(playoutSamples != 0) - { - if (bytesWritten == 0) - buffer = ManagedBuffer(bufferSize); + while (playoutSamples != 0) { + if (bytesWritten == 0) buffer = ManagedBuffer(bufferSize); - uint16_t *ptr = (uint16_t *) &buffer[bytesWritten]; + uint16_t* ptr = (uint16_t*)&buffer[bytesWritten]; if (playoutTimeUs < 0) localAmplitude = amplitude << 20; else localAmplitude += localAmplitudeDelta; - while(bytesWritten < bufferSize) - { + while (bytesWritten < bufferSize) { if (periodNs <= 0) *ptr = 0; else if (isSigned) @@ -229,45 +253,41 @@ void Synthesizer::generate(int playoutTimeUs, int envelopeStart, int envelopeEnd position += toneDelta; sigma += toneSigma; - if (playoutSamples >= 0) - playoutSamples--; + if (playoutSamples >= 0) playoutSamples--; - if (sigma > 1000) - { + if (sigma > 1000) { sigma -= 1000; position++; } - while (position >= TONE_WIDTH) // most likely at most one iteration + while (position >= TONE_WIDTH) // most likely at most one iteration { position -= TONE_WIDTH; #ifdef SYNTHESIZER_SIGMA_RESET sigma = 0; #endif - if (periodNs != newPeriodNs) - { + if (periodNs != newPeriodNs) { periodNs = newPeriodNs; - toneRate = periodNs == 0 ? 0 : ((float)samplePeriodNs * (float) TONE_WIDTH) / (float) periodNs; - toneDelta = (int) toneRate; - toneSigma = (int) ((toneRate - (float)toneDelta) * 1000.0f); + toneRate = periodNs == 0 ? 0 : ((float)samplePeriodNs * (float)TONE_WIDTH) / (float)periodNs; + toneDelta = (int)toneRate; + toneSigma = (int)((toneRate - (float)toneDelta) * 1000.0f); playoutSamples = determineSampleCount(playoutTimeUs); position = 0; - sigma = 0; + sigma = 0; } } - if (playoutSamples == 0) - return; + if (playoutSamples == 0) return; } bytesWritten = 0; output.pullRequest(); - // There's now space for another buffer. If we're generating asynchronously and a synchronous request comes in, give control to that fiber. - if (playoutTimeUs < 0 && synchronous) - { + // There's now space for another buffer. If we're generating asynchronously and a synchronous request comes in, + // give control to that fiber. + if (playoutTimeUs < 0 && synchronous) { active = false; return; } @@ -275,13 +295,12 @@ void Synthesizer::generate(int playoutTimeUs, int envelopeStart, int envelopeEnd } /** -* Define the volume of the wave to generate. -* @param volume The new output volume, in the range 0..1024 -*/ + * Define the volume of the wave to generate. + * @param volume The new output volume, in the range 0..1024 + */ int Synthesizer::setVolume(int volume) { - if (volume < 0 || volume > 1024) - return DEVICE_INVALID_PARAMETER; + if (volume < 0 || volume > 1024) return DEVICE_INVALID_PARAMETER; amplitude = volume; @@ -289,14 +308,14 @@ int Synthesizer::setVolume(int volume) } /** -* Define the size of the audio buffer to hold. The larger the buffer, the lower the CPU overhead, but the longer the delay. -* @param size The new bufer size to use, in bytes. -* @return DEVICE_OK on success, or DEVICE_INVALID_PARAMETER -*/ + * Define the size of the audio buffer to hold. The larger the buffer, the lower the CPU overhead, but the longer the + * delay. + * @param size The new bufer size to use, in bytes. + * @return DEVICE_OK on success, or DEVICE_INVALID_PARAMETER + */ int Synthesizer::setBufferSize(int size) { - if (bufferSize <= 0) - return DEVICE_INVALID_PARAMETER; + if (bufferSize <= 0) return DEVICE_INVALID_PARAMETER; this->bufferSize = size; return DEVICE_OK; @@ -308,7 +327,7 @@ int Synthesizer::setBufferSize(int size) ManagedBuffer Synthesizer::pull() { ManagedBuffer out = buffer; - buffer = ManagedBuffer(); + buffer = ManagedBuffer(); return out; } @@ -341,10 +360,10 @@ int Synthesizer::setSampleRate(int sampleRate) * Synthesizer::SawtoothTone * Synthesizer::SquareWaveTone */ -void Synthesizer::setTone(SynthesizerGetSample tonePrint, void *arg) +void Synthesizer::setTone(SynthesizerGetSample tonePrint, void* arg) { this->tonePrintArg = arg; - this->tonePrint = tonePrint; + this->tonePrint = tonePrint; } /** @@ -356,12 +375,10 @@ void Synthesizer::setTone(SynthesizerGetSample tonePrint, void *arg) */ int Synthesizer::determineSampleCount(int playoutTimeUs) { - if (playoutTimeUs < 0) - return -1; + if (playoutTimeUs < 0) return -1; int a = (playoutTimeUs / 1000) * 1000; int b = (playoutTimeUs % 1000); return ((a / samplePeriodNs) * 1000) + ((1000 * b) / samplePeriodNs); } - diff --git a/source/types/BitmapFont.cpp b/source/types/BitmapFont.cpp index bde6f684..da573af5 100644 --- a/source/types/BitmapFont.cpp +++ b/source/types/BitmapFont.cpp @@ -23,77 +23,101 @@ DEALINGS IN THE SOFTWARE. */ /** - * Class definition for a BitmapFont - * This class represents a font that can be used by the display to render text. - * - * A BitmapFont is typically 5x5, but up to 8x8. - * Each Row is represented by a byte in the array. - * - * Row Format: - * ================================================================ - * | Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 | - * ================================================================ - * | N/A | N/A | N/A | Col 1 | Col 2 | Col 3 | Col 4 | Col 5 | - * | 0x80 | 0x40 | 0x20 | 0x10 | 0x08 | 0x04 | 0x02 | 0x01 | - * - * Example: { 0x08, 0x08, 0x08, 0x0, 0x08 } - * - * The above will produce an exclaimation mark on the second column in form the left. - * - * We could compress further, but the complexity of decode would likely outweigh the gains. - */ + * Class definition for a BitmapFont + * This class represents a font that can be used by the display to render text. + * + * A BitmapFont is typically 5x5, but up to 8x8. + * Each Row is represented by a byte in the array. + * + * Row Format: + * ================================================================ + * | Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0 | + * ================================================================ + * | N/A | N/A | N/A | Col 1 | Col 2 | Col 3 | Col 4 | Col 5 | + * | 0x80 | 0x40 | 0x20 | 0x10 | 0x08 | 0x04 | 0x02 | 0x01 | + * + * Example: { 0x08, 0x08, 0x08, 0x0, 0x08 } + * + * The above will produce an exclaimation mark on the second column in form the left. + * + * We could compress further, but the complexity of decode would likely outweigh the gains. + */ -#include "CodalConfig.h" #include "BitmapFont.h" +#include "CodalConfig.h" + using namespace codal; const unsigned char pendolino3[475] = { -0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x8, 0x8, 0x0, 0x8, 0xa, 0x4a, 0x40, 0x0, 0x0, 0xa, 0x5f, 0xea, 0x5f, 0xea, 0xe, 0xd9, 0x2e, 0xd3, 0x6e, 0x19, 0x32, 0x44, 0x89, 0x33, 0xc, 0x92, 0x4c, 0x92, 0x4d, 0x8, 0x8, 0x0, 0x0, 0x0, 0x4, 0x88, 0x8, 0x8, 0x4, 0x8, 0x4, 0x84, 0x84, 0x88, 0x0, 0xa, 0x44, 0x8a, 0x40, 0x0, 0x4, 0x8e, 0xc4, 0x80, 0x0, 0x0, 0x0, 0x4, 0x88, 0x0, 0x0, 0xe, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x0, 0x1, 0x22, 0x44, 0x88, 0x10, 0xc, 0x92, 0x52, 0x52, 0x4c, 0x4, 0x8c, 0x84, 0x84, 0x8e, 0x1c, 0x82, 0x4c, 0x90, 0x1e, 0x1e, 0xc2, 0x44, 0x92, 0x4c, 0x6, 0xca, 0x52, 0x5f, 0xe2, 0x1f, 0xf0, 0x1e, 0xc1, 0x3e, 0x2, 0x44, 0x8e, 0xd1, 0x2e, 0x1f, 0xe2, 0x44, 0x88, 0x10, 0xe, 0xd1, 0x2e, 0xd1, 0x2e, 0xe, 0xd1, 0x2e, 0xc4, 0x88, 0x0, 0x8, 0x0, 0x8, 0x0, 0x0, 0x4, 0x80, 0x4, 0x88, 0x2, 0x44, 0x88, 0x4, 0x82, 0x0, 0xe, 0xc0, 0xe, 0xc0, 0x8, 0x4, 0x82, 0x44, 0x88, 0xe, 0xd1, 0x26, 0xc0, 0x4, 0xe, 0xd1, 0x35, 0xb3, 0x6c, 0xc, 0x92, 0x5e, 0xd2, 0x52, 0x1c, 0x92, 0x5c, 0x92, 0x5c, 0xe, 0xd0, 0x10, 0x10, 0xe, 0x1c, 0x92, 0x52, 0x52, 0x5c, 0x1e, 0xd0, 0x1c, 0x90, 0x1e, 0x1e, 0xd0, 0x1c, 0x90, 0x10, 0xe, 0xd0, 0x13, 0x71, 0x2e, 0x12, 0x52, 0x5e, 0xd2, 0x52, 0x1c, 0x88, 0x8, 0x8, 0x1c, 0x1f, 0xe2, 0x42, 0x52, 0x4c, 0x12, 0x54, 0x98, 0x14, 0x92, 0x10, 0x10, 0x10, 0x10, 0x1e, 0x11, 0x3b, 0x75, 0xb1, 0x31, 0x11, 0x39, 0x35, 0xb3, 0x71, 0xc, 0x92, 0x52, 0x52, 0x4c, 0x1c, 0x92, 0x5c, 0x90, 0x10, 0xc, 0x92, 0x52, 0x4c, 0x86, 0x1c, 0x92, 0x5c, 0x92, 0x51, 0xe, 0xd0, 0xc, 0x82, 0x5c, 0x1f, 0xe4, 0x84, 0x84, 0x84, 0x12, 0x52, 0x52, 0x52, 0x4c, 0x11, 0x31, 0x31, 0x2a, 0x44, 0x11, 0x31, 0x35, 0xbb, 0x71, 0x12, 0x52, 0x4c, 0x92, 0x52, 0x11, 0x2a, 0x44, 0x84, 0x84, 0x1e, 0xc4, 0x88, 0x10, 0x1e, 0xe, 0xc8, 0x8, 0x8, 0xe, 0x10, 0x8, 0x4, 0x82, 0x41, 0xe, 0xc2, 0x42, 0x42, 0x4e, 0x4, 0x8a, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0x8, 0x4, 0x80, 0x0, 0x0, 0x0, 0xe, 0xd2, 0x52, 0x4f, 0x10, 0x10, 0x1c, 0x92, 0x5c, 0x0, 0xe, 0xd0, 0x10, 0xe, 0x2, 0x42, 0x4e, 0xd2, 0x4e, 0xc, 0x92, 0x5c, 0x90, 0xe, 0x6, 0xc8, 0x1c, 0x88, 0x8, 0xe, 0xd2, 0x4e, 0xc2, 0x4c, 0x10, 0x10, 0x1c, 0x92, 0x52, 0x8, 0x0, 0x8, 0x8, 0x8, 0x2, 0x40, 0x2, 0x42, 0x4c, 0x10, 0x14, 0x98, 0x14, 0x92, 0x8, 0x8, 0x8, 0x8, 0x6, 0x0, 0x1b, 0x75, 0xb1, 0x31, 0x0, 0x1c, 0x92, 0x52, 0x52, 0x0, 0xc, 0x92, 0x52, 0x4c, 0x0, 0x1c, 0x92, 0x5c, 0x90, 0x0, 0xe, 0xd2, 0x4e, 0xc2, 0x0, 0xe, 0xd0, 0x10, 0x10, 0x0, 0x6, 0xc8, 0x4, 0x98, 0x8, 0x8, 0xe, 0xc8, 0x7, 0x0, 0x12, 0x52, 0x52, 0x4f, 0x0, 0x11, 0x31, 0x2a, 0x44, 0x0, 0x11, 0x31, 0x35, 0xbb, 0x0, 0x12, 0x4c, 0x8c, 0x92, 0x0, 0x11, 0x2a, 0x44, 0x98, 0x0, 0x1e, 0xc4, 0x88, 0x1e, 0x6, 0xc4, 0x8c, 0x84, 0x86, 0x8, 0x8, 0x8, 0x8, 0x8, 0x18, 0x8, 0xc, 0x88, 0x18, 0x0, 0x0, 0xc, 0x83, 0x60}; - + 0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x8, 0x8, 0x0, 0x8, 0xa, 0x4a, 0x40, 0x0, 0x0, 0xa, 0x5f, 0xea, 0x5f, + 0xea, 0xe, 0xd9, 0x2e, 0xd3, 0x6e, 0x19, 0x32, 0x44, 0x89, 0x33, 0xc, 0x92, 0x4c, 0x92, 0x4d, 0x8, 0x8, 0x0, + 0x0, 0x0, 0x4, 0x88, 0x8, 0x8, 0x4, 0x8, 0x4, 0x84, 0x84, 0x88, 0x0, 0xa, 0x44, 0x8a, 0x40, 0x0, 0x4, + 0x8e, 0xc4, 0x80, 0x0, 0x0, 0x0, 0x4, 0x88, 0x0, 0x0, 0xe, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x0, 0x1, + 0x22, 0x44, 0x88, 0x10, 0xc, 0x92, 0x52, 0x52, 0x4c, 0x4, 0x8c, 0x84, 0x84, 0x8e, 0x1c, 0x82, 0x4c, 0x90, 0x1e, + 0x1e, 0xc2, 0x44, 0x92, 0x4c, 0x6, 0xca, 0x52, 0x5f, 0xe2, 0x1f, 0xf0, 0x1e, 0xc1, 0x3e, 0x2, 0x44, 0x8e, 0xd1, + 0x2e, 0x1f, 0xe2, 0x44, 0x88, 0x10, 0xe, 0xd1, 0x2e, 0xd1, 0x2e, 0xe, 0xd1, 0x2e, 0xc4, 0x88, 0x0, 0x8, 0x0, + 0x8, 0x0, 0x0, 0x4, 0x80, 0x4, 0x88, 0x2, 0x44, 0x88, 0x4, 0x82, 0x0, 0xe, 0xc0, 0xe, 0xc0, 0x8, 0x4, + 0x82, 0x44, 0x88, 0xe, 0xd1, 0x26, 0xc0, 0x4, 0xe, 0xd1, 0x35, 0xb3, 0x6c, 0xc, 0x92, 0x5e, 0xd2, 0x52, 0x1c, + 0x92, 0x5c, 0x92, 0x5c, 0xe, 0xd0, 0x10, 0x10, 0xe, 0x1c, 0x92, 0x52, 0x52, 0x5c, 0x1e, 0xd0, 0x1c, 0x90, 0x1e, + 0x1e, 0xd0, 0x1c, 0x90, 0x10, 0xe, 0xd0, 0x13, 0x71, 0x2e, 0x12, 0x52, 0x5e, 0xd2, 0x52, 0x1c, 0x88, 0x8, 0x8, + 0x1c, 0x1f, 0xe2, 0x42, 0x52, 0x4c, 0x12, 0x54, 0x98, 0x14, 0x92, 0x10, 0x10, 0x10, 0x10, 0x1e, 0x11, 0x3b, 0x75, + 0xb1, 0x31, 0x11, 0x39, 0x35, 0xb3, 0x71, 0xc, 0x92, 0x52, 0x52, 0x4c, 0x1c, 0x92, 0x5c, 0x90, 0x10, 0xc, 0x92, + 0x52, 0x4c, 0x86, 0x1c, 0x92, 0x5c, 0x92, 0x51, 0xe, 0xd0, 0xc, 0x82, 0x5c, 0x1f, 0xe4, 0x84, 0x84, 0x84, 0x12, + 0x52, 0x52, 0x52, 0x4c, 0x11, 0x31, 0x31, 0x2a, 0x44, 0x11, 0x31, 0x35, 0xbb, 0x71, 0x12, 0x52, 0x4c, 0x92, 0x52, + 0x11, 0x2a, 0x44, 0x84, 0x84, 0x1e, 0xc4, 0x88, 0x10, 0x1e, 0xe, 0xc8, 0x8, 0x8, 0xe, 0x10, 0x8, 0x4, 0x82, + 0x41, 0xe, 0xc2, 0x42, 0x42, 0x4e, 0x4, 0x8a, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0x8, 0x4, 0x80, + 0x0, 0x0, 0x0, 0xe, 0xd2, 0x52, 0x4f, 0x10, 0x10, 0x1c, 0x92, 0x5c, 0x0, 0xe, 0xd0, 0x10, 0xe, 0x2, 0x42, + 0x4e, 0xd2, 0x4e, 0xc, 0x92, 0x5c, 0x90, 0xe, 0x6, 0xc8, 0x1c, 0x88, 0x8, 0xe, 0xd2, 0x4e, 0xc2, 0x4c, 0x10, + 0x10, 0x1c, 0x92, 0x52, 0x8, 0x0, 0x8, 0x8, 0x8, 0x2, 0x40, 0x2, 0x42, 0x4c, 0x10, 0x14, 0x98, 0x14, 0x92, + 0x8, 0x8, 0x8, 0x8, 0x6, 0x0, 0x1b, 0x75, 0xb1, 0x31, 0x0, 0x1c, 0x92, 0x52, 0x52, 0x0, 0xc, 0x92, 0x52, + 0x4c, 0x0, 0x1c, 0x92, 0x5c, 0x90, 0x0, 0xe, 0xd2, 0x4e, 0xc2, 0x0, 0xe, 0xd0, 0x10, 0x10, 0x0, 0x6, 0xc8, + 0x4, 0x98, 0x8, 0x8, 0xe, 0xc8, 0x7, 0x0, 0x12, 0x52, 0x52, 0x4f, 0x0, 0x11, 0x31, 0x2a, 0x44, 0x0, 0x11, + 0x31, 0x35, 0xbb, 0x0, 0x12, 0x4c, 0x8c, 0x92, 0x0, 0x11, 0x2a, 0x44, 0x98, 0x0, 0x1e, 0xc4, 0x88, 0x1e, 0x6, + 0xc4, 0x8c, 0x84, 0x86, 0x8, 0x8, 0x8, 0x8, 0x8, 0x18, 0x8, 0xc, 0x88, 0x18, 0x0, 0x0, 0xc, 0x83, 0x60}; const unsigned char* BitmapFont::defaultFont = pendolino3; -BitmapFont BitmapFont::systemFont = BitmapFont(defaultFont, BITMAP_FONT_ASCII_END); +BitmapFont BitmapFont::systemFont = BitmapFont(defaultFont, BITMAP_FONT_ASCII_END); /** - * Constructor. - * - * Sets the font represented by this font object. - * - * @param font A pointer to the beginning of the new font. - * - * @param asciiEnd the char value at which this font finishes. - */ + * Constructor. + * + * Sets the font represented by this font object. + * + * @param font A pointer to the beginning of the new font. + * + * @param asciiEnd the char value at which this font finishes. + */ BitmapFont::BitmapFont(const unsigned char* characters, int asciiEnd) { this->characters = characters; - this->asciiEnd = asciiEnd; + this->asciiEnd = asciiEnd; } /** - * Default Constructor. - * - * Configures the default font for the display to use. - */ + * Default Constructor. + * + * Configures the default font for the display to use. + */ BitmapFont::BitmapFont() { this->characters = defaultFont; - this->asciiEnd = BITMAP_FONT_ASCII_END; + this->asciiEnd = BITMAP_FONT_ASCII_END; } /** - * Modifies the current system font to the given instance of BitmapFont. - * - * @param font the new font that will be used to render characters on the display. - */ + * Modifies the current system font to the given instance of BitmapFont. + * + * @param font the new font that will be used to render characters on the display. + */ void BitmapFont::setSystemFont(BitmapFont font) { - BitmapFont::systemFont = font; + BitmapFont::systemFont = font; } /** - * Retreives the font object used for rendering characters on the display. - */ + * Retreives the font object used for rendering characters on the display. + */ BitmapFont BitmapFont::getSystemFont() { return BitmapFont::systemFont; @@ -107,8 +131,7 @@ BitmapFont BitmapFont::getSystemFont() */ const uint8_t* BitmapFont::get(char c) { - if (c < BITMAP_FONT_ASCII_START || c > BITMAP_FONT_ASCII_END) - return NULL; + if (c < BITMAP_FONT_ASCII_START || c > BITMAP_FONT_ASCII_END) return NULL; - return characters + (c-BITMAP_FONT_ASCII_START) * ((1 + (BITMAP_FONT_WIDTH / 8)) * BITMAP_FONT_HEIGHT); + return characters + (c - BITMAP_FONT_ASCII_START) * ((1 + (BITMAP_FONT_WIDTH / 8)) * BITMAP_FONT_HEIGHT); } diff --git a/source/types/CoordinateSystem.cpp b/source/types/CoordinateSystem.cpp index ccb1abca..8162afc1 100644 --- a/source/types/CoordinateSystem.cpp +++ b/source/types/CoordinateSystem.cpp @@ -23,6 +23,7 @@ DEALINGS IN THE SOFTWARE. */ #include "CoordinateSystem.h" + #include "CodalDmesg.h" using namespace codal; @@ -35,14 +36,14 @@ using namespace codal; * @param system the CoordinateSystem to generated as output. * @param upsidedown set if the sensor is mounted inverted (upside down) on the device board. * @param rotated defines the rotation of the sensor on the PCB, with respect to pin 1 being at the top left corner - * when viewing the device from its "natural" (user defined) orientation. n.b. if the sensor is upside down, the rotation - * should be defined w.r.t. lookign at the side of the device where the sensor is mounted. + * when viewing the device from its "natural" (user defined) orientation. n.b. if the sensor is upside down, the + * rotation should be defined w.r.t. lookign at the side of the device where the sensor is mounted. */ CoordinateSpace::CoordinateSpace(CoordinateSystem system, bool upsidedown, int rotated) { - this->system = system; + this->system = system; this->upsidedown = upsidedown; - this->rotated = rotated; + this->rotated = rotated; } /** @@ -61,7 +62,8 @@ Sample3D CoordinateSpace::transform(Sample3D s) * * @param a the sample point to convert, in ENU format. * @param system The coordinate system to use in the result. - * @return the equivalent location of 's' in the coordinate space specified in the constructor, and coordinate system supplied. + * @return the equivalent location of 's' in the coordinate space specified in the constructor, and coordinate system + * supplied. */ Sample3D CoordinateSpace::transform(Sample3D s, CoordinateSystem system) { @@ -69,22 +71,19 @@ Sample3D CoordinateSpace::transform(Sample3D s, CoordinateSystem system) int temp; // If we've been asked to supply raw data, simply return it. - if (system == RAW) - return result; + if (system == RAW) return result; // Firstly, handle any inversions. // As we know the input is in ENU format, this means we flip the polarity of the X and Z axes. - if(upsidedown) - { + if (upsidedown) { result.y = -result.y; result.z = -result.z; } // Now, handle any rotations. - switch (rotated) - { + switch (rotated) { case COORDINATE_SPACE_ROTATED_90: - temp = -result.x; + temp = -result.x; result.x = result.y; result.y = temp; break; @@ -95,32 +94,29 @@ Sample3D CoordinateSpace::transform(Sample3D s, CoordinateSystem system) break; case COORDINATE_SPACE_ROTATED_270: - temp = result.x; + temp = result.x; result.x = -result.y; result.y = temp; break; } // Finally, apply coordinate system transformation. - switch (system) - { + switch (system) { case NORTH_EAST_DOWN: result.y = -result.y; result.z = -result.z; break; case SIMPLE_CARTESIAN: - temp = result.x; + temp = result.x; result.x = result.y; result.y = temp; result.z = -result.z; break; - default: // EAST_NORTH_UP + default: // EAST_NORTH_UP break; } return result; - } - diff --git a/source/types/Event.cpp b/source/types/Event.cpp index 59873cbd..bdeb290b 100644 --- a/source/types/Event.cpp +++ b/source/types/Event.cpp @@ -23,43 +23,45 @@ DEALINGS IN THE SOFTWARE. */ /** - * Class definition for a Event - * - * It represents a common event that is generated by the various components on the codal device. - */ -#include "CodalConfig.h" + * Class definition for a Event + * + * It represents a common event that is generated by the various components on the codal device. + */ #include "Event.h" -#include "Timer.h" + +#include "CodalConfig.h" #include "EventModel.h" +#include "Timer.h" using namespace codal; EventModel* EventModel::defaultEventBus = NULL; /** - * Constructor. - * - * @param src The id of the Device Component that generated the event e.g. DEVICE_ID_BUTTON_A. - * - * @param value A component specific code indicating the cause of the event. - * - * @param mode Optional definition of how the event should be processed after construction (if at all): - * CREATE_ONLY: Event is initialised, and no further processing takes place. - * CREATE_AND_FIRE: Event is initialised, and its event handlers are immediately fired (not suitable for use in interrupts!). - * - * @code - * // Create and launch an event using the default configuration - * Event evt(id,DEVICE_BUTTON_EVT_CLICK); - * - * // Create an event only, do not fire onto an EventModel. - * Event evt(id,DEVICE_BUTTON_EVT_CLICK,CREATE_AND_FIRE); - * @endcode - */ + * Constructor. + * + * @param src The id of the Device Component that generated the event e.g. DEVICE_ID_BUTTON_A. + * + * @param value A component specific code indicating the cause of the event. + * + * @param mode Optional definition of how the event should be processed after construction (if at all): + * CREATE_ONLY: Event is initialised, and no further processing takes place. + * CREATE_AND_FIRE: Event is initialised, and its event handlers are immediately fired (not suitable for + * use in interrupts!). + * + * @code + * // Create and launch an event using the default configuration + * Event evt(id,DEVICE_BUTTON_EVT_CLICK); + * + * // Create an event only, do not fire onto an EventModel. + * Event evt(id,DEVICE_BUTTON_EVT_CLICK,CREATE_AND_FIRE); + * @endcode + */ REAL_TIME_FUNC Event::Event(uint16_t source, uint16_t value, EventLaunchMode mode) { this->source = source; - this->value = value; + this->value = value; #if CONFIG_ENABLED(LIGHTWEIGHT_EVENTS) this->timestamp = system_timer_current_time(); @@ -67,50 +69,48 @@ Event::Event(uint16_t source, uint16_t value, EventLaunchMode mode) this->timestamp = system_timer_current_time_us(); #endif - if(mode != CREATE_ONLY) - this->fire(); + if (mode != CREATE_ONLY) this->fire(); } /** - * Constructor. - * - * @param src The id of the Device Component that generated the event e.g. DEVICE_ID_BUTTON_A. - * - * @param value A component specific code indicating the cause of the event. - * - * @param currentTimeUs The current time in microseconds. - * - * @param mode Optional definition of how the event should be processed after construction (if at all): - * CREATE_ONLY: Event is initialised, and no further processing takes place. - * CREATE_AND_FIRE: Event is initialised, and its event handlers are immediately fired (not suitable for use in interrupts!). - * - * @code - * // Create and launch an event using the default configuration - * Event evt(id,DEVICE_BUTTON_EVT_CLICK); - * - * // Create an event only, do not fire onto an EventModel. - * Event evt(id,DEVICE_BUTTON_EVT_CLICK,CREATE_AND_FIRE); - * @endcode - */ - REAL_TIME_FUNC - Event::Event(uint16_t source, uint16_t value, CODAL_TIMESTAMP currentTimeUs, EventLaunchMode mode) - { - this->source = source; - this->value = value; - this->timestamp = currentTimeUs; - - if(mode != CREATE_ONLY) - this->fire(); - } + * Constructor. + * + * @param src The id of the Device Component that generated the event e.g. DEVICE_ID_BUTTON_A. + * + * @param value A component specific code indicating the cause of the event. + * + * @param currentTimeUs The current time in microseconds. + * + * @param mode Optional definition of how the event should be processed after construction (if at all): + * CREATE_ONLY: Event is initialised, and no further processing takes place. + * CREATE_AND_FIRE: Event is initialised, and its event handlers are immediately fired (not suitable for + * use in interrupts!). + * + * @code + * // Create and launch an event using the default configuration + * Event evt(id,DEVICE_BUTTON_EVT_CLICK); + * + * // Create an event only, do not fire onto an EventModel. + * Event evt(id,DEVICE_BUTTON_EVT_CLICK,CREATE_AND_FIRE); + * @endcode + */ +REAL_TIME_FUNC +Event::Event(uint16_t source, uint16_t value, CODAL_TIMESTAMP currentTimeUs, EventLaunchMode mode) +{ + this->source = source; + this->value = value; + this->timestamp = currentTimeUs; + if (mode != CREATE_ONLY) this->fire(); +} /** - * Default constructor - initialises all values, and sets timestamp to the current time. - */ + * Default constructor - initialises all values, and sets timestamp to the current time. + */ Event::Event() { this->source = 0; - this->value = 0; + this->value = 0; #if CONFIG_ENABLED(LIGHTWEIGHT_EVENTS) this->timestamp = system_timer_current_time(); @@ -120,24 +120,22 @@ Event::Event() } /** - * Fires this Event onto the Default EventModel, or a custom one! - */ + * Fires this Event onto the Default EventModel, or a custom one! + */ REAL_TIME_FUNC void Event::fire() { - if(EventModel::defaultEventBus) - EventModel::defaultEventBus->send(*this); + if (EventModel::defaultEventBus) EventModel::defaultEventBus->send(*this); } - /** - * Constructor. - * Create a new EventQueueItem. - * - * @param evt The event to be queued. - */ + * Constructor. + * Create a new EventQueueItem. + * + * @param evt The event to be queued. + */ EventQueueItem::EventQueueItem(Event evt) { - this->evt = evt; + this->evt = evt; this->next = NULL; } diff --git a/source/types/Image.cpp b/source/types/Image.cpp index 704160e5..bf32f0b3 100644 --- a/source/types/Image.cpp +++ b/source/types/Image.cpp @@ -23,26 +23,26 @@ DEALINGS IN THE SOFTWARE. */ /** - * Class definition for a Image. - * - * An Image is a simple bitmap representation of an image. - * n.b. This is a mutable, managed type. - */ + * Class definition for a Image. + * + * An Image is a simple bitmap representation of an image. + * n.b. This is a mutable, managed type. + */ -#include "CodalConfig.h" #include "Image.h" + #include "BitmapFont.h" #include "CodalCompat.h" -#include "ManagedString.h" +#include "CodalConfig.h" #include "ErrorNo.h" - +#include "ManagedString.h" using namespace codal; /** - * The null image. We actally create a small one byte buffer here, just to keep NULL pointers out of the equation. - */ -#define REF_TAG REF_TAG_IMAGE + * The null image. We actally create a small one byte buffer here, just to keep NULL pointers out of the equation. + */ +#define REF_TAG REF_TAG_IMAGE #define EMPTY_DATA ((ImageData*)(void*)emptyData) REF_COUNTED_DEF_EMPTY(1, 1, 0) @@ -50,86 +50,84 @@ REF_COUNTED_DEF_EMPTY(1, 1, 0) Image Image::EmptyImage(EMPTY_DATA); /** - * Default Constructor. - * Creates a new reference to the empty Image bitmap - * - * @code - * Image i(); //an empty image instance - * @endcode - */ + * Default Constructor. + * Creates a new reference to the empty Image bitmap + * + * @code + * Image i(); //an empty image instance + * @endcode + */ Image::Image() { // Create new reference to the EmptyImage and we're done. init_empty(); } - /** - * Constructor. - * Create a blank bitmap representation of a given size. - * - * @param x the width of the image. - * - * @param y the height of the image. - * - * Bitmap buffer is linear, with 8 bits per pixel, row by row, - * top to bottom with no word alignment. Stride is therefore the image width in pixels. - * in where w and h are width and height respectively, the layout is therefore: - * - * |[0,0]...[w,o][1,0]...[w,1] ... [[w,h] - * - * A copy of the image is made in RAM, as images are mutable. - * - * TODO: Consider an immutable flavour, which might save us RAM for animation spritesheets... - * ...as these could be kept in FLASH. - */ + * Constructor. + * Create a blank bitmap representation of a given size. + * + * @param x the width of the image. + * + * @param y the height of the image. + * + * Bitmap buffer is linear, with 8 bits per pixel, row by row, + * top to bottom with no word alignment. Stride is therefore the image width in pixels. + * in where w and h are width and height respectively, the layout is therefore: + * + * |[0,0]...[w,o][1,0]...[w,1] ... [[w,h] + * + * A copy of the image is made in RAM, as images are mutable. + * + * TODO: Consider an immutable flavour, which might save us RAM for animation spritesheets... + * ...as these could be kept in FLASH. + */ Image::Image(const int16_t x, const int16_t y) { - this->init(x,y,NULL); + this->init(x, y, NULL); } /** - * Copy Constructor. - * Add ourselves as a reference to an existing Image. - * - * @param image The Image to reference. - * - * @code - * Image i("0,1,0,1,0\n"); - * Image i2(i); //points to i - * @endcode - */ -Image::Image(const Image &image) + * Copy Constructor. + * Add ourselves as a reference to an existing Image. + * + * @param image The Image to reference. + * + * @code + * Image i("0,1,0,1,0\n"); + * Image i2(i); //points to i + * @endcode + */ +Image::Image(const Image& image) { ptr = image.ptr; ptr->incr(); } /** - * Constructor. - * Create a blank bitmap representation of a given size. - * - * @param s A text based representation of the image given whitespace delimited numeric values. - * - * @code - * Image i("0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n"); // 5x5 image - * @endcode - */ -Image::Image(const char *s) + * Constructor. + * Create a blank bitmap representation of a given size. + * + * @param s A text based representation of the image given whitespace delimited numeric values. + * + * @code + * Image i("0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n"); // 5x5 image + * @endcode + */ +Image::Image(const char* s) { - int width = 0; + int width = 0; int height = 0; - int count = 0; - int digit = 0; + int count = 0; + int digit = 0; char parseBuf[10]; - const char *parseReadPtr; - char *parseWritePtr; - uint8_t *bitmapPtr; + const char* parseReadPtr; + char* parseWritePtr; + uint8_t* bitmapPtr; - if (s == NULL) - { + if (s == NULL) { init_empty(); return; } @@ -138,17 +136,13 @@ Image::Image(const char *s) // We do this from first principles to avoid unecessary load of the strtok() libs etc. parseReadPtr = s; - while (*parseReadPtr) - { - if (isdigit(*parseReadPtr)) - { + while (*parseReadPtr) { + if (isdigit(*parseReadPtr)) { // Ignore numbers. digit = 1; } - else if (*parseReadPtr =='\n') - { - if (digit) - { + else if (*parseReadPtr == '\n') { + if (digit) { count++; digit = 0; } @@ -158,10 +152,8 @@ Image::Image(const char *s) width = count > width ? count : width; count = 0; } - else - { - if (digit) - { + else { + if (digit) { count++; digit = 0; } @@ -173,22 +165,18 @@ Image::Image(const char *s) this->init(width, height, NULL); // Second pass: collect the data. - parseReadPtr = s; + parseReadPtr = s; parseWritePtr = parseBuf; - bitmapPtr = this->getBitmap(); + bitmapPtr = this->getBitmap(); - while (*parseReadPtr) - { - if (isdigit(*parseReadPtr)) - { + while (*parseReadPtr) { + if (isdigit(*parseReadPtr)) { *parseWritePtr = *parseReadPtr; parseWritePtr++; } - else - { + else { *parseWritePtr = 0; - if (parseWritePtr > parseBuf) - { + if (parseWritePtr > parseBuf) { *bitmapPtr = atoi(parseBuf); bitmapPtr++; parseWritePtr = parseBuf; @@ -200,20 +188,21 @@ Image::Image(const char *s) } /** - * Constructor. - * Create an image from a specially prepared constant array, with no copying. Will call ptr->incr(). - * - * @param ptr The literal - first two bytes should be 0xff, then width, 0, height, 0, and the bitmap. Width and height are 16 bit. The literal has to be 4-byte aligned. - * - * @code - * static const uint8_t heart[] __attribute__ ((aligned (4))) = { 0xff, 0xff, 10, 0, 5, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart - * Image i((ImageData*)(void*)heart); - * @endcode - */ -Image::Image(ImageData *p) + * Constructor. + * Create an image from a specially prepared constant array, with no copying. Will call ptr->incr(). + * + * @param ptr The literal - first two bytes should be 0xff, then width, 0, height, 0, and the bitmap. Width and height + * are 16 bit. The literal has to be 4-byte aligned. + * + * @code + * static const uint8_t heart[] __attribute__ ((aligned (4))) = { 0xff, 0xff, 10, 0, 5, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, + * 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, + * 0, }; // a cute heart Image i((ImageData*)(void*)heart); + * @endcode + */ +Image::Image(ImageData* p) { - if(p == NULL) - { + if (p == NULL) { init_empty(); return; } @@ -223,114 +212,108 @@ Image::Image(ImageData *p) } /** - * Get current ptr, do not decr() it, and set the current instance to empty image. - * - * This is to be used by specialized runtimes which pass ImageData around. - */ -ImageData *Image::leakData() + * Get current ptr, do not decr() it, and set the current instance to empty image. + * + * This is to be used by specialized runtimes which pass ImageData around. + */ +ImageData* Image::leakData() { ImageData* res = ptr; init_empty(); return res; } - /** - * Constructor. - * Create a bitmap representation of a given size, based on a given buffer. - * - * @param x the width of the image. - * - * @param y the height of the image. - * - * @param bitmap a 2D array representing the image. - * - * @code - * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart - * Image i(10,5,heart); - * @endcode - */ -Image::Image(const int16_t x, const int16_t y, const uint8_t *bitmap) + * Constructor. + * Create a bitmap representation of a given size, based on a given buffer. + * + * @param x the width of the image. + * + * @param y the height of the image. + * + * @param bitmap a 2D array representing the image. + * + * @code + * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, + * 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart Image i(10,5,heart); + * @endcode + */ +Image::Image(const int16_t x, const int16_t y, const uint8_t* bitmap) { - this->init(x,y,bitmap); + this->init(x, y, bitmap); } /** - * Destructor. - * - * Removes buffer resources held by the instance. - */ + * Destructor. + * + * Removes buffer resources held by the instance. + */ Image::~Image() { ptr->decr(); } /** - * Internal constructor which defaults to the EmptyImage instance variable - */ + * Internal constructor which defaults to the EmptyImage instance variable + */ void Image::init_empty() { ptr = EMPTY_DATA; } /** - * Internal constructor which provides sanity checking and initialises class properties. - * - * @param x the width of the image - * - * @param y the height of the image - * - * @param bitmap an array of integers that make up an image. - */ -void Image::init(const int16_t x, const int16_t y, const uint8_t *bitmap) + * Internal constructor which provides sanity checking and initialises class properties. + * + * @param x the width of the image + * + * @param y the height of the image + * + * @param bitmap an array of integers that make up an image. + */ +void Image::init(const int16_t x, const int16_t y, const uint8_t* bitmap) { - //sanity check size of image - you cannot have a negative sizes - if(x < 0 || y < 0) - { + // sanity check size of image - you cannot have a negative sizes + if (x < 0 || y < 0) { init_empty(); return; } - // Create a copy of the array ptr = (ImageData*)malloc(sizeof(ImageData) + x * y); REF_COUNTED_INIT(ptr); - ptr->width = x; + ptr->width = x; ptr->height = y; - // create a linear buffer to represent the image. We could use a jagged/2D array here, but experimentation // showed this had a negative effect on memory management (heap fragmentation etc). if (bitmap) - this->printImage(x,y,bitmap); + this->printImage(x, y, bitmap); else this->clear(); } /** - * Copy assign operation. - * - * Called when one Image is assigned the value of another using the '=' operator. - * - * Decrement our reference count and free up the buffer as necessary. - * - * Then, update our buffer to refer to that of the supplied Image, - * and increase its reference count. - * - * @param s The Image to reference. - * - * @code - * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart - * Image i(10,5,heart); - * Image i1(); - * i1 = i; // i1 now references i - * @endcode - */ -Image& Image::operator = (const Image& i) + * Copy assign operation. + * + * Called when one Image is assigned the value of another using the '=' operator. + * + * Decrement our reference count and free up the buffer as necessary. + * + * Then, update our buffer to refer to that of the supplied Image, + * and increase its reference count. + * + * @param s The Image to reference. + * + * @code + * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, + * 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart Image i(10,5,heart); Image i1(); i1 = + * i; // i1 now references i + * @endcode + */ +Image& Image::operator=(const Image& i) { - if(ptr == i.ptr) - return *this; + if (ptr == i.ptr) return *this; ptr->decr(); ptr = i.ptr; @@ -340,136 +323,131 @@ Image& Image::operator = (const Image& i) } /** - * Equality operation. - * - * Called when one Image is tested to be equal to another using the '==' operator. - * - * @param i The Image to test ourselves against. - * - * @return true if this Image is identical to the one supplied, false otherwise. - * - * @code - * DeviceDisplay display; - * Image i(); - * Image i1(); - * - * if(i == i1) //will be true - * display.scroll("true"); - * @endcode - */ -bool Image::operator== (const Image& i) + * Equality operation. + * + * Called when one Image is tested to be equal to another using the '==' operator. + * + * @param i The Image to test ourselves against. + * + * @return true if this Image is identical to the one supplied, false otherwise. + * + * @code + * DeviceDisplay display; + * Image i(); + * Image i1(); + * + * if(i == i1) //will be true + * display.scroll("true"); + * @endcode + */ +bool Image::operator==(const Image& i) { if (ptr == i.ptr) return true; else - return (ptr->width == i.ptr->width && ptr->height == i.ptr->height && (memcmp(getBitmap(), i.ptr->data, getSize())==0)); + return (ptr->width == i.ptr->width && ptr->height == i.ptr->height && + (memcmp(getBitmap(), i.ptr->data, getSize()) == 0)); } - /** - * Resets all pixels in this image to 0. - * - * @code - * Image i("0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n"); // 5x5 image - * i.clear(); - * @endcode - */ + * Resets all pixels in this image to 0. + * + * @code + * Image i("0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n"); // 5x5 image + * i.clear(); + * @endcode + */ void Image::clear() { memclr(getBitmap(), getSize()); } /** - * Sets the pixel at the given co-ordinates to a given value. - * - * @param x The co-ordinate of the pixel to change. - * - * @param y The co-ordinate of the pixel to change. - * - * @param value The new value of the pixel (the brightness level 0-255) - * - * @return DEVICE_OK, or DEVICE_INVALID_PARAMETER. - * - * @code - * Image i("0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n"); // 5x5 image - * i.setPixelValue(0,0,255); - * @endcode - * - * @note all coordinates originate from the top left of an image. - */ -int Image::setPixelValue(int16_t x , int16_t y, uint8_t value) + * Sets the pixel at the given co-ordinates to a given value. + * + * @param x The co-ordinate of the pixel to change. + * + * @param y The co-ordinate of the pixel to change. + * + * @param value The new value of the pixel (the brightness level 0-255) + * + * @return DEVICE_OK, or DEVICE_INVALID_PARAMETER. + * + * @code + * Image i("0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n"); // 5x5 image + * i.setPixelValue(0,0,255); + * @endcode + * + * @note all coordinates originate from the top left of an image. + */ +int Image::setPixelValue(int16_t x, int16_t y, uint8_t value) { - //sanity check - if(x >= getWidth() || y >= getHeight() || x < 0 || y < 0) - return DEVICE_INVALID_PARAMETER; + // sanity check + if (x >= getWidth() || y >= getHeight() || x < 0 || y < 0) return DEVICE_INVALID_PARAMETER; - this->getBitmap()[y*getWidth()+x] = value; + this->getBitmap()[y * getWidth() + x] = value; return DEVICE_OK; } /** - * Retrieves the value of a given pixel. - * - * @param x The x co-ordinate of the pixel to read. Must be within the dimensions of the image. - * - * @param y The y co-ordinate of the pixel to read. Must be within the dimensions of the image. - * - * @return The value assigned to the given pixel location (the brightness level 0-255), or DEVICE_INVALID_PARAMETER. - * - * @code - * Image i("0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n"); // 5x5 image - * i.getPixelValue(0,0); //should be 0; - * @endcode - */ -int Image::getPixelValue(int16_t x , int16_t y) + * Retrieves the value of a given pixel. + * + * @param x The x co-ordinate of the pixel to read. Must be within the dimensions of the image. + * + * @param y The y co-ordinate of the pixel to read. Must be within the dimensions of the image. + * + * @return The value assigned to the given pixel location (the brightness level 0-255), or DEVICE_INVALID_PARAMETER. + * + * @code + * Image i("0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n1,0,1,0,1\n0,1,0,1,0\n"); // 5x5 image + * i.getPixelValue(0,0); //should be 0; + * @endcode + */ +int Image::getPixelValue(int16_t x, int16_t y) { - //sanity check - if(x >= getWidth() || y >= getHeight() || x < 0 || y < 0) - return DEVICE_INVALID_PARAMETER; + // sanity check + if (x >= getWidth() || y >= getHeight() || x < 0 || y < 0) return DEVICE_INVALID_PARAMETER; - return this->getBitmap()[y*getWidth()+x]; + return this->getBitmap()[y * getWidth() + x]; } /** - * Replaces the content of this image with that of a given 2D array representing - * the image. - * - * @param x the width of the image. Must be within the dimensions of the image. - * - * @param y the width of the image. Must be within the dimensions of the image. - * - * @param bitmap a 2D array representing the image. - * - * @return DEVICE_OK on success, or DEVICE_INVALID_PARAMETER. - * - * @code - * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart - * Image i(); - * i.printImage(0,0,heart); - * @endcode - * - * @note all coordinates originate from the top left of an image. - */ -int Image::printImage(int16_t width, int16_t height, const uint8_t *bitmap) + * Replaces the content of this image with that of a given 2D array representing + * the image. + * + * @param x the width of the image. Must be within the dimensions of the image. + * + * @param y the width of the image. Must be within the dimensions of the image. + * + * @param bitmap a 2D array representing the image. + * + * @return DEVICE_OK on success, or DEVICE_INVALID_PARAMETER. + * + * @code + * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, + * 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart Image i(); i.printImage(0,0,heart); + * @endcode + * + * @note all coordinates originate from the top left of an image. + */ +int Image::printImage(int16_t width, int16_t height, const uint8_t* bitmap) { - const uint8_t *pIn; - uint8_t *pOut; + const uint8_t* pIn; + uint8_t* pOut; int pixelsToCopyX, pixelsToCopyY; // Sanity check. - if (width <= 0 || width <= 0 || bitmap == NULL) - return DEVICE_INVALID_PARAMETER; + if (width <= 0 || width <= 0 || bitmap == NULL) return DEVICE_INVALID_PARAMETER; // Calcualte sane start pointer. - pixelsToCopyX = min(width,this->getWidth()); - pixelsToCopyY = min(height,this->getHeight()); + pixelsToCopyX = min(width, this->getWidth()); + pixelsToCopyY = min(height, this->getHeight()); - pIn = bitmap; + pIn = bitmap; pOut = this->getBitmap(); // Copy the image, stride by stride. - for (int i=0; igetWidth(); @@ -479,27 +457,28 @@ int Image::printImage(int16_t width, int16_t height, const uint8_t *bitmap) } /** - * Pastes a given bitmap at the given co-ordinates. - * - * Any pixels in the relevant area of this image are replaced. - * - * @param image The Image to paste. - * - * @param x The leftmost X co-ordinate in this image where the given image should be pasted. Defaults to 0. - * - * @param y The uppermost Y co-ordinate in this image where the given image should be pasted. Defaults to 0. - * - * @param alpha set to 1 if transparency clear pixels in given image should be treated as transparent. Set to 0 otherwise. Defaults to 0. - * - * @return The number of pixels written. - * - * @code - * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart - * Image i(10,5,heart); // a big heart - * i.paste(i, -5, 0); // a small heart - * @endcode - */ -int Image::paste(const Image &image, int16_t x, int16_t y, uint8_t alpha) + * Pastes a given bitmap at the given co-ordinates. + * + * Any pixels in the relevant area of this image are replaced. + * + * @param image The Image to paste. + * + * @param x The leftmost X co-ordinate in this image where the given image should be pasted. Defaults to 0. + * + * @param y The uppermost Y co-ordinate in this image where the given image should be pasted. Defaults to 0. + * + * @param alpha set to 1 if transparency clear pixels in given image should be treated as transparent. Set to 0 + * otherwise. Defaults to 0. + * + * @return The number of pixels written. + * + * @code + * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, + * 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart Image i(10,5,heart); // a big heart + * i.paste(i, -5, 0); // a small heart + * @endcode + */ +int Image::paste(const Image& image, int16_t x, int16_t y, uint8_t alpha) { uint8_t *pIn, *pOut; int cx, cy; @@ -507,35 +486,31 @@ int Image::paste(const Image &image, int16_t x, int16_t y, uint8_t alpha) // Sanity check. // We permit writes that overlap us, but ones that are clearly out of scope we can filter early. - if (x >= getWidth() || y >= getHeight() || x+image.getWidth() <= 0 || y+image.getHeight() <= 0) - return 0; + if (x >= getWidth() || y >= getHeight() || x + image.getWidth() <= 0 || y + image.getHeight() <= 0) return 0; - //Calculate the number of byte we need to copy in each dimension. + // Calculate the number of byte we need to copy in each dimension. cx = x < 0 ? min(image.getWidth() + x, getWidth()) : min(image.getWidth(), getWidth() - x); cy = y < 0 ? min(image.getHeight() + y, getHeight()) : min(image.getHeight(), getHeight() - y); // Calculate sane start pointer. pIn = image.ptr->data; pIn += (x < 0) ? -x : 0; - pIn += (y < 0) ? -image.getWidth()*y : 0; + pIn += (y < 0) ? -image.getWidth() * y : 0; pOut = getBitmap(); pOut += (x > 0) ? x : 0; - pOut += (y > 0) ? getWidth()*y : 0; + pOut += (y > 0) ? getWidth() * y : 0; // Copy the image, stride by stride // If we want primitive transparecy, we do this byte by byte. // If we don't, use a more efficient block memory copy instead. Every little helps! - if (alpha) - { - for (int i=0; igetBitmap()[y1*getWidth()+x1] = ((*v) & (0x10 >> col)) ? 255 : 0; + this->getBitmap()[y1 * getWidth() + x1] = ((*v) & (0x10 >> col)) ? 255 : 0; } v++; } @@ -608,39 +579,35 @@ int Image::print(char c, int16_t x, int16_t y) return DEVICE_OK; } - /** - * Shifts the pixels in this Image a given number of pixels to the left. - * - * @param n The number of pixels to shift. - * - * @return DEVICE_OK on success, or DEVICE_INVALID_PARAMETER. - * - * @code - * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart - * Image i(10,5,heart); // a big heart - * i.shiftLeft(5); // a small heart - * @endcode - */ + * Shifts the pixels in this Image a given number of pixels to the left. + * + * @param n The number of pixels to shift. + * + * @return DEVICE_OK on success, or DEVICE_INVALID_PARAMETER. + * + * @code + * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, + * 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart Image i(10,5,heart); // a big heart + * i.shiftLeft(5); // a small heart + * @endcode + */ int Image::shiftLeft(int16_t n) { - uint8_t *p = getBitmap(); - int pixels = getWidth()-n; + uint8_t* p = getBitmap(); + int pixels = getWidth() - n; - if (n <= 0 ) - return DEVICE_INVALID_PARAMETER; + if (n <= 0) return DEVICE_INVALID_PARAMETER; - if(n >= getWidth()) - { + if (n >= getWidth()) { clear(); return DEVICE_OK; } - for (int y = 0; y < getHeight(); y++) - { + for (int y = 0; y < getHeight(); y++) { // Copy, and blank fill the rightmost column. - memcpy(p, p+n, pixels); - memclr(p+pixels, n); + memcpy(p, p + n, pixels); + memclr(p + pixels, n); p += getWidth(); } @@ -648,37 +615,34 @@ int Image::shiftLeft(int16_t n) } /** - * Shifts the pixels in this Image a given number of pixels to the right. - * - * @param n The number of pixels to shift. - * - * @return DEVICE_OK on success, or DEVICE_INVALID_PARAMETER. - * - * @code - * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart - * Image i(10,5,heart); // a big heart - * i.shiftLeft(5); // a small heart - * i.shiftRight(5); // a big heart - * @endcode - */ + * Shifts the pixels in this Image a given number of pixels to the right. + * + * @param n The number of pixels to shift. + * + * @return DEVICE_OK on success, or DEVICE_INVALID_PARAMETER. + * + * @code + * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, + * 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart Image i(10,5,heart); // a big heart + * i.shiftLeft(5); // a small heart + * i.shiftRight(5); // a big heart + * @endcode + */ int Image::shiftRight(int16_t n) { - uint8_t *p = getBitmap(); - int pixels = getWidth()-n; + uint8_t* p = getBitmap(); + int pixels = getWidth() - n; - if (n <= 0) - return DEVICE_INVALID_PARAMETER; + if (n <= 0) return DEVICE_INVALID_PARAMETER; - if(n >= getWidth()) - { + if (n >= getWidth()) { clear(); return DEVICE_OK; } - for (int y = 0; y < getHeight(); y++) - { + for (int y = 0; y < getHeight(); y++) { // Copy, and blank fill the leftmost column. - memmove(p+n, p, pixels); + memmove(p + n, p, pixels); memclr(p, n); p += getWidth(); } @@ -686,40 +650,35 @@ int Image::shiftRight(int16_t n) return DEVICE_OK; } - /** - * Shifts the pixels in this Image a given number of pixels to upward. - * - * @param n The number of pixels to shift. - * - * @return DEVICE_OK on success, or DEVICE_INVALID_PARAMETER. - * - * @code - * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart - * Image i(10,5,heart); - * i.shiftUp(1); - * @endcode - */ + * Shifts the pixels in this Image a given number of pixels to upward. + * + * @param n The number of pixels to shift. + * + * @return DEVICE_OK on success, or DEVICE_INVALID_PARAMETER. + * + * @code + * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, + * 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart Image i(10,5,heart); i.shiftUp(1); + * @endcode + */ int Image::shiftUp(int16_t n) { uint8_t *pOut, *pIn; - if (n <= 0 ) - return DEVICE_INVALID_PARAMETER; + if (n <= 0) return DEVICE_INVALID_PARAMETER; - if(n >= getHeight()) - { + if (n >= getHeight()) { clear(); return DEVICE_OK; } pOut = getBitmap(); - pIn = getBitmap()+getWidth()*n; + pIn = getBitmap() + getWidth() * n; - for (int y = 0; y < getHeight(); y++) - { + for (int y = 0; y < getHeight(); y++) { // Copy, and blank fill the leftmost column. - if (y < getHeight()-n) + if (y < getHeight() - n) memcpy(pOut, pIn, getWidth()); else memclr(pOut, getWidth()); @@ -731,40 +690,35 @@ int Image::shiftUp(int16_t n) return DEVICE_OK; } - /** - * Shifts the pixels in this Image a given number of pixels to downward. - * - * @param n The number of pixels to shift. - * - * @return DEVICE_OK on success, or DEVICE_INVALID_PARAMETER. - * - * @code - * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart - * Image i(10,5,heart); - * i.shiftDown(1); - * @endcode - */ + * Shifts the pixels in this Image a given number of pixels to downward. + * + * @param n The number of pixels to shift. + * + * @return DEVICE_OK on success, or DEVICE_INVALID_PARAMETER. + * + * @code + * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, + * 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart Image i(10,5,heart); i.shiftDown(1); + * @endcode + */ int Image::shiftDown(int16_t n) { uint8_t *pOut, *pIn; - if (n <= 0 ) - return DEVICE_INVALID_PARAMETER; + if (n <= 0) return DEVICE_INVALID_PARAMETER; - if(n >= getHeight()) - { + if (n >= getHeight()) { clear(); return DEVICE_OK; } - pOut = getBitmap() + getWidth()*(getHeight()-1); - pIn = pOut - getWidth()*n; + pOut = getBitmap() + getWidth() * (getHeight() - 1); + pIn = pOut - getWidth() * n; - for (int y = 0; y < getHeight(); y++) - { + for (int y = 0; y < getHeight(); y++) { // Copy, and blank fill the leftmost column. - if (y < getHeight()-n) + if (y < getHeight() - n) memcpy(pOut, pIn, getWidth()); else memclr(pOut, getWidth()); @@ -776,47 +730,43 @@ int Image::shiftDown(int16_t n) return DEVICE_OK; } - /** - * Converts the bitmap to a csv ManagedString. - * - * @code - * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart - * Image i(10,5,heart); - * uBit.serial.printString(i.toString()); // "0,1,0,1,0,0,0,0,0,0\n..." - * @endcode - */ + * Converts the bitmap to a csv ManagedString. + * + * @code + * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, + * 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart Image i(10,5,heart); + * uBit.serial.printString(i.toString()); // "0,1,0,1,0,0,0,0,0,0\n..." + * @endcode + */ ManagedString Image::toString() { - //width including commans and \n * height + // width including commans and \n * height int stringSize = getSize() * 2; - //plus one for string terminator + // plus one for string terminator char parseBuffer[stringSize + 1]; parseBuffer[stringSize] = '\0'; - uint8_t *bitmapPtr = getBitmap(); + uint8_t* bitmapPtr = getBitmap(); int parseIndex = 0; int widthCount = 0; - while (parseIndex < stringSize) - { - if(*bitmapPtr) + while (parseIndex < stringSize) { + if (*bitmapPtr) parseBuffer[parseIndex] = '1'; else parseBuffer[parseIndex] = '0'; parseIndex++; - if(widthCount == getWidth()-1) - { + if (widthCount == getWidth() - 1) { parseBuffer[parseIndex] = '\n'; - widthCount = 0; + widthCount = 0; } - else - { + else { parseBuffer[parseIndex] = ','; widthCount++; } @@ -829,45 +779,42 @@ ManagedString Image::toString() } /** - * Crops the image to the given dimensions. - * - * @param startx the location to start the crop in the x-axis - * - * @param starty the location to start the crop in the y-axis - * - * @param width the width of the desired cropped region - * - * @param height the height of the desired cropped region - * - * @code - * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart - * Image i(10,5,heart); - * i.crop(0,0,2,2).toString() // "0,1\n1,1\n" - * @endcode - */ + * Crops the image to the given dimensions. + * + * @param startx the location to start the crop in the x-axis + * + * @param starty the location to start the crop in the y-axis + * + * @param width the width of the desired cropped region + * + * @param height the height of the desired cropped region + * + * @code + * const uint8_t heart[] = { 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, + * 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, }; // a cute heart Image i(10,5,heart); + * i.crop(0,0,2,2).toString() // "0,1\n1,1\n" + * @endcode + */ Image Image::crop(int startx, int starty, int cropWidth, int cropHeight) { - int newWidth = startx + cropWidth; + int newWidth = startx + cropWidth; int newHeight = starty + cropHeight; - if (newWidth >= getWidth() || newWidth <=0) - newWidth = getWidth(); + if (newWidth >= getWidth() || newWidth <= 0) newWidth = getWidth(); - if (newHeight >= getHeight() || newHeight <= 0) - newHeight = getHeight(); + if (newHeight >= getHeight() || newHeight <= 0) newHeight = getHeight(); - //allocate our storage. + // allocate our storage. uint8_t cropped[newWidth * newHeight]; - //calculate the pointer to where we want to begin cropping - uint8_t *copyPointer = getBitmap() + (getWidth() * starty) + startx; + // calculate the pointer to where we want to begin cropping + uint8_t* copyPointer = getBitmap() + (getWidth() * starty) + startx; - //get a reference to our storage - uint8_t *pastePointer = cropped; + // get a reference to our storage + uint8_t* pastePointer = cropped; - //go through row by row and select our image. - for (int i = starty; i < newHeight; i++) - { + // go through row by row and select our image. + for (int i = starty; i < newHeight; i++) { memcpy(pastePointer, copyPointer, newWidth); copyPointer += getWidth(); @@ -878,18 +825,18 @@ Image Image::crop(int startx, int starty, int cropWidth, int cropHeight) } /** - * Check if image is read-only (i.e., residing in flash). - */ + * Check if image is read-only (i.e., residing in flash). + */ bool Image::isReadOnly() { return ptr->isReadOnly(); } /** - * Create a copy of the image bitmap. Used particularly, when isReadOnly() is true. - * - * @return an instance of Image which can be modified independently of the current instance - */ + * Create a copy of the image bitmap. Used particularly, when isReadOnly() is true. + * + * @return an instance of Image which can be modified independently of the current instance + */ Image Image::clone() { return Image(getWidth(), getHeight(), getBitmap()); diff --git a/source/types/ManagedBuffer.cpp b/source/types/ManagedBuffer.cpp index c4920750..4f69fe0a 100644 --- a/source/types/ManagedBuffer.cpp +++ b/source/types/ManagedBuffer.cpp @@ -23,22 +23,23 @@ DEALINGS IN THE SOFTWARE. */ #include "ManagedBuffer.h" + #include + #include "CodalCompat.h" -#define REF_TAG REF_TAG_BUFFER +#define REF_TAG REF_TAG_BUFFER #define EMPTY_DATA ((BufferData*)(void*)emptyData) REF_COUNTED_DEF_EMPTY(0, 0) - using namespace std; using namespace codal; /** - * Internal constructor helper. - * Configures this ManagedBuffer to refer to the static empty buffer. - */ + * Internal constructor helper. + * Configures this ManagedBuffer to refer to the static empty buffer. + */ void ManagedBuffer::initEmpty() { ptr = EMPTY_DATA; @@ -88,7 +89,7 @@ ManagedBuffer::ManagedBuffer(int length, BufferInitialize initialize) * ManagedBuffer p(buf, 3); // Creates a ManagedBuffer 3 bytes long. * @endcode */ -ManagedBuffer::ManagedBuffer(uint8_t *data, int length) +ManagedBuffer::ManagedBuffer(uint8_t* data, int length) { this->init(data, length, BufferInitialize::None); } @@ -105,19 +106,19 @@ ManagedBuffer::ManagedBuffer(uint8_t *data, int length) * ManagedBuffer p2(i); // Refers to the same buffer as p. * @endcode */ -ManagedBuffer::ManagedBuffer(const ManagedBuffer &buffer) +ManagedBuffer::ManagedBuffer(const ManagedBuffer& buffer) { ptr = buffer.ptr; ptr->incr(); } /** - * Constructor. - * Create a buffer from a raw BufferData pointer. It will ptr->incr(). This is to be used by specialized runtimes. - * - * @param p The pointer to use. - */ -ManagedBuffer::ManagedBuffer(BufferData *p) + * Constructor. + * Create a buffer from a raw BufferData pointer. It will ptr->incr(). This is to be used by specialized runtimes. + * + * @param p The pointer to use. + */ +ManagedBuffer::ManagedBuffer(BufferData* p) { ptr = p; ptr->incr(); @@ -131,24 +132,22 @@ ManagedBuffer::ManagedBuffer(BufferData *p) * @param initialize The initialization mode to use for the allocted memory in the buffer * */ -void ManagedBuffer::init(uint8_t *data, int length, BufferInitialize initialize) +void ManagedBuffer::init(uint8_t* data, int length, BufferInitialize initialize) { if (length <= 0) { initEmpty(); return; } - ptr = (BufferData *) malloc(sizeof(BufferData) + length); + ptr = (BufferData*)malloc(sizeof(BufferData) + length); REF_COUNTED_INIT(ptr); ptr->length = length; // Copy in the data buffer, if provided. - if (data) - memcpy(ptr->payload, data, length); + if (data) memcpy(ptr->payload, data, length); - if (initialize == BufferInitialize::Zero) - memset(ptr->payload, 0, length); + if (initialize == BufferInitialize::Zero) memset(ptr->payload, 0, length); } /** @@ -179,10 +178,9 @@ ManagedBuffer::~ManagedBuffer() * p1 = p2; * @endcode */ -ManagedBuffer& ManagedBuffer::operator = (const ManagedBuffer &p) +ManagedBuffer& ManagedBuffer::operator=(const ManagedBuffer& p) { - if(ptr == p.ptr) - return *this; + if (ptr == p.ptr) return *this; ptr->decr(); ptr = p.ptr; @@ -210,12 +208,12 @@ ManagedBuffer& ManagedBuffer::operator = (const ManagedBuffer &p) * uBit.display.scroll("same!"); * @endcode */ -bool ManagedBuffer::operator== (const ManagedBuffer& p) +bool ManagedBuffer::operator==(const ManagedBuffer& p) { if (ptr == p.ptr) return true; else - return (ptr->length == p.ptr->length && (memcmp(ptr->payload, p.ptr->payload, ptr->length)==0)); + return (ptr->length == p.ptr->length && (memcmp(ptr->payload, p.ptr->payload, ptr->length) == 0)); } /** @@ -232,13 +230,11 @@ bool ManagedBuffer::operator== (const ManagedBuffer& p) */ int ManagedBuffer::setByte(int position, uint8_t value) { - if (0 <= position && (uint16_t)position < ptr->length) - { + if (0 <= position && (uint16_t)position < ptr->length) { ptr->payload[position] = value; return DEVICE_OK; } - else - { + else { return DEVICE_INVALID_PARAMETER; } } @@ -265,23 +261,20 @@ int ManagedBuffer::getByte(int position) } /** - * Get current ptr, do not decr() it, and set the current instance to an empty buffer. - * This is to be used by specialized runtimes which pass BufferData around. - */ -BufferData *ManagedBuffer::leakData() + * Get current ptr, do not decr() it, and set the current instance to an empty buffer. + * This is to be used by specialized runtimes which pass BufferData around. + */ +BufferData* ManagedBuffer::leakData() { BufferData* res = ptr; initEmpty(); return res; } - int ManagedBuffer::fill(uint8_t value, int offset, int length) { - if (offset < 0 || (uint16_t)offset > ptr->length) - return DEVICE_INVALID_PARAMETER; - if (length < 0) - length = (int)ptr->length; + if (offset < 0 || (uint16_t)offset > ptr->length) return DEVICE_INVALID_PARAMETER; + if (length < 0) length = (int)ptr->length; length = min(length, (int)ptr->length - offset); memset(ptr->payload + offset, value, length); @@ -292,8 +285,7 @@ int ManagedBuffer::fill(uint8_t value, int offset, int length) ManagedBuffer ManagedBuffer::slice(int offset, int length) const { offset = min((int)ptr->length, offset); - if (length < 0) - length = (int)ptr->length; + if (length < 0) length = (int)ptr->length; length = min(length, (int)ptr->length - offset); return ManagedBuffer(ptr->payload + offset, length); } @@ -301,19 +293,21 @@ ManagedBuffer ManagedBuffer::slice(int offset, int length) const void ManagedBuffer::shift(int offset, int start, int len) { if (len < 0) len = (int)ptr->length - start; - if (start < 0 || start + len > (int)ptr->length || start + len < start - || len == 0 || offset == 0 || offset == INT_MIN) return; + if (start < 0 || start + len > (int)ptr->length || start + len < start || len == 0 || offset == 0 || + offset == INT_MIN) + return; if (offset <= -len || offset >= len) { fill(0, start, len); return; } - uint8_t *data = ptr->payload + start; + uint8_t* data = ptr->payload + start; if (offset < 0) { offset = -offset; memmove(data + offset, data, len - offset); memset(data, 0, offset); - } else { + } + else { len = len - offset; memmove(data, data + offset, len); memset(data + len, 0, offset); @@ -323,82 +317,78 @@ void ManagedBuffer::shift(int offset, int start, int len) void ManagedBuffer::rotate(int offset, int start, int len) { if (len < 0) len = (int)ptr->length - start; - if (start < 0 || start + len > (int)ptr-> length || start + len < start - || len == 0 || offset == 0 || offset == INT_MIN) return; + if (start < 0 || start + len > (int)ptr->length || start + len < start || len == 0 || offset == 0 || + offset == INT_MIN) + return; - if (offset < 0) - offset += len << 8; // try to make it positive + if (offset < 0) offset += len << 8; // try to make it positive offset %= len; - if (offset < 0) - offset += len; + if (offset < 0) offset += len; - uint8_t *data = ptr->payload + start; + uint8_t* data = ptr->payload + start; - uint8_t *n_first = data + offset; - uint8_t *first = data; - uint8_t *next = n_first; - uint8_t *last = data + len; + uint8_t* n_first = data + offset; + uint8_t* first = data; + uint8_t* next = n_first; + uint8_t* last = data + len; while (first != next) { uint8_t tmp = *first; - *first++ = *next; - *next++ = tmp; + *first++ = *next; + *next++ = tmp; if (next == last) { next = n_first; - } else if (first == n_first) { + } + else if (first == n_first) { n_first = next; } } } -int ManagedBuffer::writeBuffer(int dstOffset, const ManagedBuffer &src, int srcOffset, int length) +int ManagedBuffer::writeBuffer(int dstOffset, const ManagedBuffer& src, int srcOffset, int length) { - if (length < 0) - length = src.length(); + if (length < 0) length = src.length(); - if (srcOffset < 0 || dstOffset < 0 || dstOffset > (int)ptr->length) - return DEVICE_INVALID_PARAMETER; + if (srcOffset < 0 || dstOffset < 0 || dstOffset > (int)ptr->length) return DEVICE_INVALID_PARAMETER; length = min(src.length() - srcOffset, (int)ptr->length - dstOffset); - if (length < 0) - return DEVICE_INVALID_PARAMETER; + if (length < 0) return DEVICE_INVALID_PARAMETER; if (ptr == src.ptr) { memmove(getBytes() + dstOffset, src.ptr->payload + srcOffset, length); - } else { + } + else { memcpy(getBytes() + dstOffset, src.ptr->payload + srcOffset, length); } return DEVICE_OK; } -int ManagedBuffer::writeBytes(int offset, uint8_t *src, int length, bool swapBytes) +int ManagedBuffer::writeBytes(int offset, uint8_t* src, int length, bool swapBytes) { - if (offset < 0 || length < 0 || offset + length > (int)ptr->length) - return DEVICE_INVALID_PARAMETER; + if (offset < 0 || length < 0 || offset + length > (int)ptr->length) return DEVICE_INVALID_PARAMETER; if (swapBytes) { - uint8_t *p = ptr->payload + offset + length; - for (int i = 0; i < length; ++i) - *--p = src[i]; - } else { + uint8_t* p = ptr->payload + offset + length; + for (int i = 0; i < length; ++i) *--p = src[i]; + } + else { memcpy(ptr->payload + offset, src, length); } return DEVICE_OK; } -int ManagedBuffer::readBytes(uint8_t *dst, int offset, int length, bool swapBytes) const +int ManagedBuffer::readBytes(uint8_t* dst, int offset, int length, bool swapBytes) const { - if (offset < 0 || length < 0 || offset + length > (int)ptr->length) - return DEVICE_INVALID_PARAMETER; + if (offset < 0 || length < 0 || offset + length > (int)ptr->length) return DEVICE_INVALID_PARAMETER; if (swapBytes) { - uint8_t *p = ptr->payload + offset + length; - for (int i = 0; i < length; ++i) - dst[i] = *--p; - } else { + uint8_t* p = ptr->payload + offset + length; + for (int i = 0; i < length; ++i) dst[i] = *--p; + } + else { memcpy(dst, ptr->payload + offset, length); } @@ -407,8 +397,7 @@ int ManagedBuffer::readBytes(uint8_t *dst, int offset, int length, bool swapByte int ManagedBuffer::truncate(int length) { - if (length < 0 || length > (int)ptr->length) - return DEVICE_INVALID_PARAMETER; + if (length < 0 || length > (int)ptr->length) return DEVICE_INVALID_PARAMETER; ptr->length = length; diff --git a/source/types/ManagedString.cpp b/source/types/ManagedString.cpp index 33aa114f..9350409a 100644 --- a/source/types/ManagedString.cpp +++ b/source/types/ManagedString.cpp @@ -23,59 +23,59 @@ DEALINGS IN THE SOFTWARE. */ /** - * Class definition for a ManagedString. - * - * Uses basic reference counting to implement a copy-assignable, immutable string. - * - * This maps closely to the constructs found in many high level application languages, - * such as Touch Develop. - * - * Written from first principles here, for several reasons: - * 1) std::shared_ptr is not yet available on the ARMCC compiler - * - * 2) to reduce memory footprint - we don't need many of the other features in the std library - * - * 3) it makes an interesting case study for anyone interested in seeing how it works! - * - * 4) we need explicit reference counting to inter-op with low-level application langauge runtimes. - * - * 5) the reference counting needs to also work for read-only, flash-resident strings - */ -#include + * Class definition for a ManagedString. + * + * Uses basic reference counting to implement a copy-assignable, immutable string. + * + * This maps closely to the constructs found in many high level application languages, + * such as Touch Develop. + * + * Written from first principles here, for several reasons: + * 1) std::shared_ptr is not yet available on the ARMCC compiler + * + * 2) to reduce memory footprint - we don't need many of the other features in the std library + * + * 3) it makes an interesting case study for anyone interested in seeing how it works! + * + * 4) we need explicit reference counting to inter-op with low-level application langauge runtimes. + * + * 5) the reference counting needs to also work for read-only, flash-resident strings + */ +#include "ManagedString.h" + #include +#include -#include "CodalConfig.h" -#include "ManagedString.h" #include "CodalCompat.h" +#include "CodalConfig.h" using namespace codal; -#define REF_TAG REF_TAG_STRING +#define REF_TAG REF_TAG_STRING #define EMPTY_DATA ((StringData*)(void*)emptyData) REF_COUNTED_DEF_EMPTY(0, 0) - /** - * Internal constructor helper. - * - * Configures this ManagedString to refer to the static EmptyString - */ + * Internal constructor helper. + * + * Configures this ManagedString to refer to the static EmptyString + */ void ManagedString::initEmpty() { ptr = EMPTY_DATA; } /** - * Internal constructor helper. - * - * Creates this ManagedString based on a given null terminated char array. - */ -void ManagedString::initString(const char *str, int len) + * Internal constructor helper. + * + * Creates this ManagedString based on a given null terminated char array. + */ +void ManagedString::initString(const char* str, int len) { // Initialise this ManagedString as a new string, using the data provided. // We assume the string is sane, and null terminated. - ptr = (StringData *) malloc(sizeof(StringData) + len + 1); + ptr = (StringData*)malloc(sizeof(StringData) + len + 1); REF_COUNTED_INIT(ptr); ptr->len = len; memcpy(ptr->data, str, len); @@ -83,20 +83,20 @@ void ManagedString::initString(const char *str, int len) } /** - * Constructor. - * Create a managed string from a specially prepared string literal. - * - * @param ptr The literal - first two bytes should be 0xff, then the length in little endian, then the literal. The literal has to be 4-byte aligned. - * - * @code - * static const char hello[] __attribute__ ((aligned (4))) = "\xff\xff\x05\x00" "Hello"; - * ManagedString s((StringData*)(void*)hello); - * @endcode - */ -ManagedString::ManagedString(StringData *p) + * Constructor. + * Create a managed string from a specially prepared string literal. + * + * @param ptr The literal - first two bytes should be 0xff, then the length in little endian, then the literal. The + * literal has to be 4-byte aligned. + * + * @code + * static const char hello[] __attribute__ ((aligned (4))) = "\xff\xff\x05\x00" "Hello"; + * ManagedString s((StringData*)(void*)hello); + * @endcode + */ +ManagedString::ManagedString(StringData* p) { - if(p == NULL) - { + if (p == NULL) { initEmpty(); return; } @@ -106,28 +106,28 @@ ManagedString::ManagedString(StringData *p) } /** - * Get current ptr, do not decr() it, and set the current instance to empty string. - * - * This is to be used by specialized runtimes which pass StringData around. - */ + * Get current ptr, do not decr() it, and set the current instance to empty string. + * + * This is to be used by specialized runtimes which pass StringData around. + */ StringData* ManagedString::leakData() { - StringData *res = ptr; + StringData* res = ptr; initEmpty(); return res; } /** - * Constructor. - * - * Create a managed string from a given integer. - * - * @param value The integer from which to create the ManagedString. - * - * @code - * ManagedString s(20); - * @endcode - */ + * Constructor. + * + * Create a managed string from a given integer. + * + * @param value The integer from which to create the ManagedString. + * + * @code + * ManagedString s(20); + * @endcode + */ ManagedString::ManagedString(const int value) { char str[12]; @@ -137,41 +137,39 @@ ManagedString::ManagedString(const int value) } /** - * Constructor. - * Create a managed string from a given char. - * - * @param value The character from which to create the ManagedString. - * - * @code - * ManagedString s('a'); - * @endcode - */ + * Constructor. + * Create a managed string from a given char. + * + * @param value The character from which to create the ManagedString. + * + * @code + * ManagedString s('a'); + * @endcode + */ ManagedString::ManagedString(const char value) { char str[2] = {value, 0}; initString(str, 1); } - /** - * Constructor. - * - * Create a managed string from a pointer to an 8-bit character buffer. - * - * The buffer is copied to ensure safe memory management (the supplied - * character buffer may be declared on the stack for instance). - * - * @param str The character array on which to base the new ManagedString. - * - * @code - * ManagedString s("abcdefg"); - * @endcode - */ -ManagedString::ManagedString(const char *str) + * Constructor. + * + * Create a managed string from a pointer to an 8-bit character buffer. + * + * The buffer is copied to ensure safe memory management (the supplied + * character buffer may be declared on the stack for instance). + * + * @param str The character array on which to base the new ManagedString. + * + * @code + * ManagedString s("abcdefg"); + * @endcode + */ +ManagedString::ManagedString(const char* str) { // Sanity check. Return EmptyString for anything distasteful - if (str == NULL || *str == 0) - { + if (str == NULL || *str == 0) { initEmpty(); return; } @@ -180,23 +178,23 @@ ManagedString::ManagedString(const char *str) } /** - * Private Constructor. - * - * Create a managed string based on a concat of two strings. - * The buffer is copied to ensure sane memory management (the supplied - * character buffer may be declared on the stack for instance). - * - * @param str1 The first string on which to base the new ManagedString. - * - * @param str2 The second string on which to base the new ManagedString. - */ -ManagedString::ManagedString(const ManagedString &s1, const ManagedString &s2) + * Private Constructor. + * + * Create a managed string based on a concat of two strings. + * The buffer is copied to ensure sane memory management (the supplied + * character buffer may be declared on the stack for instance). + * + * @param str1 The first string on which to base the new ManagedString. + * + * @param str2 The second string on which to base the new ManagedString. + */ +ManagedString::ManagedString(const ManagedString& s1, const ManagedString& s2) { // Calculate length of new string. int len = s1.length() + s2.length(); // Create a new buffer for holding the new string data. - ptr = (StringData*) malloc(sizeof(StringData) + len + 1); + ptr = (StringData*)malloc(sizeof(StringData) + len + 1); REF_COUNTED_INIT(ptr); ptr->len = len; @@ -206,42 +204,41 @@ ManagedString::ManagedString(const ManagedString &s1, const ManagedString &s2) ptr->data[len] = 0; } - /** - * Constructor. - * Create a ManagedString from a ManagedBuffer. All bytes in the - * ManagedBuffer are added to the ManagedString. - * - * @param buffer The ManagedBuffer from which to create the ManagedString. - * - * @code - * ManagedString s = radio.datagram.recv(); - * @endcode - */ + * Constructor. + * Create a ManagedString from a ManagedBuffer. All bytes in the + * ManagedBuffer are added to the ManagedString. + * + * @param buffer The ManagedBuffer from which to create the ManagedString. + * + * @code + * ManagedString s = radio.datagram.recv(); + * @endcode + */ ManagedString::ManagedString(ManagedBuffer buffer) { initString((char*)buffer.getBytes(), buffer.length()); } /** - * Constructor. - * Create a ManagedString from a pointer to an 8-bit character buffer of a given length. - * - * The buffer is copied to ensure sane memory management (the supplied - * character buffer may be declared on the stack for instance). - * - * @param str The character array on which to base the new ManagedString. - * - * @param length The length of the character array - * - * @code - * ManagedString s("abcdefg",7); - * @endcode - */ -ManagedString::ManagedString(const char *str, const int16_t length) + * Constructor. + * Create a ManagedString from a pointer to an 8-bit character buffer of a given length. + * + * The buffer is copied to ensure sane memory management (the supplied + * character buffer may be declared on the stack for instance). + * + * @param str The character array on which to base the new ManagedString. + * + * @param length The length of the character array + * + * @code + * ManagedString s("abcdefg",7); + * @endcode + */ +ManagedString::ManagedString(const char* str, const int16_t length) { // Sanity check. Return EmptyString for anything distasteful - if (str == NULL || *str == 0 || (uint16_t)length > strlen(str)) // XXX length should be unsigned on the interface + if (str == NULL || *str == 0 || (uint16_t)length > strlen(str)) // XXX length should be unsigned on the interface { initEmpty(); return; @@ -251,75 +248,73 @@ ManagedString::ManagedString(const char *str, const int16_t length) } /** - * Copy constructor. - * Makes a new ManagedString identical to the one supplied. - * - * Shares the character buffer and reference count with the supplied ManagedString. - * - * @param s The ManagedString to copy. - * - * @code - * ManagedString s("abcdefg"); - * ManagedString p(s); - * @endcode - */ -ManagedString::ManagedString(const ManagedString &s) + * Copy constructor. + * Makes a new ManagedString identical to the one supplied. + * + * Shares the character buffer and reference count with the supplied ManagedString. + * + * @param s The ManagedString to copy. + * + * @code + * ManagedString s("abcdefg"); + * ManagedString p(s); + * @endcode + */ +ManagedString::ManagedString(const ManagedString& s) { ptr = s.ptr; ptr->incr(); } - /** - * Default constructor. - * - * Create an empty ManagedString. - * - * @code - * ManagedString s(); - * @endcode - */ + * Default constructor. + * + * Create an empty ManagedString. + * + * @code + * ManagedString s(); + * @endcode + */ ManagedString::ManagedString() { initEmpty(); } /** - * Destructor. - * - * Free this ManagedString, and decrement the reference count to the - * internal character buffer. - * - * If we're holding the last reference, also free the character buffer. - */ + * Destructor. + * + * Free this ManagedString, and decrement the reference count to the + * internal character buffer. + * + * If we're holding the last reference, also free the character buffer. + */ ManagedString::~ManagedString() { ptr->decr(); } /** - * Copy assign operation. - * - * Called when one ManagedString is assigned the value of another. - * - * If the ManagedString being assigned is already referring to a character buffer, - * decrement the reference count and free up the buffer as necessary. - * - * Then, update our character buffer to refer to that of the supplied ManagedString, - * and increase its reference count. - * - * @param s The ManagedString to copy. - * - * @code - * ManagedString s("abcd"); - * ManagedString p("efgh"); - * p = s // p now points to s, s' ref is incremented - * @endcode - */ -ManagedString& ManagedString::operator = (const ManagedString& s) + * Copy assign operation. + * + * Called when one ManagedString is assigned the value of another. + * + * If the ManagedString being assigned is already referring to a character buffer, + * decrement the reference count and free up the buffer as necessary. + * + * Then, update our character buffer to refer to that of the supplied ManagedString, + * and increase its reference count. + * + * @param s The ManagedString to copy. + * + * @code + * ManagedString s("abcd"); + * ManagedString p("efgh"); + * p = s // p now points to s, s' ref is incremented + * @endcode + */ +ManagedString& ManagedString::operator=(const ManagedString& s) { - if (this->ptr == s.ptr) - return *this; + if (this->ptr == s.ptr) return *this; ptr->decr(); ptr = s.ptr; @@ -329,184 +324,179 @@ ManagedString& ManagedString::operator = (const ManagedString& s) } /** - * Equality operation. - * - * Called when one ManagedString is tested to be equal to another using the '==' operator. - * - * @param s The ManagedString to test ourselves against. - * - * @return true if this ManagedString is identical to the one supplied, false otherwise. - * - * @code - * DeviceDisplay display; - * ManagedString s("abcd"); - * ManagedString p("efgh"); - * - * if(p == s) - * display.scroll("We are the same!"); - * else - * display.scroll("We are different!"); //p is not equal to s - this will be called - * @endcode - */ -bool ManagedString::operator== (const ManagedString& s) + * Equality operation. + * + * Called when one ManagedString is tested to be equal to another using the '==' operator. + * + * @param s The ManagedString to test ourselves against. + * + * @return true if this ManagedString is identical to the one supplied, false otherwise. + * + * @code + * DeviceDisplay display; + * ManagedString s("abcd"); + * ManagedString p("efgh"); + * + * if(p == s) + * display.scroll("We are the same!"); + * else + * display.scroll("We are different!"); //p is not equal to s - this will be called + * @endcode + */ +bool ManagedString::operator==(const ManagedString& s) { - return ((length() == s.length()) && (strcmp(toCharArray(),s.toCharArray())==0)); + return ((length() == s.length()) && (strcmp(toCharArray(), s.toCharArray()) == 0)); } /** - * Inequality operation. - * - * Called when one ManagedString is tested to be not equal using the '!=' operator. - * - * @param s The ManagedString to test ourselves against. - * - * @return true if this ManagedString is identical to the one supplied, false otherwise. - * - * @code - * DeviceDisplay display; - * ManagedString s("abcd"); - * ManagedString p("efgh"); - * - * if(p != s) - * display.scroll("We are different!"); - * else - * display.scroll("We are the same!"); - * @endcode - */ -bool ManagedString::operator!= (const ManagedString& s) + * Inequality operation. + * + * Called when one ManagedString is tested to be not equal using the '!=' operator. + * + * @param s The ManagedString to test ourselves against. + * + * @return true if this ManagedString is identical to the one supplied, false otherwise. + * + * @code + * DeviceDisplay display; + * ManagedString s("abcd"); + * ManagedString p("efgh"); + * + * if(p != s) + * display.scroll("We are different!"); + * else + * display.scroll("We are the same!"); + * @endcode + */ +bool ManagedString::operator!=(const ManagedString& s) { return !(*this == s); } /** - * Inequality operation. - * - * Called when one ManagedString is tested to be less than another using the '<' operator. - * - * @param s The ManagedString to test ourselves against. - * - * @return true if this ManagedString is alphabetically less than to the one supplied, false otherwise. - * - * @code - * DeviceDisplay display; - * ManagedString s("a"); - * ManagedString p("b"); - * - * if(s < p) - * display.scroll("a is before b!"); //a is before b - * else - * display.scroll("b is before a!"); - * @endcode - */ -bool ManagedString::operator< (const ManagedString& s) + * Inequality operation. + * + * Called when one ManagedString is tested to be less than another using the '<' operator. + * + * @param s The ManagedString to test ourselves against. + * + * @return true if this ManagedString is alphabetically less than to the one supplied, false otherwise. + * + * @code + * DeviceDisplay display; + * ManagedString s("a"); + * ManagedString p("b"); + * + * if(s < p) + * display.scroll("a is before b!"); //a is before b + * else + * display.scroll("b is before a!"); + * @endcode + */ +bool ManagedString::operator<(const ManagedString& s) { - return (strcmp(toCharArray(), s.toCharArray())<0); + return (strcmp(toCharArray(), s.toCharArray()) < 0); } /** - * Inequality operation. - * - * Called when one ManagedString is tested to be greater than another using the '>' operator. - * - * @param s The ManagedString to test ourselves against. - * - * @return true if this ManagedString is alphabetically greater than to the one supplied, false otherwise. - * - * @code - * DeviceDisplay display; - * ManagedString s("a"); - * ManagedString p("b"); - * - * if(p>a) - * display.scroll("b is after a!"); //b is after a - * else - * display.scroll("a is after b!"); - * @endcode - */ -bool ManagedString::operator> (const ManagedString& s) + * Inequality operation. + * + * Called when one ManagedString is tested to be greater than another using the '>' operator. + * + * @param s The ManagedString to test ourselves against. + * + * @return true if this ManagedString is alphabetically greater than to the one supplied, false otherwise. + * + * @code + * DeviceDisplay display; + * ManagedString s("a"); + * ManagedString p("b"); + * + * if(p>a) + * display.scroll("b is after a!"); //b is after a + * else + * display.scroll("a is after b!"); + * @endcode + */ +bool ManagedString::operator>(const ManagedString& s) { - return (strcmp(toCharArray(), s.toCharArray())>0); + return (strcmp(toCharArray(), s.toCharArray()) > 0); } /** - * Extracts a ManagedString from this string, at the position provided. - * - * @param start The index of the first character to extract, indexed from zero. - * - * @param length The number of characters to extract from the start position - * - * @return a ManagedString representing the requested substring. - * - * @code - * DeviceDisplay display; - * ManagedString s("abcdefg"); - * - * display.scroll(s.substring(0,2)) // displays "ab" - * @endcode - */ + * Extracts a ManagedString from this string, at the position provided. + * + * @param start The index of the first character to extract, indexed from zero. + * + * @param length The number of characters to extract from the start position + * + * @return a ManagedString representing the requested substring. + * + * @code + * DeviceDisplay display; + * ManagedString s("abcdefg"); + * + * display.scroll(s.substring(0,2)) // displays "ab" + * @endcode + */ ManagedString ManagedString::substring(int16_t start, int16_t length) { // If the parameters are illegal, just return a reference to the empty string. - if (start >= this->length()) - return ManagedString(EMPTY_DATA); + if (start >= this->length()) return ManagedString(EMPTY_DATA); // Compute a safe copy length; - length = min(this->length()-start, length); + length = min(this->length() - start, length); // Build a ManagedString from this. - return ManagedString(toCharArray()+start, length); + return ManagedString(toCharArray() + start, length); } /** - * Concatenates two strings. - * - * @param lhs The first ManagedString to concatenate. - * @param rhs The second ManagedString to concatenate. - * - * @return a new ManagedString representing the joined strings. - * - * @code - * DeviceDisplay display; - * ManagedString s("abcd"); - * ManagedString p("efgh") - * - * display.scroll(s + p) // scrolls "abcdefgh" - * @endcode - */ -ManagedString (codal::operator+) (const ManagedString& lhs, const ManagedString& rhs) + * Concatenates two strings. + * + * @param lhs The first ManagedString to concatenate. + * @param rhs The second ManagedString to concatenate. + * + * @return a new ManagedString representing the joined strings. + * + * @code + * DeviceDisplay display; + * ManagedString s("abcd"); + * ManagedString p("efgh") + * + * display.scroll(s + p) // scrolls "abcdefgh" + * @endcode + */ +ManagedString(codal::operator+)(const ManagedString& lhs, const ManagedString& rhs) { - // If the either string is empty, nothing to do! - if (rhs.length() == 0) - return lhs; + if (rhs.length() == 0) return lhs; - if (lhs.length() == 0) - return rhs; + if (lhs.length() == 0) return rhs; return ManagedString(lhs, rhs); } - /** - * Provides a character value at a given position in the string, indexed from zero. - * - * @param index The position of the character to return. - * - * @return the character at position index, zero if index is invalid. - * - * @code - * DeviceDisplay display; - * ManagedString s("abcd"); - * - * display.scroll(s.charAt(1)) // scrolls "b" - * @endcode - */ + * Provides a character value at a given position in the string, indexed from zero. + * + * @param index The position of the character to return. + * + * @return the character at position index, zero if index is invalid. + * + * @code + * DeviceDisplay display; + * ManagedString s("abcd"); + * + * display.scroll(s.charAt(1)) // scrolls "b" + * @endcode + */ char ManagedString::charAt(int16_t index) { - return (index >=0 && index < length()) ? ptr->data[index] : 0; + return (index >= 0 && index < length()) ? ptr->data[index] : 0; } /** - * Empty string constant literal - */ + * Empty string constant literal + */ ManagedString ManagedString::EmptyString(EMPTY_DATA); diff --git a/source/types/Matrix4.cpp b/source/types/Matrix4.cpp index f5005b17..8317fa67 100644 --- a/source/types/Matrix4.cpp +++ b/source/types/Matrix4.cpp @@ -21,265 +21,267 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include "Matrix4.h" #include "CodalConfig.h" -#include "Matrix4.h" using namespace codal; /** -* Class definition for a simple matrix, optimised for n x 4 or 4 x n matrices. -* -* This class is heavily optimised for these commonly used matrices as used in 3D geometry, -* and is not intended as a general purpose matrix class. For programmers needing more flexible -* Matrix support, the mbed Matrix and MatrixMath classes from Ernsesto Palacios provide a good basis: -* -* https://developer.mbed.org/cookbook/MatrixClass -* https://developer.mbed.org/users/Yo_Robot/code/MatrixMath/ -*/ + * Class definition for a simple matrix, optimised for n x 4 or 4 x n matrices. + * + * This class is heavily optimised for these commonly used matrices as used in 3D geometry, + * and is not intended as a general purpose matrix class. For programmers needing more flexible + * Matrix support, the mbed Matrix and MatrixMath classes from Ernsesto Palacios provide a good basis: + * + * https://developer.mbed.org/cookbook/MatrixClass + * https://developer.mbed.org/users/Yo_Robot/code/MatrixMath/ + */ /** - * Constructor. - * Create a matrix of the given size. - * - * @param rows the number of rows in the matrix to be created. - * - * @param cols the number of columns in the matrix to be created. - * - * @code - * Matrix4(10, 4); // Creates a Matrix with 10 rows and 4 columns. - * @endcode - */ + * Constructor. + * Create a matrix of the given size. + * + * @param rows the number of rows in the matrix to be created. + * + * @param cols the number of columns in the matrix to be created. + * + * @code + * Matrix4(10, 4); // Creates a Matrix with 10 rows and 4 columns. + * @endcode + */ Matrix4::Matrix4(int rows, int cols) { - this->rows = rows; - this->cols = cols; + this->rows = rows; + this->cols = cols; - int size = rows * cols; + int size = rows * cols; - if (size > 0) - data = new float[size]; - else - data = NULL; + if (size > 0) + data = new float[size]; + else + data = NULL; } /** - * Constructor. - * Create a matrix that is an identical copy of the given matrix. - * - * @param matrix The matrix to copy. - * - * @code - * Matrix newMatrix(matrix); . - * @endcode - */ -Matrix4::Matrix4(const Matrix4 &matrix) + * Constructor. + * Create a matrix that is an identical copy of the given matrix. + * + * @param matrix The matrix to copy. + * + * @code + * Matrix newMatrix(matrix); . + * @endcode + */ +Matrix4::Matrix4(const Matrix4& matrix) { - this->rows = matrix.rows; - this->cols = matrix.cols; - - int size = rows * cols; - - if (size > 0) - { - data = new float[size]; - for (int i = 0; i < size; i++) - data[i] = matrix.data[i]; - } - else - { - data = NULL; - } - + this->rows = matrix.rows; + this->cols = matrix.cols; + + int size = rows * cols; + + if (size > 0) { + data = new float[size]; + for (int i = 0; i < size; i++) data[i] = matrix.data[i]; + } + else { + data = NULL; + } } /** - * Determines the number of columns in this matrix. - * - * @return The number of columns in the matrix. - * - * @code - * int c = matrix.width(); - * @endcode - */ + * Determines the number of columns in this matrix. + * + * @return The number of columns in the matrix. + * + * @code + * int c = matrix.width(); + * @endcode + */ int Matrix4::width() { - return cols; + return cols; } /** - * Determines the number of rows in this matrix. - * - * @return The number of rows in the matrix. - * - * @code - * int r = matrix.height(); - * @endcode - */ + * Determines the number of rows in this matrix. + * + * @return The number of rows in the matrix. + * + * @code + * int r = matrix.height(); + * @endcode + */ int Matrix4::height() { - return rows; + return rows; } /** - * Reads the matrix element at the given position. - * - * @param row The row of the element to read. - * - * @param col The column of the element to read. - * - * @return The value of the matrix element at the given position. 0 is returned if the given index is out of range. - * - * @code - * float v = matrix.get(1,2); - * @endcode - */ + * Reads the matrix element at the given position. + * + * @param row The row of the element to read. + * + * @param col The column of the element to read. + * + * @return The value of the matrix element at the given position. 0 is returned if the given index is out of range. + * + * @code + * float v = matrix.get(1,2); + * @endcode + */ float Matrix4::get(int row, int col) { - if (row < 0 || col < 0 || row >= rows || col >= cols) - return 0; + if (row < 0 || col < 0 || row >= rows || col >= cols) return 0; - return data[width() * row + col]; + return data[width() * row + col]; } /** - * Writes the matrix element at the given position. - * - * @param row The row of the element to write. - * - * @param col The column of the element to write. - * - * @param v The new value of the element. - * - * @code - * matrix.set(1,2,42.0); - * @endcode - */ + * Writes the matrix element at the given position. + * + * @param row The row of the element to write. + * + * @param col The column of the element to write. + * + * @param v The new value of the element. + * + * @code + * matrix.set(1,2,42.0); + * @endcode + */ void Matrix4::set(int row, int col, float v) { - if (row < 0 || col < 0 || row >= rows || col >= cols) - return; + if (row < 0 || col < 0 || row >= rows || col >= cols) return; - data[width() * row + col] = v; + data[width() * row + col] = v; } /** - * Transposes this matrix. - * - * @return the resultant matrix. - * - * @code - * matrix.transpose(); - * @endcode - */ + * Transposes this matrix. + * + * @return the resultant matrix. + * + * @code + * matrix.transpose(); + * @endcode + */ Matrix4 Matrix4::transpose() { - Matrix4 result = Matrix4(cols, rows); + Matrix4 result = Matrix4(cols, rows); - for (int i = 0; i < width(); i++) - for (int j = 0; j < height(); j++) - result.set(i, j, get(j, i)); + for (int i = 0; i < width(); i++) + for (int j = 0; j < height(); j++) result.set(i, j, get(j, i)); - return result; + return result; } /** - * Multiplies this matrix with the given matrix (if possible). - * - * @param matrix the matrix to multiply this matrix's values against. - * - * @param transpose Transpose the matrices before multiplication. Defaults to false. - * - * @return the resultant matrix. An empty matrix is returned if the operation canot be completed. - * - * @code - * Matrix result = matrixA.multiply(matrixB); - * @endcode - */ -Matrix4 Matrix4::multiply(Matrix4 &matrix, bool transpose) + * Multiplies this matrix with the given matrix (if possible). + * + * @param matrix the matrix to multiply this matrix's values against. + * + * @param transpose Transpose the matrices before multiplication. Defaults to false. + * + * @return the resultant matrix. An empty matrix is returned if the operation canot be completed. + * + * @code + * Matrix result = matrixA.multiply(matrixB); + * @endcode + */ +Matrix4 Matrix4::multiply(Matrix4& matrix, bool transpose) { int w = transpose ? height() : width(); int h = transpose ? width() : height(); - if (w != matrix.height()) - return Matrix4(0, 0); + if (w != matrix.height()) return Matrix4(0, 0); - Matrix4 result(h, matrix.width()); + Matrix4 result(h, matrix.width()); - for (int r = 0; r < result.height(); r++) - { - for (int c = 0; c < result.width(); c++) - { - float v = 0.0; + for (int r = 0; r < result.height(); r++) { + for (int c = 0; c < result.width(); c++) { + float v = 0.0; - for (int i = 0; i < w; i++) - v += (transpose ? get(i, r) : get(r, i)) * matrix.get(i, c); + for (int i = 0; i < w; i++) v += (transpose ? get(i, r) : get(r, i)) * matrix.get(i, c); - result.set(r, c, v); - } - } + result.set(r, c, v); + } + } - return result; + return result; } /** - * Performs an optimised inversion of a 4x4 matrix. - * Only 4x4 matrices are supported by this operation. - * - * @return the resultant matrix. An empty matrix is returned if the operation canot be completed. - * - * @code - * Matrix result = matrixA.invert(); - * @endcode - */ + * Performs an optimised inversion of a 4x4 matrix. + * Only 4x4 matrices are supported by this operation. + * + * @return the resultant matrix. An empty matrix is returned if the operation canot be completed. + * + * @code + * Matrix result = matrixA.invert(); + * @endcode + */ Matrix4 Matrix4::invert() { - // We only support square matrices of size 4... - if (width() != height() || width() != 4) - return Matrix4(0, 0); - - Matrix4 result(width(), height()); - - result.data[0] = data[5] * data[10] * data[15] - data[5] * data[11] * data[14] - data[9] * data[6] * data[15] + data[9] * data[7] * data[14] + data[13] * data[6] * data[11] - data[13] * data[7] * data[10]; - result.data[1] = -data[1] * data[10] * data[15] + data[1] * data[11] * data[14] + data[9] * data[2] * data[15] - data[9] * data[3] * data[14] - data[13] * data[2] * data[11] + data[13] * data[3] * data[10]; - result.data[2] = data[1] * data[6] * data[15] - data[1] * data[7] * data[14] - data[5] * data[2] * data[15] + data[5] * data[3] * data[14] + data[13] * data[2] * data[7] - data[13] * data[3] * data[6]; - result.data[3] = -data[1] * data[6] * data[11] + data[1] * data[7] * data[10] + data[5] * data[2] * data[11] - data[5] * data[3] * data[10] - data[9] * data[2] * data[7] + data[9] * data[3] * data[6]; - result.data[4] = -data[4] * data[10] * data[15] + data[4] * data[11] * data[14] + data[8] * data[6] * data[15] - data[8] * data[7] * data[14] - data[12] * data[6] * data[11] + data[12] * data[7] * data[10]; - result.data[5] = data[0] * data[10] * data[15] - data[0] * data[11] * data[14] - data[8] * data[2] * data[15] + data[8] * data[3] * data[14] + data[12] * data[2] * data[11] - data[12] * data[3] * data[10]; - result.data[6] = -data[0] * data[6] * data[15] + data[0] * data[7] * data[14] + data[4] * data[2] * data[15] - data[4] * data[3] * data[14] - data[12] * data[2] * data[7] + data[12] * data[3] * data[6]; - result.data[7] = data[0] * data[6] * data[11] - data[0] * data[7] * data[10] - data[4] * data[2] * data[11] + data[4] * data[3] * data[10] + data[8] * data[2] * data[7] - data[8] * data[3] * data[6]; - result.data[8] = data[4] * data[9] * data[15] - data[4] * data[11] * data[13] - data[8] * data[5] * data[15] + data[8] * data[7] * data[13] + data[12] * data[5] * data[11] - data[12] * data[7] * data[9]; - result.data[9] = -data[0] * data[9] * data[15] + data[0] * data[11] * data[13] + data[8] * data[1] * data[15] - data[8] * data[3] * data[13] - data[12] * data[1] * data[11] + data[12] * data[3] * data[9]; - result.data[10] = data[0] * data[5] * data[15] - data[0] * data[7] * data[13] - data[4] * data[1] * data[15] + data[4] * data[3] * data[13] + data[12] * data[1] * data[7] - data[12] * data[3] * data[5]; - result.data[11] = -data[0] * data[5] * data[11] + data[0] * data[7] * data[9] + data[4] * data[1] * data[11] - data[4] * data[3] * data[9] - data[8] * data[1] * data[7] + data[8] * data[3] * data[5]; - result.data[12] = -data[4] * data[9] * data[14] + data[4] * data[10] * data[13] + data[8] * data[5] * data[14] - data[8] * data[6] * data[13] - data[12] * data[5] * data[10] + data[12] * data[6] * data[9]; - result.data[13] = data[0] * data[9] * data[14] - data[0] * data[10] * data[13] - data[8] * data[1] * data[14] + data[8] * data[2] * data[13] + data[12] * data[1] * data[10] - data[12] * data[2] * data[9]; - result.data[14] = -data[0] * data[5] * data[14] + data[0] * data[6] * data[13] + data[4] * data[1] * data[14] - data[4] * data[2] * data[13] - data[12] * data[1] * data[6] + data[12] * data[2] * data[5]; - result.data[15] = data[0] * data[5] * data[10] - data[0] * data[6] * data[9] - data[4] * data[1] * data[10] + data[4] * data[2] * data[9] + data[8] * data[1] * data[6] - data[8] * data[2] * data[5]; - - float det = data[0] * result.data[0] + data[1] * result.data[4] + data[2] * result.data[8] + data[3] * result.data[12]; - - if (det == 0) - return Matrix4(0, 0); - - det = 1.0f / det; - - for (int i = 0; i < 16; i++) - result.data[i] *= det; - - return result; + // We only support square matrices of size 4... + if (width() != height() || width() != 4) return Matrix4(0, 0); + + Matrix4 result(width(), height()); + + result.data[0] = data[5] * data[10] * data[15] - data[5] * data[11] * data[14] - data[9] * data[6] * data[15] + + data[9] * data[7] * data[14] + data[13] * data[6] * data[11] - data[13] * data[7] * data[10]; + result.data[1] = -data[1] * data[10] * data[15] + data[1] * data[11] * data[14] + data[9] * data[2] * data[15] - + data[9] * data[3] * data[14] - data[13] * data[2] * data[11] + data[13] * data[3] * data[10]; + result.data[2] = data[1] * data[6] * data[15] - data[1] * data[7] * data[14] - data[5] * data[2] * data[15] + + data[5] * data[3] * data[14] + data[13] * data[2] * data[7] - data[13] * data[3] * data[6]; + result.data[3] = -data[1] * data[6] * data[11] + data[1] * data[7] * data[10] + data[5] * data[2] * data[11] - + data[5] * data[3] * data[10] - data[9] * data[2] * data[7] + data[9] * data[3] * data[6]; + result.data[4] = -data[4] * data[10] * data[15] + data[4] * data[11] * data[14] + data[8] * data[6] * data[15] - + data[8] * data[7] * data[14] - data[12] * data[6] * data[11] + data[12] * data[7] * data[10]; + result.data[5] = data[0] * data[10] * data[15] - data[0] * data[11] * data[14] - data[8] * data[2] * data[15] + + data[8] * data[3] * data[14] + data[12] * data[2] * data[11] - data[12] * data[3] * data[10]; + result.data[6] = -data[0] * data[6] * data[15] + data[0] * data[7] * data[14] + data[4] * data[2] * data[15] - + data[4] * data[3] * data[14] - data[12] * data[2] * data[7] + data[12] * data[3] * data[6]; + result.data[7] = data[0] * data[6] * data[11] - data[0] * data[7] * data[10] - data[4] * data[2] * data[11] + + data[4] * data[3] * data[10] + data[8] * data[2] * data[7] - data[8] * data[3] * data[6]; + result.data[8] = data[4] * data[9] * data[15] - data[4] * data[11] * data[13] - data[8] * data[5] * data[15] + + data[8] * data[7] * data[13] + data[12] * data[5] * data[11] - data[12] * data[7] * data[9]; + result.data[9] = -data[0] * data[9] * data[15] + data[0] * data[11] * data[13] + data[8] * data[1] * data[15] - + data[8] * data[3] * data[13] - data[12] * data[1] * data[11] + data[12] * data[3] * data[9]; + result.data[10] = data[0] * data[5] * data[15] - data[0] * data[7] * data[13] - data[4] * data[1] * data[15] + + data[4] * data[3] * data[13] + data[12] * data[1] * data[7] - data[12] * data[3] * data[5]; + result.data[11] = -data[0] * data[5] * data[11] + data[0] * data[7] * data[9] + data[4] * data[1] * data[11] - + data[4] * data[3] * data[9] - data[8] * data[1] * data[7] + data[8] * data[3] * data[5]; + result.data[12] = -data[4] * data[9] * data[14] + data[4] * data[10] * data[13] + data[8] * data[5] * data[14] - + data[8] * data[6] * data[13] - data[12] * data[5] * data[10] + data[12] * data[6] * data[9]; + result.data[13] = data[0] * data[9] * data[14] - data[0] * data[10] * data[13] - data[8] * data[1] * data[14] + + data[8] * data[2] * data[13] + data[12] * data[1] * data[10] - data[12] * data[2] * data[9]; + result.data[14] = -data[0] * data[5] * data[14] + data[0] * data[6] * data[13] + data[4] * data[1] * data[14] - + data[4] * data[2] * data[13] - data[12] * data[1] * data[6] + data[12] * data[2] * data[5]; + result.data[15] = data[0] * data[5] * data[10] - data[0] * data[6] * data[9] - data[4] * data[1] * data[10] + + data[4] * data[2] * data[9] + data[8] * data[1] * data[6] - data[8] * data[2] * data[5]; + + float det = + data[0] * result.data[0] + data[1] * result.data[4] + data[2] * result.data[8] + data[3] * result.data[12]; + + if (det == 0) return Matrix4(0, 0); + + det = 1.0f / det; + + for (int i = 0; i < 16; i++) result.data[i] *= det; + + return result; } /** - * Destructor. - * - * Frees any memory consumed by this Matrix4 instance. - */ + * Destructor. + * + * Frees any memory consumed by this Matrix4 instance. + */ Matrix4::~Matrix4() { - if (data != NULL) - { - delete data; - data = NULL; - } + if (data != NULL) { + delete data; + data = NULL; + } } diff --git a/source/types/RefCounted.cpp b/source/types/RefCounted.cpp index 37a70b36..3b6bcd47 100644 --- a/source/types/RefCounted.cpp +++ b/source/types/RefCounted.cpp @@ -23,32 +23,32 @@ DEALINGS IN THE SOFTWARE. */ /** - * Base class for payload for ref-counted objects. Used by ManagedString and DeviceImage. - * There is no constructor, as this struct is typically malloc()ed. - */ + * Base class for payload for ref-counted objects. Used by ManagedString and DeviceImage. + * There is no constructor, as this struct is typically malloc()ed. + */ +#include "RefCounted.h" + #include "CodalConfig.h" #include "CodalDevice.h" -#include "RefCounted.h" using namespace codal; /** - * Checks if the object resides in flash memory. - * - * @param t the object to check. - * - * @return true if the object resides in flash memory, false otherwise. - */ -static inline bool isReadOnlyInline(RefCounted *t) + * Checks if the object resides in flash memory. + * + * @param t the object to check. + * + * @return true if the object resides in flash memory, false otherwise. + */ +static inline bool isReadOnlyInline(RefCounted* t) { uint32_t refCount = t->refCount; - if (refCount == 0xffff) - return true; // object in flash + if (refCount == 0xffff) return true; // object in flash // Do some sanity checking while we're here - if (refCount == 1 || // object should have been deleted - (refCount & 1) == 0) // refCount doesn't look right + if (refCount == 1 || // object should have been deleted + (refCount & 1) == 0) // refCount doesn't look right target_panic(DEVICE_HEAP_ERROR); // Not read only @@ -56,33 +56,31 @@ static inline bool isReadOnlyInline(RefCounted *t) } /** - * Checks if the object resides in flash memory. - * - * @return true if the object resides in flash memory, false otherwise. - */ + * Checks if the object resides in flash memory. + * + * @return true if the object resides in flash memory, false otherwise. + */ bool RefCounted::isReadOnly() { return isReadOnlyInline(this); } /** - * Increment reference count. - */ + * Increment reference count. + */ void RefCounted::incr() { - if (!isReadOnlyInline(this)) - __sync_fetch_and_add(&refCount, 2); + if (!isReadOnlyInline(this)) __sync_fetch_and_add(&refCount, 2); } /** - * Decrement reference count. - */ + * Decrement reference count. + */ void RefCounted::decr() { - if (isReadOnlyInline(this)) - return; + if (isReadOnlyInline(this)) return; - if (__sync_fetch_and_add(&refCount, -2) == 3 ) { + if (__sync_fetch_and_add(&refCount, -2) == 3) { destroy(); } } diff --git a/source/types/RefCountedInit.cpp b/source/types/RefCountedInit.cpp index bbca5c7e..abd36253 100644 --- a/source/types/RefCountedInit.cpp +++ b/source/types/RefCountedInit.cpp @@ -30,16 +30,16 @@ using namespace codal; // These two are placed in a separate file, so that they can be overriden by user code. /** - * Releases the current instance. - */ + * Releases the current instance. + */ void RefCounted::destroy() { free(this); } /** - * Initializes for one outstanding reference. - */ + * Initializes for one outstanding reference. + */ void RefCounted::init() { // Initialize to one reference (lowest bit set to 1)