Outils pour utilisateurs

Outils du site


diy:projets:tl_partieemetteur

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentesRévision précédente
Prochaine révision
Révision précédente
diy:projets:tl_partieemetteur [2018/05/26 13:56] – [Les changements d'états de la led] sduranddiy:projets:tl_partieemetteur [2018/07/02 09:34] (Version actuelle) – [Le programme principal et la fonction qui gère la led] sdurand
Ligne 41: Ligne 41:
 </code> </code>
 avec **V** qui peut valoir **1 pour éteindre la led** ou **0 pour allumer la led** (**ceci dépend de la façon  avec **V** qui peut valoir **1 pour éteindre la led** ou **0 pour allumer la led** (**ceci dépend de la façon 
-dont vous avez branché la led au raspberry**) et **X** qui est toujours le **numéro du pin de la led**.+dont vous avez branché la led au raspberry**, notre branchement est sans doute hasardeux) et **X** qui  
 +est toujours le **numéro du pin de la led**.
  
 Quand vous aurez fini de jouer, vous devrez dé-exportez la led. Là aussi, c'est très simple: Quand vous aurez fini de jouer, vous devrez dé-exportez la led. Là aussi, c'est très simple:
Ligne 52: Ligne 53:
 **effectuer toutes les opérations** dont je viens de vous parler, c'est comme ça que je vous recommande de procéder.  **effectuer toutes les opérations** dont je viens de vous parler, c'est comme ça que je vous recommande de procéder. 
 J'ai personnellement choisi de **créer une classe** pour encapsuler ces opérations. Le code de cette classe est  J'ai personnellement choisi de **créer une classe** pour encapsuler ces opérations. Le code de cette classe est 
-disponible sur [[https://github.com/SDurand7/LedTransmitter|mon github]] (fichiers ledcontroller.cpp/hpp) au cas où vous ne souhaiteriez pas +disponible ci-dessous au cas où vous ne souhaiteriez pas 
 tout réécrire vous même.  tout réécrire vous même. 
  
Ligne 121: Ligne 122:
  
 Passons maintenant au coeur du programme, la **conversion de bits en signaux lumineux**. Nous allons commencer  Passons maintenant au coeur du programme, la **conversion de bits en signaux lumineux**. Nous allons commencer 
-par créer la boucle nous permettant d'itérer sur les caractères d'un string. En **C++* et avec +par créer la boucle nous permettant d'itérer sur les caractères d'un string. En **C++** et avec 
 **la norme C++14**, vous pouvez faire ça comme suit: **la norme C++14**, vous pouvez faire ça comme suit:
 <code C++> <code C++>
Ligne 142: Ligne 143:
 </code>  </code> 
  
 +Au final, **votre code devrait ressembler a quelque chose comme ça**:
 +<code C++>
 +void transmit(LedController& lc, const std::string& message) {
 +   // On initialise la variable timer comme le temps référence de notre transmission 
 +   auto timer = std::chrono::high_resolution_clock::now();
 +   // On allume la led pour signaler au récepteur le début de la transmission
 +   lc.turnOn();
  
 +   // On parcourt le message
 +   for(const char& c: message) {
 +      // On parcourt les bits de chaque caractère
 +      for(unsigned int i = 0; i < 8; i++) {
 +         // On incrémente le timer d'un pas pré-calculé (dépendant le la fréquence de transmission choisie)
 +         timer += time_step;
 +         // On regarde avant la pause si on doit allumer ou non la led
 +         const bool lightUp = c & powers_of_two[i]; 
 +         // On attend
 +         std::this_thread::sleep_until(timer);
 +
 +         // On positionne la led dans le bon état
 +         lightUp ? lc.turnOn() : lc.turnOff();
 +      }
 +   }
 +
 +   std::this_thread::sleep_until(timer + time_step);
 +   lc.turnOff();
 +
 +   // On attend suffisamment pour que le récepteur reçoive un octet de zéros pour marquer la fin de transmission
 +   std::this_thread::sleep_for(2 * time_step);
 +}
 +</code>
 +
 +En ce qui concerne **les pauses**, je vous invite simplement à consulter le code ci-dessus, 
 +vous avez sans doute remarquer que le "schéma" est simple et ne nécessite pas d'explications 
 +détaillées.
  
 ---- ----
Ligne 148: Ligne 183:
 ===== Sources du projet ===== ===== Sources du projet =====
  
-La totalité des sources de cette partie du projet sont disponibles à [[https://github.com/SDurand7/LedTransmitter|cette addresse]]+==== La classe pour contrôler le gpio ==== 
-Je vous invite à consulter le guide vers la partie émetteur pour récupérer les sources de la partie récepteur.+ 
 +<code C++> 
 +#include "ledcontroller.hpp" 
 + 
 + 
 +// Private method that export the choosen gpio 
 +void LedController::export_gpio() { 
 + std::ofstream exportFile("/sys/class/gpio/export"); 
 +  
 + if(!exportFile.is_open()) { 
 + std::cerr << "ERROR: Could not export gpio " << this->numero << "." << std::endl; 
 + throw ERR_EXPORT; 
 +
 + 
 + exportFile << this->numero; 
 + exportFile.close(); 
 +
 + 
 + 
 +// Private method that unexport the previously opened gpio 
 +void LedController::unexport_gpio() { 
 + std::ofstream unexportFile("/sys/class/gpio/unexport"); 
 + 
 + if(!unexportFile.is_open()) { 
 + std::cerr << "ERROR: Could not unexport gpio " << this->numero << "." << std::endl; 
 + throw ERR_UNEXPORT;  
 +
 + 
 + unexportFile << this->numero; 
 + unexportFile.close(); 
 +
 + 
 + 
 +// Constructor of our class: 
 +// numero: numero of the gpio's pin we want to open 
 +// dirOut: boolean indicating if the direction we want is out or not (as it is a LedController, it is set to true by default) 
 +// litUp: boolean indicating if the led should be initially on or off 
 +LedController::LedController(int numero, bool dirOut, bool litUp) { 
 + this->numero = numero; 
 + 
 + export_gpio(); 
 + // Adding a little delay to make sure that the files created when exporting exists before we start working on them 
 + std::this_thread::sleep_for(std::chrono::milliseconds(EXPORT_DELAY)); 
 + 
 + std::ofstream directionFile(std::string("/sys/class/gpio/gpio" + std::to_string(numero) + "/direction").c_str()); 
 + 
 + if(!directionFile.is_open()) { 
 + unexport_gpio(); 
 + 
 + std::cerr << "ERROR: Could not open \"direction\" for gpio " << numero << "." << std::endl; 
 + throw ERR_EXPORT; 
 +
 + 
 + // Setting the direction according to the boolean dirOut 
 + directionFile << (dirOut ? "out" : "in");  
 + directionFile.close(); 
 + 
 + if(!litUp) { 
 + turnOff(); 
 +
 + else { 
 + turnOn(); 
 +
 +
 + 
 + 
 +// Destructor that will unexport the gpio previously opened 
 +LedController::~LedController() { 
 + unexport_gpio(); 
 +
 + 
 + 
 +// Public method lighting up the led 
 +void LedController::turnOn() { 
 + std::ofstream value; 
 + 
 + value.open(std::string("/sys/class/gpio/gpio" + std::to_string(this->numero) + "/value").c_str()); 
 + 
 + if(!value.is_open()) { 
 + unexport_gpio(); 
 + 
 + std::cerr << "ERROR: Could not open \"value\" for gpio " << this->numero << "." << std::endl; 
 + throw ERR_VALUE; 
 +
 + 
 + value << "0"; 
 + 
 + value.close(); 
 +
 + 
 + 
 +// Public method turning off the led 
 +void LedController::turnOff() { 
 + std::ofstream value;  
 +  
 + value.open(std::string("/sys/class/gpio/gpio" + std::to_string(this->numero) + "/value").c_str()); 
 + 
 + if(!value.is_open()) { 
 + unexport_gpio(); 
 + 
 + std::cerr << "ERROR: Could not open \"value\" for gpio " << this->numero << "." << std::endl; 
 + throw ERR_VALUE; 
 +
 + 
 + value << "1"; 
 + 
 + value.close(); 
 +
 +</code> 
 + 
 +==== Son header ==== 
 + 
 +<code C++> 
 +#ifndef LEDCONTROLLER_HPP 
 +#define LEDCONTROLLER_HPP 
 + 
 +#include <iostream> 
 +#include <string> 
 +#include <chrono> 
 +#include <thread> 
 +#include <fstream> 
 + 
 +// Refer to the constructor source code for more info on this define 
 +#define EXPORT_DELAY 400 
 + 
 +// A few define to make errors handling clearer 
 +#define ERR_EXPORT -2 
 +#define ERR_UNEXPORT -3 
 +#define ERR_VALUE -4 
 +#define ERR_DIRECTION -5 
 + 
 + 
 + 
 +class LedController { 
 + public: 
 + LedController(int numero, bool dirOut = true, bool litUp = false); 
 + ~LedController(); 
 + 
 + void turnOn(); 
 + void turnOff(); 
 + 
 + private: 
 + void export_gpio(); 
 + void unexport_gpio(); 
 + int numero; 
 +}; 
 + 
 +#endif 
 +</code> 
 + 
 +==== Le programme principal et la fonction qui gère la led ==== 
 + 
 +<code C++> 
 +#include <iostream> 
 +#include <string> 
 +#include <chrono> 
 +#include <thread> 
 +#include "ledcontroller.hpp" 
 + 
 +#define GPIO_PIN 21 
 +#define BITRATE 20 
 +#define BITTIME static_cast<int>(1e6/BITRATE) 
 + 
 +#define ALL_GOOD 0 
 + 
 + 
 +const auto time_step = std::chrono::microseconds(BITTIME); 
 +// We are asuming here that a char is always an octet, and we will assume in every part of the code 
 +const unsigned char powers_of_two[8] = {128, 64, 32, 16, 8, 4, 2, 1}; 
 + 
 + 
 +// Function that iterates over message and switch on and off the led of lc according to the bits 
 +void transmit(LedController& lc, const std::string& message) { 
 + // Initializing timer as the reference time 
 + auto timer = std::chrono::high_resolution_clock::now(); 
 + // Turning on the light to tell the receptor we're starting to emit 
 + lc.turnOn(); 
 + 
 + // Iterating over the message 
 + for(const char& c: message) { 
 + // Iterating over the bits of c (again, we're assuming that a char is an octet long) 
 + for(unsigned int i = 0; i < 8; i++) { 
 + // Incrementing the timer, computing wether we should lightUp the led or not, and sleeping until it's time to change the state of the led 
 + timer += time_step; 
 + const bool lightUp = c & powers_of_two[i];  
 + std::this_thread::sleep_until(timer); 
 + 
 + lightUp ? lc.turnOn() : lc.turnOff(); 
 +
 +
 + 
 + std::this_thread::sleep_until(timer + time_step); 
 + lc.turnOff(); 
 + 
 + // Sleeping long enough to make sure that the receptor received at least a full octet of zeros (it will mark the end of transmission for it) 
 + std::this_thread::sleep_for(2 * time_step); 
 +
 + 
 +// This main simply get the input from stdin and act in consequence 
 +int main() { 
 + LedController lc(GPIO_PIN); 
 + std::string message; 
 + 
 + // Getting the first string 
 + std::cout << "Waiting for a string to send: (\"/test\" to launch a sequence of 0 and 1, \"/end\" to end the program)" << std::endl; 
 + std::getline(std::cin, message); 
 + 
 + // Sending message if it is different of "/end" and "/test" 
 + // "/end" will end the loop and therefore, the execution 
 + while(message != "/end") { 
 + // I feel like it's ok to not use a switch because I don't plan to add more commands, but if you plan to, you should definitely use one 
 + if(message == "/test") { 
 + // The test sequence is a sequence of upper case "u" because in ASCII, an U is 01010101, and this makes a pretty good test sequence 
 + transmit(lc, "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU"); 
 +
 + else { 
 + transmit(lc, message); 
 +
 + 
 + std::cout << "Transfer complete.\n" << std::endl; 
 + 
 + std::cout << "Waiting for a string to send: " << std::endl; 
 + std::getline(std::cin, message); 
 +
 + 
 + return ALL_GOOD; 
 +
 +</code> 
  
 ---- ----
-//Auteur: Sylvain Durand//+//Auteur: S. Durand//
diy/projets/tl_partieemetteur.1527342994.txt.gz · Dernière modification : 2018/05/26 13:56 de sdurand