Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Updated Binary LED Clock (BLC) #3569

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
3 changes: 3 additions & 0 deletions apps/blc/ChangeLog
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
0.10: New app introduced to the app loader!
0.20: skipped (internal revision)
0.30: skipped (internal revision)
0.40: added functionality for customizing colors
6 changes: 5 additions & 1 deletion apps/blc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,9 @@ From top to bottom the watch face shows four rows of leds:
* day (yellow leds, top row)
* month (yellow leds, bottom row)

As usual, luminous leds represent a logical one, dark leds a logcal '0'.
The colors are default colors and can be changed at the settings page, also, the outer ring can be disabled.

The rightmost LED represents 1, the second 2, the third 4, the next 8 and so on, i.e. values are the powers of two.

As usual, luminous leds represent a logical one, and "dark" leds a logcal '0'. Dark means the color of the background.
Widgets aren't affected and are shown as normal.
284 changes: 165 additions & 119 deletions apps/blc/blc.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,135 +2,181 @@

{ // must be inside our own scope here so that when we are unloaded everything disappears
// we also define functions using 'let fn = function() {..}' for the same reason. function decls are global
let drawTimeout;

// Actually draw the watch face
let draw = function()
{
// Bangle.js2 -> 176x176
var x_rgt = g.getWidth();
var y_bot = g.getHeight();
//var x_cntr = x_rgt / 2;
var y_cntr = y_bot / 18*7; // not to high because of widget-field (1/3 is to high)
g.reset().clearRect(Bangle.appRect); // clear whole background (w/o widgets)

let white = [1,1,1];
let red = [1,0,0];
let green = [0,1,0];
//let blue = [0,0,1];
let yellow = [1,1,0];
//let magenta = [1,0,1];
//let cyan = [0,1,1];
let black = [0,0,0];
let bord_col = white;
let col_off = black;

var col = new Array(red, green, yellow, yellow); // [R,G,B]

let pot_2 = [1, 2, 4, 8, 16, 32]; // array with powers of two, because power-op (**)
// doesn't work -> maybe also faster


var nr_lines = 4; // 4 rows: hour (hr), minute (min), day (day), month (mon)

// Arrays: [hr, min, day, mon]
//No of Bits: 5 6 5 4
let msbits = [4, 5, 4, 3]; // MSB = No bits - 1
let rad = [12, 12, 8, 8]; // radiuses for each row
var x_dist = 28;
let y_dist = [0, 30, 60, 85]; // y-position from y_centr for each row from top
// don't calc. automatic as for x, because of different spaces
var x_offs_rgt = 16; // distance from right border (layout)

// Date-Time-Array: 4x6 Bit
//var idx_hr = 0;
//var idx_min = 1;
//var idx_day = 2;
//var idx_mon = 3;
var dt_bit_arr = [[0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0]];

var date_time = new Date();
var hr = date_time.getHours(); // 0..23
var min = date_time.getMinutes(); // 0..59
var day = date_time.getDate(); // 1..31
var mon = date_time.getMonth() + 1; // GetMonth() -> 0..11

let dt_array = [hr, min, day, mon];

const SETTINGSFILE = "BinaryClk.settings.json";

// variables defined from settings
let HourCol;
let MinCol;
let DayCol;
let MonCol;
let RingOn;

// color arrays
// !!! don't change order unless change oder in BinaryClk.settings.js !!!
// !!! order must correspond to each other between arrays !!!
let LED_Colors = ["#FFF", "#F00", "#0F0", "#00F", "#FF0", "#F0F", "#0FF", "#000"];
let LED_ColorNames = ["white", "red", "green", "blue", "yellow", "magenta", "cyan", "black"];

////////////////////////////////////////
// compute bit-pattern from time/date and draw leds
////////////////////////////////////////
var line_cnt = 0;
var cnt = 0;
var bit_cnt = 0;
// load settings
let loadSettings = function()
{
function def (value, def) {return value !== undefined ? value : def;}

var settings = require('Storage').readJSON(SETTINGSFILE, true) || {};
// get name from setting, find index of name and assign corresponding color code by index
HourCol = LED_Colors[LED_ColorNames.indexOf(def(settings.HourCol, "red"))];
MinCol = LED_Colors[LED_ColorNames.indexOf(def(settings.MinCol, "green"))];
DayCol = LED_Colors[LED_ColorNames.indexOf(def(settings.DayCol, "yellow"))];
MonCol = LED_Colors[LED_ColorNames.indexOf(def(settings.MonCol, "yellow"))];
RingOn = def(settings.RingOn, true);

while (line_cnt < nr_lines)
{

////////////////////////////////////////
// compute bit-pattern
bit_cnt = msbits[line_cnt];
delete settings; // settings in local var -> no more required
}

while (bit_cnt >= 0)
let drawTimeout;

// actually draw the watch face
let draw = function()
{
// Bangle.js2 -> 176x176
var x_rgt = g.getWidth();
var y_bot = g.getHeight();
//var x_cntr = x_rgt / 2;
var y_cntr = y_bot / 18*7;
g.reset().clearRect(Bangle.appRect); // clear whole background (w/o widgets)

var white = "#FFF";
var black = "#000";
var bord_col = white;
var col_off = black;

var col = new Array(HourCol, MinCol, DayCol, MonCol); // each #rgb
if (g.theme.dark)
{
if (dt_array[line_cnt] >= pot_2[bit_cnt])
{
dt_array[line_cnt] -= pot_2[bit_cnt];
dt_bit_arr[line_cnt][bit_cnt] = 1;
}
else
{
dt_bit_arr[line_cnt][bit_cnt] = 0;
}
bit_cnt--;
bord_col = white;
col_off = black;
}

else
{
bord_col = black;
col_off = white;
}

let pwr2 = [1, 2, 4, 8, 16, 32]; // array with powers of 2, because poweroperator '**' doesnt work
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of this you can use bitshifting if you like:

-pwr2[bit_cnt]
+1 << bit_cnt

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is also a good solution. In my opinion the the "LUT"-way may be a bit faster an with only six values not much bigger regarding code size.

// maybe also faster


var no_lines = 4; // 4 rows: hour (hr), minute (min), day (day), month (mon)
var no_hour = 5;
var no_min = 6;
var no_day = 5;
var no_mon = 4;

// arrays: [hr, min, day, mon]
let msbits = [no_hour-1, no_min-1, no_day-1, no_mon-1]; // MSB = No bits - 1
let rad = [13, 13, 9, 9]; // radiuses for each row
var x_dist = 29;
let y_dist = [0, 35, 75, 100]; // y-position from y_centr for each row from top
// don't calc. automatic as for x, because of different spaces
var x_offs_rgt = 15; // offset from right border (layout)
var y_offs_cntr = 25; // vertical offset from center

////////////////////////////////////////
// compute bit-pattern from time/date and draw leds
////////////////////////////////////////
// draw leds (first white border for black screen, then led itself)
cnt = 0;

while (cnt <= msbits[line_cnt])
// date-time-array: 4x6 bit
//var idx_hour = 0;
//var idx_min = 1;
//var idx_day = 2;
//var idx_mon = 3;
var dt_bit_arr = [[0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0],[0, 0, 0, 0, 0, 0]];

var date_time = new Date();
var hour = date_time.getHours(); // 0..23
var min = date_time.getMinutes(); // 0..59
var day = date_time.getDate(); // 1..31
var mon = date_time.getMonth() + 1; // GetMonth() -> 0..11

let dt_array = [hour, min, day, mon];

var line_cnt = 0;
var cnt = 0;
var bit_cnt = 0;

while (line_cnt < no_lines)
{
g.setColor(bord_col[0], bord_col[1], bord_col[2]);
g.drawCircle(x_rgt-x_offs_rgt-cnt*x_dist, y_cntr-20+y_dist[line_cnt], rad[line_cnt]);

if (dt_bit_arr[line_cnt][cnt] == 1)
{
g.setColor(col[line_cnt][0], col[line_cnt][1], col[line_cnt][2]);
}
else
{
g.setColor(col_off[0], col_off[1], col_off[2]);
}
g.fillCircle(x_rgt-x_offs_rgt-cnt*x_dist, y_cntr-20+y_dist[line_cnt], rad[line_cnt]-1);
cnt++;

////////////////////////////////////////
// compute bit-pattern
bit_cnt = msbits[line_cnt];

while (bit_cnt >= 0)
{
if (dt_array[line_cnt] >= pwr2[bit_cnt])
{
dt_array[line_cnt] -= pwr2[bit_cnt];
dt_bit_arr[line_cnt][bit_cnt] = 1;
}
else
{
dt_bit_arr[line_cnt][bit_cnt] = 0;
}
bit_cnt--;
}

////////////////////////////////////////
// draw leds (and border, if enabled)
cnt = 0;

while (cnt <= msbits[line_cnt])
{
if (RingOn) // draw outer ring, if enabled
{
g.setColor(bord_col);
g.drawCircle(x_rgt-x_offs_rgt-cnt*x_dist, y_cntr-y_offs_cntr+y_dist[line_cnt], rad[line_cnt]);
}
if (dt_bit_arr[line_cnt][cnt] == 1)
{
g.setColor(col[line_cnt]);
}
else
{
g.setColor(col_off);
}
g.fillCircle(x_rgt-x_offs_rgt-cnt*x_dist, y_cntr-y_offs_cntr+y_dist[line_cnt], rad[line_cnt]-1);
cnt++;
}
line_cnt++;
}
line_cnt++;
}

// queue next draw
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = setTimeout(function()
{
drawTimeout = undefined;
draw();
}, 60000 - (Date.now() % 60000));
};

// Show launcher when middle button pressed
Bangle.setUI(
{
mode : "clock",
remove : function()
{
// Called to unload all of the clock app
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = undefined;
// queue next draw
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = setTimeout(function()
{
drawTimeout = undefined;
draw();
}, 60000 - (Date.now() % 60000));
}
});
// Load widgets
Bangle.loadWidgets();
draw();
setTimeout(Bangle.drawWidgets,0);


// Init the settings of the app
loadSettings();

// Show launcher when middle button pressed
Bangle.setUI(
{
mode : "clock",
remove : function()
{
// Called to unload all of the clock app
if (drawTimeout) clearTimeout(drawTimeout);
drawTimeout = undefined;
}
});
// Load widgets
Bangle.loadWidgets();
draw();
setTimeout(Bangle.drawWidgets,0);
}
72 changes: 72 additions & 0 deletions apps/blc/blc.settings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Change settings for BinaryClk

(function(back){

// color array -- don't change order unless change oder in BinaryClk.js
let LED_ColorNames = ["white", "red", "green", "blue", "yellow", "magenta", "cyan", "black"];

var FILE = "BinaryClk.settings.json";
// Load settings
var settings = Object.assign({
HourCol: "red",
MinCol: "green",
DayCol: "yellow",
MonCol: "yellow",
RingOn: true,
}, require('Storage').readJSON(FILE, true) || {});

function writeSettings(){
require('Storage').writeJSON(FILE, settings);
}

// Helper method which uses int-based menu item for set of string values
function stringItems(startvalue, writer, values) {
return{
value: (startvalue === undefined ? 0 : values.indexOf(startvalue)),
format: v => values[v],
min: 0,
max: values.length - 1,
wrap: true,
step: 1,
onchange: v => {
writer(values[v]);
writeSettings();
}
};
}

// Helper method which breaks string set settings down to local settings object
function stringInSettings(name, values) {
return stringItems(settings[name], v => settings[name] = v, values);
}

// Show the menu
var mainmenu = {
"" : {
"title" : "BinaryCLK"
},
"< Back" : () => back(),
'Color Hour.:': stringInSettings("HourCol", LED_ColorNames),
'Color Minute:': stringInSettings("MinCol", LED_ColorNames),
'Color Day': stringInSettings("DayCol", LED_ColorNames),
'Color Month:': stringInSettings("MonCol", LED_ColorNames),
'LED ring on/off': {
value: (settings.RingOn !== undefined ? settings.RingOn : true),
onchange: v => {
settings.RingOn = v;
writeSettings();
}
},
};

// Show submenues
//var submenu1 = {
//"": {
// "title": "Show sub1..."
//},
//"< Back": () => E.showMenu(mainmenu),
//"ItemName": stringInSettings("settingsVar", ["Yes", "No", "DontCare"]),
//};

E.showMenu(mainmenu);
});
7 changes: 7 additions & 0 deletions apps/blc/blc.settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"HourCol": "red",
"MinCol": "green",
"DayCol": "yellow",
"MonCol": "yellow",
"RingOn": true
}
Loading
Loading