/*
 * This file is part of the µOS++ distribution.
 *   (https://github.com/micro-os-plus)
 * Copyright (c) 2016 Liviu Ionescu.
 *
 * 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.
 */

// ----------------------------------------------------------------------------

/**
 @defgroup cmsis-plus-rtos-core Core & scheduler
 @ingroup cmsis-plus-rtos
 @brief  C++ API scheduler definitions.
 @details
 */

/**
 @defgroup cmsis-plus-rtos-thread Threads
 @ingroup cmsis-plus-rtos
 @brief  C++ API threads definitions.
 @details

 @par Examples

 @code{.cpp}
void*
func (void* args __attribute__((unused)))
{
  printf ("%s\n", __func__);

  return nullptr;
}

int
os_main (int argc, char* argv[])
{
    {
      // Regular threads.
      thread th1
        { func, nullptr };
      thread th2
        { "th2", func, nullptr };

      th1.join ();
      th2.join ();
    }

  using my_thread = thread_allocated<memory::new_delete_allocator<thread::stack::allocation_element_t>>;

  // Allocated threads.
    {
      my_thread ath1
        { func, nullptr };
      my_thread ath2
        { "ath2", func, nullptr };

      ath1.join ();
      ath2.join ();
    }

    {
#pragma GCC diagnostic push
#if defined(__clang__)
#pragma clang diagnostic ignored "-Wexit-time-destructors"
#endif
      // Statically allocated threads.
      static thread_inclusive<> sth1
        { func, nullptr };
      static thread_inclusive<> sth2
        { "sth2", func, nullptr };
#pragma GCC diagnostic pop

      sth1.join ();
      sth2.join ();
    }

  // --------------------------------------------------------------------------

    {
      std::size_t n;

      n = thread::stack::default_size ();
      thread::stack::default_size (n);

      n = thread::stack::min_size ();
      thread::stack::min_size (n);

      class thread::stack& stack = this_thread::thread ().stack ();

      stack.bottom ();

      stack.top ();

      stack.check_bottom_magic ();
      stack.check_top_magic ();
    }

  // --------------------------------------------------------------------------

    {
      this_thread::flags_clear (flags::all);

      this_thread::thread ().flags_raise (0x3);
      this_thread::flags_wait (0x3, nullptr, flags::mode::all);

      this_thread::thread ().flags_raise (0x3);
      this_thread::flags_try_wait (0x3);

      this_thread::thread ().flags_raise (0x3);
      this_thread::flags_timed_wait (0x3, 10);
    }
}
 @endcode
 */

/**
 @defgroup cmsis-plus-rtos-clock Clocks
 @ingroup cmsis-plus-rtos
 @brief  C++ API clocks definitions.
 @details

 @par Examples

 @code{.cpp}
  // TODO
 @endcode
 */

/**
 @defgroup cmsis-plus-rtos-condvar Condition variables
 @ingroup cmsis-plus-rtos
 @brief  C++ API condition variables definitions.
 @details

 @par Examples

 @code{.cpp}
int
os_main (int argc, char* argv[])
{
    {
      condition_variable cv1;
      cv1.signal ();

      condition_variable cv2
        { "cv2" };
      cv2.signal ();
    }
}
 @endcode
 */

/**
 @defgroup cmsis-plus-rtos-evflag Event flags
 @ingroup cmsis-plus-rtos
 @brief  C++ API event flags definitions.
 @details

 @par Examples

 @code{.cpp}
int
os_main (int argc, char* argv[])
{
    {
      event_flags ev1;
      ev1.clear (1);

      event_flags ev2
        { "ev2" };
      ev2.clear (1);
    }
}
 @endcode
 */

