/* | |
* Copyright (C) 2012 The Android Open Source Project | |
* | |
* Licensed under the Apache License, Version 2.0 (the "License"); | |
* you may not use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. | |
*/ | |
#include "ADK.h" | |
#include "HCI.h" | |
#include "fwk.h" | |
#include <string.h> | |
#include <include/uart_console.h> | |
void dbgPrintf(const char*, ...); //useful | |
//android app needs to match this | |
#define BT_ADK_UUID 0x1d, 0xd3, 0x50, 0x50, 0xa4, 0x37, 0x11, 0xe1, 0xb3, 0xdd, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66 | |
enum AdkStates{ | |
AdkClock, | |
AdkAlarm, | |
AdkBrightness, | |
AdkColor, | |
AdkVolume, | |
AdkDisplay, | |
AdkPresets, | |
//always last | |
AdkInvalid | |
}; | |
enum AdkDisplayMode{ | |
AdkShowAnimation, | |
AdkShowAccel, | |
AdkShowMag, | |
AdkShowTemp, | |
AdkShowHygro, | |
AdkShowBaro, | |
AdkShowProx, | |
AdkShowColor, | |
AdkShowLast //always last | |
}; | |
enum AdkAlarmStates { | |
AdkAlarmIdle, | |
AdkAlarmIdleWait, | |
AdkAlarmAlarm, | |
AdkAlarmSnooze | |
}; | |
/* | |
button numbering (all in hex) | |
__ __ __ __ __ __ | |
|1A| |18| |16| |14| |12| |11| 03 04 05 06 | |
-- -- -- -- -- -- 0A 09 08 07 | |
|1B| |19| |17| |15| |13| |10| | |
-- -- -- -- -- -- | |
*/ | |
#define BTN_SLIDER_0 0x00 | |
#define BTN_SLIDER_1 0x01 | |
#define BTN_SLIDER_2 0x02 | |
#define BTN_0_UP 0x1A | |
#define BTN_1_UP 0x18 | |
#define BTN_2_UP 0x16 | |
#define BTN_3_UP 0x14 | |
#define BTN_4_UP 0x12 | |
#define BTN_5_UP 0x11 | |
#define BTN_0_DN 0x1B | |
#define BTN_1_DN 0x19 | |
#define BTN_2_DN 0x17 | |
#define BTN_3_DN 0x15 | |
#define BTN_4_DN 0x13 | |
#define BTN_5_DN 0x10 | |
#define BTN_CLOCK 0x03 | |
#define BTN_ALARM 0x04 | |
#define BTN_BRIGHTNESS 0x05 | |
#define BTN_COLOR 0x06 | |
#define BTN_LOCK 0x07 | |
#define BTN_PRESETS 0x08 | |
#define BTN_DISPLAY 0x09 | |
#define BTN_VOLUME 0x0A | |
#define BTN_MASK_PRESS 0x8000 | |
#define BTN_MASK_HOLD 0x4000 | |
#define BTN_MASK_RELEASE 0x2000 | |
#define BTN_MASK_ID 0x003F | |
#define BTN_INITIAL_DELAY 10 //10ms before a click registers | |
#define BTN_HOLD_DELAY 400 //400mas before a click becomes a hold | |
#define BTN_AUTOREPEAT 100 //auto-repeat every 100ms | |
#define SETTINGS_NAME "/AdkSettings.bin" | |
#define SETTINGS_MAGIX 0xAF | |
typedef struct AdkSettings{ | |
uint8_t magix; | |
uint8_t ver; | |
//v1 settings: | |
uint8_t R, G, B, bri, vol, almH, almM, almOn; | |
char btName[249]; //null terminated | |
char btPIN[17]; //null terminated | |
uint16_t almSnooze; | |
char almTune[256]; // null terminated | |
uint8_t speed, displayMode; | |
//later settings | |
}AdkSettings; | |
AdkSettings settings; | |
const char* btPIN = 0; | |
volatile static int32_t hTemp, hHum, bPress, bTemp; | |
volatile static uint16_t prox[7]; //prox, clear, IR ,R, G, B, temp pProx, pClear, pR, pG, pB, pIR, pTemp; | |
volatile static uint16_t proxNormalized[3]; | |
volatile static int16_t accel[3], mag[3]; | |
volatile static uint32_t btSSP = ADK_BT_SSP_DONE_VAL; | |
volatile static char locked = 0; | |
static void btStart(void); | |
static void processUSBAccessory(void); | |
static uint16_t btnProcess(void){ | |
static uint64_t lastActionTime[32] = {0, }; | |
static uint32_t clickSent = 0; | |
static uint32_t holdSent = 0; | |
static uint32_t lastStates = 0; | |
uint32_t curState, t, i, mask; | |
curState = (((uint32_t)ADK_capSenseButtons()) << 16) | ADK_capSenseIcons(); | |
t = lastStates ^ curState; | |
lastStates = curState; | |
//update states for all buttons | |
for(mask = 1, i = 0; i < 32; i++, mask <<= 1) if(t & mask){ | |
lastActionTime[i] = ADK_getUptime(); | |
} | |
//generate events | |
for(mask = 1, i = 0; i < 32; i++, mask <<= 1){ | |
if(curState & mask){ | |
uint64_t time = ADK_getUptime(); | |
uint64_t lapsed = time - lastActionTime[i]; | |
if(holdSent & mask){ //maybe resend hold | |
if(lapsed > BTN_AUTOREPEAT){ | |
lastActionTime[i] = time; | |
return i | BTN_MASK_HOLD; | |
} | |
} | |
else if(clickSent & mask){ //maybe time for first hold | |
if(lapsed > BTN_HOLD_DELAY){ | |
holdSent |= mask; | |
lastActionTime[i] = time; | |
return i | BTN_MASK_HOLD; | |
} | |
} | |
else{ //maybe time to click | |
if(lapsed > BTN_INITIAL_DELAY){ | |
clickSent |= mask; | |
lastActionTime[i] = time; | |
return i | BTN_MASK_PRESS; | |
} | |
} | |
} | |
else if(clickSent & mask){ //release | |
clickSent &=~ mask; | |
holdSent &=~ mask; | |
return i | BTN_MASK_RELEASE; | |
} | |
} | |
return 0; | |
} | |
static void readSettings(void){ | |
uint32_t read; | |
FatFileP f; | |
char r; | |
AdkSettings ts; | |
//apply defaults | |
strcpy(settings.btName, "ADK 2012"); | |
strcpy(settings.btPIN, "1337"); | |
settings.magix = SETTINGS_MAGIX; | |
settings.ver = 1; | |
settings.R = 0; | |
settings.G = 0; | |
settings.B = 255; | |
settings.bri = 255; | |
settings.vol = 255; | |
settings.almH = 6; | |
settings.almM = 0; | |
settings.almOn = 0; | |
settings.speed = 1; | |
settings.displayMode = AdkShowAnimation; | |
settings.almSnooze = 10 * 60; //10-minute alarm | |
strcpy(settings.almTune, "/Tunes/Alarm_Rooster_02.ogg"); | |
r = ADK_fatfsOpen(&f, SETTINGS_NAME, FATFS_READ); | |
if(!r){ | |
r = ADK_fatfsRead(f, &ts, sizeof(AdkSettings), &read); | |
if(r || read != sizeof(AdkSettings) || settings.magix != SETTINGS_MAGIX || settings.ver != 1){ | |
//in future, check for other versions and read as needed here... | |
dbgPrintf("ADK: settings: file read failed: %d, %u/%u, 0x%x\n", r, read, sizeof(AdkSettings), settings.magix); | |
} | |
else settings = ts; | |
ADK_fatfsClose(f); | |
} | |
else dbgPrintf("ADK: settings: file open failed: %d\n", r); | |
} | |
static void writeSettings(void){ | |
FatFileP f; | |
char r; | |
ADK_fatfsUnlink(SETTINGS_NAME); | |
r = ADK_fatfsOpen(&f, SETTINGS_NAME, FATFS_WRITE | FATFS_CREATE | FATFS_TRUNCATE); | |
if(!r){ | |
uint32_t written = 0; | |
r = ADK_fatfsWrite(f, &settings, sizeof(AdkSettings), &written); | |
if(r || written != sizeof(AdkSettings)) dbgPrintf("ADK: settings: file write failed: %d, %u/%u\n", r, written, sizeof(AdkSettings)); | |
ADK_fatfsClose(f); | |
} | |
else dbgPrintf("ADK: settings: file open failed: %d\n", r); | |
} | |
static void setup(void) | |
{ | |
UART_Configure(115200, BOARD_MCK); | |
ADK_adkSetPutchar((adkPutcharF)UART_PutChar); | |
ADK_adkInit(); | |
btStart(); | |
if(ADK_fatfsMount()) dbgPrintf("ADK: failed to mount SD card\n"); | |
ADK_usbStart(); | |
} | |
static uint8_t rnd(void){ | |
static uint64_t seed = 7454131806685196871ULL; | |
seed *= 2340027325706224672ULL; | |
seed += 7310016643071172983ULL; | |
seed %= 9876543210987654321ULL; | |
seed ^= seed << 3; | |
seed += ADK_getUptime(); | |
return seed >> 53; | |
} | |
static void gethue(uint8_t h, uint8_t* Rp, uint8_t* Gp, uint8_t* Bp){ | |
uint8_t R, G, B, seg, prog; | |
if(h == 255) h = 254; | |
seg = (unsigned)h / 85; | |
prog = (((uint32_t)((unsigned)h % 85)) << 8) / 85; | |
switch(seg){ | |
case 0: R = prog; G = 0; B = 255 - prog; break; | |
case 1: R = 255 - prog; G = prog; B = 0; break; | |
case 2: R = 0; G = 255 - prog; B = prog; break; | |
} | |
*Rp = R; | |
*Gp = G; | |
*Bp = B; | |
} | |
static void screenClear(void){ | |
uint32_t i; | |
for(i = 0; i < NUM_LEDS; i++) ADK_ledWrite(i, 0, 0, 0); //clear screen if leaving display mode | |
} | |
static void adkBtSspF(const uint8_t* mac, uint32_t val){ | |
btSSP = val; | |
dbgPrintf("ssp with val %u\n", val); | |
} | |
static void loop(void) | |
{ | |
uint8_t r, g, b, dimR, dimG, dimB; | |
uint8_t colorSlider, volSlider, briSlider, speedSlider; | |
static const uint8_t dimIconFactor = 6; | |
uint8_t state = AdkInvalid; | |
uint8_t newState = AdkClock; | |
uint8_t alarmState = AdkAlarmIdle; | |
uint32_t i, j, k; | |
uint8_t loopCounter = 0; | |
uint64_t nextTime = 0; //for animation | |
unsigned int snoozeStart; | |
char alarmEnded = 1; | |
char alarmStop, alarmFake = 0; | |
int32_t alarmDirPos = -1; | |
FatDirP dir = 0; | |
char wasBt = 0; | |
static const uint8_t btSeq[] = {6,5,8,12,11}; | |
readSettings(); | |
if(0){ //very helpful to some of us - set alarm song to the first song we find :) | |
FatDirP dirT; | |
if(!ADK_fatfsOpenDir(&dirT, "/Tunes")){ | |
FatFileInfo fi; | |
fi.longName = settings.almTune + 7; | |
fi.nameSz = 100; | |
strcpy(settings.almTune, "/Tunes/"); | |
if(!ADK_fatfsReadDir(dirT, &fi)){ | |
dbgPrintf("tune: '%s'\n", settings.almTune); | |
} else dbgPrintf("file find fail\n"); | |
} else dbgPrintf("dir open fail\n"); | |
} | |
btPIN = settings.btPIN; | |
ADK_setVolume(settings.vol); | |
dbgPrintf("ADK: setting BT name '%s' and pin '%s'\n", settings.btName, settings.btPIN); | |
if(!ADK_btSetDeviceClass(DEVICE_CLASS_SERVICE_AUDIO | DEVICE_CLASS_SERVICE_RENDERING | | |
DEVICE_CLASS_SERVICE_INFORMATION | (DEVICE_CLASS_MAJOR_AV << DEVICE_CLASS_MAJOR_SHIFT) | | |
(DEVICE_CLASS_MINOR_AV_PORTBL_AUDIO << DEVICE_CLASS_MINOR_AV_SHIFT))) dbgPrintf("ADK: Failed to set device class\n"); | |
if(!ADK_btSetLocalName(settings.btName)) dbgPrintf("ADK: failed to set BT name\n"); | |
if(!ADK_btDiscoverable(1)) dbgPrintf("ADK: Failed to set discoverable\n"); | |
if(!ADK_btConnectable(1)) dbgPrintf("ADK: Failed to set connectable\n"); | |
ADK_btSetSspCallback(adkBtSspF); | |
while(1){ | |
loopCounter++; | |
uint16_t button = btnProcess(); | |
if(locked == 2){ | |
if(button == (BTN_MASK_HOLD | BTN_LOCK)) locked = 0; | |
else button = 0; | |
} | |
else if(button == (BTN_MASK_PRESS | BTN_LOCK) && locked == 0) locked = 1; | |
else if(button == (BTN_MASK_RELEASE | BTN_LOCK) && locked == 1) locked = 2; | |
ADK_adkEventProcess(); //let the adk framework do its thing | |
r = (((uint32_t)settings.R) * (settings.bri + 1)) >> 8; | |
g = (((uint32_t)settings.G) * (settings.bri + 1)) >> 8; | |
b = (((uint32_t)settings.B) * (settings.bri + 1)) >> 8; | |
dimR = (r + dimIconFactor - 1) / dimIconFactor; | |
dimG = (g + dimIconFactor - 1) / dimIconFactor; | |
dimB = (b + dimIconFactor - 1) / dimIconFactor; | |
if(newState != AdkInvalid){ | |
state = newState; | |
newState = AdkInvalid; | |
for(i = 0; i < 8; i++) ADK_ledDrawIcon(i, dimR, dimG, dimB); | |
ADK_ledDrawIcon(state, r, g, b); | |
} | |
ADK_ledDrawIcon(7, locked ? r : dimR, locked ? g : dimG, locked ? b : dimB); | |
if(!(loopCounter & 127)) if(!ADK_hygroRead((int32_t *)&hTemp, (int32_t *)&hHum)) hTemp = hHum = 0; | |
if(!(loopCounter & 7)){ | |
uint16_t proxMax; | |
ADK_baroRead(3, (long *)&bPress, (long *)&bTemp); | |
ADK_alsRead((uint16_t *)prox + 0, (uint16_t *)prox + 1, (uint16_t *)prox + 3, (uint16_t *)prox + 4, (uint16_t *)prox + 5, (uint16_t *)prox + 2, (uint16_t *)prox + 6); | |
ADK_accelRead((int16_t *)accel + 0, (int16_t *)accel + 1, (int16_t *)accel + 2); | |
ADK_magRead((int16_t *)mag + 0, (int16_t *)mag + 1, (int16_t *)mag + 2); | |
for(i = 0; i < 3; i++) mag[i] <<= 4; //convert to 16-bit value | |
//copy | |
for(i = 0; i < 3; i++) proxNormalized[i] = prox[i + 3]; | |
proxNormalized[2] *= 3; //blue needs more sensitivity | |
//find max | |
proxMax = 0; | |
for(i = 0; i < 3; i++) if(proxMax < proxNormalized[i]) proxMax = proxNormalized[i]; | |
proxMax++; | |
//normalize to 8-bits | |
for(i = 0; i < 3; i++) proxNormalized[i] = (proxNormalized[i] << 8) / proxMax; | |
//exponentize (as per human eyes) | |
static const uint16_t exp[] = | |
{ | |
0,19,39,59,79,100,121,143,165,187,209,232,255,279,303,327,352,377,402,428,454,481,508,536,564,592,621,650,680,710,741,772,804, 836,869,902, | |
936,970,1005,1040,1076,1113,1150,1187,1226,1264,1304,1344,1385,1426,1468,1511,1554,1598,1643,1688,1734,1781,1829,1877,1926,1976,2026,2078, | |
2130,2183,2237,2292,2348,2404,2461,2520,2579,2639,2700,2762,2825,2889,2954,3020,3088,3156,3225,3295,3367,3439,3513,3588,3664,3741,3819,3899, | |
3980,4062,4146,4231,4317,4404,4493,4583,4675,4768,4863,4959,5057,5156,5257,5359,5463,5568,5676,5785,5895,6008,6122,6238,6355,6475,6597, | |
6720,6845,6973,7102,7233,7367,7502,7640,7780,7922,8066,8213,8362,8513,8666,8822,8981,9142,9305,9471,9640,9811,9986,10162,10342,10524,10710, | |
10898,11089,11283,11480,11681,11884,12091,12301,12514,12731,12951,13174,13401,13632,13866,14104,14345,14591,14840,15093,15351,15612,15877,16147, | |
16421,16699,16981,17268,17560,17856,18156,18462,18772,19087,19407,19733,20063,20398,20739,21085,21437,21794,22157,22525,22899,23279,23666, | |
24058,24456,24861,25272,25689,26113,26544,26982,27426,27878,28336,28802,29275,29756,30244,30740,31243,31755,32274,32802,33338,33883,34436, | |
34998,35568,36148,36737,37335,37942,38559,39186,39823,40469,41126,41793,42471,43159,43859,44569,45290,46023,46767,47523,48291,49071,49863, | |
50668,51486,52316,53159,54016,54886,55770,56668,57580,58506,59447,60403,61373,62359,63361,64378,65412 | |
}; | |
for(i = 0; i < 3; i++) proxNormalized[i] = exp[proxNormalized[i]]; | |
} | |
if(wasBt && btSSP == ADK_BT_SSP_DONE_VAL){ //clear leftover segments | |
ADK_ledWrite(btSeq[wasBt - 1], 0, 0, 0); | |
wasBt = 0; | |
} | |
else if(btSSP != ADK_BT_SSP_DONE_VAL){ | |
k = btSSP; | |
for(i = 0, j = 100000; i < 6; i++, j /= 10){ | |
ADK_ledDrawLetter(i, k / j + '0', 0, 0, settings.bri); | |
k %= j; | |
} | |
ADK_ledWrite(9, 0, 0, 0); | |
ADK_ledWrite(2, 0, 0, 0); | |
if(wasBt) ADK_ledWrite(btSeq[wasBt - 1], 0, 0, 0); | |
k = (ADK_getUptime() >> 7) % sizeof(btSeq); | |
wasBt = k + 1; | |
ADK_ledWrite(btSeq[k], 0, 0, settings.bri); | |
button = 0; | |
} | |
else switch(state){ | |
case AdkClock:{ | |
uint16_t year; | |
uint8_t month, day, h, m, s, timechange = 1; | |
//get and draw time | |
ADK_rtcGet(&year, &month, &day, &h, &m, &s); | |
ADK_ledDrawLetter(0, h / 10 + '0', r, g, b); | |
ADK_ledDrawLetter(1, h % 10 + '0', r, g, b); | |
ADK_ledDrawLetter(2, m / 10 + '0', r, g, b); | |
ADK_ledDrawLetter(3, m % 10 + '0', r, g, b); | |
ADK_ledDrawLetter(4, s / 10 + '0', r, g, b); | |
ADK_ledDrawLetter(5, s % 10 + '0', r, g, b); | |
ADK_ledWrite(9, r, g, b); | |
ADK_ledWrite(2, r, g, b); | |
//handle buttons | |
if(button & (BTN_MASK_PRESS | BTN_MASK_HOLD)) switch(button & BTN_MASK_ID){ | |
case BTN_5_DN: | |
if(s) s--; | |
break; | |
case BTN_5_UP: | |
if(s < 59) s++; | |
break; | |
case BTN_4_UP: | |
if(s < 50) s += 10; | |
break; | |
case BTN_4_DN: | |
if(s > 9) s -= 10; | |
break; | |
case BTN_3_UP: | |
if(m < 59) m++; | |
break; | |
case BTN_3_DN: | |
if(m) m--; | |
break; | |
case BTN_2_UP: | |
if(m < 50) m += 10; | |
break; | |
case BTN_2_DN: | |
if(m > 9) m -= 10; | |
break; | |
case BTN_1_UP: | |
if(h < 23) h++; | |
break; | |
case BTN_1_DN: | |
if(h) h--; | |
break; | |
case BTN_0_UP: | |
if(h < 14) h += 10; | |
break; | |
case BTN_0_DN : | |
if(h > 9) h -=10; | |
break; | |
default: timechange = 0; | |
} else timechange = 0; | |
if(timechange){ | |
ADK_rtcSet(year, month, day, h, m, s); | |
} | |
break; | |
} | |
case AdkAlarm:{ | |
if(!alarmFake || alarmEnded){ | |
ADK_ledDrawLetter(0, settings.almH / 10 + '0', r, g, b); | |
ADK_ledDrawLetter(1, settings.almH % 10 + '0', r, g, b); | |
ADK_ledDrawLetter(2, settings.almM / 10 + '0', r, g, b); | |
ADK_ledDrawLetter(3, settings.almM % 10 + '0', r, g, b); | |
ADK_ledDrawLetter(4, 'O', r, g, b); | |
ADK_ledDrawLetter(5, (settings.almOn ? 'N' : 'F'), r, g, b); | |
ADK_ledWrite(9, r, g, b); | |
ADK_ledWrite(2, 0, 0, 0); | |
if(button & (BTN_MASK_PRESS | BTN_MASK_HOLD)) switch(button & BTN_MASK_ID){ | |
case BTN_5_DN: | |
case BTN_5_UP: | |
case BTN_4_UP: | |
case BTN_4_DN: | |
settings.almOn ^= 1; | |
break; | |
case BTN_3_UP: | |
if(settings.almM < 59) settings.almM++; | |
break; | |
case BTN_3_DN: | |
if(settings.almM) settings.almM--; | |
break; | |
case BTN_2_UP: | |
if(settings.almM < 50) settings.almM += 10; | |
break; | |
case BTN_2_DN: | |
if(settings.almM > 9) settings.almM -= 10; | |
break; | |
case BTN_1_UP: | |
if(settings.almH < 23) settings.almH++; | |
break; | |
case BTN_1_DN: | |
if(settings.almH) settings.almH--; | |
break; | |
case BTN_0_UP: | |
if(settings.almH < 14) settings.almH += 10; | |
break; | |
case BTN_0_DN : | |
if(settings.almH > 9) settings.almH -=10; | |
break; | |
} | |
} | |
else{ | |
ADK_ledWrite(9, 0, 0, 0); | |
ADK_ledWrite(2, 0, 0, 0); | |
} | |
if(button == (BTN_MASK_HOLD | BTN_ALARM) && alarmEnded && (alarmState == AdkAlarmIdle || alarmState == AdkAlarmIdleWait)){ //handle sound file selection | |
char* name = settings.almTune; | |
alarmFake = 1; | |
alarmEnded = 0; | |
alarmStop = 0; | |
dbgPrintf("Playing song '%s'\n", settings.almTune); | |
if(name[0] == '/' && (name[1] == 'T' || name[1] == 't') && | |
(name[2] == 'u' || name[2] == 'U') && (name[3] == 'n' || name[3] == 'N') && | |
(name[4] == 'e' || name[4] == 'E') && (name[5] == 's' || name[5] == 'S') && | |
name[6] == '/') name += 7; | |
for(i = 0; i < 6; i++) ADK_ledDrawLetter(i, name[i], r, g, b); | |
ADK_playOggBackground(settings.almTune, &alarmEnded, &alarmStop); | |
} | |
if(button == (BTN_MASK_PRESS | BTN_SLIDER_0) || button == (BTN_MASK_PRESS | BTN_SLIDER_1) || button == (BTN_MASK_PRESS | BTN_SLIDER_2)){ | |
char name[256] = "/Tunes/", found = 0; | |
dbgPrintf("next file\n"); | |
for(j = 0; j < 2 && !found; j++) if(!ADK_fatfsOpenDir(&dir, "/Tunes")){ | |
alarmDirPos++; | |
for(i = 0; i <= alarmDirPos; i++){ | |
FatFileInfo fi; | |
fi.longName = name + 7; | |
fi.nameSz = sizeof(name) - 7; | |
if(!ADK_fatfsReadDir(dir, &fi)){ | |
if(i == alarmDirPos){ | |
dbgPrintf("file: '%s'\n", name); | |
found = 1; | |
} | |
} | |
else{ | |
alarmDirPos = -1; | |
dbgPrintf("no more files\n"); | |
break; | |
} | |
} | |
ADK_fatfsCloseDir(dir); | |
} | |
if(found) strcpy(settings.almTune, name); | |
} | |
break; | |
} | |
case AdkVolume:{ | |
uint8_t dispVol = ((uint32_t)ADK_getVolume() * 100) >> 8; | |
ADK_ledDrawLetter(0, 'V', r, g, b); | |
ADK_ledDrawLetter(1, 'O', r, g, b); | |
ADK_ledDrawLetter(2, 'L', r, g, b); | |
ADK_ledDrawLetter(3, ' ', r, g, b); | |
ADK_ledDrawLetter(4, dispVol / 10 + '0', r, g, b); | |
ADK_ledDrawLetter(5, dispVol % 10 + '0', r, g, b); | |
dispVol = ADK_capSenseSlider(); | |
if(dispVol != volSlider){ | |
ADK_setVolume(settings.vol = dispVol); | |
volSlider = dispVol; | |
} | |
break; | |
} | |
case AdkColor:{ | |
uint8_t slider, seg, prog; | |
static const char hexch[] = "0123456789ABCDEF"; | |
ADK_ledDrawLetter(0, hexch[settings.R >> 4], r, g, b); | |
ADK_ledDrawLetter(1, hexch[settings.R & 15], r, g, b); | |
ADK_ledDrawLetter(2, hexch[settings.G >> 4], r, g, b); | |
ADK_ledDrawLetter(3, hexch[settings.G & 15], r, g, b); | |
ADK_ledDrawLetter(4, hexch[settings.B >> 4], r, g, b); | |
ADK_ledDrawLetter(5, hexch[settings.B & 15], r, g, b); | |
ADK_ledWrite(9, 0, 0, 0); | |
ADK_ledWrite(2, 0, 0, 0); | |
if(button & (BTN_MASK_PRESS | BTN_MASK_HOLD)) switch(button & BTN_MASK_ID){ | |
case BTN_5_DN: | |
if(settings.B) settings.B--; | |
break; | |
case BTN_5_UP: | |
if(settings.B < 0xFF) settings.B++; | |
break; | |
case BTN_4_UP: | |
if(settings.B < 0xF0) settings.B += 0x10; | |
break; | |
case BTN_4_DN: | |
if(settings.B > 0x0F) settings.B -= 0x10; | |
break; | |
case BTN_3_UP: | |
if(settings.G < 0xFF) settings.G++; | |
break; | |
case BTN_3_DN: | |
if(settings.G) settings.G--; | |
break; | |
case BTN_2_UP: | |
if(settings.G < 0xF0) settings.G += 0x10; | |
break; | |
case BTN_2_DN: | |
if(settings.G > 0x0F) settings.G -= 0x10; | |
break; | |
case BTN_1_UP: | |
if(settings.R < 0xFF) settings.R++; | |
break; | |
case BTN_1_DN: | |
if(settings.R) settings.R--; | |
break; | |
case BTN_0_UP: | |
if(settings.R < 0xF0) settings.R += 0x10; | |
break; | |
case BTN_0_DN : | |
if(settings.R > 0x0F) settings.R -= 0x10; | |
break; | |
} | |
slider = ADK_capSenseSlider(); | |
if(slider != colorSlider){ | |
colorSlider = slider; | |
gethue(slider, &settings.R, &settings.G, &settings.B); | |
} | |
break; | |
} | |
case AdkBrightness:{ | |
uint8_t slider; | |
uint8_t dispBri = ((uint32_t)settings.bri * 100) >> 8; | |
ADK_ledDrawLetter(0, 'B', r, g, b); | |
ADK_ledDrawLetter(1, 'R', r, g, b); | |
ADK_ledDrawLetter(2, 'I', r, g, b); | |
ADK_ledDrawLetter(3, ' ', r, g, b); | |
ADK_ledDrawLetter(4, dispBri / 10 + '0', r, g, b); | |
ADK_ledDrawLetter(5, dispBri % 10 + '0', r, g, b); | |
ADK_ledWrite(9, 0, 0, 0); | |
ADK_ledWrite(2, 0, 0, 0); | |
slider = ADK_capSenseSlider(); | |
if(slider != briSlider){ | |
slider = ((((uint32_t)slider) * 191) >> 8) + 64; | |
briSlider = slider; | |
settings.bri = slider; | |
} | |
break; | |
} | |
case AdkDisplay:{ | |
static uint8_t vals[NUM_LEDS][3] = {{0,},}; | |
static const uint8_t doNotTouch[] = {49, 33, 17, 1, 48, 32, 16, 0}; | |
uint8_t slider = ADK_capSenseSlider(); | |
if(slider != speedSlider){ | |
speedSlider = slider; | |
settings.speed = (255 - slider) >> 3; | |
} | |
if(ADK_getUptime() > nextTime){ | |
if(!nextTime){ | |
const char* name = NULL; | |
switch(settings.displayMode){ | |
default: settings.displayMode = AdkShowAnimation; //fallthrough | |
case AdkShowAnimation: name = "PRETTY"; break; | |
case AdkShowAccel: name = " ACCEL"; break; | |
case AdkShowMag: name = "MAGNET"; break; | |
case AdkShowTemp: name = " TEMP "; break; | |
case AdkShowHygro: name = " HYGRO"; break; | |
case AdkShowBaro: name = " BARO "; break; | |
case AdkShowProx: name = " PROX "; break; | |
case AdkShowColor: name = " COLOR"; break; | |
} | |
for(i = 0; i < 6; i++) ADK_ledDrawLetter(i, name[i], r, g, b); | |
ADK_ledWrite(9, 0, 0, 0); | |
ADK_ledWrite(2, 0, 0, 0); | |
nextTime = ADK_getUptime() + 1000; | |
} | |
else{ | |
nextTime = ADK_getUptime() + settings.speed; | |
volatile int16_t* arrPtr = NULL; | |
static const long valUnused = 0x7FFFFFFF; | |
int val = valUnused; | |
char isSigned = 1, cR = r, cG = g, cB = b; | |
switch(settings.displayMode){ | |
case AdkShowAnimation: | |
if(rnd() < 30){ //spawn | |
i = rnd() % NUM_LEDS; | |
gethue(rnd(), vals[i] + 0, vals[i] + 1, vals[i] + 2); | |
} | |
for(i = 0; i < NUM_LEDS; i++){ | |
for(j = 0; j < 3; j++) vals[i][j] = ((uint32_t)vals[i][j] * 127) >> 7; | |
for(j = 0; j < sizeof(doNotTouch) && i != doNotTouch[j]; j++); | |
if(j == sizeof(doNotTouch)) ADK_ledWrite(i, vals[i][0], vals[i][1], vals[i][2]); | |
} | |
break; | |
case AdkShowAccel: | |
arrPtr = accel; | |
//fallthrough | |
case AdkShowMag: | |
if(!arrPtr) arrPtr = mag; | |
//fallthrough | |
case AdkShowProx: | |
if(!arrPtr){ | |
arrPtr = (int16_t*)prox; | |
isSigned = 0; | |
} | |
//fallthrough | |
case AdkShowColor: | |
if(!arrPtr){ | |
arrPtr = (int16_t*)proxNormalized; | |
isSigned = 0; | |
cR = proxNormalized[0] >> 8; | |
cG = proxNormalized[1] >> 8; | |
cB = proxNormalized[2] >> 8; | |
} | |
for(i = 0; i < 6; i += 2){ | |
val = arrPtr[i >> 1]; | |
if(isSigned){ | |
if(val < 0){ | |
val = -val; | |
j = 0; | |
} | |
else j = 1; | |
} | |
else val = (uint16_t)val; | |
val *= 100; | |
val >>= isSigned ? 15 : 16; | |
ADK_ledDrawLetter(i + 0, + val / 10 + '0', isSigned ? (j ? settings.bri : 0) : cR, isSigned ? 0 : cG, isSigned ? (j ? 0 : settings.bri) : cB); | |
ADK_ledDrawLetter(i + 1, + val % 10 + '0', isSigned ? (j ? settings.bri : 0) : cR, isSigned ? 0 : cG, isSigned ? (j ? 0 : settings.bri) : cB); | |
} | |
break; | |
case AdkShowTemp: | |
val = bTemp; | |
//fall through | |
case AdkShowHygro: | |
if(val == valUnused) val = hHum; | |
//fall through | |
case AdkShowBaro: | |
if(val == valUnused) val = (bPress + 50) / 100; | |
if(val < 0){ | |
ADK_ledDrawLetter(0, '-', r, g, b); | |
val = -val; | |
} | |
for(j = 1000, i = 1, k = 0; i < 6; i++){ | |
if(i == 4) ADK_ledDrawLetter(i, '.', r, g, b); | |
else{ | |
if(val >= j || i >= 4 || k){ | |
k = 1; | |
ADK_ledDrawLetter(i, val / j + '0', r, g, b); | |
} | |
else ADK_ledDrawLetter(i, ' ', r, g, b); | |
val %= j; | |
j /= 10; | |
} | |
} | |
break; | |
} | |
} | |
} | |
break; | |
} | |
case AdkPresets:{ | |
ADK_ledWrite(9, 0, 0, 0); | |
ADK_ledWrite(2, 0, 0, 0); | |
ADK_ledDrawLetter(0, ' ', r, g, b); | |
ADK_ledDrawLetter(1, 'n', r, g, b); | |
ADK_ledDrawLetter(2, 'o', r, g, b); | |
ADK_ledDrawLetter(3, 'n', r, g, b); | |
ADK_ledDrawLetter(4, 'e', r, g, b); | |
ADK_ledDrawLetter(5, ' ', r, g, b); | |
break; | |
} | |
} | |
if(button == (BTN_MASK_RELEASE | BTN_ALARM) && alarmFake && !alarmEnded){ | |
dbgPrintf("Stopping song\n"); | |
alarmStop = 1; | |
alarmFake = 0; | |
} | |
if(button & BTN_MASK_PRESS) switch(button & BTN_MASK_ID){ | |
case BTN_CLOCK: newState = AdkClock; break; | |
case BTN_ALARM: | |
// eat the transition to alarm edit mode if we're in an alarm | |
if (alarmState == AdkAlarmIdle || alarmState == AdkAlarmIdleWait) | |
newState = AdkAlarm; | |
break; | |
case BTN_BRIGHTNESS: newState = AdkBrightness; briSlider = ADK_capSenseSlider(); break; | |
case BTN_COLOR: newState = AdkColor; colorSlider = ADK_capSenseSlider(); break; | |
case BTN_PRESETS: newState = AdkPresets; break; | |
case BTN_DISPLAY: newState = AdkDisplay; nextTime = 0; speedSlider = ADK_capSenseSlider(); break; | |
case BTN_VOLUME: newState = AdkVolume; volSlider = ADK_capSenseSlider(); break; | |
} | |
if(newState != AdkInvalid){ | |
writeSettings(); | |
if(state == AdkDisplay){ | |
screenClear(); | |
//switch to next display mode | |
if(newState == AdkDisplay && ++settings.displayMode == AdkShowLast) settings.displayMode = 0; | |
} | |
} | |
// alarm | |
if (settings.almOn) { | |
uint8_t month, day, h, m, sec; | |
ADK_rtcGet(0, 0, 0, &h, &m, 0); | |
switch (alarmState) { | |
case AdkAlarmIdle: // see if we need to trigger an alarm | |
if (settings.almH == h && settings.almM == m) { | |
// start alarm | |
dbgPrintf("ALARM\n"); | |
alarmState = AdkAlarmAlarm; | |
} | |
break; | |
case AdkAlarmIdleWait: // we had triggered, need to wait at least a minute before waiting for next alarm | |
if (settings.almH != h || settings.almM != m) { | |
alarmState = AdkAlarmIdle; | |
} | |
break; | |
case AdkAlarmAlarm: { | |
// check for alarm button to cancel playing alarm | |
if (((button & BTN_MASK_ID) == BTN_ALARM) && | |
(button & (BTN_MASK_PRESS | BTN_MASK_HOLD))) { | |
alarmState = AdkAlarmIdleWait; | |
alarmStop = 1; | |
ADK_ledDrawIcon(1, (settings.R + dimIconFactor - 1) / dimIconFactor, (settings.G + dimIconFactor - 1) / dimIconFactor, (settings.B + dimIconFactor - 1) / dimIconFactor); | |
break; | |
} | |
// check for snooze button | |
if (((button & BTN_MASK_ID) <= 2) && | |
(button & (BTN_MASK_PRESS | BTN_MASK_HOLD))) { | |
dbgPrintf("ALARM SNOOZE\n"); | |
alarmState = AdkAlarmSnooze; | |
snoozeStart = ADK_getUptime() / 1000; | |
alarmStop = 1; | |
break; | |
} | |
// make sure ogg is playing | |
if (alarmEnded) { | |
alarmEnded = 0; | |
alarmStop = 0; | |
alarmFake = 0; | |
ADK_playOggBackground(settings.almTune, &alarmEnded, &alarmStop); | |
} | |
// blink the alarm button red | |
if ((ADK_getUptime() / 500) & 1) | |
ADK_ledDrawIcon(1, 0xff, 0, 0); | |
else | |
ADK_ledDrawIcon(1, (settings.R + dimIconFactor - 1) / dimIconFactor, (settings.G + dimIconFactor - 1) / dimIconFactor, (settings.B + dimIconFactor - 1) / dimIconFactor); | |
break; | |
} | |
case AdkAlarmSnooze: | |
// check for alarm button to cancel playing alarm | |
if (alarmState != AdkAlarmIdle && | |
((button & BTN_MASK_ID) == 4) && | |
(button & (BTN_MASK_PRESS | BTN_MASK_HOLD))) { | |
alarmState = AdkAlarmIdleWait; | |
alarmStop = 1; | |
ADK_ledDrawIcon(1, (settings.R + dimIconFactor - 1) / dimIconFactor, (settings.G + dimIconFactor - 1) / dimIconFactor, (settings.B + dimIconFactor - 1) / dimIconFactor); | |
break; | |
} | |
// see if we need to transition back to alarm state | |
if ((ADK_getUptime() / 1000) - snoozeStart > settings.almSnooze) { | |
dbgPrintf("ALARM FROM SNOOZE\n"); | |
alarmState = AdkAlarmAlarm; | |
break; | |
} | |
// blink the alarm button blue | |
if ((ADK_getUptime() / 500) & 1) | |
ADK_ledDrawIcon(1, 0, 0, 0xff); | |
else | |
ADK_ledDrawIcon(1, (settings.R + dimIconFactor - 1) / dimIconFactor, (settings.G + dimIconFactor - 1) / dimIconFactor, (settings.B + dimIconFactor - 1) / dimIconFactor); | |
break; | |
} | |
} else { | |
// make sure there are no dangling alarms | |
if(!alarmFake) alarmStop = 1; | |
} | |
// usb accessory processing | |
processUSBAccessory(); | |
} | |
} | |
int main(void){ | |
setup(); | |
while(1) loop(); | |
} | |
//////////// bt interface (fun) | |
//commands | |
#define MAX_PACKET_SZ 260 //256b payload + header | |
// command header | |
// u8 cmd opcode | |
// u8 sequence | |
// u16 size | |
// data formats: | |
// timespec = (year,month,day,hour,min,sec) (u16,u8,u8,u8,u8,u8) | |
#define CMD_MASK_REPLY 0x80 | |
#define BT_CMD_GET_PROTO_VERSION 1 // () -> (u8 protocolVersion) | |
#define BT_CMD_GET_SENSORS 2 // () -> (sensors: i32,i32,i32,i32,u16,u16,u16,u16,u16,u16,u16,i16,i16,i16,i16,i16,i16) | |
#define BT_CMD_FILE_LIST 3 // FIRST: (char name[]) -> (fileinfo or single zero byte) OR NONLATER: () -> (fileinfo or empty or single zero byte) | |
#define BT_CMD_FILE_DELETE 4 // (char name[0-255)) -> (char success) | |
#define BT_CMD_FILE_OPEN 5 // (char name[0-255]) -> (char success) | |
#define BT_CMD_FILE_WRITE 6 // (u8 data[]) -> (char success) | |
#define BT_CMD_FILE_CLOSE 7 // () -> (char success) | |
#define BT_CMD_GET_UNIQ_ID 8 // () -> (u8 uniq[16]) | |
#define BT_CMD_BT_NAME 9 // (char name[]) -> () OR () -> (char name[]) | |
#define BT_CMD_BT_PIN 10 // (char PIN[]) -> () OR () -> (char PIN[]) | |
#define BT_CMD_TIME 11 // (timespec) -> (char success)) OR () > (timespec) | |
#define BT_CMD_SETTINGS 12 // () -> (alarm:u8,u8,u8,brightness:u8,color:u8,u8,u8:volume:u8) or (alarm:u8,u8,u8,brightness:u8,color:u8,u8,u8:volume:u8) > (char success) | |
#define BT_CMD_ALARM_FILE 13 // () -> (char file[0-255]) OR (char file[0-255]) > (char success) | |
#define BT_CMD_GET_LICENSE 14 // () -> (u8 licensechunk[]) OR () if last sent | |
#define BT_CMD_DISPLAY_MODE 15 // () -> (u8) OR (u8) -> () | |
#define BT_CMD_LOCK 16 // () -> (u8) OR (u8) -> () | |
#define BT_PROTO_VERSION_1 1 //this line marks the end of v1.0 API, all things after this are the next version | |
//constants | |
#define BT_PROTO_VERSION_CURRENT BT_PROTO_VERSION_1 | |
static const uint8_t gzippedLicences[] = { | |
0x1F, 0x8B, 0x08, 0x00, 0x36, 0xB6, 0xDF, 0x4F, 0x02, 0x03, 0xCD, 0x58, 0x5D, 0x73, 0xDA, 0x38, 0x14, 0x7D, 0xD7, 0xAF, 0xB8, 0x93, 0x97, 0x26, 0x19, 0x07, 0xB2, 0x79, 0xDA, 0x49, 0x9F, 0x0C, | |
0x18, 0xD0, 0x2C, 0xB1, 0x59, 0xDB, 0x24, 0xE5, 0xAD, 0xC2, 0x16, 0xE0, 0x1D, 0x63, 0x79, 0x2D, 0x93, 0x34, 0xFF, 0x7E, 0xEF, 0x95, 0x6D, 0x3E, 0x12, 0x92, 0xA6, 0x09, 0xDD, 0x96, 0xE9, 0x34, | |
0x06, 0x49, 0x57, 0xE7, 0x9E, 0xFB, 0x71, 0x2C, 0x31, 0x38, 0xC6, 0x87, 0xFD, 0x02, 0x2B, 0x2C, 0x5C, 0x26, 0x1A, 0xF2, 0x42, 0xC5, 0xEB, 0xA8, 0x84, 0x24, 0x8B, 0xD2, 0x75, 0x2C, 0x35, 0x68, | |
0x35, 0x2F, 0x1F, 0x44, 0x21, 0x61, 0x5E, 0xA8, 0x15, 0x74, 0x97, 0xC2, 0xBD, 0x66, 0xE7, 0x17, 0xC7, 0xFB, 0xB4, 0x59, 0x1B, 0xA0, 0x2F, 0xCA, 0xBE, 0x86, 0x0B, 0xE8, 0xDB, 0x21, 0xCC, 0x93, | |
0x54, 0x82, 0x7E, 0xD4, 0xA5, 0x5C, 0xC1, 0x0A, 0xC1, 0xE0, 0xB7, 0x1A, 0x4C, 0x35, 0x04, 0xFE, 0x65, 0xEB, 0xF2, 0xCF, 0x19, 0x41, 0x3E, 0xED, 0x9E, 0x11, 0x20, 0x0B, 0xAE, 0x2E, 0xFF, 0xF8, | |
0x83, 0xB5, 0x2F, 0x8E, 0x0C, 0xAB, 0x42, 0xD5, 0x60, 0xD0, 0x20, 0x60, 0x21, 0x33, 0x59, 0x24, 0xD1, 0x4B, 0x38, 0xE7, 0xAA, 0x00, 0xBD, 0x12, 0x69, 0x0A, 0x72, 0x35, 0x93, 0x71, 0x2C, 0xE3, | |
0x7A, 0x82, 0x6E, 0xA1, 0x39, 0xC3, 0xAF, 0x31, 0x33, 0x2F, 0xA4, 0xDC, 0x12, 0x5B, 0x2E, 0x45, 0x09, 0x2A, 0x47, 0xD3, 0xB1, 0xB1, 0x20, 0x31, 0x00, 0xA2, 0x4C, 0x54, 0x66, 0x41, 0x21, 0xB5, | |
0x14, 0x45, 0xB4, 0x04, 0x91, 0xC5, 0x10, 0xA9, 0xD5, 0x4A, 0x16, 0x51, 0x22, 0x52, 0x34, 0x16, 0xCB, 0x7B, 0x99, 0xAA, 0x7C, 0x25, 0xB3, 0x52, 0xC3, 0x3A, 0x8B, 0x65, 0x01, 0x69, 0x12, 0xC9, | |
0x4C, 0x4B, 0xC8, 0x15, 0x3E, 0x3D, 0x82, 0x9A, 0xA3, 0xB5, 0x34, 0x55, 0x0F, 0x49, 0xB6, 0x80, 0xB2, 0xA8, 0x40, 0x10, 0xD9, 0x5D, 0x95, 0x3F, 0x16, 0xC9, 0x62, 0x59, 0x12, 0x7F, 0x86, 0x3A, | |
0x0B, 0x2A, 0x1A, 0x09, 0x79, 0x35, 0x42, 0x1B, 0x17, 0xF7, 0x32, 0xAE, 0x96, 0x9C, 0x23, 0x76, 0x79, 0x80, 0x8E, 0x7D, 0x3F, 0x08, 0x63, 0xB9, 0x94, 0x85, 0x19, 0x74, 0x3D, 0xB8, 0xB3, 0x7D, | |
0xDF, 0x76, 0xC3, 0x69, 0xCB, 0x58, 0x70, 0x15, 0x19, 0x2D, 0x91, 0x3D, 0x72, 0x0D, 0xF0, 0xDF, 0x5A, 0xCB, 0x16, 0x4C, 0xD5, 0x1A, 0x22, 0x61, 0xBE, 0x58, 0x64, 0x3B, 0x99, 0x3F, 0x1A, 0x43, | |
0x85, 0x8C, 0x13, 0x9A, 0x3D, 0x5B, 0x97, 0x68, 0xAF, 0x24, 0x62, 0x08, 0x3B, 0xE4, 0xB2, 0xD0, 0x2A, 0x13, 0xA9, 0x05, 0x99, 0xCA, 0x2E, 0x30, 0x5B, 0xE7, 0x38, 0x88, 0xA4, 0x6D, 0xC9, 0xD9, | |
0xA4, 0xF0, 0xC4, 0xED, 0x39, 0x3E, 0x4C, 0xBD, 0x89, 0x0F, 0xBE, 0x13, 0x8C, 0x3D, 0x37, 0xE0, 0x1D, 0x3E, 0xE2, 0x0D, 0x20, 0x7F, 0xBB, 0x03, 0x02, 0xD2, 0xC4, 0x97, 0x56, 0xEB, 0x22, 0x92, | |
0x68, 0x0B, 0x73, 0x6D, 0xB5, 0xD6, 0x44, 0x43, 0x29, 0x92, 0x8C, 0xBC, 0x02, 0x31, 0x53, 0xF7, 0x34, 0xD4, 0x70, 0x97, 0xA9, 0x12, 0xF9, 0x36, 0xFC, 0x1C, 0x33, 0xEF, 0xCE, 0xDB, 0x8C, 0xBD, | |
0xA9, 0x12, 0x7B, 0xAB, 0xA4, 0x2C, 0x1E, 0x61, 0x50, 0x24, 0xD9, 0x4C, 0x16, 0x8B, 0x6B, 0xD6, 0x3E, 0x67, 0x3B, 0x91, 0x8D, 0x9A, 0xC8, 0x3E, 0x99, 0x07, 0xA7, 0x02, 0x4D, 0xAF, 0x67, 0x69, | |
0xA2, 0x97, 0x75, 0xBE, 0xF5, 0x06, 0x5E, 0x40, 0xF1, 0x58, 0x96, 0x65, 0x7E, 0xDD, 0x6E, 0xC7, 0x0B, 0xA5, 0x67, 0xA9, 0x5A, 0xB4, 0xE8, 0x3F, 0x9D, 0xAB, 0xB2, 0x85, 0xDC, 0x9E, 0x31, 0xBB, | |
0xC9, 0x0D, 0xBD, 0x93, 0x1C, 0x6C, 0x9F, 0x44, 0x13, 0x39, 0x8C, 0x24, 0x62, 0x6E, 0xB8, 0xA4, 0x5F, 0x66, 0x49, 0x26, 0x10, 0x02, 0xEE, 0xB5, 0xD2, 0x16, 0x3C, 0x24, 0xE5, 0x92, 0x22, 0x46, | |
0x7F, 0xD5, 0xBA, 0x64, 0x26, 0xE8, 0x49, 0x93, 0xF1, 0xE4, 0x1F, 0xC6, 0x18, 0x41, 0x97, 0x08, 0x0F, 0x39, 0xB8, 0x4F, 0xA8, 0x8C, 0x4C, 0x8D, 0x50, 0x18, 0xB6, 0x29, 0x1D, 0xA9, 0x2C, 0x4E, | |
0xCC, 0xAE, 0x48, 0xD6, 0x4A, 0x96, 0xD7, 0xC0, 0xD8, 0x91, 0xA2, 0x6A, 0xE1, 0x58, 0xA2, 0xA9, 0x7D, 0x22, 0x4D, 0x25, 0xD9, 0xD8, 0x6C, 0xA6, 0x9B, 0x34, 0xDF, 0x41, 0x82, 0x3B, 0x46, 0xA9, | |
0x48, 0x30, 0xFF, 0x5A, 0x88, 0x21, 0x1C, 0xF2, 0x00, 0x02, 0xAF, 0x1F, 0x62, 0xFE, 0x3B, 0x80, 0xCF, 0x63, 0xDF, 0xBB, 0xE5, 0x3D, 0xA7, 0x07, 0x9D, 0x29, 0x84, 0x43, 0x07, 0xBA, 0xDE, 0x78, | |
0xEA, 0xF3, 0xC1, 0x30, 0x84, 0xA1, 0x37, 0xC2, 0x14, 0x0D, 0xC0, 0x76, 0x7B, 0xF8, 0xAB, 0x1B, 0xFA, 0xBC, 0x33, 0x09, 0x3D, 0xFC, 0xE1, 0xC4, 0x0E, 0x70, 0xE5, 0x09, 0x0D, 0x30, 0xDB, 0x9D, | |
0x82, 0xF3, 0x65, 0x8C, 0x29, 0x1C, 0x80, 0xE7, 0x03, 0xBF, 0x19, 0x8F, 0x38, 0x1A, 0xAB, 0xAB, 0x8B, 0x3B, 0x81, 0x05, 0xDC, 0xED, 0x8E, 0x26, 0x3D, 0xEE, 0x0E, 0x2C, 0x40, 0x03, 0x58, 0x7B, | |
0x21, 0x8C, 0xF8, 0x0D, 0x0F, 0x71, 0x5A, 0xE8, 0x59, 0x66, 0xD3, 0x7A, 0x19, 0xDB, 0x2E, 0x03, 0xAF, 0x0F, 0x37, 0x8E, 0xDF, 0x1D, 0xE2, 0x57, 0xBB, 0x2A, 0x0C, 0x03, 0xA4, 0xCF, 0x43, 0x97, | |
0xF6, 0xEA, 0xE3, 0x66, 0x36, 0x8C, 0x6D, 0x3F, 0xE4, 0xDD, 0xC9, 0xC8, 0xF6, 0x61, 0x3C, 0xF1, 0xC7, 0x5E, 0xE0, 0x00, 0xBA, 0xC5, 0x7A, 0x3C, 0xE8, 0x8E, 0x6C, 0x7E, 0xE3, 0xF4, 0x5A, 0xB8, | |
0x3B, 0x55, 0xBB, 0x73, 0xEB, 0xB8, 0x21, 0x04, 0x43, 0x7B, 0x34, 0x7A, 0xE2, 0xA5, 0x77, 0xE7, 0x62, 0x1D, 0xA2, 0xB5, 0x3D, 0x17, 0x3B, 0x0E, 0x62, 0xB4, 0x3B, 0x23, 0x87, 0x36, 0x32, 0x4E, | |
0xF6, 0xB8, 0xEF, 0x74, 0x43, 0xF2, 0x66, 0xFB, 0xD4, 0x45, 0xE2, 0x10, 0xDE, 0xC8, 0x82, 0x60, 0xEC, 0x74, 0x39, 0x3D, 0x38, 0x5F, 0x1C, 0xF4, 0xC5, 0xF6, 0xA7, 0x56, 0x6D, 0x33, 0x70, 0xFE, | |
0x9E, 0xE0, 0x24, 0x1C, 0x84, 0x9E, 0x7D, 0x63, 0x0F, 0x9C, 0x80, 0x9D, 0x7E, 0x87, 0x11, 0x0C, 0x49, 0x77, 0xE2, 0x3B, 0x37, 0x04, 0x19, 0x69, 0x08, 0x26, 0x9D, 0x20, 0xE4, 0xE1, 0x24, 0x74, | |
0x60, 0xE0, 0x79, 0x3D, 0xC3, 0x73, 0xE0, 0xF8, 0xB7, 0xBC, 0xEB, 0x04, 0x9F, 0xD9, 0xC8, 0x0B, 0x0C, 0x59, 0x93, 0xC0, 0xC1, 0x72, 0xB2, 0x43, 0xDB, 0x6C, 0x8C, 0x26, 0x90, 0xA9, 0xE0, 0x33, | |
0x3D, 0x77, 0x26, 0x01, 0x37, 0x9C, 0x71, 0x37, 0x74, 0x7C, 0x7F, 0x32, 0x0E, 0xB9, 0xE7, 0x9E, 0x61, 0x78, 0xEF, 0x90, 0x15, 0xC4, 0x68, 0xE3, 0xD2, 0x9E, 0x09, 0xA6, 0xE7, 0x02, 0xB9, 0x8A, | |
0x04, 0x79, 0xFE, 0x94, 0x8C, 0x12, 0x07, 0x86, 0x7B, 0x0B, 0xEE, 0x86, 0x0E, 0xFE, 0xEE, 0x13, 0x9F, 0x86, 0x29, 0x9B, 0x28, 0x08, 0x90, 0xB1, 0x6E, 0xB8, 0x3B, 0x0D, 0xF7, 0x43, 0x02, 0xC3, | |
0x1D, 0x1F, 0xC1, 0x75, 0x06, 0x23, 0x3E, 0x70, 0xDC, 0xAE, 0x43, 0xA3, 0x1E, 0x59, 0xB9, 0xE3, 0x81, 0x73, 0x86, 0xA1, 0xE2, 0x01, 0x4D, 0xE0, 0xD5, 0xB6, 0x77, 0x36, 0xEE, 0x39, 0x31, 0x2E, | |
0x53, 0x88, 0x10, 0x55, 0xF5, 0xC8, 0x03, 0xD6, 0x24, 0xAC, 0x65, 0x02, 0x09, 0xBC, 0x0F, 0x76, 0xEF, 0x96, 0x13, 0xEC, 0x7A, 0x32, 0x86, 0xBE, 0xE9, 0x9F, 0x15, 0x65, 0xDD, 0x61, 0x4D, 0x77, | |
0x8B, 0xBD, 0xB9, 0x69, 0xD9, 0xE5, 0x4A, 0xA6, 0x28, 0x40, 0x45, 0xAE, 0x0A, 0x53, 0xF0, 0xD4, 0xB6, 0xE0, 0x50, 0xDB, 0x7A, 0x36, 0xF3, 0xAD, 0xAF, 0x31, 0x88, 0x05, 0x4D, 0x1E, 0xF5, 0x53, | |
0x99, 0x3C, 0xD4, 0x00, 0x3F, 0x68, 0xF2, 0x27, 0xA0, 0xFC, 0x78, 0x43, 0x7E, 0x66, 0xF2, 0x78, 0x0D, 0xFA, 0x67, 0x3A, 0x7E, 0x71, 0xAC, 0xD6, 0xBF, 0x35, 0x49, 0x22, 0xF0, 0x9A, 0x02, 0x6C, | |
0xFB, 0x3E, 0xCC, 0xF0, 0x65, 0xEC, 0xA1, 0xF5, 0x6B, 0xF2, 0x92, 0x2A, 0xE5, 0x93, 0x86, 0x4C, 0xAC, 0xD0, 0x49, 0xF1, 0x48, 0x8E, 0x20, 0x1E, 0x0A, 0x3B, 0xC2, 0x54, 0x20, 0xB3, 0x58, 0x15, | |
0x98, 0x02, 0x18, 0x61, 0x8C, 0xD6, 0x4A, 0xE1, 0xFB, 0x54, 0x5D, 0xA5, 0x1A, 0xDF, 0x22, 0x8B, 0xE4, 0x9E, 0x5E, 0x03, 0xA8, 0x38, 0x9F, 0x38, 0xBE, 0xA9, 0xDC, 0x26, 0x2F, 0x74, 0x2E, 0x23, | |
0x4A, 0x04, 0x5C, 0x9E, 0x50, 0xBA, 0x14, 0x94, 0x02, 0x59, 0x95, 0x0C, 0x5A, 0x23, 0x33, 0xAD, 0xFF, 0xD7, 0xF1, 0x8D, 0x06, 0xF9, 0x98, 0x59, 0xAF, 0xAA, 0xAE, 0x1D, 0xDE, 0x38, 0xA3, 0x5D, | |
0x51, 0x85, 0x27, 0xA2, 0xDA, 0x98, 0xFC, 0x98, 0xB8, 0xC2, 0xBE, 0xB8, 0x56, 0x26, 0x9F, 0x48, 0xAC, 0xF5, 0x06, 0x7D, 0x45, 0x7C, 0xAE, 0xE7, 0x5E, 0x70, 0xB7, 0xEF, 0xE3, 0xB6, 0x95, 0x4A, | |
0x91, 0x57, 0xCF, 0x1C, 0x3F, 0x28, 0xBE, 0x95, 0xB3, 0x7B, 0xF2, 0x0A, 0x87, 0xE5, 0x75, 0x87, 0xCB, 0xF7, 0x2A, 0x2D, 0x1C, 0x52, 0xDA, 0xCA, 0xE4, 0x7B, 0xF5, 0x16, 0x0E, 0xE8, 0x6D, 0x6D, | |
0xF2, 0xBD, 0xB2, 0x0B, 0xCF, 0x64, 0x77, 0xE3, 0xF8, 0xBB, 0xF5, 0x77, 0xC7, 0xF3, 0x27, 0x79, 0xF9, 0x71, 0x35, 0x86, 0xAD, 0x1A, 0x57, 0x26, 0x7F, 0x5C, 0x93, 0x5F, 0xAF, 0x9E, 0x97, 0xD4, | |
0x3A, 0xC4, 0x18, 0x21, 0xE6, 0x7D, 0xD1, 0xA6, 0x56, 0xF7, 0x25, 0xC9, 0x97, 0x2D, 0x85, 0xC7, 0x87, 0xBE, 0xC2, 0xC3, 0x66, 0x2D, 0xDD, 0x4F, 0x75, 0xFB, 0xF2, 0xCA, 0x3A, 0x34, 0xF1, 0xF7, | |
0x38, 0x25, 0x68, 0x46, 0x8B, 0x48, 0x86, 0x18, 0xFB, 0xA8, 0x56, 0xB0, 0xDD, 0x63, 0xC2, 0x0F, 0x9F, 0x11, 0x0E, 0xED, 0x8F, 0xFB, 0xEC, 0xF8, 0xDF, 0xEC, 0x5F, 0xC5, 0x47, 0x1E, 0x1D, 0x02, | |
0x54, 0x6E, 0xB1, 0x58, 0x45, 0x6B, 0xBA, 0x41, 0x10, 0x4D, 0x58, 0xDA, 0xC8, 0xB8, 0xA2, 0x33, 0x3C, 0x0A, 0x49, 0x89, 0xDA, 0x20, 0x52, 0xBD, 0x65, 0xD7, 0x84, 0xA4, 0xD6, 0xBD, 0x0D, 0x74, | |
0xE3, 0x8D, 0x2B, 0x13, 0xB3, 0x88, 0x06, 0x8D, 0x0C, 0x21, 0x94, 0x17, 0xB2, 0x06, 0xD5, 0x69, 0x3B, 0xCF, 0xF0, 0x9E, 0x94, 0x9A, 0x21, 0xEE, 0xCA, 0x22, 0x2A, 0x95, 0xD1, 0xB0, 0x77, 0xE8, | |
0x17, 0x7B, 0xAF, 0x6A, 0x1D, 0xE5, 0xC8, 0xC6, 0xBE, 0x7E, 0x35, 0xF2, 0xF2, 0xE9, 0xD3, 0x21, 0x7D, 0x79, 0x9B, 0xAE, 0xB0, 0xB7, 0xE9, 0xCA, 0x77, 0x0E, 0x6D, 0xEC, 0xA5, 0x43, 0xDB, 0x9E, | |
0x6E, 0xBC, 0x70, 0x6A, 0xEB, 0x7B, 0x13, 0x17, 0x5B, 0x2E, 0xF6, 0x51, 0xF6, 0xEA, 0x81, 0x0D, 0xBE, 0x7B, 0x60, 0x63, 0x1F, 0x95, 0x11, 0x76, 0x14, 0x01, 0x61, 0x1F, 0x3B, 0xB0, 0xD5, 0xCA, | |
0xC1, 0x7E, 0x9B, 0x03, 0x1B, 0x7B, 0x2E, 0x11, 0xEF, 0x38, 0xB0, 0xBD, 0xED, 0xB4, 0x46, 0x65, 0x6A, 0x67, 0x71, 0xA1, 0x92, 0x18, 0xBC, 0x5C, 0x66, 0x17, 0x41, 0xD5, 0x22, 0xC7, 0x85, 0xFA, | |
0x47, 0x46, 0xA5, 0xB9, 0x72, 0x82, 0xF3, 0xE7, 0xF7, 0x89, 0x57, 0xE6, 0xBA, 0x70, 0x77, 0x25, 0xEC, 0xAF, 0xC4, 0x55, 0xB4, 0x70, 0x54, 0x5D, 0x58, 0xC6, 0xF5, 0xFD, 0xA5, 0xD9, 0x2E, 0x17, | |
0x11, 0xFE, 0xA9, 0x47, 0x2C, 0xB8, 0x95, 0x05, 0xD5, 0x28, 0x5C, 0xB5, 0x2E, 0xE1, 0x94, 0x26, 0x9C, 0xD4, 0x43, 0x27, 0x67, 0x9F, 0xC9, 0xC4, 0xA3, 0x5A, 0x6F, 0xDE, 0x79, 0x49, 0x52, 0x4C, | |
0x0F, 0x30, 0x37, 0xB3, 0xF2, 0x5B, 0x24, 0x73, 0x72, 0x8D, 0xAE, 0x06, 0xF3, 0x34, 0x11, 0x59, 0x24, 0xB7, 0x2D, 0xAC, 0xB6, 0xD2, 0x22, 0x1B, 0xD3, 0xDA, 0x86, 0x9A, 0x99, 0x7E, 0x2F, 0x4C, | |
0x93, 0x6D, 0x5A, 0x58, 0x3D, 0x11, 0x44, 0x03, 0xDA, 0x7C, 0xEA, 0xAB, 0xB2, 0x87, 0x87, 0x87, 0x96, 0x30, 0x88, 0xA9, 0xCB, 0xB5, 0xEB, 0x0B, 0x58, 0xDD, 0x1E, 0x61, 0x1E, 0x62, 0x96, 0x5F, | |
0x20, 0xEA, 0x7A, 0xD5, 0x24, 0x4B, 0xA5, 0xA6, 0x83, 0xE3, 0xBF, 0xEB, 0xA4, 0x40, 0x8F, 0x67, 0x8F, 0x20, 0x72, 0x44, 0x15, 0x89, 0x19, 0x62, 0x4D, 0xC5, 0x03, 0xB5, 0x37, 0xB1, 0x28, 0x64, | |
0xD5, 0xF3, 0x10, 0x06, 0x35, 0x2A, 0xEC, 0xDA, 0xD6, 0x26, 0x26, 0x64, 0x66, 0x7B, 0x27, 0xBA, 0x4B, 0x5A, 0x83, 0x11, 0x5D, 0xDF, 0x9D, 0x60, 0x5A, 0xFA, 0xE6, 0xAD, 0xB7, 0x63, 0x07, 0x3C, | |
0xB0, 0xC8, 0xC8, 0x1D, 0x0F, 0x87, 0x94, 0x54, 0xBB, 0x5D, 0xC5, 0xD4, 0x65, 0x8F, 0x53, 0x19, 0x98, 0xD2, 0xA1, 0xE4, 0xFB, 0x0B, 0xEB, 0xDA, 0x82, 0xBA, 0xB5, 0xCB, 0x6F, 0x79, 0x41, 0x1E, | |
0x20, 0xCC, 0x84, 0xE8, 0xA4, 0xDB, 0x3F, 0xB4, 0x15, 0x48, 0xB9, 0x07, 0x61, 0x5E, 0x77, 0xF7, 0x4D, 0xD7, 0x4D, 0x45, 0xB6, 0x58, 0x8B, 0x85, 0x84, 0x05, 0xCA, 0x57, 0x91, 0x91, 0x0E, 0x6D, | |
0x5B, 0xAF, 0x51, 0x29, 0x32, 0x93, 0x26, 0x28, 0xE5, 0xA2, 0x12, 0xAE, 0x67, 0x7E, 0xD1, 0x46, 0xF8, 0xCA, 0xF2, 0x1F, 0xF8, 0xB9, 0x5A, 0xB2, 0x5A, 0x19, 0x00, 0x00 | |
}; | |
static void putLE32(uint8_t* buf, uint16_t* idx, uint32_t val){ | |
buf[(*idx)++] = val; | |
buf[(*idx)++] = val >> 8; | |
buf[(*idx)++] = val >> 16; | |
buf[(*idx)++] = val >> 24; | |
} | |
static void putLE16(uint8_t* buf, uint16_t* idx, uint32_t val){ | |
buf[(*idx)++] = val; | |
buf[(*idx)++] = val >> 8; | |
} | |
static uint16_t adkProcessCommand(uint8_t cmd, const uint8_t* dataIn, uint16_t sz, char fromBT, uint8_t* reply, uint16_t maxReplySz){ //returns num bytes to reply with (or 0 for no reply) | |
uint16_t sendSz = 0; | |
static FatFileP btFile = 0, usbFile = 0; | |
static FatDirP btDir = 0, usbDir = 0; | |
static uint16_t btLicPos = 0, usbLicPos = 0; | |
FatFileP* filP = fromBT ? &btFile : &usbFile; | |
FatDirP* dirP = fromBT ? &btDir : &usbDir; | |
uint16_t* licPos = fromBT ? &btLicPos : &usbLicPos; | |
dbgPrintf("ADK: BT: have cmd 0x%x with %db of data\n", cmd, sz); | |
//NOTE: this code was written in a hurry and features little error checking. yes, I know it's bad. -DG | |
//process packet | |
switch(cmd){ | |
case BT_CMD_GET_PROTO_VERSION: | |
{ | |
reply[sendSz++] = BT_PROTO_VERSION_CURRENT; | |
} | |
break; | |
case BT_CMD_GET_SENSORS: | |
{ | |
putLE32(reply, &sendSz, hTemp); | |
putLE32(reply, &sendSz, hHum); | |
putLE32(reply, &sendSz, bPress); | |
putLE32(reply, &sendSz, bTemp); | |
putLE16(reply, &sendSz, prox[0]); | |
putLE16(reply, &sendSz, prox[1]); | |
putLE16(reply, &sendSz, prox[3]); | |
putLE16(reply, &sendSz, prox[4]); | |
putLE16(reply, &sendSz, prox[5]); | |
putLE16(reply, &sendSz, prox[2]); | |
putLE16(reply, &sendSz, prox[6]); | |
putLE16(reply, &sendSz, accel[0]); | |
putLE16(reply, &sendSz, accel[1]); | |
putLE16(reply, &sendSz, accel[2]); | |
putLE16(reply, &sendSz, mag[0]); | |
putLE16(reply, &sendSz, mag[1]); | |
putLE16(reply, &sendSz, mag[2]); | |
} | |
break; | |
case BT_CMD_FILE_LIST: | |
{ | |
if(sz){ //reset | |
if(*dirP) ADK_fatfsCloseDir(*dirP); | |
if(ADK_fatfsOpenDir(dirP, (char*)dataIn)) *dirP = 0; | |
} | |
if(*dirP){ | |
FatFileInfo fi; | |
fi.longName = (char*)reply + 5; | |
fi.nameSz = maxReplySz - 5; | |
if(!ADK_fatfsReadDir(*dirP, &fi)){ | |
fi.longName[fi.nameSz - 1] = 0; | |
reply[sendSz++] = fi.fsize; | |
reply[sendSz++] = fi.fsize >> 8; | |
reply[sendSz++] = fi.fsize >> 16; | |
reply[sendSz++] = fi.fsize >> 24; | |
reply[sendSz++] = fi.attrib; | |
sendSz += strlen(fi.longName) + 1; | |
} | |
else reply[sendSz++] = 0; | |
} | |
else reply[sendSz++] = 0; | |
} | |
break; | |
case BT_CMD_FILE_DELETE: | |
{ | |
reply[sendSz++] = !ADK_fatfsUnlink((const char*)dataIn); | |
} | |
break; | |
case BT_CMD_FILE_OPEN: | |
{ | |
if(*filP) ADK_fatfsClose(*filP); | |
reply[sendSz++] = !ADK_fatfsOpen(filP, (const char*)dataIn, FATFS_WRITE | FATFS_CREATE | FATFS_TRUNCATE); | |
if(!reply[sendSz - 1]) *filP = 0; | |
} | |
break; | |
case BT_CMD_FILE_WRITE: | |
{ | |
uint32_t written; | |
reply[sendSz++] = !ADK_fatfsWrite(*filP, (void*)dataIn, sz, &written) && written == sz; | |
} | |
break; | |
case BT_CMD_FILE_CLOSE: | |
{ | |
if(*filP){ | |
reply[sendSz++] = 1; | |
ADK_fatfsClose(*filP); | |
*filP = 0; | |
} | |
else reply[sendSz++] = 0; | |
} | |
break; | |
case BT_CMD_GET_UNIQ_ID: | |
{ | |
uint32_t id[4]; | |
ADK_getUniqueId(id); | |
putLE32(reply, &sendSz, id[0]); | |
putLE32(reply, &sendSz, id[1]); | |
putLE32(reply, &sendSz, id[2]); | |
putLE32(reply, &sendSz, id[3]); | |
} | |
break; | |
case BT_CMD_BT_NAME: | |
{ | |
if(sz){ //set | |
strcpy(settings.btName, (char*)dataIn); | |
reply[sendSz++] = 1; | |
writeSettings(); | |
} | |
else{ | |
strcpy((char*)reply, settings.btName); | |
sendSz = strlen((char*)reply) + 1; | |
} | |
} | |
break; | |
case BT_CMD_BT_PIN: | |
{ | |
if(sz){ //set | |
strcpy(settings.btPIN, (char*)dataIn); | |
reply[sendSz++] = 1; | |
writeSettings(); | |
} | |
else{ | |
strcpy((char*)reply, settings.btPIN); | |
sendSz = strlen((char*)reply) + 1; | |
} | |
} | |
break; | |
case BT_CMD_TIME: | |
{ | |
if (sz >= 7) { //set | |
ADK_rtcSet(dataIn[1] << 8 | dataIn[0], dataIn[2], dataIn[3], dataIn[4], dataIn[5], dataIn[6]); | |
reply[sendSz++] = 1; | |
} else if (sz == 0) { | |
ADK_rtcGet((uint16_t *)&reply[0], &reply[2], &reply[3], &reply[4], &reply[5], &reply[6]); | |
sendSz += 7; | |
} | |
} | |
break; | |
case BT_CMD_SETTINGS: | |
{ | |
if (sz >= 8) { //set | |
settings.almH = dataIn[0]; | |
settings.almM = dataIn[1]; | |
settings.almOn = dataIn[2]; | |
settings.bri = dataIn[3]; | |
settings.R = dataIn[4]; | |
settings.G = dataIn[5]; | |
settings.B = dataIn[6]; | |
settings.vol = dataIn[7]; | |
ADK_setVolume(settings.vol); | |
writeSettings(); | |
reply[sendSz++] = 1; | |
} else { | |
reply[sendSz++] = settings.almH; | |
reply[sendSz++] = settings.almM; | |
reply[sendSz++] = settings.almOn; | |
reply[sendSz++] = settings.bri; | |
reply[sendSz++] = settings.R; | |
reply[sendSz++] = settings.G; | |
reply[sendSz++] = settings.B; | |
reply[sendSz++] = settings.vol; | |
} | |
} | |
break; | |
case BT_CMD_ALARM_FILE: | |
{ | |
if(sz){ //set | |
strcpy(settings.almTune, (char*)dataIn); | |
reply[sendSz++] = 1; | |
writeSettings(); | |
} else{ | |
strcpy((char*)reply, settings.almTune); | |
sendSz = strlen((char*)reply) + 1; | |
} | |
} | |
break; | |
case BT_CMD_GET_LICENSE: | |
{ | |
static const uint32_t maxPacket = MAX_PACKET_SZ - 10; //seems reasonable | |
if(*licPos >= sizeof(gzippedLicences)){ //send terminator | |
reply[sendSz++] = 0; | |
*licPos = 0; | |
} | |
else{ | |
uint32_t left = sizeof(gzippedLicences) - *licPos; | |
if(left > maxPacket) left = maxPacket; | |
reply[sendSz++] = 1; | |
while(left--) reply[sendSz++] = gzippedLicences[(*licPos)++]; | |
} | |
} | |
break; | |
case BT_CMD_DISPLAY_MODE: | |
{ | |
if (sz) { //set | |
settings.displayMode = dataIn[0]; | |
reply[sendSz++] = 1; | |
} else if (sz == 0) { | |
reply[sendSz++] = settings.displayMode; | |
} | |
} | |
break; | |
case BT_CMD_LOCK: | |
{ | |
if (sz) { //set | |
locked = dataIn[0] ? 2 : 0; | |
reply[sendSz++] = 1; | |
} else if (sz == 0) { | |
reply[sendSz++] = locked; | |
} | |
} | |
break; | |
} | |
return sendSz; | |
} | |
static uint8_t cmdBuf[MAX_PACKET_SZ]; | |
static uint32_t bufPos = 0; | |
static void btAdkPortOpen(void* port, uint8_t dlci){ | |
bufPos = 0; | |
} | |
static void btAdkPortClose(void* port, uint8_t dlci){ | |
//nothing here [yet?] | |
} | |
static void btAdkPortRx(void* port, uint8_t dlci, const uint8_t* data, uint16_t sz){ | |
uint8_t reply[MAX_PACKET_SZ]; | |
uint32_t i; | |
uint8_t seq, cmd; | |
uint16_t cmdSz; | |
uint8_t* ptr; | |
while(sz || bufPos){ | |
uint16_t sendSz = 0; | |
//copy to buffer as much as we can | |
while(bufPos < MAX_PACKET_SZ && sz){ | |
cmdBuf[bufPos++] = *data++; | |
sz--; | |
} | |
//see if a packet exists | |
if(bufPos < 4) return; // too small to be a packet -> discard | |
cmd = cmdBuf[0]; | |
seq = cmdBuf[1]; | |
cmdSz = cmdBuf[3]; | |
cmdSz <<= 8; | |
cmdSz += cmdBuf[2]; | |
if(bufPos - 4 < cmdSz) return; //not entire command received yet | |
sendSz = adkProcessCommand(cmd, cmdBuf + 4, cmdSz, 1, reply + 4, MAX_PACKET_SZ - 4); | |
if(sendSz){ | |
reply[0] = cmd | CMD_MASK_REPLY; | |
reply[1] = seq; | |
reply[2] = sendSz; | |
reply[3] = sendSz >> 8; | |
sendSz += 4; | |
ADK_btRfcommPortTx(port, dlci, reply, sendSz); | |
} | |
//adjust buffer as needed | |
for(i = 0; i < bufPos - cmdSz - 4; i++){ | |
cmdBuf[i] = cmdBuf[i + cmdSz + 4]; | |
} | |
bufPos = i; | |
} | |
} | |
//////////// bt support (boring) | |
#define maxPairedDevices 4 | |
static uint8_t numPairedDevices = 0; | |
static uint8_t savedMac[maxPairedDevices][BLUETOOTH_MAC_SIZE]; | |
static uint8_t savedKey[maxPairedDevices][BLUETOOTH_LINK_KEY_SIZE]; | |
static char adkBtConnectionRequest(const uint8_t* mac, uint32_t devClass, uint8_t linkType){ //return 1 to accept | |
dbgPrintf("Accepting connection from %02X:%02X:%02X:%02X:%02X:%02X\n", mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]); | |
return 1; | |
} | |
static char adkBtLinkKeyRequest(const uint8_t* mac, uint8_t* buf){ //link key create | |
uint8_t i, j; | |
dbgPrintf("Key request from %02X:%02X:%02X:%02X:%02X:%02X\n -> ", mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]); | |
for(i = 0; i < numPairedDevices; i++){ | |
for(j = 0; j < BLUETOOTH_MAC_SIZE && savedMac[i][j] == mac[j]; j++); | |
if(j == BLUETOOTH_MAC_SIZE){ //match | |
dbgPrintf("{"); | |
for(j = 0; j < BLUETOOTH_LINK_KEY_SIZE; j++){ | |
dbgPrintf(" %02X", savedKey[i][j]); | |
buf[j] = savedKey[i][j]; | |
} | |
dbgPrintf(" }"); | |
return 1; | |
} | |
} | |
dbgPrintf("FAIL\n"); | |
return 0; | |
} | |
static void adkBtLinkKeyCreated(const uint8_t* mac, const uint8_t* buf){ //link key was just created, save it if you want it later | |
uint8_t j; | |
dbgPrintf("Key created for %02X:%02X:%02X:%02X:%02X:%02X <- {", mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]); | |
for(j = 0; j < BLUETOOTH_LINK_KEY_SIZE; j++){ | |
dbgPrintf(" %02X", buf[j]); | |
} | |
dbgPrintf(" }\n"); | |
if(numPairedDevices < maxPairedDevices){ | |
for(j = 0; j < BLUETOOTH_LINK_KEY_SIZE; j++) savedKey[numPairedDevices][j] = buf[j]; | |
for(j = 0; j < BLUETOOTH_MAC_SIZE; j++) savedMac[numPairedDevices][j] = mac[j]; | |
numPairedDevices++; | |
dbgPrintf("saved to slot %d/%d\n", numPairedDevices, maxPairedDevices); | |
} | |
else{ | |
dbgPrintf("out of slots...discaring\n"); | |
} | |
} | |
static char adkBtPinRequest(const uint8_t* mac, uint8_t* buf){ //fill buff with PIN code, return num bytes used (16 max) return 0 to decline | |
uint8_t v, i = 0; | |
dbgPrintf("PIN request from %02X:%02X:%02X:%02X:%02X:%02X\n -> ", mac[5], mac[4], mac[3], mac[2], mac[1], mac[0]); | |
if(btPIN){ | |
dbgPrintf(" -> using pin '%s'\n", btPIN); | |
for(i = 0; btPIN[i]; i++) buf[i] = btPIN[i]; | |
return i; | |
} | |
else dbgPrintf(" no PIN set. rejecting\n"); | |
return 0; | |
} | |
#define MAGIX 0xFA | |
static uint8_t sdpDescrADK[] = | |
{ | |
//service class ID list | |
SDP_ITEM_DESC(SDP_TYPE_UINT, SDP_SZ_2), 0x00, 0x01, SDP_ITEM_DESC(SDP_TYPE_ARRAY, SDP_SZ_u8), 17, | |
SDP_ITEM_DESC(SDP_TYPE_UUID, SDP_SZ_16), BT_ADK_UUID, | |
//ServiceId | |
SDP_ITEM_DESC(SDP_TYPE_UINT, SDP_SZ_2), 0x00, 0x03, SDP_ITEM_DESC(SDP_TYPE_UUID, SDP_SZ_2), 0x11, 0x01, | |
//ProtocolDescriptorList | |
SDP_ITEM_DESC(SDP_TYPE_UINT, SDP_SZ_2), 0x00, 0x04, SDP_ITEM_DESC(SDP_TYPE_ARRAY, SDP_SZ_u8), 15, | |
SDP_ITEM_DESC(SDP_TYPE_ARRAY, SDP_SZ_u8), 6, | |
SDP_ITEM_DESC(SDP_TYPE_UUID, SDP_SZ_2), 0x01, 0x00, // L2CAP | |
SDP_ITEM_DESC(SDP_TYPE_UINT, SDP_SZ_2), L2CAP_PSM_RFCOMM >> 8, L2CAP_PSM_RFCOMM & 0xFF, // L2CAP PSM | |
SDP_ITEM_DESC(SDP_TYPE_ARRAY, SDP_SZ_u8), 5, | |
SDP_ITEM_DESC(SDP_TYPE_UUID, SDP_SZ_2), 0x00, 0x03, // RFCOMM | |
SDP_ITEM_DESC(SDP_TYPE_UINT, SDP_SZ_1), MAGIX, // port ### | |
//browse group list | |
SDP_ITEM_DESC(SDP_TYPE_UINT, SDP_SZ_2), 0x00, 0x05, SDP_ITEM_DESC(SDP_TYPE_ARRAY, SDP_SZ_u8), 3, | |
SDP_ITEM_DESC(SDP_TYPE_UUID, SDP_SZ_2), 0x10, 0x02, // Public Browse Group | |
//name | |
SDP_ITEM_DESC(SDP_TYPE_UINT, SDP_SZ_2), 0x01, 0x00, SDP_ITEM_DESC(SDP_TYPE_TEXT, SDP_SZ_u8), 12, 'A', 'D', 'K', ' ', 'B', 'T', ' ', 'C', 'O', 'M', 'M', 'S' | |
}; | |
static void btStart(){ | |
uint8_t i, dlci; | |
int f; | |
ADK_btEnable(adkBtConnectionRequest, adkBtLinkKeyRequest, adkBtLinkKeyCreated, adkBtPinRequest, NULL); | |
dlci = ADK_btRfcommReserveDlci(RFCOMM_DLCI_NEED_EVEN); | |
if(!dlci) dbgPrintf("BTADK: failed to allocate DLCI\n"); | |
else{ | |
//change descriptor to be valid... | |
for(i = 0, f = -1; i < sizeof(sdpDescrADK); i++){ | |
if(sdpDescrADK[i] == MAGIX){ | |
if(f == -1) f = i; | |
else break; | |
} | |
} | |
if(i != sizeof(sdpDescrADK) || f == -1){ | |
dbgPrintf("BTADK: failed to find a single marker in descriptor\n"); | |
ADK_btRfcommReleaseDlci(dlci); | |
return; | |
} | |
sdpDescrADK[f] = dlci >> 1; | |
dbgPrintf("BTADK has DLCI %u\n", dlci); | |
ADK_btRfcommRegisterPort(dlci, btAdkPortOpen, btAdkPortClose, btAdkPortRx); | |
ADK_btSdpServiceDescriptorAdd(sdpDescrADK, sizeof(sdpDescrADK)); | |
} | |
} | |
// USB accessory | |
static void processUSBAccessory() | |
{ | |
if (!ADK_accessoryConnected()) | |
return; | |
uint8_t receiveBuf[MAX_PACKET_SZ]; | |
uint8_t reply[MAX_PACKET_SZ]; | |
int res = ADK_accessoryReceive(receiveBuf, sizeof(receiveBuf)); | |
if (res >= 4) { | |
uint8_t cmd = receiveBuf[0]; | |
uint8_t seq = receiveBuf[1]; | |
uint16_t size = receiveBuf[2] | receiveBuf[3] << 8; | |
if (size + 4 > res) { | |
// short packet | |
return; | |
} | |
uint16_t replylen = adkProcessCommand(cmd, receiveBuf + 4, size, 0, reply + 4, MAX_PACKET_SZ - 4); | |
if (replylen > 0) { | |
reply[0] = cmd | CMD_MASK_REPLY; | |
reply[1] = seq; | |
reply[2] = replylen; | |
reply[3] = replylen >> 8; | |
replylen += 4; | |
dbgPrintf("ADK: USB: sending %d bytes\n", replylen); | |
ADK_accessorySend(reply, replylen); | |
} | |
} | |
} | |