Interface logicielle (API) - Bibliothèques
LibC
La bibliothèque C intégrée aux sources fournit une petite partie de la bibliothèque C classique, principalement à partir de sources tirées du Noyau Linux.
stdint.h
#include "lib/stddef.h"
Déclare tous les types int*_t, uint*_t, int_least*_t, int_fast*_t, uint_least*_t, uint_fast*_t.
Déclare les valeurs min et max des différentes tailles d'entiers : INT*_MIN, INT*_MAX, UINT*_MAX
stddef.h
#include "lib/stddef.h"
Déclare les macros offsetof() qui permet d'obtenir l'offset d'un champ dans une structure, et container_of(), qui permet d'obtenir un pointeur sur la structure contenant le champ indiqué.
Déclare aussi size_t et NULL.
/* type : type de la structure contenant le champ indiqué * member : nom du champ dans la structure * ptr : pointeur vers le champ indiqué */ offsetof(type, member); container_of(ptr, type, member);
Exemple :
#include "lib/stddef.h" struct A { int a; int b; char c; }; struct A foo; int o = offset_of(struct A, b); /* renvoie 4 (ou sizeof(int)) */ struct A* ptr = NULL; ptr = container_of(&foo.b, struct A, b); /* renvoie un pointeur sur foo */
stdlib.h
#include "lib/stdlib.h"
Inclut uniquement une version simple de la fonction strtoul(), avec peu de vérifications.
uint32_t strtoul(const char* str, char** end, uint8_t base);
errno.h
#include "lib/errno.h"
Inclut quelques codes d'erreur, pour une plus grande lisibilité des valeurs de retour des fonctions.
Les valeurs correspondent aux valeurs définies et utilisées par la GlibC.
#define EIO 5 /* Bad one: Input or Output error. */ #define E2BIG 7 /* Argument list too long or Data size beyond buffer size */ #define EAGAIN 11 /* Device already in use */ #define EFAULT 14 /* Address error */ #define EBUSY 16 /* Device or ressource Busy */ #define ENODEV 19 /* No such device */ #define EINVAL 22 /* Invalid argument */ #define EBADFD 77 /* Device not initialized */ #define EREMOTEIO 121 /* Device did not acknowledge */
string.h
#include "lib/string.h"
Regroupe les fonctions suivantes, issues du code du noyau Linux :
void * memcpy(void *dest, const void *src, size_t count); void * memset(void * s, int c, size_t count); char * strcpy(char * dest, const char *src); char * strncpy(char * dest, const char *src, size_t count); int strcmp(const char * cs, const char * ct); int strncmp(const char * cs, const char * ct, size_t count); char * strchr(const char * s, int c); size_t strlen(const char * s); char * strrchr(const char * s, int c); size_t strnlen(const char * s, size_t count);
Voir les pages man des fonctions de la libC GNU pour plus d'informations.
stdio.h
#include "lib/stdio.h"
Regroupe les fonctions suivantes, issues du code du noyau Linux :
int vsnprintf(char *buf, size_t size, const char *fmt, va_list args); int snprintf(char* buf, size_t size, const char *format, ...);
Ajoute aussi la fonction uprintf() (UART printf), qui fonctionne comme la fonction fprintf() de la bibliothèque C GNU, mais prend comme premier argument le numéro de la liaison série (UART) à utiliser à la place du pointeur vers un flux (FILE*)
int uprintf(int uart_num, const char *format, ...);
Listes chaînées circulaires
#include "lib/list.h"
Ce fichier d'entête fournit une implémentation de listes chaînées circulaires, tirée de l'implémentation disponible dans le Noyau Linux (version simplifiée).
Pour le détail des paramètres et du résultat de chaque fonction, voir la page détaillant le fonctionnement de cette implémentation des listes chaînées.
L'utilisation se fait en incluant la structure 'struct list_head' dans la structure (l'objet) que l'on veut "chaîner".
Structure utilisée :
struct list_head { struct list_head* next, *prev; };
Création et Initialisation d'une liste :
struct list_head name = LIST_HEAD_INIT(name): LIST_HEAD(other); struct list_head third; INIT_LIST_HEAD(&third);
Insersion et suppression dans une liste chaînée :
void list_add(struct list_head* new, struct list_head* head); void list_add_tail(struct list_head* new, struct list_head* head); void list_del(struct list_head* entry);
Tests :
int list_is_last(const struct list_head* list, const struct list_head* head); int list_empty(const struct list_head* head);
Modifications de listes :
void list_move_tail(struct list_head* list, struct list_head* head); void list_rotate_left(struct list_head* head);
Récupération du conteneur :
list_entry(ptr, type, member);
Parcours de listes :
list_first_entry(ptr, type, member); list_for_each(pos, head); list_for_each_prev(pos, head); list_for_each_safe(pos, n, head); list_for_each_prev_safe(pos, n, head); list_for_each_entry(pos, head, member); list_for_each_entry_reverse(pos, head, member); list_for_each_entry_safe(pos, n, head, member); list_for_each_entry_safe_reverse(pos, n, head, member);
Bit operations
#include "lib/utils.h"
Cette bibliothèque inclut les fonctions clz() et ctz() utilisées pour compter le nombre de zéros au début (clz) ou à la fin (ctz) d'un mot de 32 bits (ou trouver l'indice du premier ou du dernier '1').
Ces fonctions remplacent les instructions clz et ctz qui ne sont pas présentes dans le jeu d'instructions du Cortex-M0. L'implémentation est celle présentée ici : http://graphics.stanford.edu/~seander/bithacks.html
La fonction bits_set() permet quand à elle de compter le nombre de bits à 1 dans un entier de 32bits.
/* Count leading zeroes */ uint8_t clz(uint32_t x); /* Count traling zeroes */ uint8_t ctz(uint32_t x); /* Count bits set */ uint8_t bits_set(uint32_t x);
Gestion du temps
#include "lib/time.h"
Cette bibliothèque fournit une implémentation de gestion du temps sur le principe des timestamp Unix, le temps 0 correspondant à l'heure de démarrage du système (en l'absence de mise à l'heure).
Le temps est compté en secondes et milli-secondes au lieu des secondes et micro-secondes utilisées pour les timestamp Unix sur les systèmes GNU/Linux.
La fonction d'initialisation time_init() doit être appelée au moins une fois pour enregistrer un callback sur l'interruption systick toutes les milli-secondes, qui aura la charge de la gestion du temps (les appels suivants n'ont pas d'effet).
Structure utilisée :
struct time_spec { uint32_t seconds; uint16_t msec; };
Initialisation :
void time_init(void);
Mise à l'heure du système :
void set_time(struct time_spec* new_time); void set_time_and_get_difference(struct time_spec* new_time, struct time_spec* diff);
Au retour de ces fonctions le système est mis à l'heure. set_time_and_get_difference() remplit aussi la structure time_spec 'diff' si diff n'est pas NULL avec la différence entre l'ancien et le nouveau temps.
Écriture du temps dans un buffer en "network endian" (big endian) :
void time_to_buff_swapped(uint8_t* buf, struct time_spec* src_time);
Lecture du timestamp actuel :
void get_time(struct time_spec* save_time); void get_time_in_interrupt(struct time_spec* save_time);
Dans un contexte d'interruption il est préférable d'utiliser la fonction get_time_in_interrupt(). L'utilisation de get_time() dans un contexte d'interruption fera tout de même appel à la fonction get_time_in_interrupt(), mais avec un délai supplémentaire du au test et au branchement résultant.
Calcul de la différence entre deux timestamps :
/* Retourne 0 si les temps sont égaux, 1 si (t1 > t2), -1 si (t1 < t2) */ int get_time_diff(const struct time_spec* t1, const struct time_spec* t2, struct time_spec* diff);
Police de caractères
#include "lib/font.h"
Cette bibliothèque ne contient qu'un tableau correspondant à des bitmaps 8x8 pour les caractères ASCII entre 0x20 et 0x7E (95 caractères).
Cette police de caractères a été trouvée sur le site opengameart.org : http://opengameart.org/content/8x8-ascii-bitmap-font-with-c-source (licence GPLv3, auteur (?) "darkrose")
Elle a été choisie en raison de sa lisibilité et de sa compacité. Elle est utilisée pour le support de l'écran e-paper.
Cette "bibliothèque ne fournit aucune fonction, les fonctions d'affichage étant liées au type d'affichage et non pas à la police de caractère.