I love pain
parent
cdaec86e47
commit
cce4bee718
@ -0,0 +1,209 @@
|
||||
/*
|
||||
FlexiTimer2.h - Using timer2 with a configurable resolution
|
||||
Wim Leers <work@wimleers.com>
|
||||
|
||||
Based on MsTimer2
|
||||
Javier Valencia <javiervalencia80@gmail.com>
|
||||
|
||||
History:
|
||||
16/Dec/2011 - Added Teensy/Teensy++ support (bperrybap)
|
||||
note: teensy uses timer4 instead of timer2
|
||||
25/April/10 - Based on MsTimer2 V0.5 (from 29/May/09)
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "FlexiTimer2.h"
|
||||
|
||||
unsigned long FlexiTimer2::time_units;
|
||||
void (*FlexiTimer2::func)();
|
||||
volatile unsigned long FlexiTimer2::count;
|
||||
volatile char FlexiTimer2::overflowing;
|
||||
volatile unsigned int FlexiTimer2::tcnt2;
|
||||
|
||||
void FlexiTimer2::set(unsigned long ms, void (*f)()) {
|
||||
FlexiTimer2::set(ms, 0.001, f);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param resolution
|
||||
* 0.001 implies a 1 ms (1/1000s = 0.001s = 1ms) resolution. Therefore,
|
||||
* 0.0005 implies a 0.5 ms (1/2000s) resolution. And so on.
|
||||
*/
|
||||
void FlexiTimer2::set(unsigned long units, double resolution, void (*f)()) {
|
||||
float prescaler = 0.0;
|
||||
|
||||
if (units == 0)
|
||||
time_units = 1;
|
||||
else
|
||||
time_units = units;
|
||||
|
||||
func = f;
|
||||
|
||||
#if defined (__AVR_ATmega168__) || defined (__AVR_ATmega48__) || defined (__AVR_ATmega88__) || defined (__AVR_ATmega328P__) || defined (__AVR_ATmega1280__) || defined (__AVR_ATmega2560__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
|
||||
TIMSK2 &= ~(1<<TOIE2);
|
||||
TCCR2A &= ~((1<<WGM21) | (1<<WGM20));
|
||||
TCCR2B &= ~(1<<WGM22);
|
||||
ASSR &= ~(1<<AS2);
|
||||
TIMSK2 &= ~(1<<OCIE2A);
|
||||
|
||||
if ((F_CPU >= 1000000UL) && (F_CPU <= 16000000UL)) { // prescaler set to 64
|
||||
TCCR2B |= (1<<CS22);
|
||||
TCCR2B &= ~((1<<CS21) | (1<<CS20));
|
||||
prescaler = 64.0;
|
||||
} else if (F_CPU < 1000000UL) { // prescaler set to 8
|
||||
TCCR2B |= (1<<CS21);
|
||||
TCCR2B &= ~((1<<CS22) | (1<<CS20));
|
||||
prescaler = 8.0;
|
||||
} else { // F_CPU > 16Mhz, prescaler set to 128
|
||||
TCCR2B |= ((1<<CS22) | (1<<CS20));
|
||||
TCCR2B &= ~(1<<CS21);
|
||||
prescaler = 128.0;
|
||||
}
|
||||
#elif defined (__AVR_ATmega8__)
|
||||
TIMSK &= ~(1<<TOIE2);
|
||||
TCCR2 &= ~((1<<WGM21) | (1<<WGM20));
|
||||
TIMSK &= ~(1<<OCIE2);
|
||||
ASSR &= ~(1<<AS2);
|
||||
|
||||
if ((F_CPU >= 1000000UL) && (F_CPU <= 16000000UL)) { // prescaler set to 64
|
||||
TCCR2 |= (1<<CS22);
|
||||
TCCR2 &= ~((1<<CS21) | (1<<CS20));
|
||||
prescaler = 64.0;
|
||||
} else if (F_CPU < 1000000UL) { // prescaler set to 8
|
||||
TCCR2 |= (1<<CS21);
|
||||
TCCR2 &= ~((1<<CS22) | (1<<CS20));
|
||||
prescaler = 8.0;
|
||||
} else { // F_CPU > 16Mhz, prescaler set to 128
|
||||
TCCR2 |= ((1<<CS22) && (1<<CS20));
|
||||
TCCR2 &= ~(1<<CS21);
|
||||
prescaler = 128.0;
|
||||
}
|
||||
#elif defined (__AVR_ATmega128__)
|
||||
TIMSK &= ~(1<<TOIE2);
|
||||
TCCR2 &= ~((1<<WGM21) | (1<<WGM20));
|
||||
TIMSK &= ~(1<<OCIE2);
|
||||
|
||||
if ((F_CPU >= 1000000UL) && (F_CPU <= 16000000UL)) { // prescaler set to 64
|
||||
TCCR2 |= ((1<<CS21) | (1<<CS20));
|
||||
TCCR2 &= ~(1<<CS22);
|
||||
prescaler = 64.0;
|
||||
} else if (F_CPU < 1000000UL) { // prescaler set to 8
|
||||
TCCR2 |= (1<<CS21);
|
||||
TCCR2 &= ~((1<<CS22) | (1<<CS20));
|
||||
prescaler = 8.0;
|
||||
} else { // F_CPU > 16Mhz, prescaler set to 256
|
||||
TCCR2 |= (1<<CS22);
|
||||
TCCR2 &= ~((1<<CS21) | (1<<CS20));
|
||||
prescaler = 256.0;
|
||||
}
|
||||
#elif defined (__AVR_ATmega32U4__)
|
||||
TCCR4B = 0;
|
||||
TCCR4A = 0;
|
||||
TCCR4C = 0;
|
||||
TCCR4D = 0;
|
||||
TCCR4E = 0;
|
||||
if (F_CPU >= 16000000L) {
|
||||
TCCR4B = (1<<CS43) | (1<<PSR4);
|
||||
prescaler = 128.0;
|
||||
} else if (F_CPU >= 8000000L) {
|
||||
TCCR4B = (1<<CS42) | (1<<CS41) | (1<<CS40) | (1<<PSR4);
|
||||
prescaler = 64.0;
|
||||
} else if (F_CPU >= 4000000L) {
|
||||
TCCR4B = (1<<CS42) | (1<<CS41) | (1<<PSR4);
|
||||
prescaler = 32.0;
|
||||
} else if (F_CPU >= 2000000L) {
|
||||
TCCR4B = (1<<CS42) | (1<<CS40) | (1<<PSR4);
|
||||
prescaler = 16.0;
|
||||
} else if (F_CPU >= 1000000L) {
|
||||
TCCR4B = (1<<CS42) | (1<<PSR4);
|
||||
prescaler = 8.0;
|
||||
} else if (F_CPU >= 500000L) {
|
||||
TCCR4B = (1<<CS41) | (1<<CS40) | (1<<PSR4);
|
||||
prescaler = 4.0;
|
||||
} else {
|
||||
TCCR4B = (1<<CS41) | (1<<PSR4);
|
||||
prescaler = 2.0;
|
||||
}
|
||||
tcnt2 = (int)((float)F_CPU * resolution / prescaler) - 1;
|
||||
OCR4C = tcnt2;
|
||||
return;
|
||||
#else
|
||||
#error Unsupported CPU type
|
||||
#endif
|
||||
|
||||
tcnt2 = 256 - (int)((float)F_CPU * resolution / prescaler);
|
||||
}
|
||||
|
||||
void FlexiTimer2::start() {
|
||||
count = 0;
|
||||
overflowing = 0;
|
||||
#if defined (__AVR_ATmega168__) || defined (__AVR_ATmega48__) || defined (__AVR_ATmega88__) || defined (__AVR_ATmega328P__) || defined (__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
|
||||
TCNT2 = tcnt2;
|
||||
TIMSK2 |= (1<<TOIE2);
|
||||
#elif defined (__AVR_ATmega128__)
|
||||
TCNT2 = tcnt2;
|
||||
TIMSK |= (1<<TOIE2);
|
||||
#elif defined (__AVR_ATmega8__)
|
||||
TCNT2 = tcnt2;
|
||||
TIMSK |= (1<<TOIE2);
|
||||
#elif defined (__AVR_ATmega32U4__)
|
||||
TIFR4 = (1<<TOV4);
|
||||
TCNT4 = 0;
|
||||
TIMSK4 = (1<<TOIE4);
|
||||
#endif
|
||||
}
|
||||
|
||||
void FlexiTimer2::stop() {
|
||||
#if defined (__AVR_ATmega168__) || defined (__AVR_ATmega48__) || defined (__AVR_ATmega88__) || defined (__AVR_ATmega328P__) || defined (__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
|
||||
TIMSK2 &= ~(1<<TOIE2);
|
||||
#elif defined (__AVR_ATmega128__)
|
||||
TIMSK &= ~(1<<TOIE2);
|
||||
#elif defined (__AVR_ATmega8__)
|
||||
TIMSK &= ~(1<<TOIE2);
|
||||
#elif defined (__AVR_ATmega32U4__)
|
||||
TIMSK4 = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void FlexiTimer2::_overflow() {
|
||||
count += 1;
|
||||
|
||||
if (count >= time_units && !overflowing) {
|
||||
overflowing = 1;
|
||||
count = count - time_units; // subtract time_uints to catch missed overflows
|
||||
// set to 0 if you don't want this.
|
||||
(*func)();
|
||||
overflowing = 0;
|
||||
}
|
||||
}
|
||||
#if defined (__AVR_ATmega32U4__)
|
||||
ISR(TIMER4_OVF_vect) {
|
||||
#else
|
||||
ISR(TIMER2_OVF_vect) {
|
||||
#endif
|
||||
#if defined (__AVR_ATmega168__) || defined (__AVR_ATmega48__) || defined (__AVR_ATmega88__) || defined (__AVR_ATmega328P__) || defined (__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_AT90USB646__) || defined(__AVR_AT90USB1286__)
|
||||
TCNT2 = FlexiTimer2::tcnt2;
|
||||
#elif defined (__AVR_ATmega128__)
|
||||
TCNT2 = FlexiTimer2::tcnt2;
|
||||
#elif defined (__AVR_ATmega8__)
|
||||
TCNT2 = FlexiTimer2::tcnt2;
|
||||
#elif defined (__AVR_ATmega32U4__)
|
||||
// not necessary on 32u4's high speed timer4
|
||||
#endif
|
||||
FlexiTimer2::_overflow();
|
||||
}
|
||||
|
@ -0,0 +1,25 @@
|
||||
#ifndef FlexiTimer2_h
|
||||
#define FlexiTimer2_h
|
||||
|
||||
#ifdef __AVR__
|
||||
#include <avr/interrupt.h>
|
||||
#else
|
||||
#error FlexiTimer2 library only works on AVR architecture
|
||||
#endif
|
||||
|
||||
|
||||
namespace FlexiTimer2 {
|
||||
extern unsigned long time_units;
|
||||
extern void (*func)();
|
||||
extern volatile unsigned long count;
|
||||
extern volatile char overflowing;
|
||||
extern volatile unsigned int tcnt2;
|
||||
|
||||
void set(unsigned long ms, void (*f)());
|
||||
void set(unsigned long units, double resolution, void (*f)());
|
||||
void start();
|
||||
void stop();
|
||||
void _overflow();
|
||||
}
|
||||
|
||||
#endif
|
@ -0,0 +1,261 @@
|
||||
#include "GoBLE.h"
|
||||
|
||||
_GoBLE Goble;
|
||||
|
||||
/*
|
||||
The following constants tell, for each accelerometer
|
||||
axis, which values are returned when the axis measures
|
||||
zero acceleration.
|
||||
*/
|
||||
|
||||
_GoBLE::_GoBLE() {
|
||||
initRecvDataPack();
|
||||
|
||||
_joystickX = 127;
|
||||
_joystickY = 127;
|
||||
for (int i = 0; i < MAXBUTTONID; i++) {
|
||||
_button[i] = RELEASED;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 20; i++) bleQueue.push(0x00);
|
||||
for (int i = 0; i < 20; i++) bleQueue.pop();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
boolean _GoBLE::available() {
|
||||
/*
|
||||
function introduction:
|
||||
push the new valid data to the data buffer package
|
||||
throw away the invalid byte
|
||||
parse the data package when the command length is matching the protocol
|
||||
*/
|
||||
|
||||
if (Serial.available()) bleDataReceiver();
|
||||
/*
|
||||
if (DEBUGDATARAW) {
|
||||
Serial.println("GoBLE availalbe -> new data package!");
|
||||
for (int i = 0; i < rDataPack.commandLength; i++) {
|
||||
Serial.print(bleQueue.pop(), HEX);
|
||||
}
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
if (DEBUGPARSER) {
|
||||
Serial.print("GoBLE availalbe -> bleQueue Counter: ");
|
||||
Serial.print(bleQueue.count());
|
||||
Serial.println();
|
||||
}
|
||||
*/
|
||||
if (rDataPack.commandFlag && bleQueue.count() == rDataPack.commandLength) {
|
||||
|
||||
rDataPack.parseState = bleDataPackageParser();
|
||||
|
||||
if (rDataPack.parseState == PARSESUCCESS) {
|
||||
updateJoystickVal();
|
||||
updateButtonState();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int _GoBLE::readJoystickX() {
|
||||
return _joystickX;
|
||||
}
|
||||
int _GoBLE::readJoystickY() {
|
||||
return _joystickY;
|
||||
}
|
||||
|
||||
boolean _GoBLE::readSwitchUp() {
|
||||
return _button[SWITCH_UP];
|
||||
}
|
||||
|
||||
boolean _GoBLE::readSwitchDown() {
|
||||
return _button[SWITCH_DOWN];
|
||||
}
|
||||
|
||||
boolean _GoBLE::readSwitchLeft() {
|
||||
return _button[SWITCH_LEFT];
|
||||
}
|
||||
|
||||
boolean _GoBLE::readSwitchRight() {
|
||||
return _button[SWITCH_RIGHT];
|
||||
}
|
||||
|
||||
boolean _GoBLE::readSwitchSelect() {
|
||||
return _button[SWITCH_SELECT];
|
||||
}
|
||||
|
||||
boolean _GoBLE::readSwitchStart() {
|
||||
return _button[SWITCH_START];
|
||||
}
|
||||
|
||||
// Private functions
|
||||
|
||||
int _GoBLE::bleDataPackageParser() {
|
||||
/*
|
||||
0x10 - Parse success
|
||||
0x11 - Wrong header charactors
|
||||
0x12 - Wrong button number
|
||||
0x13 - Check Sum Error
|
||||
*/
|
||||
byte calculateSum = 0;
|
||||
|
||||
rDataPack.header1 = bleQueue.pop(), calculateSum += rDataPack.header1;
|
||||
rDataPack.header2 = bleQueue.pop(), calculateSum += rDataPack.header2;
|
||||
|
||||
if (rDataPack.header1 != DEFAULTHEADER1) return 0x11;
|
||||
if (rDataPack.header2 != DEFAULTHEADER2) return 0x11;
|
||||
|
||||
rDataPack.address = bleQueue.pop(), calculateSum += rDataPack.address;
|
||||
|
||||
rDataPack.latestDigitalButtonNumber = rDataPack.digitalButtonNumber;
|
||||
rDataPack.digitalButtonNumber = bleQueue.pop(), calculateSum += rDataPack.digitalButtonNumber;
|
||||
|
||||
int digitalButtonLength = rDataPack.digitalButtonNumber;
|
||||
|
||||
|
||||
if (DEBUGCHECKSUM) {
|
||||
Serial.print("Parser -> digitalButtonLength: ");
|
||||
Serial.println(digitalButtonLength);
|
||||
}
|
||||
if (digitalButtonLength > MAXBUTTONNUMBER) return 0x12;
|
||||
|
||||
rDataPack.joystickPosition = bleQueue.pop(), calculateSum += rDataPack.joystickPosition;
|
||||
|
||||
// read button data package - dynamic button payload length
|
||||
for (int buttonPayloadPointer = 0; buttonPayloadPointer < digitalButtonLength; buttonPayloadPointer++) {
|
||||
rDataPack.buttonPayload[buttonPayloadPointer] = bleQueue.pop();
|
||||
calculateSum += rDataPack.buttonPayload[buttonPayloadPointer];
|
||||
}
|
||||
// read 4 byte joystick data package
|
||||
for (int i = 0; i < 4; i++) rDataPack.joystickPayload[i] = bleQueue.pop(), calculateSum += rDataPack.joystickPayload[i];
|
||||
|
||||
rDataPack.checkSum = bleQueue.pop();
|
||||
|
||||
if (DEBUGCHECKSUM) {
|
||||
Serial.print("Parser -> sum calculation: ");
|
||||
Serial.println(calculateSum);
|
||||
|
||||
Serial.print("Parser -> checkSum byte value: ");
|
||||
Serial.println(rDataPack.checkSum);
|
||||
}
|
||||
|
||||
// check sum and update the parse state value
|
||||
// if the checksum byte is not correct, return 0x12
|
||||
|
||||
rDataPack.commandFlag = false;
|
||||
|
||||
if (rDataPack.checkSum == calculateSum) return PARSESUCCESS;
|
||||
else return 0x13;
|
||||
}
|
||||
|
||||
void _GoBLE::bleDataReceiver() {
|
||||
|
||||
byte inputByte = Serial.read();
|
||||
|
||||
if (DEBUGDATARECEIVER) {
|
||||
Serial.print("bleDataReceiver -> new data:");
|
||||
Serial.println(inputByte, HEX);
|
||||
}
|
||||
|
||||
// throw the trash data and restore the useful data to the queue buffer
|
||||
if (inputByte == DEFAULTHEADER1 || rDataPack.commandFlag == true) {
|
||||
bleQueue.push(inputByte);
|
||||
rDataPack.commandFlag = true;
|
||||
|
||||
// auto adjust the command length based on the button command value
|
||||
if (bleQueue.count() == PACKBUTTONSIGN) {
|
||||
// max button input at one moment should less than 6 buttons
|
||||
if (inputByte > 0 && inputByte < MAXBUTTONNUMBER) {
|
||||
|
||||
// default command length + button number
|
||||
rDataPack.commandLength = DEFAULTPACKLENGTH + inputByte;
|
||||
if (DEBUGDATARECEIVER) Serial.print("bleDataReceiver -> Command Length:"), Serial.println(rDataPack.commandLength);
|
||||
}
|
||||
else rDataPack.commandLength = DEFAULTPACKLENGTH;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void _GoBLE::initRecvDataPack() {
|
||||
rDataPack.commandFlag = false;
|
||||
rDataPack.commandLength = DEFAULTPACKLENGTH;
|
||||
rDataPack.parseState = PARSESUCCESS;
|
||||
|
||||
rDataPack.digitalButtonNumber = 0;
|
||||
rDataPack.latestDigitalButtonNumber = 0;
|
||||
}
|
||||
|
||||
void _GoBLE::updateJoystickVal() {
|
||||
_joystickX = rDataPack.joystickPayload[0];
|
||||
_joystickY = rDataPack.joystickPayload[1];
|
||||
}
|
||||
|
||||
void _GoBLE::updateButtonState() {
|
||||
|
||||
if (rDataPack.digitalButtonNumber == 0 && rDataPack.latestDigitalButtonNumber != 0) {
|
||||
for (int i = 0; i < MAXBUTTONID; i++) {
|
||||
if (_button[i] == PRESSED) {
|
||||
if (DEBUGUPDATEBUTTON) {
|
||||
Serial.print("updateButtonState -> clear Pressed button number: ");
|
||||
Serial.println(i);
|
||||
}
|
||||
_button[i] = RELEASED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < rDataPack.digitalButtonNumber; i++) _button[rDataPack.buttonPayload[i]] = PRESSED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
unsigned int _GoBLE::readChannel(byte channel) {
|
||||
|
||||
digitalWrite(MUX_ADDR_PINS[0], (channel & 1) ? HIGH : LOW);
|
||||
digitalWrite(MUX_ADDR_PINS[1], (channel & 2) ? HIGH : LOW);
|
||||
digitalWrite(MUX_ADDR_PINS[2], (channel & 4) ? HIGH : LOW);
|
||||
digitalWrite(MUX_ADDR_PINS[3], (channel & 8) ? HIGH : LOW);
|
||||
// workaround to cope with lack of pullup resistor on joystick switch
|
||||
if (channel == CH_JOYSTICK_SW) {
|
||||
pinMode(MUX_COM_PIN, INPUT_PULLUP);
|
||||
unsigned int joystickSwitchState = (digitalRead(MUX_COM_PIN) == HIGH) ? 1023 : 0;
|
||||
digitalWrite(MUX_COM_PIN, LOW);
|
||||
return joystickSwitchState;
|
||||
}
|
||||
else
|
||||
return analogRead(MUX_COM_PIN);
|
||||
|
||||
}
|
||||
|
||||
|
||||
boolean _GoBLE::readButton(byte ch) {
|
||||
if (ch >= SWITCH_1 && ch <= SWITCH_5) {
|
||||
ch;
|
||||
}
|
||||
|
||||
switch(ch) {
|
||||
|
||||
}
|
||||
|
||||
unsigned int val = readChannel(ch);
|
||||
return (val > 512) ? HIGH : LOW;
|
||||
}
|
||||
|
||||
boolean _GoBLE::readJoystickButton() {
|
||||
if (readChannel(CH_JOYSTICK_SW) == 1023) {
|
||||
return HIGH;
|
||||
} else if (readChannel(CH_JOYSTICK_SW) == 0) {
|
||||
return LOW;
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
|
@ -0,0 +1,123 @@
|
||||
#ifndef GOBLE_H_
|
||||
#define GOBLE_H_
|
||||
#include "QueueArray.h"
|
||||
|
||||
/**************** Debugger Configuration ******************/
|
||||
|
||||
#define DEBUGDATARECEIVER 0
|
||||
#define DEBUGDATARAW 0
|
||||
#define DEBUGPARSER 0
|
||||
#define DEBUGCHECKSUM 0
|
||||
#define DEBUGUPDATEBUTTON 0
|
||||
|
||||
const byte SWITCH_1 = 1;
|
||||
const byte SWITCH_2 = 2;
|
||||
const byte SWITCH_3 = 3;
|
||||
const byte SWITCH_4 = 4;
|
||||
const byte SWITCH_5 = 5;
|
||||
const byte SWITCH_6 = 6;
|
||||
|
||||
const byte SWITCH_UP = SWITCH_1;
|
||||
const byte SWITCH_RIGHT = SWITCH_2;
|
||||
const byte SWITCH_DOWN = SWITCH_3;
|
||||
const byte SWITCH_LEFT = SWITCH_4;
|
||||
|
||||
const byte SWITCH_SELECT = SWITCH_5;
|
||||
const byte SWITCH_START = SWITCH_6;
|
||||
|
||||
/*
|
||||
These constants can be use for comparison with the value returned
|
||||
by the readButton() method.
|
||||
*/
|
||||
const boolean PRESSED = LOW;
|
||||
const boolean RELEASED = HIGH;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
Data structure for the command buffer
|
||||
|
||||
*/
|
||||
|
||||
// Package protocol configuration
|
||||
#define PACKHEADER 1
|
||||
#define PACKHEADER2 2
|
||||
#define PACKADDRESS 3
|
||||
#define PACKBUTTONSIGN 4
|
||||
#define PACKJOYSTICKSIGN 5
|
||||
#define PACKPAYLOAD 6
|
||||
|
||||
|
||||
#define DEFAULTHEADER1 0x55
|
||||
#define DEFAULTHEADER2 0xAA
|
||||
#define DEFAULTADDRESS 0x11
|
||||
#define DEFAULTPACKLENGTH 10
|
||||
|
||||
#define MAXBUTTONNUMBER 6
|
||||
#define MAXBUTTONID 7
|
||||
|
||||
#define PARSESUCCESS 0x10
|
||||
|
||||
//DL package
|
||||
#pragma pack(1)
|
||||
typedef struct
|
||||
{
|
||||
byte header1; // 0x55
|
||||
byte header2; // 0xAA
|
||||
byte address; // 0x11
|
||||
|
||||
byte latestDigitalButtonNumber;
|
||||
byte digitalButtonNumber;
|
||||
|
||||
byte joystickPosition;
|
||||
byte buttonPayload[MAXBUTTONNUMBER];
|
||||
byte joystickPayload[4];
|
||||
byte checkSum;
|
||||
|
||||
byte commandLength;
|
||||
byte parseState;
|
||||
boolean commandFlag;
|
||||
} sDataLink;
|
||||
#pragma pack()
|
||||
|
||||
class _GoBLE {
|
||||
|
||||
public:
|
||||
_GoBLE();
|
||||
|
||||
boolean available();
|
||||
|
||||
int readJoystickX();
|
||||
int readJoystickY();
|
||||
/*
|
||||
Reads the current state of a button. It will return
|
||||
LOW if the button is pressed, and HIGH otherwise.
|
||||
*/
|
||||
boolean readSwitchUp();
|
||||
boolean readSwitchDown();
|
||||
boolean readSwitchLeft();
|
||||
boolean readSwitchRight();
|
||||
boolean readSwitchSelect();
|
||||
boolean readSwitchStart();
|
||||
|
||||
private:
|
||||
|
||||
sDataLink rDataPack;
|
||||
// create a queue of characters.
|
||||
QueueArray <byte> bleQueue;
|
||||
|
||||
int _joystickX, _joystickY;
|
||||
int _button[MAXBUTTONID];
|
||||
|
||||
void updateJoystickVal();
|
||||
void updateButtonState();
|
||||
|
||||
void initRecvDataPack();
|
||||
int bleDataPackageParser();
|
||||
void bleDataReceiver();
|
||||
|
||||
};
|
||||
|
||||
extern _GoBLE Goble;
|
||||
|
||||
#endif // GOBLE_H_
|
@ -0,0 +1,313 @@
|
||||
/*
|
||||
* QueueArray.h
|
||||
*
|
||||
* Library implementing a generic, dynamic queue (array version).
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* Copyright (C) 2010 Efstathios Chatzikyriakidis (contact@efxa.org)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* Version 1.0
|
||||
*
|
||||
* 2014-02-03 Brian Fletcher <brian.jf.fletcher@gmail.com>
|
||||
*
|
||||
* - added enqueue(), dequeue() and front().
|
||||
*
|
||||
* 2010-09-29 Efstathios Chatzikyriakidis <contact@efxa.org>
|
||||
*
|
||||
* - added resize(): for growing, shrinking the array size.
|
||||
*
|
||||
* 2010-09-25 Efstathios Chatzikyriakidis <contact@efxa.org>
|
||||
*
|
||||
* - added exit(), blink(): error reporting and handling methods.
|
||||
*
|
||||
* 2010-09-24 Alexander Brevig <alexanderbrevig@gmail.com>
|
||||
*
|
||||
* - added setPrinter(): indirectly reference a Serial object.
|
||||
*
|
||||
* 2010-09-20 Efstathios Chatzikyriakidis <contact@efxa.org>
|
||||
*
|
||||
* - initial release of the library.
|
||||
*
|
||||
* ---
|
||||
*
|
||||
* For the latest version see: http://www.arduino.cc/
|
||||
*/
|
||||
|
||||
// header defining the interface of the source.
|
||||
#ifndef _QUEUEARRAY_H
|
||||
#define _QUEUEARRAY_H
|
||||
#include <Arduino.h>
|
||||
// the definition of the queue class.
|
||||
template<typename T>
|
||||
class QueueArray {
|
||||
public:
|
||||
// init the queue (constructor).
|
||||
QueueArray ();
|
||||
|
||||
// clear the queue (destructor).
|
||||
~QueueArray ();
|
||||
|
||||
// add an item to the queue.
|
||||
void enqueue (const T i);
|
||||
|
||||
// remove an item from the queue.
|
||||
T dequeue ();
|
||||
|
||||
// push an item to the queue.
|
||||
void push (const T i);
|
||||
|
||||
// pop an item from the queue.
|
||||
T pop ();
|
||||
|
||||
// get the front of the queue.
|
||||
T front () const;
|
||||
|
||||
// get an item from the queue.
|
||||
T peek () const;
|
||||
|
||||
// check if the queue is empty.
|
||||
bool isEmpty () const;
|
||||
|
||||
// get the number of items in the queue.
|
||||
int count () const;
|
||||
|
||||
// check if the queue is full.
|
||||
bool isFull () const;
|
||||
|
||||
// set the printer of the queue.
|
||||
void setPrinter (Print & p);
|
||||
|
||||
private:
|
||||
// resize the size of the queue.
|
||||
void resize (const int s);
|
||||
|
||||
// exit report method in case of error.
|
||||
void exit (const char * m) const;
|
||||
|
||||
// led blinking method in case of error.
|
||||
void blink () const;
|
||||
|
||||
// the initial size of the queue.
|
||||
static const int initialSize = 2;
|
||||
|
||||
// the pin number of the on-board led.
|
||||
static const int ledPin = 13;
|
||||
|
||||
Print * printer; // the printer of the queue.
|
||||
T * contents; // the array of the queue.
|
||||
|
||||
int size; // the size of the queue.
|
||||
int items; // the number of items of the queue.
|
||||
|
||||
int head; // the head of the queue.
|
||||
int tail; // the tail of the queue.
|
||||
};
|
||||
|
||||
// init the queue (constructor).
|
||||
template<typename T>
|
||||
QueueArray<T>::QueueArray () {
|
||||
size = 0; // set the size of queue to zero.
|
||||
items = 0; // set the number of items of queue to zero.
|
||||
|
||||
head = 0; // set the head of the queue to zero.
|
||||
tail = 0; // set the tail of the queue to zero.
|
||||
|
||||
printer = NULL; // set the printer of queue to point nowhere.
|
||||
|
||||
// allocate enough memory for the array.
|
||||
contents = (T *) malloc (sizeof (T) * initialSize);
|
||||
|
||||
// if there is a memory allocation error.
|
||||
if (contents == NULL)
|
||||
exit ("QUEUE: insufficient memory to initialize queue.");
|
||||
|
||||
// set the initial size of the queue.
|
||||
size = initialSize;
|
||||
}
|
||||
|
||||
// clear the queue (destructor).
|
||||
template<typename T>
|
||||
QueueArray<T>::~QueueArray () {
|
||||
free (contents); // deallocate the array of the queue.
|
||||
|
||||
contents = NULL; // set queue's array pointer to nowhere.
|
||||
printer = NULL; // set the printer of queue to point nowhere.
|
||||
|
||||
size = 0; // set the size of queue to zero.
|
||||
items = 0; // set the number of items of queue to zero.
|
||||
|
||||
head = 0; // set the head of the queue to zero.
|
||||
tail = 0; // set the tail of the queue to zero.
|
||||
}
|
||||
|
||||
// resize the size of the queue.
|
||||
template<typename T>
|
||||
void QueueArray<T>::resize (const int s) {
|
||||
// defensive issue.
|
||||
if (s <= 0)
|
||||
exit ("QUEUE: error due to undesirable size for queue size.");
|
||||
|
||||
// allocate enough memory for the temporary array.
|
||||
T * temp = (T *) malloc (sizeof (T) * s);
|
||||
|
||||
// if there is a memory allocation error.
|
||||
if (temp == NULL)
|
||||
exit ("QUEUE: insufficient memory to initialize temporary queue.");
|
||||
|
||||
// copy the items from the old queue to the new one.
|
||||
for (int i = 0; i < items; i++)
|
||||
temp[i] = contents[(head + i) % size];
|
||||
|
||||
// deallocate the old array of the queue.
|
||||
free (contents);
|
||||
|
||||
// copy the pointer of the new queue.
|
||||
contents = temp;
|
||||
|
||||
// set the head and tail of the new queue.
|
||||
head = 0; tail = items;
|
||||
|
||||
// set the new size of the queue.
|
||||
size = s;
|
||||
}
|
||||
|
||||
// add an item to the queue.
|
||||
template<typename T>
|
||||
void QueueArray<T>::enqueue (const T i) {
|
||||
// check if the queue is full.
|
||||
if (isFull ())
|
||||
// double size of array.
|
||||
resize (size * 2);
|
||||
|
||||
// store the item to the array.
|
||||
contents[tail++] = i;
|
||||
|
||||
// wrap-around index.
|
||||
if (tail == size) tail = 0;
|
||||
|
||||
// increase the items.
|
||||
items++;
|
||||
}
|
||||
|
||||
// push an item to the queue.
|
||||
template<typename T>
|
||||
void QueueArray<T>::push (const T i) {
|
||||
enqueue(i);
|
||||
}
|
||||
|
||||
// remove an item from the queue.
|
||||
template<typename T>
|
||||
T QueueArray<T>::dequeue () {
|
||||
// check if the queue is empty.
|
||||
if (isEmpty ())
|
||||
exit ("QUEUE: can't pop item from queue: queue is empty.");
|
||||
|
||||
// fetch the item from the array.
|
||||
T item = contents[head++];
|
||||
|
||||
// decrease the items.
|
||||
items--;
|
||||
|
||||
// wrap-around index.
|
||||
if (head == size) head = 0;
|
||||
|
||||
// shrink size of array if necessary.
|
||||
if (!isEmpty () && (items <= size / 4))
|
||||
resize (size / 2);
|
||||
|
||||
// return the item from the array.
|
||||
return item;
|
||||
}
|
||||
|
||||
// pop an item from the queue.
|
||||
template<typename T>
|
||||
T QueueArray<T>::pop () {
|
||||
return dequeue();
|
||||
}
|
||||
|
||||
// get the front of the queue.
|
||||
template<typename T>
|
||||
T QueueArray<T>::front () const {
|
||||
// check if the queue is empty.
|
||||
if (isEmpty ())
|
||||
exit ("QUEUE: can't get the front item of queue: queue is empty.");
|
||||
|
||||
// get the item from the array.
|
||||
return contents[head];
|
||||
}
|
||||
|
||||
// get an item from the queue.
|
||||
template<typename T>
|
||||
T QueueArray<T>::peek () const {
|
||||
return front();
|
||||
}
|
||||
|
||||
// check if the queue is empty.
|
||||
template<typename T>
|
||||
bool QueueArray<T>::isEmpty () const {
|
||||
return items == 0;
|
||||
}
|
||||
|
||||
// check if the queue is full.
|
||||
template<typename T>
|
||||
bool QueueArray<T>::isFull () const {
|
||||
return items == size;
|
||||
}
|
||||
|
||||
// get the number of items in the queue.
|
||||
template<typename T>
|
||||
int QueueArray<T>::count () const {
|
||||
return items;
|
||||
}
|
||||
|
||||
// set the printer of the queue.
|
||||
template<typename T>
|
||||
void QueueArray<T>::setPrinter (Print & p) {
|
||||
printer = &p;
|
||||
}
|
||||
|
||||
// exit report method in case of error.
|
||||
template<typename T>
|
||||
void QueueArray<T>::exit (const char * m) const {
|
||||
// print the message if there is a printer.
|
||||
if (printer)
|
||||
printer->println (m);
|
||||
|
||||
// loop blinking until hardware reset.
|
||||
blink ();
|
||||
}
|
||||
|
||||
// led blinking method in case of error.
|
||||
template<typename T>
|
||||
void QueueArray<T>::blink () const {
|
||||
// set led pin as output.
|
||||
pinMode (ledPin, OUTPUT);
|
||||
|
||||
// continue looping until hardware reset.
|
||||
while (true) {
|
||||
digitalWrite (ledPin, HIGH); // sets the LED on.
|
||||
delay (250); // pauses 1/4 of second.
|
||||
digitalWrite (ledPin, LOW); // sets the LED off.
|
||||
delay (250); // pauses 1/4 of second.
|
||||
}
|
||||
|
||||
// solution selected due to lack of exit() and assert().
|
||||
}
|
||||
|
||||
#endif // _QUEUEARRAY_H
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue