Youtube video : https://www.youtube.com/watch?v=vfflMZcBzCA&t=2s
Hello yall !
I must confess something to you. I love playing chess. It's a quite strategic game that requires patience and throughtfulness. I thought that a backlit chessboard would look great. At first, I was thinking of a simple uniform monochrome backlighting, but as we'll see, it went a bit haywire.
In fact, this famous 8x8 slab which was supposed to be used to play chess by indicating the possible moves when lifting a piece, was finally transformed into an audio spectrum analyzer ! For our greatest pleasure, this chessboard has an outgoing jack plug, which allows to connect it to an external speaker, while we transfer the music by Bluetooth !
So let's get started !
The upper partLet's begin by the the basics. To start, we need white and black glass tiles, 32 in number each, available in DIY stores. I sanded the back of them so that the light can pass through. Then just glue them to a plexiglass plate with clear glue and you're done.
Now we will have to add the famous backlight. Let's start by creating a grid structure that will both isolate each box from the light, but also support the slab. We will cut 49 thin wooden boards (2mm thick) in which we will also make 7 notches to obtain a solid grid of 7x7.
You can see in the picture above that I cut new grooves in the center of each square. They will be used to insert the magnetic sensor grid used for the detection of the pieces, as shown on the figure below.
To finish this high part of the chessboard, it obviously misses... the LEDs! At the beginning I had started with a PCB based on MAX7219 managing 8x8 single color LEDs, but the circuit was complicated for a... mediocre result.
So I started with something much simpler and more efficient, an addressable RGBW LED ribbon (SK6812). I found that two LEDs per box was the best compromise. However, I will have to cut them in packs of 2 and then solder them, otherwise some of the LEDs on the ribbon would overlap the grid. This is a tedious task but one of the most important!
Note : RBGW LEDs has an extra pixel of true white that does not pull towards the blue. Each pixel consumes 20mA, so theoretically it can go up to several amps. Even if this never happens, the power supply should be sized accordingly.
It's good to test now our LEDs in order to be free for the next steps. We load a program in the microcontroller that lights each pixel of each LED successively (we use here an Arduino board for simplicity).
Do not forget to drill 8 holes on two sides so that the wires of the sensor array can be passed under the plate. After that, if the LED ribbon is functional, we just need to superimpose the grille-slab assembly on the backlighting plate.
We add an outline made of 4 stained pine strips and we obtain a beautiful solid structure that we will only have to control !
Well, we're getting somewhere ! However, we are missing something essential : a frame ! Knowing that the glass slab weighs about 4 kg, we need a solid frame, enough to be able to carry the chessboard without the slightest fear that it will break. Moreover, this frame will have to accommodate the few elements of the HMI, namely :
- 1 ON/OFF switch
- 2 control buttons
- 2 LEDs (BT, WiFi)
- 1 brightness control potentiometer
- USB and 12V connectors
- 3.5 jack connector
So let's go !
Knowing that our slab is about 40 cm, I chose to make a 45 cm frame using pine cleats, 5 cm wide. The inside of the frame will host all the electronic control of the chessboard, as well as the components on its front. So we choose a height of about 5 cm, which is why I superimposed two frames of 2.7 cm height. I also added a mortise-and-tenon strip in the middle to solidify the structure. By the way, I used only wood glue for this assembly.
I took the opportunity to dig a 2mm deep groove to insert a second LED ribbon (a simple non-addressable RGB 12V this time) to make a backlight towards the ground. Frankly, it looks great !
Then take the time to shape the front of the frame, as no deviation will be tolerated ! We need to drill big enough to insert the bigest elements and make the wires stand out. It's not necessarily easy especially for the button in the corner !
Now let's move on to the electronics. The central element is an Arduino Mega board, to which we connect blocks, such as :
- a Wifi module to send the game results
- a Bluetooth module that receives the audio signal
- a board with a HE20 connector to connect the top panel
- 3 MOSFETs for driving the 12V LED ribbon
- the elements of the HMI in the frame
To this, we add the Buck converter for general power supply 12V/5V@1A and one for the LED ribbon @5A.
Finally, we cable everything correctly, not forgetting to connect the USB port of the Arduino board to the USB port located on the front panel. Finally, we flash a code in the microcontroller to check each of the different elements, then, if everything is OK, we superimpose the upper and lower parts. It will be necessary to finish the wiring of the upper part (sensor matrix and LED ribbon) by the bottom of the board. Then you just have to close the bottom with a thin wooden board, add rubber feet and you're done !
That's it, we have reached the end of this project ! Once the whole code is flashed, here is what it looks like :
This chessboard in spectrum analyzer mode has 8 bands of 16 (or rather 8) pixels. Each of them is associated with an average frequency, which are 400, 900, 1400, 1900, 2400, 2900, 3400 and 3800 Hz. The calculation of the frequency spectrum is done via the FFT, every 10ms.
Discussion and areas for improvementOf course, it's always possible to find improvements for a project ! In this case, this board has a spectrum analyzer that works very well, but its performance can still be improved.
As its name could indicate, its not really possible to play chess with it today since... I haven't bought it yet ! In fact, for such big pieces, patience is required because there are a lot of fraudulent sites, and the sizes of the pieces to find are quite particular ! On the other hand, the magnetic detection of the parts (using a magnet) works perfectly. I'll update the project when I receive them.
It was a real pleasure to make this chessboard and I hope it will make you want to build an even better one ! You will find all the diagrams and codes in the appropriate sections. In the meantime, tinker well and tinker safe !
/**************************************************************
* FULL CHESSBOARD *
* Designer : Reunics *
* Description : includes leds animations, pieces detection, *
* setting,trum analyzer, *
* Wi-Fi & BT management *
* Controller : Arduino MEGA 2560 *
**************************************************************/
#include "header.h"
#define NB_MODES 4
Adafruit_NeoPixel strip(LED_COUNT, LED_STRIP, NEO_GRBW + NEO_KHZ800);
SoftwareSerial ESP8266(52, 53);
byte currentMode = 0;
bool possibilitiesEnabled = true;
// Debug
String menu = "";
/* ---------------------------------
* -------- INTERRUPTIONS ----------
* --------------------------------- */
/*
* Interrupt for Mode Button - triggered on falling edge
*/
unsigned long t_buttonPushingTime = millis();
unsigned long lastDuration = 0;
void fallingInterruptModeButton()
{
detachInterrupt(digitalPinToInterrupt(BT_MODE));
attachInterrupt(digitalPinToInterrupt(BT_MODE), risingInterruptModeButton, RISING);
t_buttonPushingTime = millis();
Serial.println("F");
}
/*
* Interrupt for Mode Button - triggered on rising edge
*/
void risingInterruptModeButton()
{
detachInterrupt(digitalPinToInterrupt(BT_MODE));
attachInterrupt(digitalPinToInterrupt(BT_MODE), fallingInterruptModeButton, FALLING);
lastDuration = millis()-t_buttonPushingTime;
// short push
// long push is managed inside each mode if necessary
if(lastDuration < WAITING_TIME_BT)
{
lastDuration = 0;
changeMode();
}
Serial.println("R");
}
/*
* Interrupt for Poss Button - triggered on any edge
*/
void changeInterruptPossButton()
{
buttonLightManagement();
}
void setup() // -------------------------------------------------------- SETUP --------------------------------------------------------------
{
pinMode(LED_STRIP , OUTPUT);
pinMode(LED_WIFI , OUTPUT);
pinMode(LED_BLUETOOTH , OUTPUT);
pinMode(BT_MODE , INPUT_PULLUP);
pinMode(BT_POSS , INPUT_PULLUP);
pinMode(LED_BT_MODE , OUTPUT);
pinMode(LED_BT_POSS , OUTPUT);
pinMode(CD4017_CLK , OUTPUT);
pinMode(CD4017_Q7_IN , INPUT);
pinMode(CD4051_A , OUTPUT);
pinMode(CD4051_B , OUTPUT);
pinMode(CD4051_C , OUTPUT);
pinMode(CD4051_X , INPUT);
pinMode(BUZZER , OUTPUT);
pinMode(BACKLIGHT_R , OUTPUT);
pinMode(BACKLIGHT_G , OUTPUT);
pinMode(BACKLIGHT_B , OUTPUT);
attachInterrupt(digitalPinToInterrupt(BT_MODE), fallingInterruptModeButton, FALLING);
attachInterrupt(digitalPinToInterrupt(BT_POSS), changeInterruptPossButton, CHANGE);
/* ----------------------------------- */
// Serial
Serial.begin(115200);
// Leds
for(int i=0; i<2; i++) {
digitalWrite(LED_WIFI, LOW);
digitalWrite(LED_BLUETOOTH, LOW);
delay(100);
digitalWrite(LED_WIFI, HIGH);
digitalWrite(LED_BLUETOOTH, HIGH);
delay(100);
}
delay(200);
digitalWrite(LED_BLUETOOTH, HIGH);
// Button lights
buttonLightInit();
// Chessboard
init_sensor_array();
initPieces();
// Led strip
strip.begin();
strip.clear();
strip.show();
if(ENABLE_START_LED_SEQUENCE)
{
random_filling(true);
byte color[3] = {0,200,0}, stripColor[3] = {200,0,20};
scroll_text(1, "Let's go", 50,0, color, stripColor);
/*
tone(BUZZER, 1030);
delay(1000);
*/
}
}
void loop() // --------------------------------------------------------- LOOP ------------------------------------------------------------
{
//temperature_check(1000); // DEFAULT
leds_management();
//exchangeWithESP(ESP8266);
//backlight_wheel(10); // currently cannot be dispayed in led_animations bc there's only delay() functions
serial_event();
chooseMode();
}
/* -----------------------------------------------------
* ------------------- MODE FUNCTIONS ------------------
* ----------------------------------------------------- */
/*
* Change the current mode. Triggered by a short push on BT_MODE.
*/
void changeMode()
{
currentMode++;
if(currentMode >= NB_MODES)
currentMode = 0;
Serial.println(currentMode);
chooseMode();
}
/*
* Runs the current mode
*/
void chooseMode()
{
strip.clear();
//Serial.println("choose mode");
switch(currentMode)
{
case 0:
spectrum_analyser(40);
break;
case 1:
led_animations();
break;
case 2:
chessboard_mode();
break;
case 4:
choose_color();
break;
case 5:
debug();
break;
}
}
/*
* Lauches some LED animations
*/
void led_animations()
{
french_flag();
while(true)
{
sparkling(0xff,0xff,0xff, 25);
runningLights(0xff,0xff,0x00, 7, false);
//runningLights(0xff,0x00,0xA0, 8, false);
runningLights(0x00,0xbf,0xdf, 7, true);
//french_flag();
random_filling(true);
for(int i=0; i<2; i++)rainbowCycle(5);
//meteorRain(0xff,0xff,0xff,10, 64, true, 20);
meteorRain(0xff,0x00,0xA0,10, 64, true, 10);
//meteorRain(0x00,0x00,0xff,10, 64, true, 8);
snake(5);
byte color[3] = {150,60,0}, stripColor[3] = {0,150,40};
scroll_text(1, " Thanks for watching ! ", 20,0, color, stripColor);
//scroll_text(2, " Let's go ! ", 30,0, color, stripColor);
}
}
/*
* Lauches the chessboard function serie
*/
void chessboard_mode()
{
init_sensor_array();
initPieces();
draw();
//possibilitiesEnabled = (buttonManagement(BT_POSS)==1) ? true : false;
delay(50);
}
/* -----------------------------------------------------
* ------------------- DEBUG METHODS -------------------
* ----------------------------------------------------- */
/*
* Launch the debug interface
*/
void debug()
{
// diplay a red cross
strip.clear();
byte ledArray[] = {18,28,36,42,54,56,70,72,84,90,98,108};
for(byte i=0; i<3; i++) {
for(int led=0; led<(sizeof(ledArray)/sizeof(ledArray[0])); led++)
{
strip.setPixelColor(ledArray[led], 255, 0, 0);
strip.setPixelColor(ledArray[led+1], 255, 0, 0);
strip.show();
}
if(i<2) {
delay(100);
strip.clear();
strip.show();
delay(100);
}
}
while(1)
{
setStripBrightness();
serial_event();
}
}
/*
* Launch the test corresponding to the user entry
*/
void serial_event()
{
if(!Serial.available())
return;
String availableTests[] = {"BUTTONS","BUZZER","LEDS","LEDSTRIP","POT","POWER"};
if(menu == "")
{
if(serialTestWord("DEBUG")) {
Serial.println("Please select an element to test :\n1. BUTTONS\n2. BUZZER\n3. LEDS\n4. LEDSTRIP\n5. POT\n6. POWER ?\n");
menu = "menu";
}
}
else if(menu == "menu")
{
int wordTest = serialTestWord(availableTests);
if(wordTest==0)
return;
Serial.println("---------- " + availableTests[wordTest-1] + " TEST START ----------\n");
delay(50);
switch(wordTest)
{
case 1:
testButtons();
menu = "inTest";
break;
case 2:
testBuzzer();
menu = "inTest";
break;
case 3:
testLeds();
menu = "inTest";
break;
case 4:
testLedStrip(strip);
menu = "inTest";
break;
case 5:
testPot();
menu = "inTest";
break;
case 6:
testPowerSupply();
menu = "inTest";
break;
}
Serial.println("\n-------<<\n");
if(menu=="inTest")
menu="menu";
}
}
/*
* Check if the send word match the one passed in parameter
*/
int serialTestWord(String wordToTest)
{
if(Serial.available())
{
// read data from serial
char mot[20], i = 0;
while(Serial.available())
{
mot[i] = Serial.read();
delay(10);
i++;
if(i>=18) break;
}
mot[i] = '\0';
delay(10);
// comparison
String endingChars = "\r\n";
strcat(wordToTest.c_str(), endingChars.c_str());
return (strcmp(mot, wordToTest.c_str()) == 0);
}
return 0;
}
/*
* Check if the send word matches one of those contained in the array
*/
int serialTestWord(String wordsToTest[])
{
if(Serial.available())
{
// read data from serial
char mot[20], i = 0;
while(Serial.available())
{
mot[i] = Serial.read();
delay(10);
i++;
if(i>=18) break;
}
mot[i] = '\0';
delay(10);
// comparison
String motStr = mot, endingChars = "\r\n";
for(int j=0; j<6; j++)
{
strcat(wordsToTest[j].c_str(), endingChars.c_str());
if(motStr.equals(wordsToTest[j].c_str()))
return j+1;
}
}
return 0;
}
/**************************************************************
* File: header.h *
* Content: all the pin, prototypes and constants defs *
**************************************************************/
#ifndef DEF_HEADER
#define DEF_HEADER
#include <Adafruit_NeoPixel.h>
#include <SoftwareSerial.h>
#include "fix_fft.h"
#include <binary.h>
// ------ ENABLE MODULES -------
#define ENABLE_WIFI 0
#define ENABLE_LED_STRIP 1
#define ENABLE_START_LED_SEQUENCE 0
/* ---------------------------------
* ---------- OUTPUT PINS ----------
* --------------------------------- */
// --------- DIGITAL I/O ----------
#define LED_STRIP 24
#define LED_BLUETOOTH 40 // bleu
#define LED_WIFI 38 // vert
#define BT_MODE 21 // IN INTERRUPT
#define BT_POSS 20 // IN INTERRUPT
#define LED_BT_MODE 9 // PWM
#define LED_BT_POSS 8 // PWM
#define CD4017_CLK 11
#define CD4017_Q7_IN 12 // IN
#define CD4051_A 5 // possible inversion dans le cablage
#define CD4051_B 6
#define CD4051_C 7
#define CD4051_X 13 // IN
#define BUZZER 10
#define ESP_RX 18 // (Arduino TX1)
#define ESP_TX 19 // (Arduino RX1)
#define BACKLIGHT_R 3
#define BACKLIGHT_G 2
#define BACKLIGHT_B 4
// -------- ANALOG INPUTS ---------
#define ALIM A1
#define LED_BLUETOOTH_IN A3 // delivered LED voltage about 1.5V
#define LM35_VIRTUAL_GND A4
#define LM35_RAW_VOUT A8
#define AUDIO_PIN A13
#define POTENTIOMETER A15
/* ---------------------------------
* ------------ CONSTANTS ----------
* --------------------------------- */
// ---------- SETTINGS -----------
#define WAITING_TIME_BT 300
// ------------ WIFI ------------
#define WLAN_SSID " your_SSID :) "
#define WLAN_PASS " your_password :) "
#define WEBSITE "wifitest.adafruit.com"
#define WEBPAGE "/testwifi/index.html"
// ------ SENSORS VARIABLES -------
#define MAX_TEMP 50
// -------- LEDS VARIABLES --------
#define LED_COUNT 8*16
#define MAX_VALUE_BACKLIGHT 180
/* ---------------------------------
* ----------- PROTOTYPES ----------
* --------------------------------- */
// LED animations
void setStripBrightness();
void runningLights(byte red, byte green, byte blue, int WaveDelayn, bool endFlash);
void rainbowCycle(int SpeedDelay);
void fadeToBlack(int ledNo, byte fadeValue);
void meteorRain(byte red, byte green, byte blue, byte meteorSize, byte meteorTrailDecay, boolean meteorRandomDecay, int SpeedDelay);
void french_flag();
void scroll_text(char equipe, String chaine, int t_scrolling, int t_letterBreak, byte color[], byte stripColor[]);
void random_filling(bool beginning);
void snake(int speedDelay);
void sparkling(byte red, byte green, byte blue, int speedDelay);
void backlight_wheel(byte speed_ms);
void choose_color();
// Spectrum analyzer
void spectrum_analyser(byte backlightPulseTime);
void analyzerBacklight(int barht[], char *color, byte backlightPulseTime);
void analyzingProcess(char data[], char im[], int barht[]);
void analyserButtonCkeck();
void displayBars(int barht[], bool displayDirection);
void setDisplaySettings(int *brightness, bool *displayDirection);
// Chessboard
void init_sensor_array();
void sensor_acquisition();
void init_chessboard();
void initPieces();
void draw();
void chessboard_main();
int possibilities(int xtakeoff, int ytakeoff, int piece, int chessboard[8][8]);
void caseMarking(byte x, byte y);
// Serial
int serialTestWord(String wordToTest);
int serialTestWord(String wordsToTest[]);
// Debug
void testBuzzer();
void testPowerSupply();
void testLedStrip(Adafruit_NeoPixel strip);
void testLeds();
void testPot();
void testButtons();
// Features
void changeMode();
void chooseMode();
int temperature_check(int checkInterval);
bool leds_management();
byte buttonManagement(int button);
void buttonLightInit();
void buttonLightManagement();
void choose_color();
void led_flash(int output, int delayTime);
byte acquirePotValue255();
float acquirePotValuePercent();
byte calculateStepOfPotValue();
// Wi-Fi
void exchangeWithESP(SoftwareSerial ESP8266);
#endif
/**************************************************************
* File: spectrum_analyzer.cpp *
* Content: the whole spectrum analyzer process *
**************************************************************/
#include "Arduino.h"
#include "header.h"
#define SAMPLES 64 // 128
#define NB_ANALYZER_MODES 3
unsigned long t_backlightPulseTime;
bool backlightEnabled = true;
byte spectrumAnalyzerMode = 0;
extern unsigned long lastDuration;
bool displayDirection = false;
int brightness;
extern Adafruit_NeoPixel strip;
/*
* Runs all the functions needed to spectrum analyzer mode
*/
void spectrum_analyser(byte backlightPulseTime)
{
char color = 'r';
char im[SAMPLES];
char data[SAMPLES];
int barht[SAMPLES];
while(1)
{
setDisplaySettings(&brightness, &displayDirection);
analyserButtonCkeck();
analyzingProcess(data, im, barht);
displayBars(barht, displayDirection);
analyzerBacklight(barht, &color, backlightPulseTime);
}
}
/* ----------------------------------
* --------- GENERAL PROCESS --------
* ---------------------------------- */
/*
* analyze the audio signal thanks to FFT
* manage too the display rendering updrade
*/
void analyzingProcess(char data[], char im[], int barht[])
{
static int i, j;
int val;
// get audio data
for(i = 0; i < SAMPLES; i++)
{
val = analogRead(AUDIO_PIN); // 0-1023
data[i] = (char)(val/4 - 128); // store as char
im[i] = 0; // init all as 0
}
// run FFT
fix_fft(data, im, 5, 0);
// extract absolute value of data only, for 8 results
int divider = 4; // 2
for(i = 0; i < SAMPLES/divider; i++) // i<SAMPLES
barht[i] = (int)sqrt(data[i] * data[i] + im[i] * im[i]);
for(i = 0, j = 0; i < SAMPLES/divider; i++, j += 2)
barht[i] = barht[j] + barht[j + 1];
if(!leds_management()) {
for(int i=0; i<SAMPLES/divider; i++)
barht[i] = 0;
}
// upgrade rendering
if(true)
{
float coef = 2.1;
barht[0]*=0.6;
barht[1]*=coef;
barht[2]*=coef;
barht[3]*=coef;
barht[4]*=coef;
barht[5]*=coef;
barht[6]*=coef;
}
}
/*
* Update brightness and diaply direction
*/
void setDisplaySettings(int *brightness, bool *displayDirection)
{
if( acquirePotValue255() < 126) {
*brightness = 255-acquirePotValue255()*2;
*displayDirection = false;
}
else {
*brightness = (acquirePotValue255()-127)*2;
*displayDirection = true;
}
if(*brightness > 255) *brightness = 255;
strip.setBrightness( *brightness );
}
/*
* check whether a button is pushed
*/
void analyserButtonCkeck()
{
backlightEnabled = (buttonManagement(BT_POSS)==1) ? true : false;
if(buttonManagement(BT_MODE)==2)
spectrumAnalyzerMode++;
if(spectrumAnalyzerMode >= NB_ANALYZER_MODES)
spectrumAnalyzerMode=0;
}
/* ----------------------------------
* --- VISUAL ELEMENTS MANAGEMENT ---
* ---------------------------------- */
/*
* Diplay bars on LED matrix
*/
void displayBars(int barht[], bool displayDirection)
{
byte led;
float r,g,b,w;
switch(spectrumAnalyzerMode)
{
// multi color
case 0:
for (int i=0; i<8; i++) // each bar
{
for (int j=0; j<16; j+=1) // each LED of a bar
{
if(displayDirection)
led = LED_COUNT - 1 - (i * 16 + j);
else
led = (i * 16 + j);
if (j <= barht[i])
{
switch (j)
{
case 0: strip.setPixelColor(led, 50, 0, 200, 0); break; // purple
case 1: strip.setPixelColor(led, 10, 0, 200, 0); break;
case 2: strip.setPixelColor(led, 0, 20, 200, 0); break; // blue
case 3: strip.setPixelColor(led, 0, 60, 150, 0); break;
case 4: strip.setPixelColor(led, 0, 100, 90, 0); break; // cyan
case 5: strip.setPixelColor(led, 0, 140, 60, 0); break;
case 6: strip.setPixelColor(led, 0, 170, 30, 0); break; // green
case 7: strip.setPixelColor(led, 30, 150, 0, 0); break;
case 8: strip.setPixelColor(led, 60, 110, 0, 0); break; // yellow
case 9: strip.setPixelColor(led, 100, 80, 0, 0); break;
case 10: strip.setPixelColor(led, 130, 60, 0, 0); break; // orange
case 11: strip.setPixelColor(led, 160, 80, 0, 0); break;
case 12: strip.setPixelColor(led, 190, 40, 0, 0); break; // red
case 13:
case 14:
case 15: strip.setPixelColor(led, 200, 0, 0, 0); break; // red
}
}
else
strip.setPixelColor(led, 0, 0, 0, 0);
}
strip.show();
}
break;
// solid color
case 1:
r=0; g=0; b=0; w=255; // white
for (int i=0; i<8; i++) // each bar
{
for (int j=0; j<16; j++) // each LED of bar
{
if(displayDirection)
led = LED_COUNT - 1 - (i * 16 + j);
else
led = (i * 16 + j);
if (j <= barht[i])
{
if(!leds_management())
j=0;
strip.setPixelColor(led, r, g, b, w);
}
else
strip.setPixelColor(led, 0, 0, 0, 0);
}
strip.show();
}
break;
// solid color with residue
case 2:
r=0; g=0; b=0; w=255; // white
for (int i=0; i<8; i++) // each bar
{
for (int j=0; j<16; j++) // each LED of bar
{
if(displayDirection)
led = LED_COUNT - 1 - (i * 16 + j);
else
led = (i * 16 + j);
if (j < barht[i])
{
if(!leds_management())
j=0;
strip.setPixelColor(led, r, g, b, w);
}
else if (j == barht[i])
strip.setPixelColor(led, 200, 30, 30, 0); // residue
else
strip.setPixelColor(led, 0, 0, 0, 0);
}
strip.show();
}
break;
}
}
/*
* Flash the backlight on peaks
*/
void analyzerBacklight(int barht[], char *color, byte backlightPulseTime)
{
if(backlightEnabled)
{
if(barht[0]>8 || barht[1]>8 || barht[2]>8)
{
if(*color=='r')
analogWrite(BACKLIGHT_R, brightness);
else if(*color=='g')
analogWrite(BACKLIGHT_G, brightness);
else if(*color=='b')
analogWrite(BACKLIGHT_B, brightness);
}
if(millis()-t_backlightPulseTime > backlightPulseTime)
{
digitalWrite(BACKLIGHT_R, LOW);
digitalWrite(BACKLIGHT_G, LOW);
digitalWrite(BACKLIGHT_B, LOW);
if(*color=='r')
*color='g';
else if(*color=='g')
*color='b';
else if(*color=='b')
*color='r';
t_backlightPulseTime = millis();
}
}
else
{
digitalWrite(BACKLIGHT_R, LOW);
digitalWrite(BACKLIGHT_G, LOW);
digitalWrite(BACKLIGHT_B, LOW);
}
}
/**************************************************************
* File: led_animations.cpp *
* Content: all the functions running a LED strip animation *
**************************************************************/
#include "Arduino.h"
#include "header.h"
#include "characters.h"
extern unsigned long lastDuration;
extern Adafruit_NeoPixel strip;
/* -----------------------------------------------------
* ------------------ LED ANIMATIONS -------------------
* ----------------------------------------------------- */
/*
* Running lights : twinkle LEDs in yellow
*/
void runningLights(byte red, byte green, byte blue, int WaveDelay, bool endFlash)
{
int Position = 0;
for (int j = 0; j < LED_COUNT/3; j++)
{
Position++; // = 0; //Position + Rate;
for (int i = 0; i < LED_COUNT; i++)
{
setStripBrightness();
strip.setPixelColor(i, ((sin(i + Position) * 127 + 128) / 255)*red,
((sin(i + Position) * 127 + 128) / 255)*green,
((sin(i + Position) * 127 + 128) / 255)*blue,
0);
}
strip.show();
delay(WaveDelay);
}
if(endFlash)
{
float r = (float)red/255.0;
float g = (float)green/255.0;
float b = (float)blue/255.0;
for(int i=240; i>0; i--)
{
float lum = acquirePotValuePercent();
strip.fill( strip.Color(r*i*lum, g*i*lum, b*i*lum) );
strip.show();
delay(1);
}
}
}
/*
* Rainbow Cycle : vary a solid color
*/
byte * Wheel(byte WheelPos)
{
static byte c[3];
if (WheelPos < 85) {
c[0] = WheelPos * 3;
c[1] = 255 - WheelPos * 3;
c[2] = 0;
} else if (WheelPos < 170) {
WheelPos -= 85;
c[0] = 255 - WheelPos * 3;
c[1] = 0;
c[2] = WheelPos * 3;
} else {
WheelPos -= 170;
c[0] = 0;
c[1] = WheelPos * 3;
c[2] = 255 - WheelPos * 3;
}
return c;
}
void rainbowCycle(int SpeedDelay)
{
byte *c;
uint16_t i, j;
for (j = 0; j < 256; j++)
{
setStripBrightness();
for (i = 0; i < LED_COUNT; i++) {
c = Wheel(((i * 256 / LED_COUNT) + j) & 255);
strip.setPixelColor(i, *c, *(c + 1), *(c + 2));
}
strip.show();
delay(SpeedDelay);
}
}
/*
* Meteor Rain : displays a shooting star with a little streak
* Fade To Black : erases the steak
*/
void fadeToBlack(int ledNo, byte fadeValue)
{
#ifdef ADAFRUIT_NEOPIXEL_H
// NeoPixel
uint32_t oldColor;
uint8_t r, g, b;
int value;
oldColor = strip.getPixelColor(ledNo);
r = (oldColor & 0x00ff0000UL) >> 16;
g = (oldColor & 0x0000ff00UL) >> 8;
b = (oldColor & 0x000000ffUL);
r = (r <= 10) ? 0 : (int) r - (r * fadeValue / 256);
g = (g <= 10) ? 0 : (int) g - (g * fadeValue / 256);
b = (b <= 10) ? 0 : (int) b - (b * fadeValue / 256);
strip.setPixelColor(ledNo, r, g, b);
#endif
#ifndef ADAFRUIT_NEOPIXEL_H
// FastLED
leds[ledNo].fadeToBlackBy( fadeValue );
#endif
}
void meteorRain(byte red, byte green, byte blue, byte meteorSize, byte meteorTrailDecay, boolean meteorRandomDecay, int SpeedDelay)
{
for (int i = 0; i < LED_COUNT + LED_COUNT; i++)
{
// fade brightness all LEDs one step
for (int j = 0; j < LED_COUNT; j++)
{
if ( (!meteorRandomDecay) || (random(10) > 5) )
fadeToBlack(j, meteorTrailDecay );
}
// draw meteor
for (int j = 0; j < meteorSize; j++)
{
if ( ( i - j < LED_COUNT) && (i - j >= 0) )
strip.setPixelColor(i - j, red, green, blue);
}
setStripBrightness();
strip.show();
delay(SpeedDelay);
if(i > 160)
break;
}
}
/*
* French Flag : display the french flag
*/
void french_flag()
{
for(int rounds=0; rounds<2; rounds++)
{
for(int lum=0; lum<255; lum+=10)
{
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 16; j++)
{
setStripBrightness();
if (j < 5)
strip.setPixelColor(i * 16 + j, 0, 0, lum, 0);
else if (j > 10)
strip.setPixelColor(i * 16 + j, lum, 0, 0, 0);
else
strip.setPixelColor(i * 16 + j, 0, 0, 0, lum);
}
}
strip.show();
delay(2);
}
for(int lum=240; lum>0; lum-=10)
{
for (int i = 0; i < 8; i++)
{
for (int j = 0; j < 16; j++)
{
setStripBrightness();
if (j < 5)
strip.setPixelColor(i * 16 + j, 0, 0, lum, 0);
else if (j > 10)
strip.setPixelColor(i * 16 + j, lum, 0, 0, 0);
else
strip.setPixelColor(i * 16 + j, 0, 0, 0, lum);
}
}
strip.show();
delay(2);
}
}
}
/*
* Scroll Text : Allow us to scroll a string in both ways
*/
void scroll_text(char equipe, String chaine, int t_scrolling, int t_letterBreak, byte color[], byte stripColor[])
{
// Set the text color and the high & low strip color
int red, blue, green;
for(int i=0; i<3; i++)
{
red = color[0];
green = color[1];
blue = color[2];
for(int j=0; j<16; j++) {
strip.setPixelColor(0*16+j, stripColor[0], stripColor[1], stripColor[2]);
strip.setPixelColor(7*16+j, stripColor[0], stripColor[1], stripColor[2]);
}
}
//t_letterBreak = 0; // display time of a letter
//t_scrolling = 50; // scrolling speed (in ms)
// Scrolling process
int taille = chaine.length();
char mot[taille + 1];
chaine.toCharArray(mot, taille + 1);
for (int n = 0; n < taille - 1; n++) // loop that displays all letters following
{
// recovers the corresponding line in the array
int l;
for (l = 0; l < sizeof(lettres); l++)
{
if (lettres[l] == (char)mot[n])
break;
}
// we display and lock the letter on
for (int i = 2; i <= 7; i++) // displays only from 2nd to 7th line bc others are 0x00
{
byte c = lettres[l + 1 + (i - 2)]; // cuurent byte
byte invc = 0; // bool invert column
if (equipe == 1)
for (int colonne = 0; colonne < 8; colonne++) {
bool b = bitRead(c, 7 - colonne);
strip.setPixelColor((i - 1) * 16 + 2 * colonne, b*red, b*green, b*blue);
strip.setPixelColor((i - 1) * 16 + 2 * colonne + 1, b*red, b*green, b*blue);
}
else
{
// this part aims to make a glide reflectional symmetry of the sent pics.
// we start by inverting all line byte and then we send it to rows in descending ordrer.
invc = 0;
for (int b = 0; b < 8; b++)
{
// we make our own 2^j bc there was trouble with pow() function
int a = 0;
for (int k = 0; k <= (7 - b); k++) {
a *= 2;
if (a == 0)
a = 1;
}
invc = invc + ( ((c >> b) & 1) != 0) * a; // utilisation de booleen
}
for (int colonne = 0; colonne < 8; colonne++) {
bool b = bitRead(invc, 7-colonne);
strip.setPixelColor((8 - i) * 16 + 2 * colonne, b*red, b*green, b*blue);
}
}
setStripBrightness();
strip.show();
}
delay(t_letterBreak);
// Shifts all bits 1 by 1
for (int j = 1; j <= 8; j++) // shift on 8 bits
{
int m;
for (m = 0; m < sizeof(lettres); m++) // recovers 2nd letter location
{
if (n + 1 >= taille)
{
if (lettres[m] == (char)mot[0]) // goes get the 2nd letter
break;
}
else
{
if (lettres[m] == (char)mot[n + 1])
break;
}
}
byte s, t;
for (int i = 0; i < 6; i++) // one tour per row
{
s = lettres[l + 1 + i];
s = s << j; // shifts the current letter
t = (lettres[m + i + 1]); // and take the new one
s = s | (t >> 8 - j); // adds the next letter
if (equipe == 1) {
for (int colonne = 0; colonne < 8; colonne++) {
bool b = bitRead(s, 7 - colonne);
strip.setPixelColor((i + 1) * 16 + 2 * colonne, b*red, b*green, b*blue);
strip.setPixelColor((i + 1) * 16 + 2 * colonne + 1, b*red, b*green, b*blue);
}
}
else
{
// inverts again all row bytes
// and send it back in descending order
byte invc = 0;
for (int b = 0; b < 8; b++)
{
// we make our own 2^j bc there was trouble with pow() function
int a = 0;
for (int k = 0; k <= (7 - b); k++)
{
a *= 2;
if (a == 0)
a = 1;
}
invc = invc + ( ((s >> b) & 1) != 0) * a; // using booleans
}
for (int colonne = 0; colonne < 8; colonne++) {
bool b = bitRead(invc, 7-colonne);
strip.setPixelColor((6 - i) * 16 + 2 * colonne, b*red, b*green, b*blue);
}
}
setStripBrightness();
strip.show();
}
delay(t_scrolling);
}
}
return;
}
// ---------------------------------------------------------------------------------------
void random_filling(bool beginning)
{
bool cases[64];
for (int i = 0; i < 64; i++)
cases[i] = false;
int n;
float delayTime = 25, timeDecreasing = delayTime/17.0;
for (int i = 0; i < 64; i++)
{
do {
n = random(0, 64);
} while (cases[n]);
cases[n] = true;
for (int j = 0; j < 100; j += 5) {
strip.setPixelColor(n * 2, 0, j, j, 0);
strip.setPixelColor(n * 2 + 1, j, j, 0, 0);
setStripBrightness();
strip.show();
delay(delayTime);
}
if(beginning)
{
setStripBrightness();
if(delayTime=0 && i>50)
delay(1);
else if(delayTime=0 && i>40)
delay(3);
else
delay(5);
delayTime-=timeDecreasing;
if(delayTime<0)
delayTime=0;
}
}
for (int i = 0; i < 128; i++)
strip.setPixelColor(i, 0, 0, 0, 0);
setStripBrightness();
strip.show();
}
// -------------------------------------------------------------------------------
void snake(int speedDelay)
{
char x=0, y=0, k=7;
byte r1,g1,b1, r2,g2,b2;
for (byte rounds = 0; rounds < 8; rounds++) // nb of rounds
{
x=0; y=0; k=7;
if (rounds==0) {r1=250; g1=0; b1=40; r2=0; g2=80; b2=80; }
else if(rounds==1) {r1=0; g1=240; b1=40; r2=100; g2=70; b2=0; }
else if(rounds==2) {r1=230; g1=230; b1=230; r2=100; g2=0; b2=80; }
else if(rounds==3) {r1=170; g1=230; b1=80; r2=30; g2=20; b2=100;}
else if(rounds==4) {r1=100; g1=200; b1=10; r2=170; g2=50; b2=40; }
else if(rounds==5) {r1=100; g1=0; b1=230; r2=30; g2=180; b2=50; }
else if(rounds==6) {r1=190; g1=50; b1=230; r2=200; g2=100; b2=0; }
else if(rounds==7) {r1=150; g1=150; b1=200; r2=250; g2=0; b2=60; }
// permanent
for (byte n = 0; n < 9; n++) // 4 narrowing + 5 enlargements
{
for(byte c = 0; c < 4; c++) // 4 sides
{
for (byte i = 0; i < k; i++) // 7 cases
{
setStripBrightness();
if(n<4) strip.setPixelColor(y * 16 + 2 * x, r1, g1, b1);
else strip.setPixelColor(y * 16 + 2 * x, r2, g2, b2);
strip.show();
delay(speedDelay);
if(c==0) x++;
if(c==1) y++;
if(c==2) x--;
if(c==3) y--;
}
}
if(n<4) {x++; y++; k -= 2;} // narrowings
else {x--; y--; k += 2;} // enlargements
}
}
}
/*
* Generate random pixels
*/
void sparkling(byte red, byte green, byte blue, int speedDelay)
{
strip.clear();
int rounds = 100;
for(int i=0; i<rounds; i++)
{
setStripBrightness();
byte pixel1 = random(LED_COUNT), pixel2;
byte r = random(red), g = random(green), b = random(blue);
if(i>rounds/2) r/=2;
else b/=2;
strip.setPixelColor(pixel1, r, g, b);
if(pixel1%2==0) // even nb
pixel2 = pixel1 + 1;
else
pixel2 = pixel1 - 1;
strip.setPixelColor(pixel2,random(r),random(g),random(b));
strip.show();
delay(speedDelay);
strip.setPixelColor(pixel1,0,0,0);
strip.setPixelColor(pixel2,0,0,0);
}
}
/* -----------------------------------------------------
* ---------------- CONTROL FUNCTIONS ------------------
* ----------------------------------------------------- */
void setStripBrightness()
{
strip.setBrightness(acquirePotValue255());
}
/* -----------------------------------------------------
* ---------------- BACKLIGHT METHODS ------------------
* ----------------------------------------------------- */
unsigned long t_backlightTime;
byte lightStep=0, rValue=0, gValue=0, bValue=0;
void backlight_wheel(byte speed_ms)
{
byte max_value = MAX_VALUE_BACKLIGHT;
if(millis()-t_backlightTime > speed_ms)
{
switch(lightStep)
{
case 0: // red
rValue++;
if(rValue > max_value)
lightStep++;
break;
case 1: // jaune
gValue++;
if(gValue>max_value)
lightStep++;
break;
case 2: // cyan
rValue--;
bValue++;
if(rValue==0 || bValue > max_value)
lightStep++;
break;
case 3: // bleu
rValue = 0; bValue = max_value;
gValue--;
if(gValue==0)
lightStep++;
break;
case 4: // violet
rValue++;
if(rValue == max_value)
lightStep++;
break;
case 5: // vert
rValue--;
gValue++;
bValue--;
if(rValue==0 && gValue==max_value && bValue==0)
lightStep++;
else if(rValue<0) rValue = 0;
else if(gValue>max_value) gValue = max_value;
else if(bValue<0) bValue = 0;
break;
case 6: // rouge
rValue++;
gValue--;
if(rValue>max_value || gValue<1)
lightStep=0;
break;
}
analogWrite(BACKLIGHT_R , rValue);
analogWrite(BACKLIGHT_G , gValue);
analogWrite(BACKLIGHT_B , bValue);
t_backlightTime = millis();
}
}
/*
* Choose a solid color using the potentiometer
*/
void choose_color()
{
byte currentSolidColor; // r/g/b
bool stripControl = false;
static byte strip_r, strip_g, strip_b, bk_r, bk_g, bk_b;
strip.clear();
strip.show();
while(1)
{
// button check
stripControl = (buttonManagement(BT_POSS)==1) ? true : false;
if(buttonManagement(BT_MODE)==2)
{
currentSolidColor++;
if(currentSolidColor > 2)
currentSolidColor = 0;
}
// colors
if(stripControl)
{
switch(currentSolidColor)
{
case 0: bk_r = acquirePotValue255();
break;
case 1: bk_g = acquirePotValue255();
break;
case 2: bk_b = acquirePotValue255();
break;
}
analogWrite(BACKLIGHT_R, bk_r);
analogWrite(BACKLIGHT_G, bk_g);
analogWrite(BACKLIGHT_B, bk_b);
}
else
{
switch(currentSolidColor)
{
case 0: strip_r = acquirePotValue255();
break;
case 1: strip_g = acquirePotValue255();
break;
case 2: strip_b = acquirePotValue255();
break;
}
strip.fill( strip.Color(strip_r, strip_g, strip_b) );
strip.show();
}
delay(5);
}
}
/**************************************************************
* File: characters.h *
* Content: the mostly used ASCII characters on 8x6 bits *
**************************************************************/
byte lettres [500] = {
32, // space
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
B00000000,
66, // B
B01111100,
B01000010,
B01111100,
B01111100,
B01000010,
B01111100,
90, // Z
B01111110,
B00000100,
B00001000,
B00010000,
B00100000,
B01111110,
33, // !
B00010000,
B00010000,
B00010000,
B00010000,
B00000000,
B00010000,
35, // #
B00000000,
B00100100,
B01111110,
B00100100,
B01111110,
B00100100,
39, // '
B00000000,
B00000100,
B00000100,
B00000000,
B00000000,
B00000000,
45, // -
B00000000,
B00000000,
B00000000,
B00111100,
B00000000,
B00000000,
63, // ?
B00111100,
B01000010,
B00000100,
B00001000,
B00000000,
B00010000,
64, // @
B00111100,
B10000001,
B10011101,
B10011110,
B10000000,
B01111100,
65, // A
B00011000,
B00100100,
B00100100,
B01111110,
B01000010,
B01000010,
97, // a
B00000000,
B01111100,
B00000010,
B00111110,
B01000010,
B01111100,
98, // b
B01000000,
B01000000,
B01111000,
B01000100,
B01000100,
B01111000,
67, // C
B00111110,
B01000000,
B01000000,
B01000000,
B01000000,
B00111100,
99, // c
B00000000,
B00000000,
B00111100,
B01000000,
B01000000,
B00111100,
68, // D
B01111000,
B01000100,
B01000010,
B01000010,
B01000100,
B01111000,
100, // d
B00000010,
B00000010,
B00011110,
B00100010,
B00100010,
B00011110,
69, // E
B01111100,
B01000000,
B01110000,
B01110000,
B01000000,
B01111100,
101, // e
B00000000,
B00111000,
B01000100,
B01111000,
B01000000,
B00111100,
70, // F
B01111100,
B01000000,
B01110000,
B01110000,
B01000000,
B01000000,
102, // f
B00000000,
B00011100,
B00100000,
B00110000,
B00100000,
B00100000,
71, // G
B00011110,
B00100000,
B01000000,
B01001110,
B01000100,
B00111000,
103, // g
B00011100,
B00100010,
B00011110,
B00000010,
B00100110,
B00011110,
72, // H
B01000010,
B01000010,
B01111110,
B01111110,
B01000010,
B01000010,
104, // h
B00000000,
B01000000,
B01000000,
B01111000,
B01000100,
B01000100,
73, //I
B00111000,
B00010000,
B00010000,
B00010000,
B00010000,
B00111000,
105, //i
B00000000,
B00010000,
B00000000,
B00010000,
B00010000,
B00010000,
74, // J
B00011110,
B00000100,
B00000100,
B00000100,
B01000100,
B00111000,
106, // j
B00011000,
B00101000,
B01001000,
B00011000,
B01001000,
B00111000,
75, // K
B01000100,
B01011000,
B01100000,
B01100000,
B01011000,
B01000100,
107, // k
B01000000,
B01000000,
B01111000,
B01001000,
B01101100,
B01000100,
76, // L
B01000000,
B01000000,
B01000000,
B01000000,
B01000000,
B01111100,
108, // l
B00000000,
B00010000,
B00010000,
B00010000,
B00010000,
B00010000,
77, // M
B01100110,
B01011010,
B01000010,
B01000010,
B01000010,
B01000010,
109, // m
B00000000,
B00000000,
B00000000,
B01101100,
B10010010,
B10010010,
78, // N
B01000010,
B01100010,
B01010010,
B01001010,
B01000110,
B01000010,
110, // n
B00000000,
B00000000,
B01111100,
B01000010,
B01000010,
B01000010,
79, // O
B00000000,
B00111100,
B01000010,
B01000010,
B01000010,
B00111100,
111, // o
B00000000,
B00000000,
B00111100,
B01000010,
B01000010,
B00111100,
80, // P
B01111100,
B01000010,
B01000010,
B01111100,
B01000000,
B01000000,
112, // p
B00000000,
B01111000,
B01000100,
B01111000,
B01000000,
B01000000,
81, // Q
B00111100,
B01000010,
B01000010,
B01001010,
B00111100,
B00000100,
113, // q
B00000000,
B00111100,
B01000100,
B00111100,
B00000100,
B00000100,
82, // R
B01111100,
B01000010,
B01000010,
B01111100,
B01000010,
B01000010,
114, // r
B00000000,
B00000000,
B01111100,
B01000010,
B01000000,
B01000000,
83, // S
B00111100,
B01000000,
B00110000,
B00001100,
B00000010,
B00111100,
115, // s
B00000000,
B00111110,
B01000000,
B00111100,
B00000010,
B01111100,
84, // T
B01111100,
B00010000,
B00010000,
B00010000,
B00010000,
B00010000,
116, // t
B00000000,
B00100000,
B00100000,
B00111000,
B00100000,
B00011100,
85, // U
B01000010,
B01000010,
B01000010,
B01000010,
B01000010,
B00111100,
117, // u
B00000000,
B00000000,
B01000010,
B01000010,
B01000010,
B00111100,
86, // V
B01000010,
B01000010,
B01000100,
B00100100,
B00100100,
B00011000,
118, // v
B00000000,
B00000000,
B01000010,
B01000010,
B00100100,
B00011000,
87, // W
B00000000,
B01000010,
B01000010,
B01000010,
B01011010,
B01100110,
119, // w
B00000000,
B00000000,
B00000000,
B01000100,
B01010100,
B00101000,
87, // X
B00000000,
B01000100,
B00101000,
B00010000,
B00101000,
B01000100,
87, // x
B00000000,
B01000100,
B00101000,
B00010000,
B00101000,
B01000100,
89, // Y
B01000010,
B00100100,
B00011000,
B00010000,
B00100000,
B01000000,
121, // y
B00000000,
B01000100,
B00101000,
B00010000,
B00100000,
B01000000,
122, // z
B00000000,
B00111110,
B00000100,
B00001000,
B00010000,
B00111110
};
/**************************************************************
* File: chessboard_mode.cpp *
* Content: the functions used to run the chessboard mode *
**************************************************************/
#include "Arduino.h"
#include "header.h"
#define COLOR_VALUE 150
#define MARKING_COLOR_R 50
#define MARKING_COLOR_G 100
#define MARKING_COLOR_B 0
int chessboard[8][8];
bool bin_chessb[8][8];
int sensor_array[8][8];
bool everInit = false;
int xtakeoff, ytakeoff, xput, yput;
int piece;
int n = 0, player = 1;
bool validation = false, p = false;
int currentPossX[100], currentPossY[100], z=0; // z=indice de possActuelles
extern Adafruit_NeoPixel strip;
/* -----------------------------------------------------
* -------------- ILS SENSOR ACQUISITION ---------------
* ----------------------------------------------------- */
/*
* Initialize the ILS sensor array and reset sensor matrix counter
*/
void init_sensor_array()
{
digitalWrite(CD4017_CLK, LOW);
while(analogRead(CD4017_Q7_IN) < 300) // reset CD4017
{
digitalWrite(CD4017_CLK,HIGH);
delay(5);
digitalWrite(CD4017_CLK,LOW);
}
for(int i=0;i<8;i++) // init chessboard array
for(int j=0;j<8;j++)
sensor_array[i][j]=0;
}
/*
* ILS signals recovery
*/
void sensor_acquisition()
{
for(int checkRow=0; checkRow<8; checkRow++)
{
// Select one row
digitalWrite(CD4017_CLK, HIGH); // send a rising edge to CD4017
// Check each column
for(byte checkColumn=0; checkColumn<8; checkColumn++)
{
byte i=0;
digitalWrite(CD4051_A, ( ((checkColumn >> i) & 1) !=0) ); i++;
digitalWrite(CD4051_B, ( ((checkColumn >> i) & 1) !=0) ); i++;
digitalWrite(CD4051_C, ( ((checkColumn >> i) & 1) !=0) );
sensor_array[checkRow][checkColumn] = (digitalRead(CD4051_X)==HIGH) ? 1 : 0;
}
digitalWrite(CD4017_CLK,LOW);
delay(2);
}
// Display / Unnecessary
/*
for(int i=0;i<8;i++)
{
for(int j=0;j<8;j++)
{
Serial.print(sensor_array[i][j]); Serial.print(" ");
strip.setPixelColor(i*16+2*j, sensor_array[i][j]*250, 0, 0);
strip.setPixelColor(i*16+2*j+1, sensor_array[i][j]*200, 0, 0);
}
Serial.println("");
}
Serial.println("\n\n");
setStripBrightness();
strip.show();
*/
}
/* -----------------------------------------------------
* ------------- CHESSBOARD INITIALIZATION -------------
* ----------------------------------------------------- */
/*
* Initialize chessboard array
*/
void initPieces()
{
/**
* Chessboard initialization
* 1st player below (white), 2nd player up (black)
* Rook 0, Knight 1, Bishop 2, King 3, Queen 4, Pawn 5
**/
int chess_init[8][8] = {02,12,22,42,32,22,12,02,
52,52,52,52,52,52,52,52,
60,60,60,60,60,60,60,60,
60,60,60,60,60,60,60,60,
60,60,60,60,60,60,60,60,
60,60,60,60,60,60,60,60,
51,51,51,51,51,51,51,51,
01,11,21,41,31,21,11,01
};
for(int i=0;i<8;i++) {
for(int j=0;j<8;j++) {
chessboard[i][j]=chess_init[i][j];
if(chessboard[i][j]!=60)
bin_chessb[i][j] = true;
else
bin_chessb[i][j] = false;
}
}
}
/*
* Draw the chessboard array on the LED matrix
*/
void draw()
{
//everInit = true;
if(everInit)
{
for(int i=0;i<8;i++)
{
for(int j=0; j<8; j++)
{
if(chessboard[i][j]!=60) {
strip.setPixelColor(i*16+2*j, 0,0,255);
strip.setPixelColor(i*16+2*j+1, 0,0,255);
}
}
}
setStripBrightness();
strip.show();
}
else
{
// show cases which must be occupied in red
for(int i=0;i<8;i++){
for(int j=0; j<8; j++) {
if(chessboard[i][j]!=60) {
strip.setPixelColor(i*16+2*j, 255,0,0);
strip.setPixelColor(i*16+2*j+1, 255,0,0);
}
}
}
// wait for all the pieces to be placed
byte nbOfCorrectPieces;
do{
sensor_acquisition();
nbOfCorrectPieces = 0;
for(int i=0;i<8;i++){
for(int j=0; j<8; j++) {
// piece is here
if(chessboard[i][j]!=60 && sensor_array[i][j]) {
strip.setPixelColor(i*16+2*j, 0,255,0); // turn case in green
strip.setPixelColor(i*16+2*j+1, 0,255,0);
nbOfCorrectPieces++;
}
// piece is not here
else if(/*chessboard[i][j]!=60 && !*/sensor_array[i][j]) {
strip.setPixelColor(i*16+2*j, 255,0,0);
strip.setPixelColor(i*16+2*j+1, 255,0,0);
}
strip.show();
}
}
}while(nbOfCorrectPieces<32);
/* consider here that all pieces are correctly placed on the board */
byte maxValue=150;
if(nbOfCorrectPieces==64) {
for(int v=maxValue; v>=0; v--) {
for(int i=0; i<8; i++) {
for(int j=0; j<8; j++) {
strip.setPixelColor(i*16+2*j, 0,v,0,0);
strip.setPixelColor(i*16+2*j+1, 0,v,0,0);
setStripBrightness();
strip.show();
delay(10);
}
}
}
for(int v=0; v<maxValue; v++) {
for(int i=0; i<8; i++) {
for(int j=0; j<8; j++) {
strip.setPixelColor(i*16+2*j, 0,v,0,0);
strip.setPixelColor(i*16+2*j+1, 0,v,0,0);
setStripBrightness();
strip.show();
delay(10);
}
}
}
}
for(int i=0; i<8; i++) {
for(int j=0; j<8; j++) {
strip.setPixelColor(i*16+2*j, COLOR_VALUE,0,0,0);
strip.setPixelColor(i*16+2*j+1, COLOR_VALUE,0,0,0);
delay(10);
}
}
setStripBrightness();
strip.show();
}
}
/* -----------------------------------------------------
* ---------------- CHESSBOARD PROCESS -----------------
* ----------------------------------------------------- */
/*
* Analyzes pieces moves and draw them
*/
void chessboard_main()
{
// wait for a movement by comparing sensor_array and the last saved chessboard
for(int x=0; x<8; x++)
{
for(int y=0; y<8; y++)
{
if(bin_chessb[x][y] != sensor_array[x][y])
{
if(sensor_array[x][y] == 0) // removed piece
{
xtakeoff = x;
ytakeoff = y;
strip.setPixelColor(x*16+2*y, 0,0,0,0);
strip.setPixelColor(x*16+2*y+1, 0,0,0,0);
if( (chessboard[x][y]%10==1 && player==1) || (chessboard[x][y]%10==2 && player==2) )
p = true;
if(p==true)
piece = possibilities(xtakeoff, ytakeoff, chessboard[xtakeoff][ytakeoff], chessboard);
}
else // put back piece
{
xput = x;
yput = y;
strip.setPixelColor(x*16+2*y, COLOR_VALUE,0,0,0);
strip.setPixelColor(x*16+2*y+1, COLOR_VALUE,0,0,0);
setStripBrightness();
strip.show();
piece = possibilities(xput, yput, chessboard[xput][yput], chessboard);
for(int i=0; i<z; i++) // comparison between wished move and possibilities
{
if(!(xput==xtakeoff && yput==ytakeoff)) // can't move to the same square
{
if(currentPossX[i]==xput && currentPossY[i] ==xput) // in agreement with possibilities ?
validation=true;
// invalid case : led animation
else {
for(int m=0; m<2; m++) {
strip.setPixelColor(x*16+2*y, 0,0,0,0);
strip.setPixelColor(x*16+2*y+1, 0,0,0,0);
setStripBrightness();
strip.show();
delay(200);
strip.setPixelColor(x*16+2*y, COLOR_VALUE,0,0,0);
strip.setPixelColor(x*16+2*y+1, COLOR_VALUE,0,0,0);
setStripBrightness();
strip.show();
delay(200);
strip.setPixelColor(x*16+2*y, 0,0,0,0);
strip.setPixelColor(x*16+2*y+1, 0,0,0,0);
setStripBrightness();
strip.show();
}
}
}
else
p=false;
}
// color management
if(validation==true && p==true)
{
// move on enemy case
if( (chessboard[xput][yput]%10==1 && piece%10==2) || (chessboard[xput][yput]%10==2 && piece%10==2) )
{
chessboard[xput][yput] = piece;
chessboard[xtakeoff][ytakeoff] = 60;
// recuperation(echiquier);
// ecritureLogs(n,piece,echiquier[xzoneup][yzoneup],xzone, yzone,xzoneup,yzoneup,true);
// led animation if piece is eaten
for(int m=0; m<2; m++) {
strip.setPixelColor(x*16+2*y, 0,0,0,0);
strip.setPixelColor(x*16+2*y+1, 0,0,0,0);
setStripBrightness();
strip.show();
delay(200);
strip.setPixelColor(x*16+2*y, COLOR_VALUE,0,0,0);
strip.setPixelColor(x*16+2*y+1, COLOR_VALUE,0,0,0);
setStripBrightness();
strip.show();
delay(200);
}
}
// move on unoccupied case
if(chessboard[xput][yput] == 60)
{
chessboard[xput][yput] = piece;
chessboard[xtakeoff][ytakeoff] = 60;
// recuperation(echiquier);
// ecritureLogs(n,piece,echiquier[xzoneup][yzoneup],xzone, yzone,xzoneup,yzoneup,true);
}
// next round
if(player==1)
player = 2;
else
player = 1;
p = false;
validation = false;
}
}
}
}
}
}
/*
* Cast play possibilities when a piece is pulled
*/
int possibilities(int xtakeoff, int ytakeoff, int piece, int chessboard[8][8])
{
int x, y, parallel=0;
z=0;
for(int i=0; i<100; i++) {
currentPossX[i] = 0;
currentPossY[i] = 0;
}
int knightx[8] = {xtakeoff+2, xtakeoff+1, xtakeoff-1, xtakeoff-2, xtakeoff-2, xtakeoff-1, xtakeoff+1, xtakeoff+2};
int knighty[8] = {ytakeoff-1, ytakeoff-2, ytakeoff-2, ytakeoff-1, ytakeoff+1, ytakeoff+2, ytakeoff+2, ytakeoff+1};
int kingx[8] = {xtakeoff+1, xtakeoff+1, xtakeoff, xtakeoff-1, xtakeoff-1, xtakeoff-1, xtakeoff, xtakeoff+1};
int kingy[8] = {ytakeoff, ytakeoff-1, ytakeoff-1, ytakeoff-1, ytakeoff, ytakeoff+1, ytakeoff+1, ytakeoff+1};
int temp = piece;
debut:
switch(temp)
{
case 01: // -------------------------------------------- ROOK ------------------------------------------
case 02:
for(int t=0; t<4; t++)
{
for(int i=1;i<8;i++)
{
if(t==0) {
x = xtakeoff+i;
y = ytakeoff;
}
else if(t==1) {
x = xtakeoff-i;
y = ytakeoff;
}
else if(t==2) {
x = xtakeoff;
y = ytakeoff+i;
}
else {
x = xtakeoff;
y = ytakeoff-i;
}
if(chessboard[x][y]%10==1) // studied case
{
if(piece%10==2) // team of the played case
{
caseMarking(x, y);
currentPossX[z] = x;
currentPossY[z] = y;
z++;
break;
}
else
break;
}
else if(chessboard[x][y]%10==2)
{
if(piece%10==1)
{
caseMarking(x, y);
currentPossX[z] = x;
currentPossY[z] = y;
z++;
break;
}
else
break;
}
else
{
caseMarking(x, y);
currentPossX[z] = x;
currentPossY[z] = y;
z++;
}
}
}
if(parallel==1)
{
temp=21;
goto debut;
}
break;
case 11: // -------------------------------------------- KNIGHT ------------------------------------------
case 12:
for(int i=0;i<8;i++)
{
if( (( (chessboard[knightx[i]][knighty[i]]%10==1 || chessboard[knightx[i]][knighty[i]]==60) && piece%10==2) )
|| ((chessboard[knightx[i]][knighty[i]]%10==2 || chessboard[knightx[i]][knighty[i]]==60) && piece%10==1 ) )
{
caseMarking(knightx[i], knighty[i]);
currentPossX[z] = knightx[i];
currentPossY[z] = knighty[i];
z++;
}
}
break;
case 21: // -------------------------------------------- BISHOP ------------------------------------------
case 22:
for(int dir=0; dir<4; dir++)
{
for(int i=1; i<8; i++)
{
if(dir==0) {
x = xtakeoff+i;
y = ytakeoff+i;
}
else if(dir==1) {
x = xtakeoff-i;
y = ytakeoff+i;
}
else if(dir==2) {
x = xtakeoff+i;
y = ytakeoff-i;
}
else {
x = xtakeoff-i;
y = ytakeoff-i;
}
if(piece%10==1) // team n1 bishop
{
if(chessboard[x][y]%10==1)
break;
else if(chessboard[x][y]%10==2)
{
caseMarking(x, y);
currentPossX[z] = x;
currentPossY[z] = y;
z++;
break;
}
else
{
caseMarking(x, y);
currentPossX[z] = x;
currentPossY[z] = y;
z++;
}
}
else // team n2 bishop
{
if(chessboard[x][y]%10==2)
break;
else if(chessboard[x][y]%10==1)
{
caseMarking(x, y);
currentPossX[z] = x;
currentPossY[z] = y;
z++;
break;
}
else
{
caseMarking(x, y);
currentPossX[z] = x;
currentPossY[z] = y;
z++;
}
}
}
}
break;
case 31: // -------------------------------------------- KING ------------------------------------------
case 32:
for(int i=0;i<8;i++)
{
if((( (chessboard[kingx[i]][kingy[i]]%10==1 || chessboard[kingx[i]][kingy[i]]==60) && piece%10==2))
|| ((chessboard[kingx[i]][kingy[i]]%10==2 || chessboard[kingx[i]][kingy[i]]==60) && piece%10==1 ) )
{
caseMarking(kingx[i],kingy[i]);
currentPossX[z] = kingx[i];
currentPossY[z] = kingy[i];
z++;
}
}
break;
case 41: // -------------------------------------------- QUEEN ------------------------------------------
case 42:
temp=01;
parallel=1;
goto debut;
break;
case 51: // -------------------------------------------- PAWN ------------------------------------------
case 52:
if(piece%10==1) // team n1 pawn
{
if(ytakeoff==6) // pawn never played (starting line)
{
for(int i=1;i<=2;i++)
{
if(chessboard[xtakeoff][ytakeoff-i]==60)
{
caseMarking(xtakeoff,ytakeoff-i);
currentPossX[z] = xtakeoff;
currentPossY[z] = ytakeoff-i;
z++;
}
}
}
else // pawn already played
{
if(chessboard[xtakeoff][ytakeoff-1]==60)
{
caseMarking(xtakeoff,ytakeoff-1);
currentPossX[z] = xtakeoff;
currentPossY[z] = ytakeoff-1;
z++;
}
}
for(int i=0;i<2;i++) // diagonal piece to eat
{
if(i==0)
x = xtakeoff-1;
else
x = xtakeoff+1;
if(chessboard[x][ytakeoff-1]%10==2)
{
caseMarking(x,ytakeoff-1);
currentPossX[z] = x;
currentPossY[z] = ytakeoff-1;
z++;
}
}
}
else // team n2 pawn
{
if(ytakeoff==1) // pawn never played (starting line)
{
for(int i=1;i<=2;i++)
{
if(chessboard[xtakeoff][ytakeoff+1]==60)
{
caseMarking(xtakeoff,ytakeoff+i);
currentPossX[z] = xtakeoff;
currentPossY[z] = ytakeoff+i;
z++;
}
}
}
else // pawn already played
{
if(chessboard[xtakeoff][ytakeoff+1]==60)
{
caseMarking(xtakeoff,ytakeoff+1);
currentPossX[z] = xtakeoff;
currentPossY[z] = ytakeoff+1;
z++;
}
}
for(int i=0;i<2;i++) // diagonal piece to eat
{
if(i==0)
x = xtakeoff-1;
else
x = xtakeoff+1;
if(chessboard[x][ytakeoff+1]%10==1)
{
caseMarking(x, ytakeoff+1);
currentPossX[z] = x;
currentPossY[z] = ytakeoff+1;
z++;
}
}
}
break;
default:
break;
}
return piece;
}
/*
* Show the studied case
*/
void caseMarking(byte x, byte y)
{
strip.setPixelColor(x*16+2*y, MARKING_COLOR_R, MARKING_COLOR_G, MARKING_COLOR_B, 0);
strip.setPixelColor(x*16+2*y+1, MARKING_COLOR_R, MARKING_COLOR_G, MARKING_COLOR_B, 0);
strip.show();
}
/**************************************************************
* File: features.cpp *
* Content: functions controlling elements serving as HMI *
**************************************************************/
#include "Arduino.h"
#include "header.h"
/*
* Check if card temperature don't exceed a 50C, else trigger an alert
*/
unsigned long t_timeTemperature;
int temperature_check(int checkInterval)
{
if(millis()-t_timeTemperature > checkInterval)
{
float temperature = (analogRead(LM35_RAW_VOUT) - analogRead(LM35_VIRTUAL_GND)) * (5.0 / 1023.0 * 100.0);
//Serial.println("raw: " + (String)analogRead(LM35_RAW_VOUT) + " virtual gnd: " + (String)analogRead(LM35_VIRTUAL_GND));
if(temperature > MAX_TEMP){
tone(BUZZER, 2000, 500);
led_flash(LED_WIFI, 100);
led_flash(LED_BLUETOOTH, 100);
}
t_timeTemperature = millis();
return temperature;
}
return;
}
/*
* Manage the Wi-Fi and Bluetooth LEDs
*/
unsigned long timeLedBluetooth;
bool wifiState = false;
bool bluetoothLedState, wifiLedState;
/*
* Manage the Bluetooth LED and return 0 or 1 depending on the Bluetooth state
*/
bool leds_management()
{
// Bluetooth LED
//Serial.println(analogRead(LED_BLUETOOTH_IN));
// if there's a signal
if(analogRead(LED_BLUETOOTH_IN) > 100)
{
digitalWrite(LED_BLUETOOTH, HIGH);
return true;
}
// if there's no signal
else
{
if(millis()-timeLedBluetooth > 200) {
if(digitalRead(LED_BLUETOOTH)==HIGH)
digitalWrite(LED_BLUETOOTH, LOW);
else
digitalWrite(LED_BLUETOOTH, HIGH);
timeLedBluetooth = millis();
}
return false;
}
}
/*
* Return the potentiometer value as a percentage
*/
float acquirePotValuePercent()
{
float potStep = calculateStepOfPotValue();
potStep/=24.0;
return (float)potStep;
}
/*
* Return the potentiometer value out of 255
*/
byte acquirePotValue255()
{
byte potStep = calculateStepOfPotValue();
potStep*=(255.0/24.0);
//Serial.println(potStep*4);
return potStep;
}
/*
* Returns the step of the pot value (from 0 to 11)
*/
byte calculateStepOfPotValue()
{
int value = analogRead(POTENTIOMETER);
// value between 0 and 100
byte s=0;
if(value>150) s++;
if(value>230) s++;
if(value>290) s++;
if(value>305) s++;
if(value>310) s++;
if(value>315) s++;
if(value>320) s++;
if(value>325) s++;
if(value>330) s++;
if(value>335) s++;
if(value>340) s++;
if(value>345) s++;
if(value>350) s++;
if(value>355) s++;
if(value>370) s++;
if(value>385) s++;
if(value>410) s++;
if(value>450) s++;
if(value>500) s++;
if(value>580) s++;
if(value>650) s++;
if(value>750) s++;
if(value>891) s++;
//Serial.println(value);
return s;
}
/*
* Receives a button name and returns a result in terms of the duration of the last push
*
* For poss button : returns 1 on falling edge, else 0
* For mode button : returns 0 for no push, 1 for quick push and 2 for long
*/
extern bool possibilitiesEnabled;
extern unsigned long lastDuration;
byte buttonManagement(int button)
{
// Bt mode
if(button == BT_MODE)
{
// no new push
if(lastDuration == 0)
return 0;
// quick push
else if(lastDuration > WAITING_TIME_BT) {
lastDuration = 0;
return 2;
}
}
// Bt poss
else if(button == BT_POSS)
{
bool buttonState = digitalRead(BT_POSS);
if(buttonState == LOW)
return 1;
else
return 0;
}
return false;
}
/*
* Manages indicator lights of buttons
*/
unsigned long t_buttonLedTime;
extern byte currentMode;
/* only for initialization */
void buttonLightInit()
{
// Bt mode
digitalWrite(LED_BT_MODE, HIGH);
// Bt poss
if(digitalRead(BT_POSS) == LOW)
digitalWrite(LED_BT_POSS, HIGH);
else
digitalWrite(LED_BT_POSS, LOW);
}
/* on edge */
void buttonLightManagement()
{
// Bt mode
/*
if(millis()-t_buttonLedTime > (currentMode*2)+1) // light of the mode button
{
analogWrite(LED_BT_MODE, lumValueModeBt);
if(lumValueModeBt > 253)
isRisingLumModeBt = false;
else if(lumValueModeBt < 4)
isRisingLumModeBt = true;
if(isRisingLumModeBt)
lumValueModeBt += 2;
else
lumValueModeBt -= 2;
t_buttonLedTime = millis();
}
*/
// Bt poss
bool buttonState = digitalRead(BT_POSS);
if(buttonState == LOW)
digitalWrite(LED_BT_POSS, HIGH);
else
digitalWrite(LED_BT_POSS, LOW);
}
/*
* Flash a LED passed in parameter
*/
unsigned long timeLedFlash;
void led_flash(int output, int delayTime)
{
if(millis()-timeLedFlash > delayTime)
{
byte outputState = digitalRead(output);
digitalWrite(output, !outputState);
timeLedFlash = millis();
}
}
/**************************************************************
* File: debug.cpp *
* Content: f made to test some elements using the Serial *
**************************************************************/
#include "header.h"
/*
* Button Test : check if pushs on pushbuttons are detected
*/
void testButtons()
{
Serial.println(F("Push one of the buttons."));
delay(50);
for(int i=0; i<2; i++)
{
Serial.println(F("Push one of the buttons."));
delay(50);
while(digitalRead(BT_MODE)==HIGH && digitalRead(BT_POSS)==HIGH );
if(digitalRead(BT_MODE)==HIGH) {
Serial.println(F("MODE button pushed."));
while(digitalRead(BT_MODE)==LOW);
}
else if(digitalRead(BT_POSS)==HIGH) {
Serial.println(F("POSS button pushed."));
while(digitalRead(BT_POSS)==LOW);
}
}
}
/*
* Buzzer Test : emits a sound signal on a large frequency range
*/
void testBuzzer()
{
double fDo = 32.70, fMi = 41.20, fSol = 49.00;
for(int r=1; r<11; r++)
{
Serial.println(F("Listen the C major chord - Range ")); Serial.println(r); Serial.println(F("..."));
tone(BUZZER, fDo*r, 100);
delay(150);
tone(BUZZER, fMi*r, 100);
delay(150);
tone(BUZZER, fSol*r, 100);
delay(150);
}
}
/*
* LEDs Test : blinks WiFi and Bluetooth LEDs
*/
void testLeds()
{
Serial.println(F("WiFi led blinking..."));
for(int i=0; i<8; i++) {
digitalWrite(LED_WIFI, HIGH);
delay(200);
digitalWrite(LED_WIFI, LOW);
delay(200);
}
Serial.println(F("Bluetooth led blinking..."));
for(int i=0; i<8; i++) {
digitalWrite(LED_BLUETOOTH, HIGH);
delay(200);
digitalWrite(LED_BLUETOOTH, LOW);
delay(200);
}
}
/*
* LED Strip Test : runs the Rainbow Circle animation on the strip
*/
void testLedStrip(Adafruit_NeoPixel strip)
{
Serial.print(F("Testing power supply... "));
delay(50);
if(analogRead(ALIM)<200) {
Serial.println(F("KO\nPlease check that the external power supply is well plugged in."));
return;
}
else
Serial.println(F("OK"));
Serial.println(F("Starting led strip... "));
strip.begin();
delay(50);
Serial.println(F("Look at the Rainbow Cycle animation..."));
rainbowCycle(8);
Serial.println(F("If you can see it, the test is OK, else no."));
}
/*
* Potentiometer Test : displays potentiometer value for 15 seconds
*/
void testPot()
{
Serial.println(F("While 15 sec, potentiometer values will be printed at screen. Move it and observe values."));
delay(150);
unsigned long time_testPotard = millis(), time_display = millis();
while(millis()-time_testPotard < 15000)
{
if(millis()-time_display > 500) {
Serial.print(F("Value: ")); Serial.print(analogRead(POTENTIOMETER)); Serial.println(F(" / 1023"));
time_display = millis();
}
}
}
/*
* Power Supply Test : check whether an external power supply is plugged on or not
*/
void testPowerSupply()
{
if(analogRead(ALIM)<200)
Serial.println(F("No external power supply has been detected.\nUSB powered."));
else
{
Serial.println(F("External power supply has been detected. "));
Serial.print(F("Input voltage : ~")); Serial.print((float)analogRead(ALIM)*0.031, 2); Serial.println(F("V"));
}
}
/**************************************************************
* File: wifi.cpp *
* Content: f used to echange data between Serial & ESP *
**************************************************************/
#include "Arduino.h"
#include "header.h"
/*
* Exchange data sent by Serial to ESP and vice versa
*/
void exchangeWithESP(SoftwareSerial ESP8266)
{
if(!ENABLE_WIFI)
return;
if (ESP8266.available()) {
Serial.write(ESP8266.read());
}
if (Serial.available()) {
ESP8266.write(Serial.read());
}
}
Comments
Please log in or sign up to comment.