From 8aff41fcf803a3702520a0ba92b9abc3e52ef81a Mon Sep 17 00:00:00 2001 From: Peter Marquardt Date: Sun, 27 Nov 2016 04:43:23 +0100 Subject: [PATCH] dynamic step goal and preliminary HR zone support --- package.json | 3 +- src/c/squared.c | 234 +++++++++++++++++++++++++---------------- src/pkjs/pebble-app.js | 32 +----- 3 files changed, 146 insertions(+), 123 deletions(-) diff --git a/package.json b/package.json index 44d24a3..9435aa7 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "cheeky": 22, "contrast": 13, "debugwatch": 50, + "dynamicstepgoal": 23, "eu_date": 1, "invert": 9, "large_mode": 0, @@ -52,5 +53,5 @@ "watchface": true } }, - "version": "4.15.0" + "version": "4.16.0" } diff --git a/src/c/squared.c b/src/c/squared.c index 0cc0a02..c0188e3 100644 --- a/src/c/squared.c +++ b/src/c/squared.c @@ -32,6 +32,7 @@ typedef struct { uint8_t bottomrow; uint8_t wristflick; uint16_t stepgoal; + bool dynamicstepgoal; bool cheeky; } Preferences; @@ -73,6 +74,7 @@ enum { KEY_WRISTFLICK, KEY_STEPGOAL, KEY_CHEEKY, + KEY_DYNAMICSTEPGOAL, }; #define KEY_DEBUGWATCH 50 @@ -87,6 +89,7 @@ enum { #define BOTTOMROW (curPrefs.bottomrow) #define WRISTFLICK (curPrefs.wristflick) #define STEP_GOAL (curPrefs.stepgoal) +#define DYNAMIC_STEP_GOAL (curPrefs.dynamicstepgoal) #define CHEEKY_REMARKS (curPrefs.cheeky) #define EU_DATE (curPrefs.eu_date) // true == MM/DD, false == DD/MM @@ -147,6 +150,7 @@ static char weekday_buffer[2]; AnimationImplementation animImpl; Animation *anim; static bool splashEnded = false, debug = false, in_shake_mode = false, prev_chargestate = false; +static uint16_t stepgoal = 0; static uint16_t stepprogress = 0; static uint8_t battprogress = 0; static uint8_t heartrate = 0; @@ -186,7 +190,8 @@ static const uint8_t character_map[] = { [17] = 13, // same as 13 [37] = 17, // % [42] = 18, // * -[47] = 60, // slash +[45] = 62, // - +[47] = 61, // slash // UPPERCASE ASCII CHARACTERS [65] = 19, [66] = 20, @@ -213,29 +218,31 @@ static const uint8_t character_map[] = { [87] = 40, [88] = 41, [89] = 42, +[90] = 43, // PROGRESS [100] = 10, // same as ornament 10 -[101] = 43, -[102] = 44, -[103] = 45, -[104] = 46, -[105] = 47, -[106] = 48, -[107] = 49, -[108] = 50, +[101] = 44, +[102] = 45, +[103] = 46, +[104] = 47, +[105] = 48, +[106] = 49, +[107] = 50, +[108] = 51, [109] = 13, // same as ornament 13 [110] = 11, // same as ornament 11 -[111] = 51, -[112] = 52, -[113] = 53, -[114] = 54, -[115] = 55, -[116] = 56, -[117] = 57, -[118] = 58, +[111] = 52, +[112] = 53, +[113] = 54, +[114] = 55, +[115] = 56, +[116] = 57, +[117] = 58, +[118] = 59, [119] = 12, // same as ornament 12 // SYMBOLS -[120] = 59, // heart +[120] = 60, // heart +[121] = 63, // zone }; // left column is digit color, right column is ornament color @@ -546,6 +553,13 @@ static const uint8_t characters[][10] = { 0b00001, 0b00000, 0b11111, 0b00000 }, +{ // Z + 0b11111, 0b00000, + 0b00010, 0b00000, + 0b00100, 0b10001, + 0b01000, 0b00000, + 0b11111, 0b00000 +}, // PROGRESS // 01% is same as ornament 10 { // 12% @@ -680,6 +694,20 @@ static const uint8_t characters[][10] = { 0b00100, 0b00000, 0b01000, 0b00000, 0b10000, 0b00000 +}, +{ // - + 0b00000, 0b11111, + 0b00000, 0b00000, + 0b11111, 0b00000, + 0b00000, 0b00000, + 0b00000, 0b11111 +}, +{ // HR zone + 0b00010, 0b01000, + 0b00011, 0b11000, + 0b00000, 0b11000, + 0b00000, 0b01110, + 0b00000, 0b00100 } }; @@ -959,28 +987,79 @@ static void destroyAnimation() { anim = NULL; } -static void setNumericSlots(uint16_t number, bool heartrate) { +static void setNumericSlots(uint16_t number, bool isHeartrate, bool isBottom) { static uint8_t digits[4]; - digits[0] = 4; - digits[1] = 5; - digits[2] = 6; - digits[3] = 7; - if (heartrate) { + digits[0] = 0; + digits[1] = 1; + digits[2] = 2; + digits[3] = 3; + if (isBottom) { + digits[0] = 4; + digits[1] = 5; + digits[2] = 6; + digits[3] = 7; + } + if (isHeartrate) { slot[digits[0]].curDigit = 120; + slot[digits[1]].curDigit = 10; + slot[digits[2]].curDigit = 10; + slot[digits[3]].curDigit = 10; } - uint16_t input = number; - uint16_t hundreds = input/100; - input -= (hundreds)*100; - uint8_t tens = input/10; - input -= (tens)*10; - uint8_t units=input; - if (hundreds > 0) { - slot[digits[1]].curDigit = hundreds; + if (isHeartrate && number == 0) { + if (isBottom) { + slot[digits[1]].curDigit = 'N'; + slot[digits[2]].curDigit = '/'; + slot[digits[3]].curDigit = 'A'; + } else { + slot[digits[2]].curDigit = 'N'; + slot[digits[3]].curDigit = 'A'; + } + } else { + uint16_t input = number; + uint16_t hundreds = input/100; + input -= (hundreds)*100; + uint8_t tens = input/10; + input -= (tens)*10; + uint8_t units=input; + if (hundreds > 0) { + slot[digits[1]].curDigit = hundreds; + } + if (tens > 0 || hundreds > 0) { + slot[digits[2]].curDigit = tens; + } + slot[digits[3]].curDigit = units; } - if (tens > 0 || hundreds > 0) { - slot[digits[2]].curDigit = tens; + if (!isBottom) { + slot[4].curDigit = 121; + slot[5].curDigit = 101; + slot[6].curDigit = 10; + slot[7].curDigit = 10; + if (number > 158) { + slot[5].curDigit = 13; + slot[6].curDigit = 13; + slot[7].curDigit = 13; + } else if (number > 130) { + slot[5].curDigit = 13; + slot[6].curDigit = 13; + } else if (number > 93) { + slot[5].curDigit = 13; + } + } +} + +static void showHeartRate(bool isBbottom) { + #if defined(PBL_PLATFORM_EMERY) || defined(PBL_PLATFORM_DIORITE) + HealthServiceAccessibilityMask hr = health_service_metric_accessible(HealthMetricHeartRateBPM, time(NULL), time(NULL)); + if (hr & HealthServiceAccessibilityMaskAvailable) { + heartrate = (int)health_service_peek_current_value(HealthMetricHeartRateBPM); + } + #endif + //heartrate = 167; + if (heartrate > 0) { + setNumericSlots(heartrate, true, isBbottom); + } else { + setNumericSlots(0, true, isBbottom); } - slot[digits[3]].curDigit = units; } static void setProgressSlots(uint16_t progress, bool showgoal, bool bottom) { @@ -1214,16 +1293,27 @@ static void setProgressSlots(uint16_t progress, bool showgoal, bool bottom) { static void update_step_goal() { #if defined(PBL_HEALTH) - HealthMetric metric = HealthMetricStepCount; + const HealthMetric metric_stepcount = HealthMetricStepCount; time_t start = time_start_of_today(); - time_t end = time(NULL); + time_t now = time(NULL); + time_t end = start + SECONDS_PER_DAY; + const HealthServiceTimeScope scope = HealthServiceTimeScopeDaily; + + // Check the metric has data available for us + HealthServiceAccessibilityMask mask_steps = health_service_metric_accessible(metric_stepcount, start, now); + HealthServiceAccessibilityMask mask_average = health_service_metric_averaged_accessible(metric_stepcount, start, end, scope); + + if (DYNAMIC_STEP_GOAL && (mask_average & HealthServiceAccessibilityMaskAvailable)) { + stepgoal = (uint16_t)health_service_sum_averaged(metric_stepcount, start, end, scope); + } else { + stepgoal = STEP_GOAL; + } - // Check the metric has data available for today - HealthServiceAccessibilityMask mask = health_service_metric_accessible(metric, - start, end); - if(mask & HealthServiceAccessibilityMaskAvailable) { + if(mask_steps & HealthServiceAccessibilityMaskAvailable) { // Data is available! - stepprogress = (uint16_t)(((float)health_service_sum_today(metric)/(float)STEP_GOAL)*100); + uint16_t stepcount = health_service_sum_today(metric_stepcount); + stepprogress = (uint16_t)(((float)stepcount/(float)stepgoal)*100); + APP_LOG(APP_LOG_LEVEL_INFO, "Stepcount: %d / Stepgoal: %d", stepcount, stepgoal); APP_LOG(APP_LOG_LEVEL_INFO, "Step progress: %d%%", stepprogress); } else { // No data recorded yet today @@ -1317,20 +1407,7 @@ static void handle_tick(struct tm *t, TimeUnits units_changed) { battprogress = charge_state.charge_percent; setProgressSlots(battprogress, false, true); } else if (BOTTOMROW == 3) { - #if defined(PBL_PLATFORM_EMERY) || defined(PBL_PLATFORM_DIORITE) - HealthServiceAccessibilityMask hr = health_service_metric_accessible(HealthMetricHeartRateBPM, time(NULL), time(NULL)); - if (hr & HealthServiceAccessibilityMaskAvailable) { - heartrate = (int)health_service_peek_current_value(HealthMetricHeartRateBPM); - } - #endif - if (heartrate > 0) { - setNumericSlots(heartrate, true); - } else { - slot[4].curDigit = 120; - slot[5].curDigit = 'N'; - slot[6].curDigit = '/'; - slot[7].curDigit = 'A'; - } + showHeartRate(true); } else { if (!EU_DATE) { if (WEEKDAY) { @@ -1362,38 +1439,6 @@ static void handle_tick(struct tm *t, TimeUnits units_changed) { } } } - - /*if (NO_ZERO) { - if (slot[0].curDigit == 0) { - if (NUMSLOTS > 8) { - if (slot[10].prevDigit != 10 && slot[10].prevDigit != 12) { - slot[0].curDigit = 11; - } else { - slot[0].curDigit = 10; - } - } else { - if (slot[0].prevDigit == 10) { - slot[0].curDigit = 11; - } else { - slot[0].curDigit = 10; - } - } - } - if (BOTTOMROW == 0) { - if (slot[4].curDigit == 0) { - slot[4].curDigit = 10; - if (slot[4].prevDigit == 10) { - slot[4].curDigit++; - } - } - if (slot[6].curDigit == 0) { - slot[6].curDigit = 10; - if (slot[6].prevDigit == 10) { - slot[6].curDigit++; - } - } - } - }*/ setupAnimation(); animation_schedule(anim); } @@ -1420,13 +1465,15 @@ static void tap_handler(AccelAxisType axis, int32_t direction) { for (uint8_t i=0; ivalue->int8; } if (wristflick_t) { curPrefs.wristflick = wristflick_t->value->int8; } if (stepgoal_t) { curPrefs.stepgoal = stepgoal_t->value->int16; } + if (dynamicstepgoal_t) { curPrefs.dynamicstepgoal = dynamicstepgoal_t->value->int8; } if (cheeky_t) { curPrefs.cheeky = cheeky_t->value->int8; } if (debug) { @@ -1674,6 +1723,7 @@ static void init() { .bottomrow = 0, .wristflick = 0, .stepgoal = 10000, + .dynamicstepgoal = false, .cheeky = true }; } diff --git a/src/pkjs/pebble-app.js b/src/pkjs/pebble-app.js index cbf0fbe..0a268aa 100644 --- a/src/pkjs/pebble-app.js +++ b/src/pkjs/pebble-app.js @@ -1,24 +1,3 @@ -String.prototype.hashCode = function(){ - var hash = 0; - if (this.length === 0) return hash; - for (var i = 0; i < this.length; i++) { - var char = this.charCodeAt(i); - hash = ((hash<<5)-hash)+char; - hash = hash & hash; // Convert to 32bit integer - } - return hash; -}; - -var debugwatches = Array( - -826258655, //a - 1135189913, //b - -1783317168, //em - 91860716, //a sl - -1462573071 //b sl -); -var tokenhash; - - Pebble.addEventListener('ready', function() { console.log('PebbleKit JS ready!'); console.log('WatchToken '+Pebble.getWatchToken()); @@ -29,15 +8,11 @@ Pebble.addEventListener('appmessage', function() { }); Pebble.addEventListener('showConfiguration', function() { - var url='http://pebble.lastfuture.de/config/squared414/'; + var url='http://pebble.lastfuture.de/config/squared416/'; var watch = Pebble.getActiveWatchInfo ? Pebble.getActiveWatchInfo() : null; if (watch) { url += "?model="+watch.model+"&hardware="+watch.platform; } - tokenhash = Pebble.getWatchToken().hashCode(); - if (debugwatches.indexOf(tokenhash) > -1) { - url += "&debug=true"; - } console.log('Showing configuration page: '+url); Pebble.openURL(url); }); @@ -68,12 +43,9 @@ Pebble.addEventListener('webviewclosed', function(e) { bottomrow: parseInt(configData.bottomrow), wristflick: parseInt(configData.wristflick), stepgoal: parseInt(configData.stepgoal), + dynamicstepgoal: 0+(configData.dynamicstepgoal === 'true'), cheeky: 0+(configData.cheeky === 'true') }; - if (debugwatches.indexOf(tokenhash) > -1) { - console.log('Debug Watch with Hash '+tokenhash+'. Setting debug flag on watchface …'); - options.debugwatch = 1; - } if (configData.background_color) { Pebble.sendAppMessage(options, function() { console.log('Send successful!');