mirror of
https://github.com/espruino/Espruino.git
synced 2025-12-08 19:06:15 +00:00
287 lines
8.9 KiB
C
287 lines
8.9 KiB
C
/*
|
|
* This file is part of Espruino, a JavaScript interpreter for Microcontrollers
|
|
*
|
|
* Copyright (C) 2013 Gordon Williams <gw@pur3.co.uk>
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* ----------------------------------------------------------------------------
|
|
* This file is designed to be parsed during the build process
|
|
*
|
|
* Contains JavaScript interface for trigger wheel functionality
|
|
* ----------------------------------------------------------------------------
|
|
*/
|
|
|
|
/* DO_NOT_INCLUDE_IN_DOCS - this is a special token for common.py */
|
|
#include "trigger.h"
|
|
#include "jswrap_trigger.h"
|
|
|
|
/*JSON{
|
|
"type" : "class",
|
|
"class" : "Trig"
|
|
}
|
|
This class exists in order to interface Espruino with fast-moving trigger
|
|
wheels. Trigger wheels are physical discs with evenly spaced teeth cut into
|
|
them, and often with one or two teeth next to each other missing. A sensor sends
|
|
a signal whenever a tooth passed by, and this allows a device to measure not
|
|
only RPM, but absolute position.
|
|
|
|
This class is currently in testing - it is NOT AVAILABLE on normal boards.
|
|
*/
|
|
|
|
/*JSON{
|
|
"type" : "staticmethod",
|
|
"class" : "Trig",
|
|
"name" : "getPosAtTime",
|
|
"generate" : "jswrap_trig_getPosAtTime",
|
|
"params" : [
|
|
["time","float","The time at which to find the position"]
|
|
],
|
|
"return" : ["float","The position of the trigger wheel in degrees - as a floating point number"]
|
|
}
|
|
Get the position of the trigger wheel at the given time (from getTime)
|
|
*/
|
|
JsVarFloat jswrap_trig_getPosAtTime(JsVarFloat time) {
|
|
JsSysTime sTime = (JsSysTime)(time * (JsVarFloat)jshGetTimeFromMilliseconds(1000));
|
|
TriggerStruct *trig = &mainTrigger;
|
|
JsVarFloat position = trigGetToothAtTime(trig, sTime);
|
|
return wrapAround((position * 360 / trig->teethTotal) + trig->keyPosition, 360);
|
|
}
|
|
|
|
/*JSON{
|
|
"type" : "staticmethod",
|
|
"class" : "Trig",
|
|
"name" : "setup",
|
|
"generate" : "jswrap_trig_setup",
|
|
"params" : [
|
|
["pin","pin","The pin to use for triggering"],
|
|
["options","JsVar","Additional options as an object. defaults are: ```{teethTotal:60,teethMissing:2,minRPM:30,keyPosition:0}```"]
|
|
]
|
|
}
|
|
Initialise the trigger class
|
|
*/
|
|
void jswrap_trig_setup(Pin pin, JsVar *options) {
|
|
if (!jshIsPinValid(pin)) {
|
|
jsError("Invalid pin supplied as an argument to Trig.setup");
|
|
return;
|
|
}
|
|
|
|
TriggerStruct *trig = &mainTrigger;
|
|
// static info
|
|
trig->teethMissing = 2;
|
|
trig->teethTotal = 60;
|
|
trig->keyPosition = 0;
|
|
JsVarFloat minRPM = 30;
|
|
if (jsvIsObject(options)) {
|
|
JsVar *v;
|
|
v = jsvObjectGetChildIfExists(options, "teethMissing");
|
|
if (!jsvIsUndefined(v)) trig->teethMissing = (unsigned char)jsvGetInteger(v);
|
|
jsvUnLock(v);
|
|
v = jsvObjectGetChildIfExists(options, "teethTotal");
|
|
if (!jsvIsUndefined(v)) trig->teethTotal = (unsigned char)jsvGetInteger(v);
|
|
jsvUnLock(v);
|
|
v = jsvObjectGetChildIfExists(options, "minRPM");
|
|
if (!jsvIsUndefined(v)) minRPM = jsvGetFloat(v);
|
|
jsvUnLock(v);
|
|
v = jsvObjectGetChildIfExists(options, "keyPosition");
|
|
if (!jsvIsUndefined(v)) trig->keyPosition = jsvGetFloat(v);
|
|
jsvUnLock(v);
|
|
}
|
|
trig->maxTooth = (unsigned int)jshGetTimeFromMilliseconds(60000 / (JsVarFloat)(trig->teethTotal * minRPM));
|
|
|
|
// semi-static info
|
|
int i;
|
|
for (i=0;i<TRIGGER_TRIGGERS_COUNT;i++) {
|
|
trig->triggers[i].tooth = TRIGGERPOINT_TOOTH_DISABLE;
|
|
trig->triggers[i].newTooth = TRIGGERPOINT_TOOTH_DISABLE;
|
|
}
|
|
// dynamic info
|
|
trig->lastTime = jshGetSystemTime();
|
|
trig->avrTrigger = (unsigned int)jshGetTimeFromMilliseconds(10); // average time for a trigger pulse
|
|
trig->avrTooth = (unsigned int)jshGetTimeFromMilliseconds(10); // average time for a tooth
|
|
trig->currTooth = 0;
|
|
trig->teethSinceStart = 0;
|
|
trig->wrongTriggerTeeth = 0;
|
|
// finally set up the watch!
|
|
if (jshIsPinValid(trig->sensorPin))
|
|
jshPinWatch(trig->sensorPin, false, JSPW_NONE);
|
|
trig->sensorPin = pin;
|
|
jshPinWatch(trig->sensorPin, true, JSPW_HIGH_SPEED);
|
|
}
|
|
|
|
/*JSON{
|
|
"type" : "staticmethod",
|
|
"class" : "Trig",
|
|
"name" : "setTrigger",
|
|
"generate" : "jswrap_trig_setTrigger",
|
|
"params" : [
|
|
["num","int","The trigger number (0..7)"],
|
|
["pos","float","The position (in degrees) to fire the trigger at"],
|
|
["pins","JsVar","An array of pins to pulse (max 4)"],
|
|
["pulseLength","float","The time (in msec) to pulse for"]
|
|
]
|
|
}
|
|
Set a trigger for a certain point in the cycle
|
|
*/
|
|
void jswrap_trig_setTrigger(JsVarInt num, JsVarFloat position, JsVar *pins, JsVarFloat pulseLength) {
|
|
TriggerStruct *trig = &mainTrigger;
|
|
if (num<0 || num>=TRIGGER_TRIGGERS_COUNT) {
|
|
jsWarn("Invalid trigger number\n");
|
|
return;
|
|
}
|
|
if (!jsvIsArray(pins)) {
|
|
jsWarn("Second argument must be an array of pins\n");
|
|
return;
|
|
}
|
|
if (jsvGetArrayLength(pins) > TRIGGERPOINT_TRIGGERS_COUNT) {
|
|
jsWarn("Too many pins in array\n");
|
|
return;
|
|
}
|
|
|
|
// convert from degrees to teeth
|
|
position = wrapAround(((position - trig->keyPosition) * trig->teethTotal / 360), trig->teethTotal);
|
|
|
|
TriggerPointStruct *tp = &trig->triggers[num];
|
|
tp->newTooth = (unsigned char)position;
|
|
tp->newToothFraction = (unsigned char)((position - tp->tooth)*256);
|
|
tp->pulseLength = jshGetTimeFromMilliseconds(pulseLength);
|
|
int i, l=(int)jsvGetArrayLength(pins);
|
|
for (i=0;i<TRIGGERPOINT_TRIGGERS_COUNT;i++) {
|
|
tp->pins[i] = (Pin)((i<l) ? jshGetPinFromVarAndUnLock(jsvGetArrayItem(pins, i)) : PIN_UNDEFINED);
|
|
}
|
|
// now copy over data if we need to do it immediately
|
|
if (tp->tooth==TRIGGERPOINT_TOOTH_DISABLE || tp->newTooth==TRIGGERPOINT_TOOTH_DISABLE) {
|
|
tp->tooth = tp->newTooth;
|
|
tp->toothFraction = tp->newToothFraction;
|
|
}
|
|
// all done!
|
|
}
|
|
|
|
/*JSON{
|
|
"type" : "staticmethod",
|
|
"class" : "Trig",
|
|
"name" : "killTrigger",
|
|
"generate" : "jswrap_trig_killTrigger",
|
|
"params" : [
|
|
["num","int","The trigger number (0..7)"]
|
|
]
|
|
}
|
|
Disable a trigger
|
|
*/
|
|
void jswrap_trig_killTrigger(JsVarInt num) {
|
|
TriggerStruct *trig = &mainTrigger;
|
|
if (num<0 || num>=TRIGGER_TRIGGERS_COUNT) {
|
|
jsWarn("Invalid trigger number\n");
|
|
return;
|
|
}
|
|
|
|
TriggerPointStruct *tp = &trig->triggers[num];
|
|
tp->tooth = TRIGGERPOINT_TOOTH_DISABLE;
|
|
tp->newTooth = TRIGGERPOINT_TOOTH_DISABLE;
|
|
}
|
|
|
|
/*JSON{
|
|
"type" : "staticmethod",
|
|
"class" : "Trig",
|
|
"name" : "getTrigger",
|
|
"generate" : "jswrap_trig_getTrigger",
|
|
"params" : [
|
|
["num","int","The trigger number (0..7)"]
|
|
],
|
|
"return" : ["JsVar","A structure containing all information about the trigger"]
|
|
}
|
|
Get the current state of a trigger
|
|
*/
|
|
JsVar *jswrap_trig_getTrigger(JsVarInt num) {
|
|
TriggerStruct *trig = &mainTrigger;
|
|
if (num<0 || num>=TRIGGER_TRIGGERS_COUNT) {
|
|
jsWarn("Invalid trigger number\n");
|
|
return 0;
|
|
}
|
|
TriggerPointStruct *tp = &trig->triggers[num];
|
|
|
|
// get offset in teeth
|
|
JsVarFloat position = tp->tooth + (tp->toothFraction/256.0);
|
|
// convert from teeth to degrees
|
|
position = wrapAround((position * 360 / trig->teethTotal) + trig->keyPosition, 360);
|
|
|
|
|
|
JsVar *obj = jsvNewObject();
|
|
if (!obj) return 0;
|
|
jsvAddNamedChildAndUnLock(obj, jsvNewFromFloat(position), "pos");
|
|
jsvAddNamedChildAndUnLock(obj, jsvNewFromFloat(jshGetMillisecondsFromTime(tp->pulseLength)), "pulseLength");
|
|
JsVar *v = jsvNewEmptyArray();
|
|
int i;
|
|
if (v) {
|
|
for (i=0;i<TRIGGERPOINT_TRIGGERS_COUNT;i++)
|
|
if (tp->pins[i] != PIN_UNDEFINED) {
|
|
jsvArrayPushAndUnLock(v, jsvNewFromPin(tp->pins[i]));
|
|
}
|
|
}
|
|
jsvAddNamedChildAndUnLock(obj, v, "pins");
|
|
return obj;
|
|
}
|
|
|
|
/*JSON{
|
|
"type" : "staticmethod",
|
|
"class" : "Trig",
|
|
"name" : "getRPM",
|
|
"generate" : "jswrap_trig_getRPM",
|
|
"return" : ["float","The current RPM of the trigger wheel"]
|
|
}
|
|
Get the RPM of the trigger wheel
|
|
*/
|
|
JsVarFloat jswrap_trig_getRPM() {
|
|
TriggerStruct *trig = &mainTrigger;
|
|
|
|
if (jshGetSystemTime() > (trig->lastTime + trig->maxTooth)) return 0;
|
|
return jshGetTimeFromMilliseconds(60000) / (JsVarFloat)(trig->avrTooth * trig->teethTotal);
|
|
}
|
|
|
|
/*JSON{
|
|
"type" : "staticmethod",
|
|
"class" : "Trig",
|
|
"name" : "getErrors",
|
|
"generate" : "jswrap_trig_getErrors",
|
|
"return" : ["int","The error flags"]
|
|
}
|
|
Get the current error flags from the trigger wheel - and zero them
|
|
*/
|
|
JsVarInt jswrap_trig_getErrors() {
|
|
TriggerStruct *trig = &mainTrigger;
|
|
TriggerError errors = trig->errors;
|
|
trig->errors = 0;
|
|
return (JsVarInt)errors;
|
|
}
|
|
|
|
/*JSON{
|
|
"type" : "staticmethod",
|
|
"class" : "Trig",
|
|
"name" : "getErrorArray",
|
|
"generate" : "jswrap_trig_getErrorArray",
|
|
"return" : ["JsVar","An array of error strings"]
|
|
}
|
|
Get the current error flags from the trigger wheel - and zero them
|
|
*/
|
|
JsVar* jswrap_trig_getErrorArray() {
|
|
TriggerStruct *trig = &mainTrigger;
|
|
TriggerError errors = trig->errors;
|
|
trig->errors = 0;
|
|
|
|
JsVar *arr = jsvNewEmptyArray();
|
|
if (arr) {
|
|
int i;
|
|
for (i=1;i<=errors;i<<=1) {
|
|
if (errors & i) {
|
|
const char *s = trigGetErrorString(i);
|
|
if (s) {
|
|
jsvArrayPushString(arr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return arr;
|
|
}
|