/**
 @defgroup cmsis-plus-rtos-mempool Memory pools
 @ingroup cmsis-plus-rtos
 @brief  C++ API memory pools definitions.
 @details

 @par Examples

 @code{.cpp}
typedef struct my_blk_s
{
  int i;
  const char* s;
} my_blk_t;

int
os_main (int argc, char* argv[])
{
  my_blk_t* blk;

  // Classic usage; block size and cast to char* must be supplied manually.
    {
      memory_pool cp1
        { 3, sizeof(my_blk_t) };

      blk = static_cast<my_blk_t*> (cp1.alloc ());
      cp1.free (blk);

      blk = static_cast<my_blk_t*> (cp1.try_alloc ());
      cp1.free (blk);

      blk = static_cast<my_blk_t*> (cp1.timed_alloc (1));
      cp1.free (blk);

      memory_pool cp2
        { "cp2", 3, sizeof(my_blk_t) };

      blk = static_cast<my_blk_t*> (cp2.alloc ());
      cp2.free (blk);

    }

  // --------------------------------------------------------------------------

  // Template usage; block size and cast are supplied automatically.

  // Define a custom queue type parametrised with the
  // message type.
  using My_pool = memory_pool_typed<my_blk_t>;

    {
      My_pool tp1
        { 7 };

      blk = tp1.alloc ();
      tp1.free (blk);

      blk = tp1.try_alloc ();
      tp1.free (blk);

      blk = tp1.timed_alloc (1);
      tp1.free (blk);

      My_pool tp2
        { "tp2", 7 };

      blk = tp2.alloc ();
      tp2.free (blk);
    }

  // --------------------------------------------------------------------------

  // Allocated template usage; block size is supplied automatically.

  // Define a custom pool type parametrised with the
  // block type and the pool size.
  using My_inclusive_pool = memory_pool_inclusive<my_blk_t, 4>;

    {
      // The space for the pool is allocated inside the pool
      // object, in this case on the stack.
      My_inclusive_pool sp1;

      blk = sp1.alloc ();
      sp1.free (blk);

      blk = sp1.try_alloc ();
      sp1.free (blk);

      blk = sp1.timed_alloc (1);
      sp1.free (blk);

      My_inclusive_pool sp2
        { "sp2" };

      blk = sp2.alloc ();
      sp2.free (blk);
    }
}
 @endcode
 */

/**
 @defgroup cmsis-plus-rtos-mqueue Message queues
 @ingroup cmsis-plus-rtos
 @brief  C++ API message queues definitions.
 @details

 @par Examples

 @code{.cpp}
typedef struct my_msg_s
{
  int i;
  const char* s;
} my_msg_t;

int
os_main (int argc, char* argv[])
{
  my_msg_t msg_out
    { 1, "msg" };

  my_msg_t msg_in;

  // --------------------------------------------------------------------------

  // Classic usage; message size and cast to char* must be supplied manually.
    {
      message_queue cq1
        { 3, sizeof(my_msg_t) };

      cq1.send (&msg_out, sizeof(my_msg_t));

      message_queue cq2
        { "cq2", 3, sizeof(my_msg_t) };

      cq2.send (&msg_out, sizeof(my_msg_t));
    }

  // --------------------------------------------------------------------------

  // Template usage; message size and cast are supplied automatically.

  // Define a custom queue type parametrised with the
  // message type.
  using My_queue = message_queue_typed<my_msg_t>;

    {
      My_queue tq1
        { 7 };

      tq1.send (&msg_out);
      tq1.receive (&msg_in);

      tq1.try_send (&msg_out);
      tq1.try_receive (&msg_in);

      tq1.timed_send (&msg_out, 1);
      tq1.timed_receive (&msg_in, 1);

      My_queue tq2
        { "tq2", 7 };

      tq2.send (&msg_out);
      tq2.receive (&msg_in);
    }

  // --------------------------------------------------------------------------

  // Allocated template usage; message size and cast are supplied automatically.

  // Define a custom queue type parametrised with the
  // message type and the queue size.
  using My_inclusive_queue = message_queue_inclusive<my_msg_t, 4>;

    {
      // The space for the queue is allocated inside the queue
      // object, in this case on the stack.
      My_inclusive_queue sq1;

      sq1.send (&msg_out);
      sq1.receive (&msg_in);

      sq1.try_send (&msg_out);
      sq1.try_receive (&msg_in);

      sq1.timed_send (&msg_out, 1);
      sq1.timed_receive (&msg_in, 1);

      My_inclusive_queue sq2
        { "sq2" };

      sq2.send (&msg_out);
      sq2.receive (&msg_in);
    }
}
 @endcode
 */

/**
 @defgroup cmsis-plus-rtos-mutex Mutexes
 @ingroup cmsis-plus-rtos
 @brief  C++ API mutexes definitions.
 @details

 @par Examples

 @code{.cpp}
int
os_main (int argc, char* argv[])
{
    {
      mutex mx1;
      mx1.lock ();
      mx1.unlock ();

      mx1.try_lock ();
      mx1.unlock ();

      mx1.timed_lock (10);
      mx1.unlock ();

      mx1.name ();

      mx1.type ();
      mx1.protocol ();
      mx1.robustness ();
      mx1.owner ();

      thread::priority_t prio = mx1.prio_ceiling ();
      mx1.prio_ceiling (prio);

      mx1.reset ();
    }

    {
      mutex mx2
        { "mx2" };
      mx2.lock ();
      mx2.unlock ();
    }

    {
      mutex mx3
        { "mx2", mutex::initializer_recursive };
      mx3.lock ();
      mx3.unlock ();
    }
}
 @endcode
 */

