/** * * User: Martin Donnelly * Date: 2016-05-20 * Time: 10:13 * */ /* global CAPABILITY, inheritsFrom, capabilityManager */ /* global ble */ /* jshint browser: true , devel: true*/ var CC2650_ACCEL; CC2650_ACCEL = function(p) { 'use strict'; this.name = 'Accelerometer'; this.deviceID = p.deviceID || null; this.target = p.target || null; this.capabilityID = 'F000AA80-0451-4000-B000-000000000000'; this.serviceDef = { service: 'F000AA80-0451-4000-B000-000000000000', data: 'F000AA81-0451-4000-B000-000000000000', // Read/notify 3 bytes X : Y : Z notification: 'F0002902-0451-4000-B000-000000000000', configuration: 'F000AA82-0451-4000-B000-000000000000', // Read/write 1 byte period: 'F000AA83-0451-4000-B000-000000000000' // Read/write 1 byte Period = [Input*10]ms }; this.frames = {}; this.$id = {}; this.$result = {}; this.data = { gyro: {x: [], y: [], z: []}, accel: {x: [], y: [], z: []}, mag: {x: [], y: [], z: []} }; this.setFrame(); this.sensorMpu9250GyroConvert = function(data) { return (data * 1.0) / (65536 / 500); }; this.sensorMpu9250AccConvert = function(data) { // Change /2 to match accel range...i.e. 16 g would be /16 return (data * 1.0) / (32768 / 2); }; this.processData = function(data) { var a = new Int16Array(data); var calcData = { gyro: { x: this.sensorMpu9250GyroConvert(a[0]), y: this.sensorMpu9250GyroConvert(a[1]), z: this.sensorMpu9250GyroConvert(a[2]) }, accel: { x: this.sensorMpu9250AccConvert(a[3]), y: this.sensorMpu9250AccConvert(a[4]), z: this.sensorMpu9250AccConvert(a[5]) }, mag: { x: a[6], y: a[7], z: a[8] } }; return calcData; }; this.onAccelerometerData = function(data) { // Console.log(data); var message; var calcData; function gString(v) { return [v.toFixed(3),'G'].join(''); } function aString(v) { return [v.toFixed(3),'\'/s'].join(''); } function mString(v) { return [v.toFixed(3),'mT'].join(''); } calcData = this.processData(data); this.$result[this.frames.gyroID + '-x'].text(gString(calcData.gyro.x)); this.$result[this.frames.gyroID + '-y'].text(gString(calcData.gyro.y)); this.$result[this.frames.gyroID + '-z'].text(gString(calcData.gyro.z)); this.$result[this.frames.accelID + '-x'].text(aString(calcData.accel.x)); this.$result[this.frames.accelID + '-y'].text(aString(calcData.accel.y)); this.$result[this.frames.accelID + '-z'].text(aString(calcData.accel.z)); this.$result[this.frames.magID + '-x'].text(mString(calcData.mag.x)); this.$result[this.frames.magID + '-y'].text(mString(calcData.mag.y)); this.$result[this.frames.magID + '-z'].text(mString(calcData.mag.z)); this.data.gyro.x = this.storeData(calcData.gyro.x, this.data.gyro.x); this.data.gyro.y = this.storeData(calcData.gyro.y, this.data.gyro.y); this.data.gyro.z = this.storeData(calcData.gyro.z, this.data.gyro.z); this.data.accel.x = this.storeData(calcData.accel.x, this.data.accel.x); this.data.accel.y = this.storeData(calcData.accel.y, this.data.accel.y); this.data.accel.z = this.storeData(calcData.accel.z, this.data.accel.z); this.data.mag.x = this.storeData(calcData.mag.x, this.data.mag.x); this.data.mag.y = this.storeData(calcData.mag.y, this.data.mag.y); this.data.mag.z = this.storeData(calcData.mag.z, this.data.mag.z); }; this.startService = function() { this.maxLength = 500; if (this.deviceID !== null) { console.log('Starting CC2650 Accelerometer Service on ', this.deviceID); console.log(this.serviceDef); this.setInternalID(); this.insertFrame('gyro'); this.insertFrame('accel'); this.insertFrame('mag'); ble.startNotification(this.deviceID, this.serviceDef.service, this.serviceDef.data, this.onAccelerometerData.bind(this), this.onError); // Turn accelerometer on var configData = new Uint16Array(1); // Turn on gyro, accel, and mag, 2G range, Disable wake on motion configData[0] = 0x007F; ble.write(this.deviceID, this.serviceDef.service, this.serviceDef.configuration, configData.buffer, function() { console.log('Started accelerometer.'); }, this.onError); var periodData = new Uint8Array(1); periodData[0] = 0x0A; ble.write(this.deviceID, this.serviceDef.service, this.serviceDef.period, periodData.buffer, function() { console.log('Configured accelerometer period.'); }, this.onError); } }; this.advancedGraphFFT = function(mode, data, subID) { var startX; var _cdata; var xstep; var scalePos; var lm; var ceiling; var elm; var text2ID; var ceilingLimit; var calcArray; var floor; var _subID; var _data; var text1ID; var lineID; var max; var yscale = 125; var height = 125; var yOffset; var reducer = function(p, v) { return (Math.abs(p) > Math.abs(v) ? Math.abs(p) : Math.abs(v)); }; var parts = ['x', 'y', 'z']; var _newData = {x: [],y: [],z: []}; var fnFillNewData = function(c_value, i) { ceiling = reducer(c_value.real ,ceiling); _newData[lm].push(c_value.real); }; if (subID === 'gyro') { height = 300; yscale = 300; } _data = data || this.data; _subID = subID || ''; // LineID = [this.frameID , _subID , '-line'].join(''); text1ID = [this.frameID, _subID, '-txt1'].join(''); text2ID = [this.frameID, _subID, '-txt2'].join(''); ceiling = 0; if (_data.x.length > 0) { max = 2; for (var lineMode = 0; lineMode < parts.length; lineMode++) { lm = parts[lineMode]; _cdata = new complex_array.ComplexArray(_data[lm]); _cdata.FFT(); _cdata.forEach(fnFillNewData); } if (ceiling > 500) { max = (ceiling > max) ? (Math.ceil((Math.round(ceiling) + 1) / 50) * 50) : max; } else { max = (ceiling > max) ? (Math.ceil((Math.round(ceiling) + 1) / 10) * 10) : max; } ceiling = max; floor = ceiling * -1; ceilingLimit = ceiling; scalePos = (yscale / 2) / ceiling; xstep = (680 - 46) / this.maxLength; yOffset = ((height - (14 + 12)) / 2) + 12; for (lineMode = 0; lineMode < parts.length; lineMode++) { lm = parts[lineMode]; startX = 46 + (this.maxLength - _newData[lm].length) * xstep; calcArray = []; lineID = this.frameID + _subID + '-' + lm + '-line'; for (var x = 0; x < _newData[lm].length; x++) { calcArray.push((startX + (x * xstep)).toFixed(2) + ',' + (yOffset - ((_newData[lm][x]) * scalePos)).toFixed( 2)); } elm = document.getElementById(lineID); elm.setAttribute('points', calcArray.join(' ')); } elm = document.getElementById(text1ID); elm.textContent = ceilingLimit; elm = document.getElementById(text2ID); elm.textContent = floor; } this.previousCeil = ceiling; }; this.advancedGraph = function(mode, data, subID) { var startX; var xstep; var scalePos; var lm; var ceiling; var elm; var text2ID; var ceilingLimit; var calcArray; var floor; var _subID; var _data; var text1ID; var lineID; var max; var yscale = 125; var height = 125; var yOffset; var reducer = function(p, v) { return (Math.abs(p) > Math.abs(v) ? Math.abs(p) : Math.abs(v)); }; var parts = ['x', 'y', 'z']; _data = data || this.data; _subID = subID || ''; text1ID = [this.frameID, _subID, '-txt1'].join(''); text2ID = [this.frameID, _subID, '-txt2'].join(''); if (mode === 'gyro') { height = 300; yscale = 300; } if (_data.x.length > 0) { max = 2; for (var lineMode = 0; lineMode < parts.length; lineMode++) { lm = parts[lineMode]; ceiling = _data[lm].reduce(reducer); if (ceiling > 500) { max = (ceiling > max) ? (Math.ceil((Math.round(ceiling) + 1) / 50) * 50) : max; } else { max = (ceiling > max) ? (Math.ceil((Math.round(ceiling) + 1) / 10) * 10) : max; } } ceiling = max; floor = ceiling * -1; ceilingLimit = ceiling; scalePos = (yscale / 2) / ceiling; xstep = (680 - 46) / this.maxLength; // YOffset should be about 71; yOffset = ((height - (14 + 12)) / 2) + 12; for (lineMode = 0; lineMode < parts.length; lineMode++) { lm = parts[lineMode]; startX = 46 + (this.maxLength - _data[lm].length) * xstep; calcArray = []; lineID = this.frameID + _subID + '-' + lm + '-line'; for (var x = 0; x < _data[lm].length; x++) { calcArray.push((startX + (x * xstep)).toFixed(2) + ',' + (yOffset - ((_data[lm][x]) * scalePos)).toFixed( 2)); } elm = document.getElementById(lineID); elm.setAttribute('points', calcArray.join(' ')); } elm = document.getElementById(text1ID); elm.textContent = ceilingLimit; elm = document.getElementById(text2ID); elm.textContent = floor; } this.previousCeil = ceiling; }; this.animateGraph = function() { // Nothing to animate yet // return -1; this.advancedGraphFFT(0, this.data.gyro, 'gyro'); this.advancedGraph(0, this.data.accel, 'accel'); this.advancedGraph(0, this.data.mag, 'mag'); // This.simpleGraph(this.data.temp, 'temp'); // this.simpleGraph(this.data.pressure, 'pressure'); }; this.generateBlankGraphBase = function(subID, settings) { var _subID = subID || ''; var xmlns = 'http://www.w3.org/2000/svg'; var svgID = this.frameID + _subID + '-svg'; var text1ID = this.frameID + _subID + '-txt1'; var text2ID = this.frameID + _subID + '-txt2'; var _width = settings.width || 300; var _height = settings.height || 150; var _fill = settings.fill || 'blue'; var viewbox = [0,0,_width, _height].join(' '); var svg = document.createElementNS(xmlns, 'svg'); svg.setAttribute('id', svgID); // Svg.setAttribute(xmlns, 'version', '1.1'); svg.setAttribute('width', _width.toString()); svg.setAttribute('height', _height.toString()); svg.setAttribute('fill', _fill); svg.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xlink', 'http://www.w3.org/1999/xlink'); svg.setAttributeNS(xmlns, 'viewBox', viewbox); // Svg.setAttributeNS(xmlns, 'style', 'width:700px;height:150px;'); svg = this.graphAddXAxis(svg, {y: 12, x2: 680, colour: '#004c6d', id: text1ID}); svg = this.graphAddXAxis(svg, {y: _height - 14, x2: 680, colour: '#004c6d', id: text2ID}); svg = this.graphAddXAxis(svg, {y: ((_height - (14 + 12)) / 2) + 12, x2: 680, colour: '#004c6d', text: '0'}); return svg; }; this.generateBlankGraph = function(subID, height) { var _height = height || 150; var _subID = subID || ''; var xlineID = this.frameID + _subID + '-x-line'; var ylineID = this.frameID + _subID + '-y-line'; var zlineID = this.frameID + _subID + '-z-line'; var svg = this.generateBlankGraphBase(_subID,{width: '700',height: _height}); svg = this.graphAddLine(svg, xlineID, 'rgba(255,0,99,1)'); svg = this.graphAddLine(svg, ylineID, 'rgba(46,255,0,1)'); svg = this.graphAddLine(svg, zlineID, 'rgba(0,191,255,1)'); return svg; }; this.insertFrame = function(mode) { var _graph; var row; var elm; var frame; var title; var modeID = mode + 'ID'; var height = 150; this.frames[modeID] = this.frameID + '-' + mode; var titles = { gyro: 'Gyroscope', accel: 'Accelerometer', mag: 'Magnetometer' }; console.log('FrameID: ', this.frames[modeID]); title = [titles[mode], ' - ', this.deviceID].join(' '); frame = $('
', { class: 'mui-panel', id: this.frames[modeID] }); if (mode === 'gyro') { height = 300; } if (mode === 'mag') { elm = $('
', {class: 'mui-row'}); elm.append($('
', { class: 'mui-col-xs-8 mui--text-title mui-ellipsis-2', text: title})); // Elm.append($('
', {class: 'mui-col-xs-4 mui--text-right'}).append(button)); frame.append(elm); } else { $('
', {class: 'mui-row'}).append($('
', { class: 'mui-col-xs-12 mui--text-title mui-ellipsis-2', text: title })).appendTo(frame); } this.$frame.append(frame); this.$id[modeID] = $('#' + this.frames[modeID]); // Call the parent displayForm first... row = $('
', {class: 'mui-row'}); $('
', { class: 'mui-col-xs-4 mui--text-accent mui--text-center', text: 'X' }).appendTo(row); $('
', { class: 'mui-col-xs-4 mui--text-accent mui--text-center', text: 'Y' }).appendTo(row); $('
', { class: 'mui-col-xs-4 mui--text-accent mui--text-center', text: 'Z' }).appendTo(row); this.$id[modeID].append(row); row = $('
', {class: 'mui-row'}); $('
', { class: 'mui-col-xs-4 mui--text-light mui--text-center', text: '--', id: this.frames[modeID] + '-x' }).appendTo(row); $('
', { class: 'mui-col-xs-4 mui--text-light mui--text-center', text: '--', id: this.frames[modeID] + '-y' }).appendTo(row); $('
', { class: 'mui-col-xs-4 mui--text-light mui--text-center', text: '--', id: this.frames[modeID] + '-z' }).appendTo(row); this.$id[modeID].append(row); this.$result[this.frames[modeID] + '-x'] = $('#' + this.frames[modeID] + '-x'); this.$result[this.frames[modeID] + '-y'] = $('#' + this.frames[modeID] + '-y'); this.$result[this.frames[modeID] + '-z'] = $('#' + this.frames[modeID] + '-z'); row = $('
', {class: 'mui-row'}); _graph = this.generateBlankGraph(mode, height); row.append($('
', {class: 'mui-col-sm-12'}).append(_graph)); this.$id[modeID].append(row); }; }; inheritsFrom(CC2650_ACCEL, CAPABILITY); capabilityManager.register({id: 'F000AA80-0451-4000-B000-000000000000', module: CC2650_ACCEL});