/** * @file PropWare/runnable.h * * @author David Zemon * * @copyright * The MIT License (MIT)
*
Copyright (c) 2013 David Zemon
*
Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions:
*
The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software.
*
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ #pragma once #include #include #include #include namespace PropWare { /** * @brief Helper class for creating easy parallel applications * * To create a Runnable instance which will blink an LED, try the simple example below: * * @code * #include * #include * #include * #include * * class BlinkingThread : public PropWare::Runnable { * public: * template * BlinkingThread (const uint32_t (&stack)[N], const PropWare::Pin::Mask mask) * : Runnable(stack), * m_mask(mask) {} * * void run () { * const PropWare::Pin pin(this->m_mask, PropWare::Pin::OUT); * while (1) { * pin.toggle(); * waitcnt(250 * MILLISECOND + CNT); * } * } * * private: * const PropWare::Pin::Mask m_mask; * }; * * int main (int argc, char *argv[]) { * uint32_t stack[64]; * BlinkingThread blinkyThread(stack, PropWare::Pin::P16); * * int8_t cog = PropWare::Runnable::invoke(blinkyThread); * pwOut << "Blink thread started in cog " << cog << "\n"; * while(1); * } * @endcode */ class Runnable { public: /** * @brief Start a new cog running the given object * * @param[in] runnable Object that should be invoked in a new cog * * @returns If the cog was successfully started, the new cog ID is returned. Otherwise, -1 is returned */ template static int8_t invoke(T &runnable) { static_assert(std::is_base_of::value, "Only PropWare::Runnable and its children can be invoked"); #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wpmf-conversions" return (int8_t) cogstart((void (*)(void *)) &T::run, (void *) &runnable, (void *) (runnable.m_stack), runnable.m_stackSizeInBytes); #pragma GCC diagnostic pop } public: /** * @brief Invoked in the new cog, this method should be the root of the business logic */ virtual void run() = 0; protected: /** * @brief Construct a new instance that runs on the given stack * * @param[in] stack[] Statically-allocated array which will be used for stack memory by the new cog */ template Runnable(const uint32_t (&stack)[N]) : m_stack(stack), m_stackSizeInBytes(N * sizeof(uint32_t)) { } /** * @brief Construct an instance based on a dynamically allocated stack * * The first constructor is recommended because it calculates the size of the stack at compile time. If your * stack is allocated during runtime (i.e., with `malloc` or `new`), then you'll have to use this two-parameter * constructor. * * @warning Use the single-parameter constructor whenever possible! * * @warning The second parameter requests the length of the stack, not the size in bytes! * * @param[in] *stack Address where the stack begins * @param[in] stackLength Number of elements in the stack. For instance, an array initialized as * `uint32_t *myStack = (uint32_t) malloc(16*sizeof(uint32_t));` would have a * length of 16, not 64. */ Runnable(const uint32_t *stack, const size_t stackLength) : m_stack(stack), m_stackSizeInBytes(stackLength * sizeof(uint32_t)) { } protected: const uint32_t *m_stack; size_t m_stackSizeInBytes; }; }