Polytech Tours - Projet C++ embarqué sur cible mbed
Revision 0:21e183c9ef81, committed 2016-04-24
- Comitter:
- LecomteDelys
- Date:
- Sun Apr 24 15:43:51 2016 +0000
- Commit message:
- Programme final
Changed in this revision
diff -r 000000000000 -r 21e183c9ef81 Color.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Color.h Sun Apr 24 15:43:51 2016 +0000 @@ -0,0 +1,26 @@ +#include "mbed.h" + +// enum de l'ensemble des couleurs gérées par notre jeu. NUM_COLORS permet de connaitre le nombre de couleurs et NA pour les couleurs captées non assignées +enum Colour_t { + GREEN, + RED, + BLUE, + YELLOW, + CYAN, + NUM_COLORS, + NA +}; + +// Structure utilisée pour définir les composantes rouge, vert et bleu d'une couleur +struct RGB { + uint16_t red; + uint16_t green; + uint16_t blue; +}; + +// Structure utilisée pour définir les valeurs de teinte, saturation et valeur d'une couleur +struct HSV { + double hue; + double saturation; + double value; +};
diff -r 000000000000 -r 21e183c9ef81 ColorManager.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ColorManager.cpp Sun Apr 24 15:43:51 2016 +0000 @@ -0,0 +1,117 @@ +#include "ColorManager.h" + +// Méthode permettant d'obtenir des valeurs de HSV avec des valeurs de RGB. Il faut donner en paramètre des structures RGB et HSV, par référence. +void ColorManager::RGBtoHSV(RGB &rgb, HSV &hsv) +{ + double min, max, delta; + + min = rgb.red < rgb.green ? rgb.red : rgb.green; + min = min < rgb.blue ? min : rgb.blue; + + max = rgb.red > rgb.green ? rgb.red : rgb.green; + max = max > rgb.blue ? max : rgb.blue; + + hsv.value = max; + delta = max - min; + + if (delta < 0.00001) + { + hsv.saturation = 0; + hsv.hue = 0; + return; + } + if( max > 0.0 ) { + hsv.saturation = (delta/max); + } else { + hsv.saturation = 0.0; + hsv.hue = NAN; + return; + } + if(rgb.red >= max) + hsv.hue = (rgb.green-rgb.blue)/delta; + else + if(rgb.green >= max) + hsv.hue = 2.0 + (rgb.blue - rgb.red)/delta; + else + hsv.hue = 4.0 + (rgb.red - rgb.green ) / delta; + + hsv.hue *= 60.0; + + if(hsv.hue < 0.0) + hsv.hue += 360.0; +} + +// Méthode permettant d'obtenir des valeurs de RGB avec des valeurs de HSV. Il faut donner en paramètre des structures RGB et HSV, par référence. +void ColorManager::HSVtoRGB(RGB &rgb, HSV &hsv) +{ + double hh, p, q, t, ff; + long i; + + if(hsv.saturation <= 0.0) { // < is bogus, just shuts up warnings + rgb.red = hsv.value; + rgb.green = hsv.value; + rgb.blue = hsv.value;; + return; + } + hh = hsv.hue; + if(hh >= 360.0) + hh = 0.0; + hh /= 60.0; + i = (long)hh; + ff = hh - i; + p = hsv.value * (1.0 - hsv.saturation); + q = hsv.value * (1.0 - (hsv.saturation * ff)); + t = hsv.value * (1.0 - (hsv.saturation * (1.0 - ff))); + + switch(i) { + case 0: + rgb.red = hsv.value; + rgb.green = t; + rgb.blue = p; + break; + case 1: + rgb.red = q; + rgb.green = hsv.value; + rgb.blue = p; + break; + case 2: + rgb.red = p; + rgb.green = hsv.value; + rgb.blue = t; + break; + + case 3: + rgb.red = p; + rgb.green = q; + rgb.blue = hsv.value; + break; + case 4: + rgb.red = t; + rgb.green = p; + rgb.blue = hsv.value; + break; + case 5: + default: + rgb.red = hsv.value; + rgb.green = p; + rgb.blue = q; + break; + } +} + +// Métode qui retourne une couleur (de type Colour_t) en fonction d'une valeur de teinte passée en paramètre +Colour_t ColorManager::getColorFromHue(double hue) +{ + if(hue>=50 && hue < 100) + return YELLOW; + else if(hue >= 100 && hue < 135) + return GREEN; + else if(hue >= 135 && hue < 165) + return CYAN; + else if(hue >= 165 && hue < 270) + return BLUE; + else if( (hue >=270 && hue <360) || (hue >=0 && hue <50) ) + return RED; + else + return NA; +}
diff -r 000000000000 -r 21e183c9ef81 ColorManager.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ColorManager.h Sun Apr 24 15:43:51 2016 +0000 @@ -0,0 +1,21 @@ +#ifndef COLORMANAGER_H +#define COLORMANAGER_H + +#ifndef COLOR_H +#define COLOR_H +#include "Color.h" +#endif + +#include "mbed.h" +#include <iostream> + +class ColorManager +{ + public : + // Méthodes + void HSVtoRGB(RGB &rgb, HSV &hsv); + void RGBtoHSV(RGB &rgb, HSV &hsv); + Colour_t getColorFromHue(double hue); +}; + +#endif
diff -r 000000000000 -r 21e183c9ef81 ConfigFile.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ConfigFile.hpp Sun Apr 24 15:43:51 2016 +0000 @@ -0,0 +1,67 @@ +#ifndef CONFIGURATION_FILE_H +#define CONFIGURATION_FILE_H + +#include "mbed.h" +#include "rpc.h" +#include <fstream> +#include <iostream> + +struct configSPI { + PinName mosi; + PinName miso; + PinName sck; +}; + +struct configI2C { + PinName sda; + PinName scl; +}; + +class ConfigFile +{ + public: + /*Constructeur*/ + ConfigFile(const char* fileName, uint8_t &level, uint8_t &numLeds, configSPI &spi, configI2C &i2c, PinName &latchPin) { + int l, n; + char configPins[6][3]; + + /*Utiliser le système de fichier local*/ + LocalFileSystem local("local"); + + /*Ouvrir le fichier de configuration*/ + FILE* ConfigFile = fopen(fileName, "r"); + + if(ConfigFile) { + + /*Lire les données de configuration*/ + fscanf(ConfigFile, + "Difficulte = %d\nNombre de LEDs = %d\n\nMOSI pin = %s\nMISO pin = %s\nSCK pin = %s\nLatch pin = %s\n\nSDA pin = %s\nSCL pin = %s", + &l, &n, configPins[0], configPins[1], configPins[2], configPins[3], configPins[4], configPins[5]); + + /*Niveau du jeu*/ + level = (uint8_t) l; + + /*Nombre de LEDs sur le bandeau*/ + numLeds = (uint8_t) n; + + /*SPI*/ + spi.mosi = parse_pins(configPins[0]); + spi.miso = parse_pins(configPins[1]); + spi.sck = parse_pins(configPins[2]); + + /*Latch pin*/ + latchPin = parse_pins(configPins[3]); + + /*I2C*/ + i2c.sda = parse_pins(configPins[4]); + i2c.scl = parse_pins(configPins[5]); + + /*Fermer le fichier de configuration*/ + fclose(ConfigFile); + + } else { + std::cerr << "Erreur lors de l'ouverture du fichier de configuration !" << std::endl; + } + } +}; +#endif
diff -r 000000000000 -r 21e183c9ef81 GroveColourSensor.hpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/GroveColourSensor.hpp Sun Apr 24 15:43:51 2016 +0000 @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2006-2013 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __GROVE_COLOUR_SENSOR_HPP__ +#define __GROVE_COLOUR_SENSOR_HPP__ + +#include "mbed.h" + +/** + * This module is based on the color sensor TCS3414CS with digital output over I2C. + * http://www.seeedstudio.com/wiki/index.php?title=Twig_-_I2C_Color_Sensor_v0.9b + */ +#ifndef COLOR_H +#define COLOR_H +#include "Color.h" +#endif + +class GroveColourSensor { +public: + + // Constructeur qui initialise la connexion I2C + GroveColourSensor(PinName sda, PinName scl) : m_i2c(sda, scl) { + /* empty*/ + } + + // Méthode pour allumer le capteur + void powerUp(void) { + static const char powerUpCommand[] = {0x80, 0x03}; + if (m_i2c.write((SEVEN_BIT_ADDRESS << 1), powerUpCommand, sizeof(powerUpCommand)) != 0) { + std::cerr << "failed to power up the sensor" << std::endl; + } + } + + // Méthode pour éteindre le capteur + void powerDown(void) { + static const char powerDownCommand[] = {0x80, 0x00}; + /* turn down the color sensor */ + if (m_i2c.write((SEVEN_BIT_ADDRESS << 1), powerDownCommand, sizeof(powerDownCommand)) != 0) { + std::cerr << "failed to power down the sensor" << std::endl; + } + } + + // Méthode permettant de récupérer la valeur d'une couleur en donnant en paramètre une couleur de l'enum Colour_t + uint16_t readColour(Colour_t colour) { + char readColorRegistersCommand = 0xb0 + (2 * static_cast<unsigned>(colour)); + m_i2c.write((SEVEN_BIT_ADDRESS << 1), &readColorRegistersCommand, 1 /* size */); + + uint16_t colourValue; + m_i2c.read((SEVEN_BIT_ADDRESS << 1), reinterpret_cast<char *>(&colourValue), sizeof(uint16_t)); + return colourValue; + } + + // Méthode permettant de récupérer la valeur d'une couleur en donnant en paramètre le numéro de la couleur dans l'énum + uint16_t readColour(unsigned colour) { + if (colour >= NUM_COLORS) { + return 0; + } + return readColour(static_cast<Colour_t>(colour)); + } + + // Méthode permettant de récupérer les trois couleurs en donnant en paramètre une structure RGB (par référence) + void readColours(RGB &rgb) { + rgb.red= readColour(RED); + rgb.blue= readColour(BLUE); + rgb.green= readColour(GREEN); + } + +private: + static const uint8_t SEVEN_BIT_ADDRESS = 0x39; + I2C m_i2c; +}; +#endif /* #ifndef __GROVE_COLOUR_SENSOR_HPP__ */
diff -r 000000000000 -r 21e183c9ef81 HL1606Stripe.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HL1606Stripe.cpp Sun Apr 24 15:43:51 2016 +0000 @@ -0,0 +1,171 @@ +#include "HL1606Stripe.h" +#include <iostream> + +/*Constructeur*/ +HL1606Stripe::HL1606Stripe(PinName mosi, PinName miso, PinName sclk, PinName latch, uint8_t numLEDs, uint8_t numColors) : m_numLEDs(numLEDs), m_numColors(numColors), m_SPI(mosi, miso, sclk), m_latchPin(latch) +{ + m_SPI.format(8,3); // 8 bits per frame, SPI mode 3 + m_SPI.frequency(450000); // 450kHz freq + + /*Allocation en fonction du nombre de LEDs sur le bandeau*/ + m_redPWM = new uint8_t[m_numLEDs]; + m_greenPWM = new uint8_t[m_numLEDs]; + m_bluePWM = new uint8_t[m_numLEDs]; + + /*Eteindre le bandeau de LEDs*/ + SwitchOffRGB(); + + /*Mettre à jour les LEDs du bandeau toutes les 45ms*/ + m_tickerUpdate.attach(this, &HL1606Stripe::Update, 0.0045); +} + +/*Destructeur*/ +HL1606Stripe::~HL1606Stripe() +{ + m_tickerUpdate.detach(); + + delete [] m_redPWM; + delete [] m_greenPWM; + delete [] m_bluePWM; +} + +/*Mettre à jour le bandeau de LEDs*/ +void HL1606Stripe::Update(void) +{ + uint8_t i, data; + static int m_pwmCounter; + + /*Ecrire les données sur le bus SPI*/ + for (i = 0; i < m_numLEDs; i++) { + + data = 0x80; + + /*Calculer la couleur de la LED suivante*/ + if (m_pwmCounter < m_redPWM[i]){ + data |= 0x04; + } + + if (m_pwmCounter < m_bluePWM[i]){ + data |= 0x10; + } + + if (m_pwmCounter < m_greenPWM[i]){ + data |= 0x01; + } + + m_SPI.write(data); + } + + /*Incrémenter le compteur de PWM (soft)*/ + m_pwmCounter += 1; + + if (m_pwmCounter > 3){ + m_pwmCounter = 0; + } + + /*Latch*/ + m_latchPin = 1; + wait_us(1); + m_latchPin = 0; +} + +/*Eteindre le bandeau de LEDs*/ +void HL1606Stripe::SwitchOffRGB() +{ + FillRGB(OFF,OFF,OFF); +} + +/*Set d'une LED sur le bandeau*/ +void HL1606Stripe::setLED(uint8_t Color, uint8_t LEDx) +{ + if(LEDx>m_numLEDs) + { + std::cerr << "Erreur lors du set d'une LED du bandeau : index error" << std::endl; + return; + } + if(Color>NUM_COLORS) + { + std::cerr << "Erreur lors du set d'une LED du bandeau : Num color error" << std::endl; + return; + } + switch(Color) + { + case BLUE: + m_redPWM[LEDx] = OFF; + m_greenPWM[LEDx] = OFF; + m_bluePWM[LEDx] = LOW; + break; + + case RED: + m_redPWM[LEDx] = LOW; + m_greenPWM[LEDx] = OFF; + m_bluePWM[LEDx] = OFF; + break; + + case GREEN: + m_redPWM[LEDx] = OFF; + m_greenPWM[LEDx] = LOW; + m_bluePWM[LEDx] = OFF; + break; + + case YELLOW: + m_redPWM[LEDx] = LOW; + m_greenPWM[LEDx] = LOW; + m_bluePWM[LEDx] = OFF; + break; + + case CYAN: + m_redPWM[LEDx] = OFF; + m_greenPWM[LEDx] = MEDIUM; + m_bluePWM[LEDx] = LOW; + break; + + /*OFF*/ + default: + m_redPWM[LEDx] = OFF; + m_greenPWM[LEDx] = OFF; + m_bluePWM[LEDx] = OFF; + } +} + +/*Remplir aléatoirement le bandeau de LEDs*/ +void HL1606Stripe::FillRandomlyRGB(uint8_t* randomColors) +{ + for(int LEDx = 0; LEDx < m_numLEDs; LEDx++) + { + randomColors[LEDx] = rand()%(m_numColors); + setLED(randomColors[LEDx],LEDx); + } +} + +/*Remplir le bandeau de LEDs avec une couleur définie dans Colour_t*/ +void HL1606Stripe::FillRGB(uint8_t color) +{ + if(color>NUM_COLORS) + { + std::cerr << "Erreur lors du set d'une LED du bandeau : Num color error" << std::endl; + return; + } + for (int LEDx = 0; LEDx < m_numLEDs; LEDx++) + { + setLED(color,LEDx); + } +} + +/*Remplir le bandeau de LEDs avec des composantes RGB définie par l'utilisateur*/ +void HL1606Stripe::FillRGB(uint8_t red, uint8_t green, uint8_t blue) +{ + for (int i = 0; i < m_numLEDs; i++) { + m_redPWM[i] = red; + m_greenPWM[i] = green; + m_bluePWM[i] = blue; + } +} + +/*Remplir le bandeau de LEDs avec des couleurs définies par l'utilisateur*/ +void HL1606Stripe::FillRGB(uint8_t* colors) +{ + for(int LEDx = 0; LEDx < m_numLEDs; LEDx++) { + setLED(colors[LEDx],LEDx); + } +}
diff -r 000000000000 -r 21e183c9ef81 HL1606Stripe.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HL1606Stripe.h Sun Apr 24 15:43:51 2016 +0000 @@ -0,0 +1,47 @@ +#ifndef HL1606_STRIPE_H +#define HL1606_STRIPE_H + +#ifndef COLOR_H +#define COLOR_H +#include "Color.h" +#endif + +#include "mbed.h" +#include "Intensity.h" + +class HL1606Stripe +{ + +public: + /* Constructeur */ + HL1606Stripe(PinName mosi, PinName miso, PinName sclk, PinName latch, uint8_t numLEDs, uint8_t m_numColors); + + /* Destructeur */ + ~HL1606Stripe(); + + /* Méthodes */ + void Update(void); + void SwitchOffRGB(void); + void FillRGB(uint8_t color); + void FillRGB(uint8_t* colors); + void FillRGB(uint8_t red, uint8_t green, uint8_t blue); + void FillRandomlyRGB(uint8_t* randomColors); + + void setLED(uint8_t Color, uint8_t LEDx); + +private: + /*Attributs*/ + uint8_t* m_redPWM; + uint8_t* m_greenPWM; + uint8_t* m_bluePWM; + + uint8_t m_numLEDs; + uint8_t m_numColors; + + SPI m_SPI; + DigitalOut m_latchPin; + Ticker m_tickerUpdate; + +}; + +#endif
diff -r 000000000000 -r 21e183c9ef81 Intensity.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Intensity.h Sun Apr 24 15:43:51 2016 +0000 @@ -0,0 +1,8 @@ +// enum de l'ensemble des intensités possibles pour les LEDs du bandeau de LEDs +enum Intensity +{ + OFF, + LOW, + MEDIUM, + HIGH +};
diff -r 000000000000 -r 21e183c9ef81 MatchColors.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MatchColors.cpp Sun Apr 24 15:43:51 2016 +0000 @@ -0,0 +1,152 @@ +#include "MatchColors.h" +#define TIME_TO_WAIT 10 + +/*Constructeur*/ +MatchColors::MatchColors() +{ + uint8_t nbColors = 0; + configSPI spi; + configI2C i2c; + PinName latchPin; + + /*Lecture des paramètres de jeu et de configuration des pins*/ + ConfigFile("/local/Config.txt", m_difficulty, m_nbleds, spi, i2c, latchPin); + + /*Instanciation du capteur de couleur*/ + m_colourSensor = new GroveColourSensor(i2c.sda, i2c.scl); + m_colourSensor->powerUp(); + + /*Définition du nombre de couleur max affichées en fonction de la difficulté sélectionnée*/ + switch(m_difficulty){ + case 0 : + nbColors = 3 ; + break; + case 1 : + nbColors = 4 ; + break; + case 2 : + nbColors = 5 ; + break; + default : + nbColors = 4 ; + break; + } + + /*Instanciation du bandeau de LEDs RGB*/ + m_stripe = new HL1606Stripe(spi.mosi, spi.miso, spi.sck, latchPin, m_nbleds, nbColors); + + /*Instanciation de la gestion de couleurs*/ + m_colormManager = new ColorManager(); + + m_randomColors = new uint8_t[m_nbleds]; +} + +/*Destructeur*/ +MatchColors::~MatchColors() +{ + m_timeoutInit.detach(); + m_timeoutPlay.detach(); + m_tickerResultat.detach(); + + if(m_colourSensor != NULL) + delete m_colourSensor; + + if(m_stripe != NULL) + delete m_stripe; +} + +/*Initialisation d'une partie*/ +void MatchColors::InitGame() +{ + static bool stripeIsON = false; + + m_timeoutInit.detach(); + + if(stripeIsON) { + /*Masquer les couleurs au joueur*/ + stripeIsON = false; + m_stripe->SwitchOffRGB(); + + /*Lancer la série de match*/ + m_timeoutPlay.attach(this, &MatchColors::Play, 3); + } else { + /*Remplir le bandeau de leds avec des couleurs aléatoires*/ + m_stripe->FillRandomlyRGB(m_randomColors); + stripeIsON = true; + m_result = false; + + /*Lancer la seconde phase de l'initialisation pour masquer les couleurs*/ + m_timeoutInit.attach(this, &MatchColors::InitGame, TIME_TO_WAIT-2*m_difficulty); + } +} + +void MatchColors::Play() +{ + HSV hsv; + RGB rgb; + static uint8_t tour = 0; + Colour_t color; + + /*Lire la couleur sélectionnée par le joueur*/ + m_colourSensor->readColours(rgb); + m_colormManager->RGBtoHSV(rgb, hsv); + color=m_colormManager->getColorFromHue(hsv.hue); + + /*Matcher la couleur sélectionnée avec la solution*/ + if(color == m_randomColors[tour]) { + /*La couleur sélectionnée est bonne*/ + m_timeoutPlay.detach(); + m_stripe->setLED(color,tour); + tour++; + + /*Est ce la fin de la manche? (tour = 8)*/ + if(tour == m_nbleds) { + m_result = true; + tour = 0; + + /*Afficher animation de victoire*/ + m_tickerResultat.attach(this, &MatchColors::ShowResult, 0.125); + } else { + /*Tour suivant*/ + m_timeoutPlay.attach(this, &MatchColors::Play, 4); + } + } else { + /*La couleur sélectionnée est fausse*/ + m_result = false; + tour = 0; + + /*Afficher animation de défaite*/ + m_tickerResultat.attach(this, &MatchColors::ShowResult, 0.125); + } +} + +void MatchColors::ShowResult() +{ + static uint8_t counter = 0; + static bool status = false; + + if(counter < 20) { + if(status) { + /*Animation de victoire ou de défaite*/ + if(m_result) { + m_stripe->FillRGB(GREEN); + } else { + m_stripe->FillRGB(m_randomColors); + } + } else { + m_stripe->SwitchOffRGB(); + } + + counter++; + status = !status; + + } else { + m_tickerResultat.detach(); + counter = 0; + status = false; + m_stripe->SwitchOffRGB(); + + /*Lancer l'initialisation d'une nouvelle partie*/ + m_timeoutInit.attach(this, &MatchColors::InitGame, 2); + } +}
diff -r 000000000000 -r 21e183c9ef81 MatchColors.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MatchColors.h Sun Apr 24 15:43:51 2016 +0000 @@ -0,0 +1,47 @@ +#ifndef MATCHCOLORS_H +#define MATCHCOLORS_H + +#ifndef COLOR_H +#define COLOR_H +#include "Color.h" +#endif + +#include <iostream> +#include "GroveColourSensor.hpp" +#include "HL1606Stripe.h" +#include "ConfigFile.hpp" +#include "ColorManager.h" + +class MatchColors +{ + +public : + /*Constructeur*/ + MatchColors(); + + /*Desctructeur*/ + ~MatchColors(); + + /*Méthodes*/ + void InitGame(); + +private : + /*Méthodes privées*/ + void Play(); + void ShowResult(); + + /*Attributs*/ + uint8_t m_nbleds; + uint8_t m_difficulty; + GroveColourSensor* m_colourSensor; + HL1606Stripe* m_stripe; + uint8_t* m_randomColors; + ColorManager* m_colormManager; + bool m_result; + + Timeout m_timeoutInit; + Timeout m_timeoutPlay; + Ticker m_tickerResultat; +}; + +#endif
diff -r 000000000000 -r 21e183c9ef81 main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Sun Apr 24 15:43:51 2016 +0000 @@ -0,0 +1,13 @@ +#include "mbed.h" +#include <iostream> +#include <string> +#include "MatchColors.h" +int main() { + + /*Instanciation du jeu*/ + MatchColors* jeu = new MatchColors(); + + /*Initialisation du jeu*/ + jeu->InitGame(); +} +
diff -r 000000000000 -r 21e183c9ef81 mbed.lib --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.lib Sun Apr 24 15:43:51 2016 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/gokmenascioglu/code/mbed/#a8fa94490a0a