diff --git a/README.md b/README.md index 2362bbd..3a52e6f 100644 --- a/README.md +++ b/README.md @@ -21,9 +21,6 @@ de la carte électronique : - Jouer des sons - Contrôle du gain -Les données utilisées pour l'affichage sur le LCD ou pour la sortie audio doivent -être chargés depuis une carte SD insérée dans la carte microcontrôleur. - En plus de contrôler la carte, le firmware doit pouvoir intéragir avec une application développée sur Unity. En premier lieu, il doit renvoyer des identifiants correspondants aux tags RFID @@ -42,8 +39,8 @@ se synchroniser avec le firmware et potentiellement le mettre à jour. - [ ] Contrôle des modules - [x] RFID (base) - [ ] RFID (avancé, écriture des tags) - - [x] LCD (base) - - [x] LCD (animations) + - [ ] LCD (base) + - [ ] LCD (animations) - [ ] LCD (UI) - [ ] Audio (sons de figurines) - [ ] Audio (sons d'UI) @@ -72,100 +69,6 @@ mise à jour et suivi des dépendances. La structure du code assume une carte Teensy. En particulier, il est conçu pour la [Teensy 4.1](https://www.pjrc.com/store/teensy41.html). -# Carte SD et données - -La carte SD est utilisée pour lire les animations et les sons, lors de l'utilisation -des figurines ou pour des cas génériques (démarrage, batterie faible…). -Le firmware attend les fichiers dans certains endroits et sous certaines formes, -détaillés ici. - -## Structure de fichiers - -Les fichiers sur la carte SD sont structurés comme suit : -``` -/ -├── RANDONNEE/ -│ ├── ANIM/ -│ │ ├── 00 -│ │ ├── 01 -│ │ ├── 02 -│ │ ├── .. -│ │ └── XX -│ └── audio.wav -├── RESTO/ -│ ├── ANIM/ -│ │ └── .. -│ └── audio.wav -├── .../ -└── SYS/ - ├── ANIM*/ - ├── ../ - └── *.wav -``` - -Tous les fichiers liés à une figurine en particulier doivent être placés dans un -dossier associé au nom de la figurine. -Les noms attendus sont ceux des tableaux définis dans `src/IDs.cpp`. -Les différentes images d'une même animation doivent être dans un même dossier, -numérotés dans l'ordre avec deux chiffres et sans extension, les fichiers audio -doivent garder leur extension. - -Le dossier SYS sera utilisé pour toute interaction qui n'est pas liée à une figurine. - -## Structure des données -### Audio - -Le format audio supporté est assez précis : les fichiers doivent être des WAV -16 bit PCM, 44100 Hz. -Mono ou stéréo n'est pas important : la carte ne supporte qu'un haut-parleur, -les deux canaux stéréo seront moyennés `(Gauche+Droit)/2`. - -### Animations - -Le format des animations est d'autant plus précis et particulier et demandera -probablement du traitement pour qu'elles soient correctes. - -Tout d'abord, chaque image de l'animation doit être dans son propre fichier, un -seul fichier pour l'animation (comme un gif) n'est pas possible. - -L'écran LCD choisi est un module pour écran Nokia 5110 de 84x48 pixels monochromes, -les images de l'animation doivent donc être à ce format et monochromes. -L'image attendue est exclusivement une bitmap d'un bit par pixel, sans aucune -autre information. -De plus, il est probable que les bits attendus soient inversés par rapport à ceux -produits "logiquement" depuis un programme normal. Par exemple `0b11001100` devrait -en réalité être `0b00110011`. - -Je n'ai pas connaissance d'un format connu qui peut être généré depuis un logiciel -et répondre à ces conditions, cependant il est possible d'y arriver automatiquement -avec quelques opérations de transformation. -Pour la facilité, il est donc possible d'arriver aux fichiers individuels requis -à partir d'un simple gif aux proportions correctes. - -À l'aide d'[ImageMagick](https://imagemagick.org/), on peut découper le gif en -ses images individuelles, et les convertir en un format de bitmap presque correct -(aux bits inversés) avec la commande suivante : - -```shell -convert -resize 84x48 -coalesce .gif -threshold 50% %02d.mono -``` - -Il peut être nécessaire d'inverser les bits comme mentionné plus haut et je n'ai -pas trouvé de façon existante de le faire. -Vous trouverez donc dans `Utils/bitmap_helper` un projet Rust qui permet de -réaliser cette opération sur les fichiers produits par la commande ci-dessus. -Une fois compilé, vous pouvez convertir les fichiers `.mono` dans le format adapté -(avec une extension `.bin` en les passant à l'utilitaire : -```shell -bitmap_helper *.mono -``` - -N'oubliez pas de retirer l'extension et de les placer dans un dossier `ANIM` sur -la carte SD, comme décrit ci-dessus. - -Un script bash est aussi fourni pour automatiser tout ce processus : -`Utils/convertAnimGif.sh`. - # Interfaçage avec l'application Unity Afin de permettre la détection automatique de l'objet, la communication se fait diff --git a/Utils/.gitignore b/Utils/.gitignore deleted file mode 100644 index 977a0f9..0000000 --- a/Utils/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.gif -ANIM*/ diff --git a/Utils/README.md b/Utils/README.md deleted file mode 100644 index d27866d..0000000 --- a/Utils/README.md +++ /dev/null @@ -1,56 +0,0 @@ -# Utilitaires - -Ce sous-dossier rassemble divers utilitaires liés au projet. - -# Conversion des animations - -Deux outils sont disponnibles pour aider à la conversion : un pour faire l'inversion -de bit nécessaire, et un script pour automatiser tout le protocole. - -Pour des détails sur le format de sortie, référez-vous au README principal. - -## bitmap_helper - -Un projet Rust a été créé pour permettre la conversion d'une bitmap MONO gérée -par ImageMagick en une bitmap correcte pour le LCD, en inversant les bits de chaque -octet. - -Il est possible qu'une version compilée soit disponible dans les versions sur -Github. - -### Compilation - -Pour le compiler, il suffit d'utiliser Cargo, qui peut être installé via -[rustup](https://rustup.rs/) par exemple. -Une fois Rust et Cargo disponibles, la compilation peut être faite depuis le -dossier `bitmap_helper` avec la commande suivante : -```shell -cargo build -``` -L'exécutable produit est alors `bitmap_helper/target/debug/bitmap_helper`. - -### Utilisation - -L'utilitaire peut convertir plusieurs fichiers `.mono` à la fois, passés directement -sur la ligne de commande. -```shell -bitmap_helper/target/debug/bitmap_helper .mono .mono ... -``` -Tout autre format de fichier ne sera pas traité. -⚠️ La détection du format n'est basée que sur les extensions ! - -## convertAnimGif.sh - -Ce script permet d'automatiser tout le protocole de conversion d'un ou plusieurs -gifs en suites de bitmaps utilisables par le projet. - -Il prend en argument un ou plusieurs fichier(s) `.gif` et produit les bitmap -individuelles correctement numérotées dans un dossier portant le nom du fichier -original. - -```shell -./convertAnimGif.sh .gif .gif ... -``` - -Il suffit ensuite de déposer les dossiers sur la carte SD, sous les dossiers correspondants -(voir noms dans `src/IDs.cpp`) et les renommer pour ne laisser que `ANIM`. diff --git a/Utils/bitmap_helper/.gitignore b/Utils/bitmap_helper/.gitignore deleted file mode 100644 index ea8c4bf..0000000 --- a/Utils/bitmap_helper/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target diff --git a/Utils/bitmap_helper/Cargo.lock b/Utils/bitmap_helper/Cargo.lock deleted file mode 100644 index ef6ca90..0000000 --- a/Utils/bitmap_helper/Cargo.lock +++ /dev/null @@ -1,7 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "bitmap_helper" -version = "0.1.0" diff --git a/Utils/bitmap_helper/Cargo.toml b/Utils/bitmap_helper/Cargo.toml deleted file mode 100644 index e3a07c7..0000000 --- a/Utils/bitmap_helper/Cargo.toml +++ /dev/null @@ -1,8 +0,0 @@ -[package] -name = "bitmap_helper" -version = "0.1.0" -edition = "2021" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/Utils/bitmap_helper/src/main.rs b/Utils/bitmap_helper/src/main.rs deleted file mode 100644 index a96029a..0000000 --- a/Utils/bitmap_helper/src/main.rs +++ /dev/null @@ -1,51 +0,0 @@ -use std::fs::File; -use std::fs::write; -use std::env; -use std::io::Read; - -fn main() { - let args: Vec = env::args().collect(); - - for arg in &args[1..] { - println!("Processing : {}", arg); - if !arg.ends_with(".mono") { - eprintln!("{} : unsupported file type.", arg); - continue; - } - let file_r = File::open(arg); - if file_r.is_err() { - eprintln!("{} : could not open file.", arg); - continue; - } - let mut image_data = vec![]; - if file_r.unwrap().read_to_end(&mut image_data).is_err() { - eprintln!("{} : could not read file.", arg); - continue; - } - - let out_file = arg.replace(".mono", ".bin"); - flip_bits(&mut image_data); - if write(&out_file, &image_data).is_err() { - eprintln!("Failed to write bit flipped bitmap to file : {}", out_file); - } - println!("Processing successful, flipped bits and wrote to {}", out_file); - } -} - -/// Flips the bits of each individual byte (except zeroes). -/// This would transform 0b11001100 in 0b00110011. -fn flip_bits(data: &mut Vec) { - for source_id in 0..data.len() { - let mut new_int = 0; - for i in 0..8 { - if data[source_id] == 0 { break; } - new_int |= ((data[source_id] & (1 << 7 - i)) >> 7 - i) << i; - } - data[source_id] = new_int; - } - // for i in 0..data.len() { - // print!("{:2X}", data[i]); - // if i > 0 && i%16 == 0 { println!(); } - // } - // println!(); -} diff --git a/Utils/convertAnimGif.sh b/Utils/convertAnimGif.sh deleted file mode 100755 index d8d33d1..0000000 --- a/Utils/convertAnimGif.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -if [[ $# -eq 0 ]]; then - echo "This script expects the name of the files to convert as arguments" - exit 1 -fi - -if [[ ! $(command -v convert) ]]; then - echo "Could not find 'convert' utility, cannot proceed." - exit 1 -fi - -# Get the absolute path to the source of the script -scriptSrcDir="$(dirname -- "$0")" -pushd "$scriptSrcDir" -scriptSrcDir="$(pwd)" -popd - -if [[ $(command -v bitmap_helper) ]]; then - bmp_help="$(command -v bitmap_helper)" -elif [[ $(command -v "$scriptSrcDir"/bitmap_helper/target/debug/bitmap_helper) ]]; then - bmp_help="$scriptSrcDir"/bitmap_helper/target/debug/bitmap_helper -elif [[ $(command -v "$scriptSrcDir"/bitmap_helper) ]]; then - bmp_help="$scriptSrcDir"/bitmap_helper -else - echo "Could not find 'bitmap_helper'." - echo "Have you compiled it or placed it in the same directory as the script ?" - exit 1 -fi - -for gifToConvert in "$@"; do - if [[ -z "$(echo "$gifToConvert" | grep -e 'gif')" ]]; then - echo "Cannot convert $gifToConvert : not a gif." - continue - fi - - animDir=ANIM_"${gifToConvert//.gif//}" - mkdir "$animDir" - pushd "$animDir" - - convert -resize 84x48 -coalesce ../"$gifToConvert" -threshold 50% %02d.mono - "$bmp_help" ./*.mono - # Clean up and remove the extension - rm -f ./*.mono - for f in ./*.bin; do - mv "$f" "${f//.bin/}" - done - - popd -done diff --git a/include/IDs.h b/include/IDs.h deleted file mode 100644 index 783e2d0..0000000 --- a/include/IDs.h +++ /dev/null @@ -1,37 +0,0 @@ -// -// Created by Teo-CD on 19/10/23. -// - -#ifndef JIN_BARBAPAPA_IDS_H -#define JIN_BARBAPAPA_IDS_H - -#include - -/*** - * Convenience functions and variables to handle IDs and data that they link to. - */ - -constexpr uint8_t idMaskGone = 0b10000000; -constexpr uint8_t idMaskChar = 0b01000000; - -bool isIdGone(int8_t ID); -bool isIdCharacter(int8_t ID); -/*** - * Get the ID without the control bits : direction and character/promotion bit. - * @param ID to check, with all bits - * @return The ID with only index bits. - */ -uint8_t getRawId(int8_t ID); -/*** - * Checks if the ID is known to the firmware, either as a character or promotion. - * @param ID to check, with all bits - * @return True if valid as a character or promotion, false otherwise. - */ -bool isValidId(int8_t ID); - -static constexpr uint8_t dirStrSize = 10; -extern const char promoDirs[][dirStrSize]; -extern const char charDirs[][dirStrSize]; - - -#endif //JIN_BARBAPAPA_IDS_H diff --git a/include/LCD.h b/include/LCD.h deleted file mode 100644 index b3111a1..0000000 --- a/include/LCD.h +++ /dev/null @@ -1,46 +0,0 @@ -// -// Created by Teo-CD on 17/10/23. -// - -#ifndef JIN_BARBAPAPA_LCD_H -#define JIN_BARBAPAPA_LCD_H - -#include -#include -#include - -#include - -#include "Com.h" -#include "IDs.h" -#include "Pinout.h" - -class LCD { -public: - LCD() : sd(SD) {}; - void init(); - /*** - * Check if time has passed and we should display a new frame. - * @return True if a new frame was displayed. - */ - bool checkAndDisplay(); - void startNewAnim(int8_t ID); -private: - Adafruit_PCD8544 lcd{pin_LCD_DC, pin_LCD_CS, pin_LCD_RST}; - - SDClass &sd; - /* Directory where the current animation frames are stored. */ - File animDir; - - /*** - * Array storing the bitmap that will be passed to the LCD. - * The LCD is 84x48 so that should be 504 bytes, but the row length (84) - * is not byte aligned. Thus, the last byte is padded, giving 88x48 = 528. - */ - static uint8_t bitmap[528]; - uint32_t lastFrameTime = 0; - /* Delay between two frames, in milliseconds. Above 10 FPS is mushy, avoid. */ - static constexpr uint32_t frameTarget = 1000 / 7; -}; - -#endif //JIN_BARBAPAPA_LCD_H diff --git a/include/RFID.h b/include/RFID.h index 88d4c65..bcec1d8 100644 --- a/include/RFID.h +++ b/include/RFID.h @@ -15,7 +15,6 @@ #include #include -#include "IDs.h" #include "Pinout.h" /*** @@ -24,7 +23,7 @@ struct uidNode { MFRC522Constants::Uid uid{}; uidNode* next = nullptr; - // IDs should be positive integers < 127 as the sign bit is used for direction. + // IDs should be positive integers < 127 as the sign is used for direction. int8_t tag_ID = 0; }; @@ -37,7 +36,7 @@ public: * at a time, another call would be needed to get eventual concurrent events. * This updates the respective lists and returns the ID with the direction * of the change. - * @return 0 if no change, ID if new tag detected, ID & sign bit if the tag left. + * @return 0 if no change, +ID if new tag detected, -ID if the tag left. */ int8_t checkTags(); private: diff --git a/src/IDs.cpp b/src/IDs.cpp deleted file mode 100644 index 8a3ae9a..0000000 --- a/src/IDs.cpp +++ /dev/null @@ -1,45 +0,0 @@ -// -// Created by Teo-CD on 19/10/23. -// - -#include "IDs.h" - -/* IDs are greater than one, offset the array to make it easier to use. */ -constexpr char promoDirs[][dirStrSize] = { - "INVALIDE", - "RANDONNEE", - "RESTO", - "AUTOBUS", - "MAYO", - "MADO", - "COOP", - "OURS", - "BAGAR", - "INCAPABLE", - "MYSTERE" -}; -constexpr char charDirs[][dirStrSize] = { - "INVALIDE", - "GUILLAUME", - "MICHEL" -}; - -bool isIdGone(int8_t ID) { - return ID & idMaskGone; -} - -bool isIdCharacter(int8_t ID) { - return ID & idMaskChar; -} - -uint8_t getRawId(int8_t ID) { - return ID & ~(idMaskGone | idMaskChar); -} - -bool isValidId(int8_t ID) { - uint8_t rawId = getRawId(ID); - if (isIdCharacter(ID)) - return rawId < sizeof(charDirs) / dirStrSize; - else - return rawId < sizeof(promoDirs) / dirStrSize; -} diff --git a/src/LCD.cpp b/src/LCD.cpp deleted file mode 100644 index 0b9e478..0000000 --- a/src/LCD.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// -// Created by Teo-CD on 17/10/23. -// - -#include "LCD.h" - -uint8_t LCD::bitmap[528] = {}; - -void LCD::init() { - lcd.begin(60, 4); - lcd.clearDisplay(); - lastFrameTime = millis(); - /* Needed to keep the display clean at boot. */ - lcd.display(); - /* TODO: JIN splash welcome ? */ -} - -void LCD::startNewAnim(int8_t ID) { - char directoryPath[15]; - uint8_t rawID = getRawId(ID); - - if (!SD.mediaPresent()) { - Com::sendComment("SD Card not present, cannot play animation"); - return; - } - if (!isValidId(ID)) { - Com::sendComment("Unknown ID for animation : %d", rawID); - return; - } - - /* Interrupt previous running animation if there's one. */ - if (animDir) - animDir.close(); - - /* TODO: If adding remove animation, change path + check isIdGone */ - snprintf(directoryPath, 15, "%s/ANIM", - (isIdCharacter(ID) ? charDirs : promoDirs)[rawID]); - animDir = SD.open(directoryPath); - if (!animDir) { - Com::sendComment("Could not open directory %s for ID %d", directoryPath, rawID); - return; - } - checkAndDisplay(); -} - -bool LCD::checkAndDisplay() { - if (!animDir || millis() - lastFrameTime < frameTarget) - return false; - - File frame = animDir.openNextFile(); - if (!frame) { - /* There are no frames anymore, the animation is complete. */ - animDir.close(); - return false; - } - frame.read(bitmap, 528); - frame.close(); - - lcd.clearDisplay(); - lcd.drawBitmap(0, 0, bitmap, 84, 48, 1); - lcd.display(); - - lastFrameTime = millis(); - return true; -} diff --git a/src/RFID.cpp b/src/RFID.cpp index 22c69fc..0ba5e1b 100644 --- a/src/RFID.cpp +++ b/src/RFID.cpp @@ -39,7 +39,7 @@ int8_t RFID::checkTags() { removeActiveTag(node, previousNode); // Return the ID with the sign bit set to signal it has gone. // If other tags are gone we can check on the next loop. - return node->tag_ID | idMaskGone; + return node->tag_ID | 1<<7; } } } diff --git a/src/main.cpp b/src/main.cpp index 6615fef..ddebea6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,9 +2,8 @@ #include "Pinout.h" -#include "Com.h" -#include "LCD.h" #include "RFID.h" +#include "Com.h" __attribute__((noreturn)) int main() { pinMode(pin_DBG_LED_1, OUTPUT); @@ -38,34 +37,22 @@ __attribute__((noreturn)) int main() { */ Serial.begin(115200); - Com::sendComment("System is powered up, running set-up."); + Com::sendComment("# System is powered up, running set-up."); /* TODO: Setups once module structure is up. */ RFID rfid; digitalWrite(pin_NFC1_RST, HIGH); rfid.init(); - if (!SD.begin(BUILTIN_SDCARD)) - Com::sendComment("Could not use the SD Card."); - - LCD lcd; - digitalWrite(pin_LCD_RST, HIGH); - lcd.init(); - /* Main loop */ while (true) { int8_t tagEvent; - /* Display first, in case the RFID communication delays it too much. */ - lcd.checkAndDisplay(); - tagEvent = rfid.checkTags(); if (tagEvent) { Com::sendFigUpdate(tagEvent); - lcd.startNewAnim(tagEvent); } - /* TODO: Drop delay, WFE+timer interrupt(s) ? */ - delay(25); + delay(100); } }