forked from espruino/EspruinoApps
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.js
More file actions
103 lines (80 loc) · 3.13 KB
/
Copy pathapp.js
File metadata and controls
103 lines (80 loc) · 3.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
/**
* Copyright reelyActive 2022-2024
* We believe in an open Internet of Things
*/
// User-configurable constants
const LED_BLINK_MILLISECONDS = 50;
const STABLE_ACCELERATION_TOLERANCE_G = 0.1;
const ANGLE_ADVERTISING_DURATION_MILLISECONDS = 5000;
const ANGLE_ADVERTISING_PERIOD_MILLISECONDS = 500;
const NAME_ADVERTISING_PERIOD_MILLISECONDS = 5000;
// Non-user-configurable constants
const ACC_SAMPLE_RATE_HZ = 12.5; // Valid values are 1.6, 12.5, 26, 52, 104, 208
const ACC_PER_G = 8192;
const DEG_PER_RAD = 180 / Math.PI;
// Global variables
let advertisingTimeoutId;
// Calculate the angle of rotation based on the given accelerometer reading
function calculateAngleOfRotation(acc) {
let ratioXY = ((acc.y === 0) ? Infinity : Math.abs(acc.x / acc.y));
let ratioYX = ((acc.x === 0) ? Infinity : Math.abs(acc.y / acc.x));
if((acc.x >= 0) && (acc.y >= 0)) {
return Math.round(Math.atan(ratioYX) * DEG_PER_RAD);
}
if((acc.x <= 0) && (acc.y >= 0)) {
return Math.round(90 + (Math.atan(ratioXY) * DEG_PER_RAD));
}
if((acc.x <= 0) && (acc.y <= 0)) {
return Math.round(180 + (Math.atan(ratioYX) * DEG_PER_RAD));
}
if((acc.x >= 0) && (acc.y <= 0)) {
return Math.round(270 + (Math.atan(ratioXY) * DEG_PER_RAD));
}
}
// Advertise the name "Knob.js"
function advertiseName() {
NRF.setAdvertising({}, {
showName: false,
manufacturer: 0x0590,
manufacturerData: JSON.stringify({ name: "Knob.js" }),
interval: NAME_ADVERTISING_PERIOD_MILLISECONDS
});
}
// Advertise the angle of rotation for a specific period
function advertiseAngleOfRotation(angleOfRotation) {
if(advertisingTimeoutId) {
clearTimeout(advertisingTimeoutId);
}
NRF.setAdvertising({}, {
showName: false,
manufacturer: 0x0590,
manufacturerData: JSON.stringify({ angleOfRotation: angleOfRotation }),
interval: ANGLE_ADVERTISING_PERIOD_MILLISECONDS
});
advertisingTimeoutId = setTimeout(advertiseName,
ANGLE_ADVERTISING_DURATION_MILLISECONDS);
}
// Handle a button press: blink green LED and initiate accelerometer readings
function handleButton() {
Puck.accelOn(ACC_SAMPLE_RATE_HZ);
LED2.write(true);
setTimeout(function() { LED2.write(false); }, LED_BLINK_MILLISECONDS);
}
// Handle accelerometer reading: terminate accelerometer readings and advertise
// angle of rotation once magnitude is stable
function handleAcceleration(data) {
let magnitude = Math.sqrt((data.acc.x * data.acc.x) +
(data.acc.y * data.acc.y) +
(data.acc.z * data.acc.z)) / ACC_PER_G;
let isStableMagnitude = (magnitude < 1.0 + STABLE_ACCELERATION_TOLERANCE_G) &&
(magnitude > 1.0 - STABLE_ACCELERATION_TOLERANCE_G);
if(isStableMagnitude) {
let angleOfRotation = calculateAngleOfRotation(data.acc);
Puck.accelOff();
advertiseAngleOfRotation(angleOfRotation);
}
}
// Advertise "Knob.js", wake on button press and handle accelerometer readings
advertiseName();
Puck.on('accel', handleAcceleration);
setWatch(handleButton, BTN, { edge: "rising", repeat: true, debounce: 50 });