/**
 @defgroup cmsis-plus-rtos-semaphore Semaphores
 @ingroup cmsis-plus-rtos
 @brief  C++ API semaphores definitions.
 @details

 @par Examples

 @code{.cpp}
int
os_main (int argc, char* argv[])
{
    {
      // Binary semaphore.
      semaphore_binary sp1;
      sp1.post ();
    }

    {
      // Named binary semaphore.
      semaphore_binary sp2
        { "sp2" };

      sp2.post ();
      sp2.wait ();

      sp2.post ();
      sp2.try_wait ();

      sp2.post ();
      sp2.timed_wait (1);

      sp2.post ();
      sp2.timed_wait (0xFFFFFFFF);
    }

    {
      // Named counting semaphore.
      semaphore_counting sp3
        { "sp3", 7 };
      sp3.post ();
    }

    {
      // Named counting semaphore with custom initial value.
      semaphore_counting sp4
        { "sp4", 7, 7 };
      sp4.post ();
    }
}
 @endcode
 */

/**
 @defgroup cmsis-plus-rtos-timer Timers
 @ingroup cmsis-plus-rtos
 @brief  C++ API timers definitions.
 @details

 @par Examples

 @code{.cpp}
void
tmfunc (void* args __attribute__((unused)))
{
  printf ("%s\n", __func__);
}

int
os_main (int argc, char* argv[])
{
    {
      // Single-shot timer.
      timer tm1
        { tmfunc, nullptr };
      sysclock.sleep_for (1); // Sync
      tm1.start (1);

      sysclock.sleep_for (2);
      tm1.stop ();
    }

    {
      // Named single-shot timer.
      timer tm2
        { "tm2", tmfunc, nullptr };
      sysclock.sleep_for (1); // Sync
      tm2.start (1);

      sysclock.sleep_for (2);
      tm2.stop ();
    }

    {
      // Named periodic timer.
      timer tm3
        { "tm3", tmfunc, nullptr, timer::periodic_initializer };
      sysclock.sleep_for (1); // Sync
      tm3.start (1);

      sysclock.sleep_for (2);
      tm3.stop ();
    }
}
 @endcode
 */

/**
 @defgroup cmsis-plus-rtos-memres Memory management
 @ingroup cmsis-plus-rtos
 @brief  C++ API memory management definitions.
 @details
 The µOS++ RTOS includes several advanced and flexible 
 memory management features.
 
 First, it defines a configurable memory manager for the application
 free store (also known as the "heap"). 

 Second, it defines a separate memory manager to be used by the 
 RTOS system objects. This separate manager can be configured
 to use any allocation policy. It may use either a statically 
 or a dynamically allocated area. 

 The reason for the system memory manager is to allow  RTOS 
 system objects to be separated from application objects; this has 
 several advantages:

 - it helps to protect the system objects from application bugs; 
 this is beneficial during debug and it can improve reliability 
 in the field.
 - it helps improve system performances, by allowing to locate the 
 system objects on a fast, on-chip RAM, in case the platform has
 multiple RAM regions with different performances.

 Third, system objects that require dynamic memory may be created with
 custom allocators, defined by the user.

 Access to the application memory manager is done using the 
 standard functions:

 - `malloc()`/`free()` in C (thread safe)
 - `std::malloc()`/`std::free()` in C++ (thread safe)
 - `new`/`delete` in C++ (thread safe)

 The default application memory manager is set in the
 `os_startup_initialize_free_store()` function, called by the 
 startup code when running on bare metal.

 On synthetic POSIX platforms the default memory manager is 
 `os::memory::malloc_memory_resource`, which uses memory from 
 the system free store.

 By default the RTOS system memory manager is the same as the application
 memory manager, but, for isolation reasons, it is recommended to define
 a separate memory mananger for the RTOS system objects.

 The basic memory management class is `os::rtos::memory::memory_resource`, 
 which will
 be standard starting with C++17. The µOS++ version of this class
 includes several extensions, like out of memory processing and 
 statistics (and this is the reason the class is not defined in `os::estd`). 
  
 */

// ----------------------------------------------------------------------------
