--- title: "Documentation can-iveau" date: "16-02-2024" link: "https://hackmd.io/Wdf8yaC0RYC7sUG_4QsEFQ" tags: EVOLUTEK, CAN --- # DOCUMENTATION CAN-IVEAU ## Introduction Can-iveau est un protocole et ses implémentations développé par Evolutek<< pour communiquer en CAN entre des STM32 et une raspberry. Les principes généraux du CAN et la partie théorique du protocol sont décrites ici: https://hackmd.io/WtYb7Yl2RWy5PWPDJITdcA. Ce document-ci servira plutôt à parler de l'implémentation pratique. Il est aussi à noter que can-iveau utilisant une file pour stocker les messages reçus en attente de lecture, il est fourni avec une implémentation de file. ~~A des fins d'optimisation, cette partie sera une bibliothèque C, la file sera de taille finie et elle sera stockée de façon contigue en mémoire.~~ ----> Finalement vu toutes les conversions que cela impliquerai et l'implémentation python actuelle, étendre la bibliothèque queue de Python pour avoir un comportement similaire à celui de la bibliothèque C sera, je pense, plus raisonnable. ## Repo Le repo actuel est : https://github.com/reza0310/can-iveau ## Fonctions communes ### Fonctions de file ``` start: Entrée(s): La taille de la file et une booléenne disant si, pour le traitement des données ajoutées à une file pleine, vous voulez réécrire sur les plus anciens (TRUE) ou les ignorer (FALSE) Fonction: Initialise une file Sortie(s): Un lien vers la file initialisée Déclaration C: void queueNew(canMessageQueue_t* res, uint8_t queueSize, bool shallOverwrite) Déclaration Python: def __init__(self, queue_size: int, shall_overwrite: bool) -> None: ``` ``` add: Entrée(s): La donnée à ajouter à la file choisie Fonction: Ajoute la donnée donnée à la file choisie Sortie(s): Un booléen disant si ça s'est bien passé (l'ajout a put se faire sans dépasser la taille maximale de la file) Déclaration C: HAL_StatusTypeDef queueAdd(canMessageQueue_t* queue, canData_t element); Déclaration Python: def add(self, element: can_data) -> bool: ``` ``` pop: Entrée(s): La file choisie Fonction: Retire une donnée de la file (FIFO) Sortie(s): La donnée qui a été retirée ainsi qu'un booléen disant si ça s'est bien passé (le retrait a put se faire) Déclaration C: HAL_StatusTypeDef queuePop(canMessageQueue_t* queue, canData_t* data); Déclaration Python: def pop(self) -> Tuple[can_data, bool]: ``` ``` length: Entrée(s): La file choisie Fonction: Permet d'accéder à la quantité de données dans la file Sortie(s): La taille (remplie) de la file Déclaration C: uint8_t queueLength(canMessageQueue_t* queue); Déclaration Python: def length(self) -> int: # len(q) fonctionne aussi ``` ``` has_lost_data: Entrée(s): La file choisie Fonction: Permet de savoir si oui ou non, dans l'histoire de cette file, quelqu'un a déjà essayé d'y ajouter une donnée alors qu'elle était déjà pleine. Sortie(s): Un booléen Déclaration C: bool queueHasLostData(canMessageQueue_t* queue); Déclaration Python: def has_lost_data(self) -> bool: ``` ``` stop: Entrée(s): La file choisie Fonction: Arrête proprement la file et libère la mémoire Sortie(s): Un booléen disant si ça s'est bien passé Déclaration C: HAL_StatusTypeDef queueStop(canMessageQueue_t* queue); Déclaration Python: def stop(self) -> bool: ``` ### Fonctions de communication ``` start: Entrée(s): Le bus à utiliser, le type de board que nous sommes, l'id de board que nous avons et la taille de la boîte aux lettres Fonction: Permet d'initialiser le can-iveau Sortie(s): Un lien permettant d'utiliser le bus ainsi initialisé Déclaration C: HAL_StatusTypeDef caniveauStart(canManager_t* manager, CAN_HandleTypeDef* hcan, uint8_t board_type, uint8_t board_id, uint8_t mailbox_size); Déclaration Python: def __init__(self, bus: str, board_type: int, board_id: int, mailbox_size: int) -> None: ``` ``` add_filter: (automatiquement appelé par generate_filters) Entrée(s): Le can-iveau, le numéro de filtre, le filter_id et le filter_mask Notes sur le fonctionnement des filtres: Pour chaque bit, on passe le masque si [!filter_mask | (filter_mask & !(filter_id ^ received_id))] Fonction: Permet d'appliquer un filter sur le can-iveau Sortie(s): Un booléen disant si ça s'est bien passé Déclaration C: HAL_StatusTypeDef caniveauAddFilter(CAN_HandleTypeDef* hcan, uint8_t filter_num, uint32_t filter_id, uint32_t filter_mask); Déclaration Python: def add_filter(self, filter_num: int, filter_id: int, filter_mask: int) -> bool: ``` ``` generate_filters: (automatique appelé par start) Entrée(s): Le can-iveau Fonction: Permet de générer tous les filtres en rapport avec le protocole can-iveau Sortie(s): Un booléen disant si ça s'est bien passé Déclaration C: HAL_StatusTypeDef caniveauGenerateFilters(canManager_t* manager); Déclaration Python: def generate_filters(self) -> bool: ``` ``` send_raw: Entrée(s): Le can-iveau, le header et les datas Fonction: Sert à envoyer une trame can telle qu'elle Sortie(s): Un booléen disant si ça s'est bien passé Déclaration C: HAL_StatusTypeDef caniveauSendRaw(canManager_t* manager, uint32_t header, uint64_t data); Déclaration Python: def send_raw(self, header: int, data: List[int]) -> bool: ``` ``` send_parsed: Entrée(s): Le can-iveau, un niveau de priorité valide, un type de message valide, un identifiant de message valide, un type de board auquel on veut s'adresser valide, un id de board auquel on veut s'adresser valide, un numéro de tracking valide et les datas Fonction: Permet d'envoyer une trame can-iveau valide à partir des informations constituantes plutôt que l'identifiant. Sortie(s): Un booléen disant si ça s'est bien passé Déclaration C: HAL_StatusTypeDef caniveauSendParsed(canManager_t* manager, uint8_t priority, uint8_t message_type, uint8_t message_id, uint8_t board_type, uint8_t board_id, uint8_t tracking, uint64_t data); Déclaration Python: def send_parsed(self, priority: int, message_type: int, message_id: int, board_type: int, board_id: int, tracking: int, data: List[int]) -> bool: ``` ``` send_parsed_checked: Entrée(s): Le can-iveau, un niveau de priorité valide, un type de message valide, un identifiant de message valide, un type de board auquel on veut s'adresser valide, un id de board auquel on veut s'adresser valide, un numéro de tracking valide et les datas Fonction: Fonctionne comme send_parsed mais vérifie que les données sont valides d'abord Sortie(s): Un booléen disant si ça s'est bien passé Déclaration C: HAL_StatusTypeDef caniveauSendParsedChecked(canManager_t* manager, uint8_t priority, uint8_t message_type, uint8_t message_id, uint8_t board_type, uint8_t board_id, uint8_t tracking, uint64_t data); Déclaration Python: def send_parsed_checked(self, priority: int, message_type: int, message_id: int, board_type: int, board_id: int, tracking: int, data: List[int]) -> bool: ``` ``` receive_raw: Entrée(s): Le can-iveau Fonction: Permet de retirer une donnée brute de la boîte de réception can-iveau Sortie(s): La donnée retirée ainsi qu'un booléen disant si ça s'est bien passé Déclaration C: HAL_StatusTypeDef caniveauGetRaw(canManager_t* manager, canData_t* data); Déclaration Python: def receive_raw(self) -> Tuple[can_data, bool]: ``` ``` receive_parsed: Entrée(s): Le can-iveau Fonction: Permet de retirer une donnée de la boîte de réception can-iveau et de séparer et traiter son identifiant Sortie(s): Les données retirées, la priorité, le type de message, l'identifiant de message, le type de board qui reçoit (savoir si c'est diffusé ou ciblé), l'identifiant de board qui recoit (savoir si c'est diffusé ou ciblé), le numéro de tracking de la conversation ainsi qu'un booléen disant si ça s'est bien passé Déclaration C: HAL_StatusTypeDef caniveauReceiveParsed(canManager_t* manager, uint8_t* priority, uint8_t* message_type, uint8_t* message_id, uint8_t* board_type, uint8_t* board_id, uint8_t* tracking, uint64_t* data); Déclaration Python: def receive_parsed(self) -> Tuple[int, int, int, int, int, int, List[int], bool]: ``` ``` stop: Entrée(s): Le can-iveau Fonction: Permet d'arrêter proprement la communication CAN Sortie(s): Un booléen disant si ça s'est bien passé Déclaration C: HAL_StatusTypeDef caniveauStop(canManager_t* manager); Déclaration Python: def stop(self) -> bool: ``` ## Spécificités de la version en C En C, les messages étant récupérés par un interrupt, nous ne pouvons pas spécifier à chaque réceptions dans quelle boîte aux lettres le mettre donc on utilise une variable globale que l'on peut set: ``` set_receiving_manager: Déclaration: void setReceivingManager(canManager_t* manager); Fonction: Permet de set la variable globale disant quel manager va recevoir les nouvelles trames (on ne peut modifier la déclaration de l'interrupt). ``` ## Spécificités de la version en Python En python, le code est réparti dans 3 objets: 1) "can_data" de "can_queue.py" contient juste un string header et un string data. 2) "can_queue" de "can_queue.py" contient toutes les fonctions de queue. Il est aussi à noter que cet objet hérite de "queue.SimpleQueue" du module queue de python et que globalement il interface quasi directement avec son objet parent. 3) "Caniveau" de "caniveau.py" qui contient les fonctions de can-iveau et gère directement les fonctions de queue.