crossbario / autobahn-c

Apache License 2.0
14 stars 5 forks source link

Futures and tasks #11

Open oberstet opened 7 years ago

oberstet commented 7 years ago

FreeRTOS provides a relatively sopisticated task abstraction to schedule and run user code on a shared, limited resources system, and with real-time reaction constraints in place.

The question would be if we could create a Future abstraction for use in C that is implemented on top of FreeRTOS tasks. Each Future created is a new FreeRTOS task, and the callback and errback code attached run in that task. When there is no more code to run, the task auto-destroys itself.

Here are a few resources:

oberstet commented 7 years ago

Here is a Future implementation in C++ (outside the Future one coming in the C++ stdlib): https://github.com/facebook/folly/tree/master/folly/futures

Here is Coroutines in less than 20 lines of standard C: http://fanf.livejournal.com/105413.html

Here are Coroutines in FreeRTOS: http://www.360doc.com/content/14/0224/14/839052_355276683.shtml

oberstet commented 7 years ago

FreeRTOS: xCoRoutineCreate

oberstet commented 7 years ago
#include "main.h"
#include "serial.h"
#include "hardware.h"

/**
 * Tablica buforów, za pomocą których komunikują się korutyny obsługujące diody
 */
xQueueHandle xDiodesOn[4];

/**
 * Deklaracje funkcji wykonywanych przez korutyny.
 */
static void vKlawisze(xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex);
static void vDioda(xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex);

void vApplicationIdleHook( void );

portSHORT main( void )
{
  /// Utworzenie kolejek
  xDiodesOn[0] = xQueueCreate( 4, 1);
  xDiodesOn[1] = xQueueCreate( 4, 1);
  xDiodesOn[2] = xQueueCreate( 4, 1);
  xDiodesOn[3] = xQueueCreate( 4, 1);

  ///Konfiguracja portów
  hardwareInit();
  ///Inicjacja portu szeregowego. Utworzenie kolejek do komunikacji z portem szeregowym
  xSerialPortInitMinimal(8);

  /// Utworzenie korutyn
  xCoRoutineCreate(vKlawisze, 0, 0);
  xCoRoutineCreate(vDioda, 0, 0);
  xCoRoutineCreate(vDioda, 0, 1);
  xCoRoutineCreate(vDioda, 0, 2);
  xCoRoutineCreate(vDioda, 0, 3);
  xCoRoutineCreate(vProtocol, 0, 0);

  /// Uruchomienie planisty. Rozpoczyna się praca systemu FreeRtos
  vTaskStartScheduler();
  return 0;
}

static void vKlawisze(xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex)
{
  /**
   * Jest tylko jedna korutyna do obsługi klawiszy.
   * Zatem nie wykorzystyjemy zmiennej uxIndex.
   * By pozbyć się ostrzeżenia po kompilacji należy rzutować tą zmienną na void.
   */
  (void) uxIndex;

  static uint8_t klawiszNr = 0;
  static int16_t result;

  crSTART( xHandle );
  for( ;; )
  {
    if (readKey(klawiszNr) == 0)
    {
                                                    /// 0 oznacza, że klawisz został wciśnięty
    }
    klawiszNr++;                                     /// Nie ma potrzeby w pętli for robić kolejnej pętli
    klawiszNr &= 0x03;                               /// Operacja %4 zrealizowana za pomoca iloczynu bitowego (klawiszNr = klawiszNr % 4)

    crDELAY( xHandle, 0);                            /// Wymuszenie przełączenia korutyny.
  }                                                  /// Makro crQUEUE_SEND z parametrem ticksToWait równym 0 nie przełącza korutyny
  crEND();
}

static void vDioda(xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex)
{
  crSTART( xHandle );
  for (;;)
  {

    crDELAY(xHandle, 0);                             /// Wymuszenie przełączenia korutyny, makro do odbioru wiadomości z czasem 0 nie przełącza korutyn
  }
  crEND();
}

void vProtocol(xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex)
{
  (void) uxIndex;

  crSTART( xHandle );
  for( ;; )
  {
    crDELAY(xHandle, 100);
  }
  crEND();
}

void vApplicationIdleHook( void )
{
  for( ;; )
  {
    vCoRoutineSchedule();
  }
}