diff options
author | Romain Forlot <romain.forlot@iot.bzh> | 2017-04-29 18:17:08 +0200 |
---|---|---|
committer | Romain Forlot <romain.forlot@iot.bzh> | 2017-05-02 16:17:08 +0200 |
commit | 7e6d6d0a37e37804e3a751e2bfde11a9c1e85b0b (patch) | |
tree | dcc513f232f608021a55fd317ccd3b1f623ccb70 | |
parent | 10e7cf8b0d84be658069f60e5dd4831ec202cd70 (diff) |
Adding HTML5 UI with cpu stat binding
Change-Id: Id63b7d338140097a5f2f0943f1b63ee978141829
Signed-off-by: Romain Forlot <romain.forlot@iot.bzh>
27 files changed, 2148 insertions, 0 deletions
diff --git a/CAN-binder/low-can-demo/.gitignore b/CAN-binder/low-can-demo/.gitignore new file mode 100644 index 0000000..46f791d --- /dev/null +++ b/CAN-binder/low-can-demo/.gitignore @@ -0,0 +1,5 @@ +dist.prod +dist.dev +build +bower_components +node_modules diff --git a/CAN-binder/low-can-demo/LICENSE b/CAN-binder/low-can-demo/LICENSE new file mode 100644 index 0000000..8dada3e --- /dev/null +++ b/CAN-binder/low-can-demo/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/CAN-binder/low-can-demo/README.md b/CAN-binder/low-can-demo/README.md new file mode 100644 index 0000000..bb8f239 --- /dev/null +++ b/CAN-binder/low-can-demo/README.md @@ -0,0 +1,13 @@ +# Build + +Run: + +``` +# npm install +# mkdir build +# cd build +# cmake .. +# make +``` + + diff --git a/CAN-binder/low-can-demo/app/Frontend/images/car-top-view.png b/CAN-binder/low-can-demo/app/Frontend/images/car-top-view.png Binary files differnew file mode 100644 index 0000000..a5ad096 --- /dev/null +++ b/CAN-binder/low-can-demo/app/Frontend/images/car-top-view.png diff --git a/CAN-binder/low-can-demo/app/Frontend/images/cluster.png b/CAN-binder/low-can-demo/app/Frontend/images/cluster.png Binary files differnew file mode 100644 index 0000000..c6b8d90 --- /dev/null +++ b/CAN-binder/low-can-demo/app/Frontend/images/cluster.png diff --git a/CAN-binder/low-can-demo/app/Frontend/images/favicon.ico b/CAN-binder/low-can-demo/app/Frontend/images/favicon.ico Binary files differnew file mode 100644 index 0000000..eeb7ab7 --- /dev/null +++ b/CAN-binder/low-can-demo/app/Frontend/images/favicon.ico diff --git a/CAN-binder/low-can-demo/app/Frontend/images/gas-pump-black.png b/CAN-binder/low-can-demo/app/Frontend/images/gas-pump-black.png Binary files differnew file mode 100644 index 0000000..46e875e --- /dev/null +++ b/CAN-binder/low-can-demo/app/Frontend/images/gas-pump-black.png diff --git a/CAN-binder/low-can-demo/app/Frontend/images/gas-pump-green.png b/CAN-binder/low-can-demo/app/Frontend/images/gas-pump-green.png Binary files differnew file mode 100644 index 0000000..c3aebad --- /dev/null +++ b/CAN-binder/low-can-demo/app/Frontend/images/gas-pump-green.png diff --git a/CAN-binder/low-can-demo/app/Frontend/images/gas-pump-red.png b/CAN-binder/low-can-demo/app/Frontend/images/gas-pump-red.png Binary files differnew file mode 100644 index 0000000..ad84283 --- /dev/null +++ b/CAN-binder/low-can-demo/app/Frontend/images/gas-pump-red.png diff --git a/CAN-binder/low-can-demo/app/Frontend/images/logo_iot_bzh_lightgrey_325x90_50dpi.png b/CAN-binder/low-can-demo/app/Frontend/images/logo_iot_bzh_lightgrey_325x90_50dpi.png Binary files differnew file mode 100644 index 0000000..7ba4196 --- /dev/null +++ b/CAN-binder/low-can-demo/app/Frontend/images/logo_iot_bzh_lightgrey_325x90_50dpi.png diff --git a/CAN-binder/low-can-demo/app/Frontend/index.html b/CAN-binder/low-can-demo/app/Frontend/index.html new file mode 100644 index 0000000..b1b8a81 --- /dev/null +++ b/CAN-binder/low-can-demo/app/Frontend/index.html @@ -0,0 +1,137 @@ +<!DOCTYPE html> +<!--[if lt IE 7]> <html lang="en" ng-app="@@APPNAME@@" class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]--> +<!--[if IE 7]> <html lang="en" ng-app="@@APPNAME@@" class="no-js lt-ie9 lt-ie8"> <![endif]--> +<!--[if IE 8]> <html lang="en" ng-app="@@APPNAME@@" class="no-js lt-ie9"> <![endif]--> +<!--[if gt IE 8]><!--> <html lang="en" ng-app="@@APPNAME@@" class="no-js"> <!--<![endif]--> +<head> + <meta http-equiv="content-type" content="text/html; charset=utf-8"> + <title>AGL Low CAN binding demo</title> + <base href="@@URLBASE@@"> + <!-- bower:css --> + <!-- endinject --> + <!-- vendor:css --> + <!-- endinject --> + <!-- appli:css --> + <!-- endinject --> + <!-- inject:css --> + <!-- endinject --> + <!-- bower:js --> + <!-- endinject --> + <!-- inject:js --> + <!-- endinject --> +</head> +<body class="not-connected"> + <!-- Navigation --> + <nav class="navbar navbar-inverse navbar-fixed-top" role="navigation"> + <div class="container-fluid"> + <!-- Brand and toggle get grouped for better mobile display --> + <a class="navbar-brand" href="http://iot.bzh" target="_blank" alt="IoT.bzh"> + <img id="iotbzh-logo" src="/images/logo_iot_bzh_lightgrey_325x90_50dpi.png"/> + </a> + <div class="collapse navbar-collapse"> + <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"> + <span class="sr-only">Toggle navigation</span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + <span class="icon-bar"></span> + </button> + <p class="navbar-text navbar-right">AGL Low CAN binding</p> + <ul class="nav navbar-nav"> + <li class="if-not-connected"> + <a role="button" onclick="doConnect();">Connect</a> + </li> + <li class="if-connecting"> + Connecting... + </li> + <li class="if-started"> + <a role="button" onclick="doDisconnect();">Disconnect</a> + </li> + </ul> + </div> + <!-- /.navbar-collapse --> + </div> + <!-- /.container --> + </nav> + + <div class="content"> + <div id="quad1" class="quad"> + <img id="view1"/> +<!-- + <div id="vspan"> + <svg height="100" width="100"> + <g> + <circle cx="50" cy="50" r="49" stroke="white" stroke-width="3"/> + <text x="50%" y="80%" fill="white" text-anchor="middle">Km/h</text> + </g> + </svg> + <div id="vspeed" class="number">0</div> + </div> + <div id="espan"> + <svg height="100" width="100"> + <g> + <circle cx="50" cy="50" r="49" stroke="white" stroke-width="3"/> + <text x="50%" y="80%" fill="white" text-anchor="middle">Rpm</text> + </g> + </svg> + <div id="espeed" class="number">0</div> + </div> +--> + <div id="cluster"> + <canvas id="torqueGauge"></canvas> + <canvas id="rpmGauge"></canvas> + <canvas id="MAFGauge"></canvas> + <canvas id="speedGauge"></canvas> + <canvas id="IATempGauge"></canvas> + </div> + </div> + +<!-- + <div id="quad2" class="quad"> + <div id="mapsat"></div> + <img id="car" class="invisible" src="images/car-top-view.png"/> + <div id="gaspan"> + <div id="gas"> + <div id="gpgreen"></div> + <div id="gpblack"></div> + <div id="gpred"></div> + </div> + <div id="copan"> + <div id="con1"></div> + <div id="con2"></div> + <div id="con3"></div> + <div id="con4"></div> + <div id="con5"></div> + <div id="con6"></div> + <div id="con7"></div> + <div id="con8"></div> + <div id="con9"></div> + </div> + </div> + </div> +--> + <div id="quad3" class="quad"> + <table id="xcdata" class="table table-striped table-bordered table-condensed"> + <thead> + <tr><th colspan="2">AGL CAN messages Details</th></tr> + <tr><th class="col-md-4">Data</th><th>Value</th></tr> + </thead> + <tbody> + <tr> <td>Vehicle Speed</td> <td><span id="vsp">?</span> km/h</td> </tr> + <tr> <td>Engine Speed</td> <td><span id="esp">?</span> tr/mn</td> </tr> + <tr> <td>Engine Load</td> <td><span id="trq">?</span> %</td> </tr> + <tr> <td>MAF air flow rate</td> <td><span id="fue">?</span> grams/sec</td> </tr> + <tr> <td>Intake Air temp</td> <td><span id="tem">?</span> °C</td> </tr> + <tr> <td>Messages rate</td> <td><span id="msg">?</span> received events/s</td> </tr> + <tr> <td>CPU load</td> <td><span id="stat">?</span> %</td> </tr> + </tbody> + </table> + </div> + +<!-- + <div id="quad4" class="quad"> + <div id="mapstreet"></div> + </div> +--> + </div> +</body> +</html> diff --git a/CAN-binder/low-can-demo/app/Frontend/js/AFB.js b/CAN-binder/low-can-demo/app/Frontend/js/AFB.js new file mode 100644 index 0000000..aa1198c --- /dev/null +++ b/CAN-binder/low-can-demo/app/Frontend/js/AFB.js @@ -0,0 +1,170 @@ +AFB = function(base, initialtoken){ + +var urlws = "ws://"+window.location.host+"/"+base; +var urlhttp = "http://"+window.location.host+"/"+base; + +/*********************************************/ +/**** ****/ +/**** AFB_context ****/ +/**** ****/ +/*********************************************/ +var AFB_context = (function() { + var UUID; + var TOKEN = initialtoken; + + var context = function(token, uuid) { + this.token = token; + this.uuid = uuid; + }; + + context.prototype = { + get token() {return TOKEN;}, + set token(tok) {if(tok) TOKEN=tok;}, + get uuid() {return UUID;}, + set uuid(id) {if(id) UUID=id;} + }; + + return new context(); +})(); +/*********************************************/ +/**** ****/ +/**** AFB_websocket ****/ +/**** ****/ +/*********************************************/ +var AFB_websocket = (function() { + var CALL = 2; + var RETOK = 3; + var RETERR = 4; + var EVENT = 5; + + var PROTO1 = "x-afb-ws-json1"; + + var result = function(onopen, onabort) { + var u = urlws; + if (AFB_context.token) { + u = u + '?x-afb-token=' + AFB_context.token; + if (AFB_context.uuid) + u = u + '&x-afb-uuid=' + AFB_context.uuid; + } + this.ws = new WebSocket(u, [ PROTO1 ]); + this.pendings = {}; + this.awaitens = {}; + this.counter = 0; + this.ws.onopen = onopen.bind(this); + this.ws.onerror = onerror.bind(this); + this.ws.onclose = onclose.bind(this); + this.ws.onmessage = onmessage.bind(this); + this.onopen = onopen; + this.onabort = onabort; + }; + + function onerror(event) { + var f = this.onabort; + if (f) { + delete this.onopen; + delete this.onabort; + f && f(this); + } + this.onerror && this.onerror(this); + } + + function onopen(event) { + var f = this.onopen; + delete this.onopen; + delete this.onabort; + f && f(this); + } + + function onclose(event) { + for (var id in this.pendings) { + var ferr = this.pendings[id].onerror; + ferr && ferr(null, this); + } + this.pendings = {}; + this.onclose && this.onclose(); + } + + function fire(awaitens, name, data) { + var a = awaitens[name]; + if (a) + a.forEach(function(handler){handler(data);}); + var i = name.indexOf("/"); + if (i >= 0) { + a = awaitens[name.substring(0,i)]; + if (a) + a.forEach(function(handler){handler(data);}); + } + a = awaitens["*"]; + if (a) + a.forEach(function(handler){handler(data);}); + } + + function reply(pendings, id, ans, offset) { + if (id in pendings) { + var p = pendings[id]; + delete pendings[id]; + var f = p[offset]; + f && f(ans); + } + } + + function onmessage(event) { + var obj = JSON.parse(event.data); + var code = obj[0]; + var id = obj[1]; + var ans = obj[2]; + AFB_context.token = obj[3]; + switch (code) { + case RETOK: + reply(this.pendings, id, ans, 0); + break; + case RETERR: + reply(this.pendings, id, ans, 1); + break; + case EVENT: + default: + fire(this.awaitens, id, ans); + break; + } + } + + function close() { + this.ws.close(); + } + + function call(method, request, onsuccess, onfailure) { + var id, arr; + do { + id = String(this.counter = 4095 & (this.counter + 1)); + } while (id in this.pendings); + this.pendings[id] = [ onsuccess, onfailure ]; + arr = [CALL, id, method, request ]; + if (AFB_context.token) arr.push(AFB_context.token); + this.ws.send(JSON.stringify(arr)); + } + + function onevent(name, handler) { + var id = name; + var list = this.awaitens[id] || (this.awaitens[id] = []); + list.push(handler); + } + + result.prototype = { + close: close, + call: call, + onevent: onevent + }; + + return result; +})(); +/*********************************************/ +/**** ****/ +/**** ****/ +/**** ****/ +/*********************************************/ +return { + context: AFB_context, + ws: AFB_websocket +}; +}; + diff --git a/CAN-binder/low-can-demo/app/Frontend/js/low-can-demo.js b/CAN-binder/low-can-demo/app/Frontend/js/low-can-demo.js new file mode 100644 index 0000000..2e8b99e --- /dev/null +++ b/CAN-binder/low-can-demo/app/Frontend/js/low-can-demo.js @@ -0,0 +1,351 @@ +// parse location to get security token +var urlParams={}; +location.search.substr(1).split("&").forEach(function(item) { + var k = item.split("=")[0]; + var v = decodeURIComponent(item.split("=")[1]); + if (k in urlParams) urlParams[k].push(v); else urlParams[k] = [v]; +}); + +var afb = new AFB("api"/*root*/, urlParams.token[0]); +var ws; +var vspeed = 0, espeed = 0, torque = 0; +var R2D = 180.0 / Math.PI; +var D2R = Math.PI / 180.0; +var fuel; +var con,cons,consa = [ ]; +var minspeed = 5; +var temp = 18; +var wdgTem, wdgVsp, wdgEsp, wdgTrq; +var wdgFue, wdgGpred, wdgGpblack; +var conscale = 40; +var condt = 60000; + +/* gauges creation */ +var gauges={}; +function initGauges() { + gauges.speed = new steelseries.Radial('speedGauge', { + gaugeType: steelseries.GaugeType.TYPE4, + frameDesign: steelseries.FrameDesign.BLACK_METAL, + backgroundColor: steelseries.BackgroundColor.CARBON, + size: 250, + titleString: "Speed", + unitString: "Km/h", + lcdVisible: true, + niceScale: true, + maxValue: 200, + maxMeasuredValue: 0, + maxMeasuredValueVisible: true, + thresholdVisible: false, + ledVisible: false, + pointerType: steelseries.PointerType.TYPE11, + useOdometer: false, + odometerParams: { + digits: 6 + } + }); + + gauges.rpm = new steelseries.Radial('rpmGauge', { + gaugeType: steelseries.GaugeType.TYPE4, + frameDesign: steelseries.FrameDesign.BLACK_METAL, + backgroundColor: steelseries.BackgroundColor.CARBON, + size: 200, + titleString: "RPM", + unitString: "x1000", + lcdVisible: false, + niceScale: true, + maxValue: 5, + maxMeasuredValue: 0, + maxMeasuredValueVisible: false, + section: [ + steelseries.Section(4, 8, 'rgba(255, 0, 0, 0.7)') + ], + area: [ + steelseries.Section(5, 8, 'rgba(255, 0, 0, 0.3)') + ], + thresholdVisible: false, + ledVisible: false, + pointerType: steelseries.PointerType.TYPE11 + }); + + gauges.maf = new steelseries.Radial('MAFGauge', { + gaugeType: steelseries.GaugeType.TYPE4, + frameDesign: steelseries.FrameDesign.BLACK_METAL, + backgroundColor: steelseries.BackgroundColor.CARBON, + size: 200, + titleString: "Air flow Rate", + unitString: "grams/sec", + lcdVisible: true, + lcdColor: steelseries.LcdColor.STANDARD, + lcdDecimals: 1, + niceScale: true, + minValue: 0, + maxValue: 655, + minMeasuredValue: 0, + maxMeasuredValue: conscale, + maxMeasuredValueVisible: true, + section: [ + steelseries.Section(0, 255, 'rgba(0, 255, 0, 0.5)'), + steelseries.Section(256, 326, 'rgba(255, 255, 0, 0.5)'), + steelseries.Section(327, 600, 'rgba(255, 128, 0, 0.5)'), + steelseries.Section(601, 655, 'rgba(255, 0, 0, 0.5)') + ], + useValueGradient: true, + thresholdVisible: false, + ledVisible: false, + pointerType: steelseries.PointerType.TYPE11 + }); + + gauges.iatemp = new steelseries.Radial('IATempGauge', { + gaugeType: steelseries.GaugeType.TYPE4, + frameDesign: steelseries.FrameDesign.BLACK_METAL, + backgroundColor: steelseries.BackgroundColor.CARBON, + size: 200, + titleString: "Intake air temp", + unitString: "°C", + lcdVisible: true, + lcdColor: steelseries.LcdColor.STANDARD, + lcdDecimals: 1, + niceScale: true, + minValue: 0, + maxValue: 100, + minMeasuredValue: 0, + maxMeasuredValue: 100, + maxMeasuredValueVisible: true, + section: [ + steelseries.Section(0, 30, 'rgba(0, 255, 0, 0.5)'), + steelseries.Section(31, 50, 'rgba(255, 255, 0, 0.5)'), + steelseries.Section(51, 70, 'rgba(255, 128, 0, 0.5)'), + steelseries.Section(71, 100, 'rgba(255, 0, 0, 0.5)') + ], + useValueGradient: true, + thresholdVisible: false, + ledVisible: false, + pointerType: steelseries.PointerType.TYPE11 + }); + + gauges.torque = new steelseries.Radial('torqueGauge', { + gaugeType: steelseries.GaugeType.TYPE2, + frameDesign: steelseries.FrameDesign.BLACK_METAL, + backgroundColor: steelseries.BackgroundColor.CARBON, + size: 200, + titleString: "Load", + unitString: "%", + lcdVisible: false, + niceScale: true, + minValue: 0, + maxValue: 100, + maxMeasuredValue: 0, + maxMeasuredValueVisible: false, + section: [ + steelseries.Section(0, 0, 'rgba(0, 255, 0, 0.7)'), + steelseries.Section(50, 1500, 'rgba(255, 128, 0, 0.7)') + ], + area: [ + steelseries.Section(0, 0, 'rgba(0, 255, 0, 0.3)'), + steelseries.Section(50, 1500, 'rgba(255, 128, 0, 0.3)') + ], + threshold: 0, + thresholdVisible: true, + ledVisible: false, + pointerType: steelseries.PointerType.TYPE4 + }); + + /* adjust cluster background size upon resize */ + // TODO: could be doable through CSS, but a bit tricky + function adjustCluster() { + var qh=$("#quad1").outerHeight(); + var sh=$("#speedGauge").outerHeight(); + var pct=Math.ceil((1000*sh/qh))/10+1; + $('#cluster').css("height",pct+"%"); + } + $(window).resize(adjustCluster); + adjustCluster(); +} + +function clearGauges() { + for (var g in gauges) { + switch(g) { + case "clock": + gauges[g].setValue("-"); + break; + case "speed": + gauges[g].setValue(0); + break; + default: + gauges[g].setValue(0); + break; + } + } +} + +function gotVehicleSpeed(obj) { + vspeed = Math.round(obj.data.value); + wdgVsp.innerHTML = /* wdgVspeed.innerHTML = */ String(vspeed); + //gauges.speed.setValueAnimated(vspeed); + gauges.speed.setValue(vspeed); +} + +function gotTorque(obj) { + torque=Math.round(obj.data.value); + wdgTrq.innerHTML=String(torque); + gauges.torque.setValue(torque); +} + +function gotEngineSpeed(obj) { + espeed = Math.round(obj.data.value); + wdgEsp.innerHTML = /* wdgEspeed.innerHTML = */ String(espeed); + //gauges.rpm.setValueAnimated(espeed/1000); + gauges.rpm.setValue(espeed/1000); +} + +function gotFuelLevel(obj) { + fuel = Math.round(obj.data.value); + wdgFue.innerHTML = fuel; + gauges.maf.setValue(fuel); +} + +function gotTemp(obj) { + temp = Math.round(obj.data.value); + wdgTem.innerHTML = temp; + gauges.iatemp.setValue(temp); +} + +function gotStart(obj) { + document.body.className = "started"; + vspeed = 0; + espeed = 0; + heading = 0; + cons = undefined; + consa = [ ]; + + wdgVsp.innerHTML = /*wdgVspeed.innerHTML = */ + wdgEsp.innerHTML = /*wdgEspeed.innerHTML = */ + wdgTem.innerHTML = wdgFue.innerHTML = "?"; + for (var i = 0 ; i < 9 ; i++) { + wdgConX[i].style.height = "0%"; + wdgConX[i].innerHTML = ""; + } +} + +function gotStop(obj) { + document.body.className = "connected"; +} + +var msgcnt=0; +var msgprv=0; +var msgprvts=0; + +function gotAny(obj) { + if (obj.event != "low-can/STOP") { + document.body.className = "started"; + } + msgcnt++; + + wdgTem.innerHTML = temp; + gauges.iatemp.setValue(temp); +// updateClock(obj.data.timestamp); +} + +function updateMsgRate() { + var now=+new Date(); + if (msgprvts) { + var dt=now-msgprvts; + msgrate=Math.round((msgcnt-msgprv)*10000/dt)/10; + wdgMsg.innerHTML=String(msgrate); + } + + msgprv=msgcnt; + msgprvts=now; +} + +function gotStat(obj) { + wdgStat.innerHTML = obj.data; +} + +function onAbort() { + document.body.className = "not-connected"; +} + +function onOpen() { + ws.call("low-can/subscribe", {event:[ + "diagnostic_messages.vehicle.speed", + "diagnostic_messages.mass.airflow", + "diagnostic_messages.engine.speed", + "diagnostic_messages.engine.load", + "diagnostic_messages.intake.air.temperature"]}, + onSubscribed, onAbort); + ws.call("stat/subscribe", true); + ws.onevent("stat/stat", gotStat); +} + +function onClose() { + ws.call("low-can/unsubscribe", {event:[ + "diagnostic_messages.engine.speed", + "diagnostic_messages.mass.airflow", + "diagnostic_messages.vehicle.speed", + "diagnostic_messages.engine.load", + "diagnostic_messages.intake.air.temperature"]}, + onUnsubscribed, onAbort); + ws.call("stat/unsubscribe", true); + ws.onevent("stat/stat", gotStat); +} + +function onSubscribed() { + document.body.className = "connected"; + ws.onevent("low-can/diagnostic_messages.engine.speed", gotEngineSpeed); + ws.onevent("low-can/diagnostic_messages.mass.airflow", gotFuelLevel); + ws.onevent("low-can/diagnostic_messages.vehicle.speed", gotVehicleSpeed); + ws.onevent("low-can/diagnostic_messages.engine.load", gotTorque); + ws.onevent("low-can/diagnostic_messages.intake.air.temperature", gotTemp); + ws.onevent("low-can",gotAny); +} + +function onUnsubscribed() { + document.body.className = "disconnected"; + ws.onevent("low-can/diagnostic_messages.engine.speed", gotEngineSpeed); + ws.onevent("low-can/diagnostic_messages.mass.airflow", gotFuelLevel); + ws.onevent("low-can/diagnostic_messages.vehicle.speed", gotVehicleSpeed); + ws.onevent("low-can/diagnostic_messages.engine.load", gotTorque); + ws.onevent("low-can/diagnostic_messages.intake.air.temperature", gotTemp); + ws.onevent("low-can",gotAny); +} + +function replyok(obj) { + document.getElementById("output").innerHTML = "OK: "+JSON.stringify(obj); +} +function replyerr(obj) { + document.getElementById("output").innerHTML = "ERROR: "+JSON.stringify(obj); +} +function send(message) { + var api = document.getElementById("api").value; + var verb = document.getElementById("verb").value; + ws.call(api+"/"+verb, {data:message}, replyok, replyerr); +} + +function doConnect() { + document.body.className = "connecting"; + ws = new afb.ws(onOpen, onAbort); +} + +function doDisconnect() { + document.body.className = "connecting"; + ws = new afb.ws(onClose, onAbort); +} + +$(function() { + wdgVsp = document.getElementById("vsp"); + wdgEsp = document.getElementById("esp"); + wdgTrq = document.getElementById("trq"); + wdgFue = document.getElementById("fue"); + wdgTem = document.getElementById("tem"); + wdgStat = document.getElementById("stat"); + wdgMsg = document.getElementById("msg"); + + initGauges(); + + doConnect(); + + // init interval to compute message rate + setInterval(updateMsgRate,250); +}); + diff --git a/CAN-binder/low-can-demo/app/Frontend/styles/bootstrap.scss b/CAN-binder/low-can-demo/app/Frontend/styles/bootstrap.scss new file mode 100644 index 0000000..e72d1de --- /dev/null +++ b/CAN-binder/low-can-demo/app/Frontend/styles/bootstrap.scss @@ -0,0 +1,56 @@ +/*! + * Bootstrap v3.3.7 (http://getbootstrap.com) + * Copyright 2011-2016 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) + */ + +// Core variables and mixins +@import "bootstrap/variables"; +@import "bootstrap/mixins"; + +// Reset and dependencies +@import "bootstrap/normalize"; +@import "bootstrap/print"; +@import "bootstrap/glyphicons"; + +// Core CSS +@import "bootstrap/scaffolding"; +@import "bootstrap/type"; +@import "bootstrap/code"; +@import "bootstrap/grid"; +@import "bootstrap/tables"; +@import "bootstrap/forms"; +@import "bootstrap/buttons"; + +// Components +@import "bootstrap/component-animations"; +@import "bootstrap/dropdowns"; +@import "bootstrap/button-groups"; +@import "bootstrap/input-groups"; +@import "bootstrap/navs"; +@import "bootstrap/navbar"; +@import "bootstrap/breadcrumbs"; +@import "bootstrap/pagination"; +@import "bootstrap/pager"; +@import "bootstrap/labels"; +@import "bootstrap/badges"; +@import "bootstrap/jumbotron"; +@import "bootstrap/thumbnails"; +@import "bootstrap/alerts"; +@import "bootstrap/progress-bars"; +@import "bootstrap/media"; +@import "bootstrap/list-group"; +@import "bootstrap/panels"; +@import "bootstrap/responsive-embed"; +@import "bootstrap/wells"; +@import "bootstrap/close"; + +// Components w/ JavaScript +@import "bootstrap/modals"; +@import "bootstrap/tooltip"; +@import "bootstrap/popovers"; +@import "bootstrap/carousel"; + +// Utility classes +@import "bootstrap/utilities"; +@import "bootstrap/responsive-utilities"; diff --git a/CAN-binder/low-can-demo/app/Frontend/styles/low-can-demo.scss b/CAN-binder/low-can-demo/app/Frontend/styles/low-can-demo.scss new file mode 100644 index 0000000..d7e5213 --- /dev/null +++ b/CAN-binder/low-can-demo/app/Frontend/styles/low-can-demo.scss @@ -0,0 +1,187 @@ +html,body { + padding:0; + margin: 0 auto; + width:100%; + height:100%; + min-height:100%; + color: black; + background: #FFF; +} + +/* http://stackoverflow.com/questions/18474564/bootstrap-3-navbar-with-logo */ +.navbar-brand { + padding: 0px; +} +.navbar-brand>img { + height: 100%; + padding: 5px; + width: auto; +} +.navbar-right { + margin-right: 0; +} + +/* used in navbar to show/hide items depending on connection status */ +.not-connected .if-connecting { display: none; } +.not-connected .if-connected { display: none; } +.not-connected .if-started { display: none; } +.connecting .if-not-connected { display: none; } +.connecting .if-connected { display: none; } +.connecting .if-started { display: none; } +.connected .if-not-connected { display: none; } +.connected .if-connecting { display: none; } +.connected .if-started { display: none; } +.started .if-not-connected { display: none; } +.started .if-connecting { display: none; } +.started .if-connected { display: none; } + +.content{ + position: absolute; + left:0; + right:0; + bottom:0; + top: 50px; + padding:0; + overflow: hidden; +} + +.quad { + position: relative; + overflow: hidden; + width:100%; + height:50%; + padding:0; + margin: 0; + box-sizing:border-box; + -moz-box-sizing:border-box; + -webkit-box-sizing:border-box; + border: 4px ridge silver; + border-radius: 15px; + text-align: left; +} + +.center { + display: table-cell; + width:100%; + height:100%; + vertical-align: middle; +} + +#quad1 { border-bottom-right-radius: 0;} +#quad2 { border-bottom-left-radius: 0; } +#quad3 { border-top-right-radius: 0; overflow: auto; } +#quad4 { border-top-left-radius: 0; } + +/* in quad 1 */ +#view1,#view2 { + position: relative; + width: auto !important; + height: auto !important; + min-width: 100%; + min-height: 100%; + display: block; + top: 50%; + left: 50%; + transform: translate(-50%,-50%); + -webkit-transform: translate(-50%,-50%); +} + +.number { text-align: center; vertical-align: middle; font: italic bold 12px monospace; } + +/* +#espan { position: absolute; left: 1em; bottom: 1em; } +#espeed { position: absolute; top: 30px; width: 100px; color: green; font-size: 28px; } + +#vspan { position: absolute; right: 1em; bottom: 1em; } +#vspeed { position: absolute; top: 16px; width: 100px; color: cyan; font-size: 42px; } +*/ + +#cluster { + position: absolute; + bottom:0; + left:0; + right:0; + background: rgba(50,50,50,.4); + height: 43%; + border-top: 2px outset silver; + border-top-left-radius: 50%; + border-top-right-radius: 50%; +} + +#torqueGauge { position: absolute; bottom: -2%; left: 1%; width: 14%; } +#rpmGauge { position: absolute; bottom: -4%; left: 16%; width: 21%; } +#speedGauge { position: absolute; bottom: -3%; left: 38%; width: 24%; } +#MAFGauge { position: absolute; bottom: -4%; right: 16%; width: 21%; } +#IATempGauge { position: absolute; bottom: -2%; right: 1%; width: 14%; } + +/* in quad 2 */ +#mapstreet { + position: absolute; + width: 100%; + height: 100%; +} + +#car { + position: absolute; + top: 50%; + left: 50%; + z-index: 2000; + +} + +#gaspan { position: absolute; bottom:0; left:0; right:0; background: rgba(200,200,200,.3); padding: 1em; z-index: 2000;} + +#gas { position: relative; float: right; width: 69px; height: 92px; } +#gas div { position: absolute; top: 0px; left: 0px; width: 100%; height: 100%; overflow: hidden; } + +#copan { overflow: hidden; min-height: 50px; position: relative; height: 92px;} +#copan div { + display:inline; + position: absolute; + bottom: 0; + width: 10%; + height: 0%; + font-size: 10px; + color: black; + background: yellow; + border: 1px solid grey; + padding: 0; +} +#copan div p { + text-align: center; + position: absolute; + bottom: 2px; + margin: 0; + width: 100%; +} + +#con1 { left: 0%; } +#con2 { left: 11%; } +#con3 { left: 22%; } +#con4 { left: 33%; } +#con5 { left: 44%; } +#con6 { left: 55%; } +#con7 { left: 66%; } +#con8 { left: 77%; } +#con9 { left: 88%; } + +#gpblack { background: url(/images/gas-pump-black.png); } +#gpgreen { background: url(/images/gas-pump-green.png); } +#gpred { background: url(/images/gas-pump-red.png); visibility: hidden; } + +/* quad 3 */ +#xcdata { + text-align: left; +} + +.leaflet-control-layers-toggle { + background-image: url(/images/layers.png); +} + +/* quad 4 */ +#mapsat { + position: absolute; + width: 100%; + height: 100%; +} + diff --git a/CAN-binder/low-can-demo/app/etc/AppDefaults.js b/CAN-binder/low-can-demo/app/etc/AppDefaults.js new file mode 100644 index 0000000..164a6f2 --- /dev/null +++ b/CAN-binder/low-can-demo/app/etc/AppDefaults.js @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2015 "IoT.bzh" + * Author "Fulup Ar Foll" + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +var SESSION_TIMEOUT= 3600000; // default is 1h loggin session + +// Default config will be superseaded by ProjectRoot/.config-l4a.js $HOME/.config-l4a.js /etc/default/config-l4a.js +config = { + + APPNAME : 'low-can-demo', // Application name, specified in config.xml + APPVER : '0.1', // version (config.xml) + FRONTEND: "Frontend", // HTML5 frontend [no leading ./] + BACKEND : "Backend", // NodeJS Rest API [no leading ./] + URLBASE : '/', // HTML basedir when running in production [should end with a /] + APIBASE : '/api/' // Api url base dir [should end with a /] +}; + +module.exports = config; + diff --git a/CAN-binder/low-can-demo/app/etc/_Config.js b/CAN-binder/low-can-demo/app/etc/_Config.js new file mode 100644 index 0000000..ce93d43 --- /dev/null +++ b/CAN-binder/low-can-demo/app/etc/_Config.js @@ -0,0 +1,44 @@ +/* + * Copyright 2014 Fulup Ar Foll + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var fs = require('fs'); + +function Config () { + 'use strict'; + var values=[]; + var extention='-l4a.js'; + var conf; + + // Configs file path last one supersead first one. + var files= [__dirname + "/AppDefaults.js", "/etc/default/noderc"+ extention, process.env.NODERC, process.env.HOME + "/.noderc"+ extention , __dirname +"/../../.noderc.js" ]; + + // Parse any existing files within config list & merge them + for (var idx in files) { + if (files[idx]) { + //console.log ("files=", files[idx]); + if (fs.existsSync (files[idx])) conf=require (files[idx]); + for (var i in conf) values[i] = conf[i]; + } + } + + // set path to search for node_module within parent directory + process.env.NODE_PATH= process.env.NODE_PATH + '../node_modules'; + + // console.log ("values=", values); + return values; +} + +module.exports = Config(); diff --git a/CAN-binder/low-can-demo/app/etc/_Trace.js b/CAN-binder/low-can-demo/app/etc/_Trace.js new file mode 100644 index 0000000..79ef4f5 --- /dev/null +++ b/CAN-binder/low-can-demo/app/etc/_Trace.js @@ -0,0 +1,55 @@ +/* + * Copyright 2014 Fulup Ar Foll + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +var util = require("util"); +var path = require("path"); +var config= require('./_Config'); + +function TracePoint () { + var saved = Error.prepareStackTrace; // save default prepareStack function + Error.prepareStackTrace = function(_, stack){ return stack; }; // overload err stack handling + Error.captureStackTrace(this, arguments.callee); // request a stack + this.trace = this.stack; // effectively build trace + Error.prepareStackTrace = saved; // restore original nodejs function +} + +// ------- Public Methods -------------- +var dbgLevel = function(target, level, format) { //+ arguments + // try to get debugLevel from calling object or global config + if (target && target.dbgLevel) dbgLevel = target.dbgLevel; + else dbgLevel = config.DBG_LVL || 1; + + if (dbgLevel >= level ) { + + var args = [].slice.call(arguments, 2); // copy argument in a real array leaving out level + var message = util.format.apply(null, args); + + var trace = new TracePoint().trace; + var info = { + fullpath : trace[1].getFileName(), + linenum : trace[1].getLineNumber(), + basename : path.basename (trace[1].getFileName()) + }; + + if (dbgLevel >= 5) { + console.log("%s:%d", info.fullpath, info.linenum); + console.log("\t[%d] %j", dbgLevel, message); + } + else console.log("--%d-- [%s:%d] -- %j", dbgLevel, info.basename, info.linenum, message); + } +}; + +module.exports = dbgLevel; diff --git a/CAN-binder/low-can-demo/binding/CMakeLists.txt b/CAN-binder/low-can-demo/binding/CMakeLists.txt new file mode 100644 index 0000000..4078e2b --- /dev/null +++ b/CAN-binder/low-can-demo/binding/CMakeLists.txt @@ -0,0 +1,42 @@ +########################################################################### +# Copyright 2015, 2016, 2017 IoT.bzh +# +# author: Fulup Ar Foll <fulup@iot.bzh> +# contrib: Romain Forlot <romain.forlot@iot.bzh> +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +########################################################################### + +# Add target to project dependency list +PROJECT_TARGET_ADD(stat-binding) + + # Define project Targets + add_library(${TARGET_NAME} MODULE ${TARGET_NAME}.c) + + # Binder exposes a unique public entry point + SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES + PREFIX "" + LABELS "BINDING" + LINK_FLAGS ${BINDINGS_LINK_FLAG} + OUTPUT_NAME ${TARGET_NAME} + ) + + # Library dependencies (include updates automatically) + TARGET_LINK_LIBRARIES(${TARGET_NAME} + ${link_libraries}) + + # installation directory + INSTALL(TARGETS ${TARGET_NAME} + LIBRARY DESTINATION ${BINDINGS_INSTALL_DIR}) + + populate_widget() diff --git a/CAN-binder/low-can-demo/binding/export.map b/CAN-binder/low-can-demo/binding/export.map new file mode 100644 index 0000000..52c1b4a --- /dev/null +++ b/CAN-binder/low-can-demo/binding/export.map @@ -0,0 +1 @@ +{ global: afbBindingV1*; local: *; }; diff --git a/CAN-binder/low-can-demo/binding/stat-binding.c b/CAN-binder/low-can-demo/binding/stat-binding.c new file mode 100644 index 0000000..1e5b2db --- /dev/null +++ b/CAN-binder/low-can-demo/binding/stat-binding.c @@ -0,0 +1,272 @@ +/* + * Copyright (C) 2016 "IoT.bzh" + * Author José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _GNU_SOURCE +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <netdb.h> +#include <fcntl.h> +#include <math.h> +#include <sys/time.h> +#include <sys/types.h> +#include <sys/timerfd.h> + +#include <json-c/json.h> + +#include <systemd/sd-event.h> + +#include <afb/afb-binding.h> +#include <afb/afb-service-itf.h> + +/* + * the interface to afb-daemon + */ +const struct afb_binding_interface *afbitf; + +#define DEFAULT_PERIOD 1 /* 1 second */ + +struct event; + +const char *cpu_fields[]= { + "user", + "nice", + "system", + "idle", + "iowait", + "irq", + "softirq", + "steal", + "guest", + "guest_nice" +}; + +#define CPU_FIELD_COUNT (sizeof cpu_fields / sizeof *cpu_fields) + +struct status { + uint64_t cpu[CPU_FIELD_COUNT]; +}; + +static int fd_proc; +static int fd_timer; +static struct sd_event_source *source = NULL; + +static struct status older; +static struct status newer; +static struct status diff; +static struct afb_event event; + +/***************************************************************************************/ +/***************************************************************************************/ +/** **/ +/** **/ +/** SECTION: BINDING VERBS IMPLEMENTATION **/ +/** **/ +/** **/ +/***************************************************************************************/ +/***************************************************************************************/ + +static int read_status(int fd, struct status *s) +{ + int n; + ssize_t sz; + off_t off; + char buffer[8192]; + long long unsigned x[CPU_FIELD_COUNT]; + + off = lseek(fd, 0, SEEK_SET); + if (off == (off_t)-1) + return -1; + + sz = read(fd, buffer, sizeof buffer); + if (sz == -1) + return -1; + + n = sscanf(buffer, "cpu %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu %Lu", &x[0], &x[1], &x[2], &x[3], &x[4], &x[5], &x[6], &x[7], &x[8], &x[9]); + if (n != CPU_FIELD_COUNT) + return -1; + while(n) { + n--; + s->cpu[n] = x[n]; + } + return 0; +} + +static void stop() +{ + sd_event_source_unref(source); + afb_event_drop(event); + close(fd_timer); + close(fd_proc); + fd_timer = -1; + fd_proc = -1; + event.itf = NULL; + source = NULL; +} + +static int emit(sd_event_source *src, int fd, uint32_t revents, void *userdata) +{ + int f, rc, p; + struct json_object *obj; + uint64_t u, s, i; + + read(fd, &i, sizeof i); + + memcpy(&older, &newer, sizeof older); + rc = read_status(fd_proc, &newer); + for(f = 0; f < (int)CPU_FIELD_COUNT ; f++) + diff.cpu[f] = newer.cpu[f] - older.cpu[f]; + + u = 0; + s = 0; + i = 0; + u += diff.cpu[0]; // "user", + u += diff.cpu[1]; // "nice", + s += diff.cpu[2]; // "system", + i += diff.cpu[3]; // "idle", + i += diff.cpu[4]; // "iowait", + s += diff.cpu[5]; // "irq", + s += diff.cpu[6]; // "softirq", + i += diff.cpu[7]; // "steal", + u += diff.cpu[8]; // "guest", + u += diff.cpu[9]; // "guest_nice" + p = (int)(unsigned)((100 * (u + s)) / (u + s + i)); + + obj = json_object_new_int(p); + if (afb_event_push(event, obj) == 0) + stop(); + return 0; +} + +static int start() +{ + int fdp, fdt, rc; + struct itimerspec ts; + struct sd_event_source *src; + + fdp = open("/proc/stat", O_RDONLY|O_CLOEXEC); + if (fdp >= 0) { + rc = read_status(fdp, &newer); + if (rc >= 0) { + fdt = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC); + if (fdt >= 0) { + ts.it_interval.tv_sec = 1; + ts.it_value.tv_sec = 1; + ts.it_interval.tv_nsec = 0; + ts.it_value.tv_nsec = 0; + rc = timerfd_settime(fdt, 0, &ts, NULL); + if (rc >= 0) { + event = afb_daemon_make_event(afbitf->daemon, "stat"); + if (afb_event_is_valid(event)) { + rc = sd_event_add_io(afb_daemon_get_event_loop(afbitf->daemon), &src, fdt, EPOLLIN, emit, NULL); + if (rc >= 0) { + fd_proc = fdp; + fd_timer = fdt; + source = src; + return 0; + } + afb_event_drop(event); + } + } + close(fdt); + } + } + close(fdp); + } + return -1; +} + +static int ensure_started() +{ + return source == NULL ? start() : 0; +} + +/***************************************************************************************/ +/***************************************************************************************/ +/** **/ +/** **/ +/** SECTION: BINDING VERBS IMPLEMENTATION **/ +/** **/ +/** **/ +/***************************************************************************************/ +/***************************************************************************************/ + +/* + * subscribe to notification of stat + */ +static void subscribe(struct afb_req req) +{ + int rc; + + rc = ensure_started(); + if (rc < 0) { + afb_req_fail(req, "failed", "Can't start"); + } else if (afb_req_subscribe(req, event) != 0) { + afb_req_fail_f(req, "failed", "afb_req_subscribe returned an error: %m"); + } else { + afb_req_success(req, NULL, NULL); + } +} + +/* + * unsubscribe a previous subscription + * + * parameters of the unsubscription are: + * + * id: integer: the numeric identifier of the event as returned when subscribing + */ +static void unsubscribe(struct afb_req req) +{ + if (afb_event_is_valid(event)) + afb_req_unsubscribe(req, event); + afb_req_success(req, NULL, NULL); +} + +/* + * array of the verbs exported to afb-daemon + */ +static const struct afb_verb_desc_v1 binding_verbs[] = { + /* VERB'S NAME SESSION MANAGEMENT FUNCTION TO CALL SHORT DESCRIPTION */ + { .name= "subscribe", .session= AFB_SESSION_NONE, .callback= subscribe, .info= "subscribe to notification of statistics" }, + { .name= "unsubscribe", .session= AFB_SESSION_NONE, .callback= unsubscribe, .info= "unsubscribe a previous subscription" }, + { .name= NULL } /* marker for end of the array */ +}; + +/* + * description of the binding for afb-daemon + */ +static const struct afb_binding binding_description = +{ + /* description conforms to VERSION 1 */ + .type= AFB_BINDING_VERSION_1, + .v1= { /* fills the v1 field of the union when AFB_BINDING_VERSION_1 */ + .prefix= "stat", /* the API name (or binding name or prefix) */ + .info= "Get system statistics", /* short description of of the binding */ + .verbs = binding_verbs /* the array describing the verbs of the API */ + } +}; + +/* + * activation function for registering the binding called by afb-daemon + */ +const struct afb_binding *afbBindingV1Register(const struct afb_binding_interface *itf) +{ + afbitf = itf; /* records the interface for accessing afb-daemon */ + return &binding_description; /* returns the description of the binding */ +} + diff --git a/CAN-binder/low-can-demo/bower.json b/CAN-binder/low-can-demo/bower.json new file mode 100644 index 0000000..f3f2789 --- /dev/null +++ b/CAN-binder/low-can-demo/bower.json @@ -0,0 +1,19 @@ +{ + "name": "low-can-demo", + "version": "0.0.1", + "authors": "", + "private": true, + "dependencies": { + "bootstrap-sass": "~3", + "leaflet": "~1.0.0", + "steelseries": "https://github.com/iotbzh/SteelSeries-Canvas.git" + }, + "overrides": { + "steelseries": { + "main": [ + "tween.js", + "steelseries.js" + ] + } + } +} diff --git a/CAN-binder/low-can-demo/config.xml.in b/CAN-binder/low-can-demo/config.xml.in new file mode 100644 index 0000000..f3ff5c9 --- /dev/null +++ b/CAN-binder/low-can-demo/config.xml.in @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8"?> +<widget xmlns="http://www.w3.org/ns/widgets" id="@@APPNAME@@" version="@@APPVER@@"> + <name>App Framework - @@APPNAME@@</name> + <icon src="icon.png"/> + <content src="@@CONTENT@@" type="application/vnd.agl.html.hybrid"/> + <description>This is a demo using OpenXC trace</description> + <author>Jose Bollo <jobol@iot.bzh> / Stephane Desneux <sdx@iot.bzh></author> + <license>APL 2.0</license> +</widget> + + diff --git a/CAN-binder/low-can-demo/credits.md b/CAN-binder/low-can-demo/credits.md new file mode 100644 index 0000000..8f54fd5 --- /dev/null +++ b/CAN-binder/low-can-demo/credits.md @@ -0,0 +1,7 @@ +Credits +======= + +The data are coming from [OpenXC](http://openxcplatform.com/): [traces for developers](http://openxcplatform.com/resources/traces.html) + +The car is coming from [clipart.me](http://clipart.me): [Car Top View Vector Free](http://clipart.me/transportation/car-top-view-vector-free-26970) + diff --git a/CAN-binder/low-can-demo/gulpfile.js b/CAN-binder/low-can-demo/gulpfile.js new file mode 100644 index 0000000..50dff81 --- /dev/null +++ b/CAN-binder/low-can-demo/gulpfile.js @@ -0,0 +1,484 @@ +// BUG Symlink not working + +var gulp = require('gulp'); +var debug = require('gulp-debug'); +var plugins = require('gulp-load-plugins')(); +var del = require('del'); +var es = require('event-stream'); +var bowerFiles = require('main-bower-files'); +var print = require('gulp-print'); +var Q = require('q'); +var imagemin = require('gulp-imagemin'), pngquant = require('imagemin-pngquant'); +var taskListing = require('gulp-task-listing'); +var symlink = require('gulp-sym'); +var rename = require("gulp-rename"); +var exec = require('child_process').exec +var argv = require('yargs').argv; + +// == PATH STRINGS ======== +var appdir = "./app/"; // Warning to not forget trailling '/' +config=require (appdir + "etc/_Config"); // upload user local preferences if any + +var frontend= appdir + config.FRONTEND; + +var paths = { + application : frontend, + scripts : frontend+'/**/*.js', + appStyles : [frontend+'/**/*.scss', '!'+frontend+'/styles/*.scss'], + globalStyles: [frontend+'/styles/*.scss'], + images : [ + frontend+'/**/*.png', + frontend+'/**/*.jpg', + frontend+'/**/*.jpeg', + frontend+'/**/*.svg', + frontend+'/**/*.ttf', + 'bower_components/leaflet/dist/images/*.png' + ], + index : frontend+'/index.html', + partials : [frontend + '/**/*.html', '!' + frontend +'/index.html'], + distDev : './dist.dev', + distProd : './dist.prod', + sass: [ + frontend+'/styles', + 'bower_components/bootstrap-sass/assets/stylesheets' + ], + fonts: ['bower_components/**/*.woff'], + favicon: frontend+'/images/favicon.ico', + wgtconfig: 'config.xml' +}; + +// add bower files to global styles +bowerFiles('**/*.css').forEach(function(p) { + paths.globalStyles.unshift(p); +}); + +paths['distAppDev'] = paths.distDev + config.URLBASE; +paths['distAppProd'] = paths.distProd + config.URLBASE; + +// Run node in debug mode in developpement mode ? +var nodeopts = config.DEBUG !== undefined ? '--debug='+config.DEBUG : ''; + +// == PIPE SEGMENTS ======== +var pipes = {}; + +pipes.orderedVendorScripts = function() { + return plugins.order(['jquery.js', 'bootstrap.js','leaflet-src.js','tween.js','steelseries.js']); +}; + +pipes.minifiedFileName = function() { + return plugins.rename(function (path) { + path.extname = '.min' + path.extname; + }); +}; + +pipes.validatedAppScripts = function() { + return gulp.src(paths.scripts) + .pipe(plugins.replace('@@APPNAME@@', config.APPNAME)) + .pipe(plugins.replace('@@APPVER@@', config.APPVER)) + .pipe(plugins.jshint()) + .pipe(plugins.jshint.reporter('jshint-stylish')); +}; + +pipes.builtAppScriptsDev = function() { + return pipes.validatedAppScripts() + .pipe(gulp.dest(paths.distAppDev)); +}; + +pipes.builtAppScriptsProd = function() { + var scriptedPartials = pipes.scriptedPartials(); + var validatedAppScripts = pipes.validatedAppScripts(); + return es.merge(scriptedPartials, validatedAppScripts) + .pipe(plugins.sourcemaps.init()) + .pipe(plugins.concat(config.APPNAME+'.min.js')) + .pipe(plugins.uglify({compress: {drop_console: true}})) + .pipe(plugins.sourcemaps.write()) + .pipe(gulp.dest(paths.distAppProd+'/js')); +}; + +pipes.builtVendorScriptsDev = function() { + return gulp.src(bowerFiles('**/*.js')) + .pipe(gulp.dest( paths.distDev +'/bower_components')); +}; + +pipes.builtVendorScriptsProd = function() { + return gulp.src(bowerFiles('**/*.js')) + .pipe(pipes.orderedVendorScripts()) + .pipe(plugins.concat('vendor.min.js')) + .pipe(plugins.uglify()) + .pipe(gulp.dest(paths.distProd+ '/bower_components')); +}; + + +pipes.validatedPartials = function() { + return gulp.src(paths.partials) + .pipe(plugins.htmlhint({'doctype-first': false})) + .pipe(plugins.htmlhint.reporter()); +}; + +pipes.builtPartialsDev = function() { + return pipes.validatedPartials() + .pipe(gulp.dest(paths.distAppDev)); +}; + +pipes.scriptedPartials = function() { + return pipes.validatedPartials() + .pipe(plugins.htmlhint.failReporter()) + .pipe(plugins.htmlmin({collapseWhitespace: true, removeComments: true})); +}; + +pipes.builtAppStylesDev = function() { + return gulp.src(paths.appStyles) + .pipe(plugins.sass({includePaths: paths.sass})) + .pipe(gulp.dest(paths.distAppDev + '/styles')); +}; + +pipes.builtglobalStylesDev = function() { + return gulp.src(paths.globalStyles) + .pipe(plugins.sass({includePaths: paths.sass})) + .pipe(gulp.dest(paths.distDev + '/global_styles')); +}; + +pipes.builtAppStylesProd = function() { + return gulp.src(paths.appStyles) + .pipe(plugins.sourcemaps.init()) + .pipe(plugins.sass({includePaths: paths.sass})) + // .pipe(debug({title: '***** appStyle:'})) + .pipe(plugins.cleanCss()) + .pipe(plugins.concat(config.APPNAME+'.css')) + .pipe(plugins.sourcemaps.write()) + .pipe(pipes.minifiedFileName()) + .pipe(gulp.dest(paths.distAppProd)); +}; + +pipes.builtglobalStylesProd = function() { + return gulp.src(paths.globalStyles) + .pipe(plugins.sourcemaps.init()) + .pipe(plugins.sass({includePaths: paths.sass})) + .pipe(plugins.cleanCss()) + .pipe(plugins.sourcemaps.write()) + .pipe(pipes.minifiedFileName()) + .pipe(rename(function (path) {path.dirname="";return path;})) + .pipe(plugins.concat('output.min.css')) + .pipe(gulp.dest(paths.distProd + '/global_styles')); +}; + +pipes.processedFontsDev = function() { + return gulp.src(paths.fonts) + .pipe(rename(function (path) {path.dirname="";return path;})) + .pipe(gulp.dest(paths.distDev+'/bower_components')); +}; + +pipes.processedFontsProd = function() { + return gulp.src(paths.fonts) + .pipe(rename(function (path) {path.dirname="";return path;})) + .pipe(gulp.dest(paths.distProd+'/bower_components')); +}; + + +pipes.processedImagesDev = function() { + return gulp.src(paths.images) + .pipe(rename(function(path) { path.dirname=""; return path; })) + .pipe(gulp.dest(paths.distAppDev+"/images/")); +}; + +pipes.processedFaviconDev = function() { + return gulp.src(paths.favicon) + .pipe(gulp.dest(paths.distDev)); +}; + +pipes.processedImagesProd = function() { + return gulp.src(paths.images) + .pipe(rename(function(path) { path.dirname=""; return path; })) + .pipe(imagemin({ + progressive: true, + svgoPlugins: [{removeViewBox: false}], + use: [pngquant()] + })) + .pipe(gulp.dest(paths.distAppProd+"/images/")); +}; + +pipes.processedFaviconProd = function() { + return gulp.src(paths.favicon) + .pipe(gulp.dest(paths.distProd)); +}; + +// Create an Symlink when config.URLBASE exist +pipes.createDevSymLink = function() { + return gulp.src(paths.distDev).pipe(symlink(paths.distDev+config.URLBASE, {force: true})); +}; + +pipes.createProdSymLink = function() { + return gulp.src(paths.distProd).pipe(symlink(paths.distDev+config.URLBASE,{force: true})); +}; + +pipes.validatedIndex = function() { + return gulp.src(paths.index) + .pipe(plugins.replace('@@APPNAME@@', config.APPNAME)) + .pipe(plugins.replace('@@APPVER@@', config.APPVER)) + .pipe(plugins.replace('@@URLBASE@@', config.URLBASE)) + .pipe(plugins.htmlhint()) + .pipe(plugins.htmlhint.reporter()); +}; + +pipes.builtIndexDev = function() { + + var orderedVendorScripts = pipes.builtVendorScriptsDev() + .pipe(pipes.orderedVendorScripts()); + + var orderedAppScripts = pipes.builtAppScriptsDev(); + + var appStyles = pipes.builtAppStylesDev(); + var globalStyles = pipes.builtglobalStylesDev(); + + return pipes.validatedIndex() + // Vendor and Global should have absolute path to rootdir application one are relative to BaseURL + .pipe(plugins.inject(orderedVendorScripts, {relative: false, ignorePath: "/dist.dev", name: 'bower'})) + .pipe(plugins.inject(globalStyles, {relative: false, ignorePath: "/dist.dev", name:'vendor'})) + .pipe(gulp.dest(paths.distAppDev)) // write first to get relative path for inject + .pipe(plugins.inject(orderedAppScripts, {relative: true})) + .pipe(plugins.inject(appStyles, {relative: true, name: 'appli'})) + .pipe(gulp.dest(paths.distAppDev)); +}; + +pipes.builtIndexProd = function() { + + var vendorScripts= pipes.builtVendorScriptsProd(); + var appScripts = pipes.builtAppScriptsProd(); + var appStyles = pipes.builtAppStylesProd(); + var globalStyles = pipes.builtglobalStylesProd(); + + return pipes.validatedIndex() + // Vendor and Global should have absolute path to rootdir application one are relative to BaseURL + .pipe(plugins.inject(vendorScripts, {relative: false, ignorePath: "/dist.prod", name: 'bower'})) + .pipe(plugins.inject(globalStyles, {relative: false, ignorePath: "/dist.prod", name:'vendor'})) + .pipe(gulp.dest(paths.distAppProd)) // write first to get relative path for inject + .pipe(plugins.inject(appScripts, {relative: true})) + .pipe(plugins.inject(appStyles, {relative: true, name:'appli'})) + .pipe(plugins.htmlmin({collapseWhitespace: true, removeComments: true})) + .pipe(gulp.dest(paths.distAppProd)); +}; + +pipes.builtAppDev = function() { + return es.merge(pipes.builtIndexDev(), pipes.builtPartialsDev(), pipes.processedFaviconDev(), pipes.processedImagesDev(), pipes.processedFontsDev() ) + .pipe(pipes.doRsync("Dev")); +}; + +pipes.builtAppProd = function() { + return es.merge(pipes.builtIndexProd(), pipes.processedFaviconProd(), pipes.processedImagesProd(), pipes.processedFontsProd()) + .pipe(pipes.doRsync("Prod")); +}; + +pipes.widgetConfig = function(type) { + var dst=paths["dist"+type]; + var content="."+config.URLBASE+"/index.html"; + content=content.replace(/\/+/g,"/"); + return gulp.src(paths.wgtconfig+".in") + .pipe(plugins.replace('@@APPNAME@@', config.APPNAME)) + .pipe(plugins.replace('@@APPVER@@', config.APPVER)) + .pipe(plugins.replace('@@CONTENT@@', content)) + .pipe(plugins.rename("config.xml")) + .pipe(gulp.dest(dst)) +}; + +pipes.widgetPack = function(type,cb) { + var dst=paths["dist"+type]; + var wgtfile=config.APPNAME+"_"+type+".wgt" + + exec( + "wgtpkg-pack -f -o "+wgtfile+" "+dst, + function(err,stdout,stderr) { + console.log(stdout); + console.log(stderr); + cb(err); + }); +}; + +pipes.doRsync=function(type) { + var dst=paths["dist"+type]; + if (!argv.host) return plugins.empty(); + + return plugins.rsync({ + root: dst+"/", + hostname: argv.host, + username: "root", + destination: "/usr/share/afm/applications/"+config.APPNAME+"/"+config.APPVER+"/htdocs/", + archive: true, + compress: true, + recursive: true + }); +} + +// == TASKS ======== + +// Add a task to render the output +gulp.task('help', taskListing.withFilters(/-/)); + +// clean, build of production environement +gulp.task('build', ['clean-build-app-prod']); + +// removes all compiled dev files +gulp.task('clean-dev', function() { + var deferred = Q.defer(); + del(paths.distDev, function() { + deferred.resolve(); + }); + return deferred.promise; +}); + +// removes all compiled production files +gulp.task('clean-prod', function() { + var deferred = Q.defer(); + del(paths.distProd, function() { + deferred.resolve(); + }); + return deferred.promise; +}); + +// checks html source files for syntax errors +gulp.task('validate-partials', pipes.validatedPartials); + +// checks index.html for syntax errors +gulp.task('validate-index', pipes.validatedIndex); + +// moves html source files into the dev environment +gulp.task('build-partials-dev', pipes.builtPartialsDev); + +// converts partials to javascript using html2js +gulp.task('convert-partials-to-js', pipes.scriptedPartials); + +// runs jshint on the app scripts +gulp.task('validate-app-scripts', pipes.validatedAppScripts); + +// moves app scripts into the dev environment +gulp.task('build-app-scripts-dev', pipes.builtAppScriptsDev); + +// concatenates, uglifies, and moves app scripts and partials into the prod environment +gulp.task('build-app-scripts-prod', pipes.builtAppScriptsProd); + +// compiles app sass and moves to the dev environment +gulp.task('build-app-styles-dev', pipes.builtAppStylesDev); + +// compiles and minifies app sass to css and moves to the prod environment +gulp.task('build-app-styles-prod', pipes.builtAppStylesProd); + +// moves vendor scripts into the dev environment +gulp.task('build-vendor-scripts-dev', pipes.builtVendorScriptsDev); + +// concatenates, uglifies, and moves vendor scripts into the prod environment +gulp.task('build-vendor-scripts-prod', pipes.builtVendorScriptsProd); + +// validates and injects sources into index.html and moves it to the dev environment +gulp.task('build-index-dev', pipes.builtIndexDev); + +// validates and injects sources into index.html, minifies and moves it to the dev environment +gulp.task('build-index-prod', pipes.builtIndexProd); + +// builds a complete dev environment +gulp.task('build-app-dev', pipes.builtAppDev); + +// builds a complete prod environment +gulp.task('build-app-prod', pipes.builtAppProd); + +// cleans and builds a complete dev environment +gulp.task('clean-build-app-dev', ['clean-dev'], pipes.builtAppDev); + +// cleans and builds a complete prod environment +gulp.task('clean-build-app-prod', ['clean-prod'], pipes.builtAppProd); + +// clean, build, and watch live changes to the dev environment +gulp.task('watch-dev', ['clean-build-app-dev'], function() { + + // watch index + gulp.watch(paths.index, function() { + return pipes.builtIndexDev() + .pipe(pipes.doRsync("Dev")) + .pipe(plugins.livereload()); + }); + + // watch app scripts + gulp.watch(paths.scripts, function() { + return pipes.builtAppScriptsDev() + .pipe(pipes.doRsync("Dev")) + .pipe(plugins.livereload()); + }); + + // watch html partials + gulp.watch(paths.partials, function() { + return pipes.builtPartialsDev() + .pipe(pipes.doRsync("Dev")) + .pipe(plugins.livereload()); + }); + + // watch Images + gulp.watch(paths.images, function() { + return pipes.processedImagesDev() + .pipe(pipes.doRsync("Dev")) + .pipe(plugins.livereload()); + }); + + // watch styles + gulp.watch(paths.appStyles, function() { + return pipes.builtAppStylesDev() + .pipe(pipes.doRsync("Dev")) + .pipe(plugins.livereload()); + }); + gulp.watch(paths.globalStyles, function() { + return pipes.builtglobalStylesDev() + .pipe(pipes.doRsync("Dev")) + .pipe(plugins.livereload()); + }); + +}); + +// clean, build, and watch live changes to the prod environment +gulp.task('watch-prod', ['clean-build-app-prod'], function() { + + // watch index + gulp.watch(paths.index, function() { + return pipes.builtIndexProd() + .pipe(pipes.doRsync("Prod")) + .pipe(plugins.livereload()); + }); + + // watch app scripts + gulp.watch(paths.scripts, function() { + return pipes.builtAppScriptsProd() + .pipe(pipes.doRsync("Prod")) + .pipe(plugins.livereload()); + }); + + // watch hhtml partials + gulp.watch(paths.partials, function() { + return pipes.builtAppScriptsProd() + .pipe(pipes.doRsync("Prod")) + .pipe(plugins.livereload()); + }); + + // watch Images + gulp.watch(paths.images, function() { + return pipes.processedImagesProd() + .pipe(pipes.doRsync("Prod")) + .pipe(plugins.livereload()); + }); + + // watch styles + gulp.watch(paths.appStyles, function() { + return pipes.builtAppStylesProd() + .pipe(pipes.doRsync("Prod")) + .pipe(plugins.livereload()); + }); + gulp.watch(paths.globalStyles, function() { + return pipes.builtglobalStylesProd() + .pipe(pipes.doRsync("Prod")) + .pipe(plugins.livereload()); + }); + +}); + +gulp.task('widget-config-dev', ['build-app-dev'], function() { return pipes.widgetConfig("Dev"); }); +gulp.task('widget-config-prod', ['build-app-prod'], function() { return pipes.widgetConfig("Prod"); }); +gulp.task('widget-dev', ['widget-config-dev'], function(cb) { return pipes.widgetPack("Dev",cb); }); +gulp.task('widget-prod', ['widget-config-prod'], function(cb) { return pipes.widgetPack("Prod",cb); }); + +// default task builds for prod +gulp.task('default', ['widget-prod']); diff --git a/CAN-binder/low-can-demo/icon_hybrid_html5_128.png b/CAN-binder/low-can-demo/icon_hybrid_html5_128.png Binary files differnew file mode 100644 index 0000000..bf39b23 --- /dev/null +++ b/CAN-binder/low-can-demo/icon_hybrid_html5_128.png diff --git a/CAN-binder/low-can-demo/package.json b/CAN-binder/low-can-demo/package.json new file mode 100644 index 0000000..8786473 --- /dev/null +++ b/CAN-binder/low-can-demo/package.json @@ -0,0 +1,60 @@ +{ + "name": "low-can-demo", + "private": true, + "version": "0.0.1", + "repository": { + "type": "git", + "url": "https://github.com/iotbzh/app-framework-templates" + }, + "scripts": { + "postinstall": "bower install", + "build": "./node_modules/.bin/gulp clean-build-app-dev", + "start": "node node_modules/.bin/gulp watch-dev" + }, + "devDependencies": { + "body-parser": "^1.5.2", + "bower": "^1.3.1", + "cookie-parser": "^1.4.0", + "del": "^1.1.1", + "event-stream": "^3.2.2", + "express": "^4.7.2", + "express-session": "^1.12.1", + "gulp": "^3.9.0", + "gulp-debug": "^2.1.2", + "gulp-concat": "^2.4.3", + "gulp-empty": "^0.1.1", + "gulp-htmlhint": "0.0.9", + "gulp-htmlmin": "^1.0.0", + "gulp-imagemin": "*", + "gulp-inject": "^1.1.1", + "gulp-jshint": "^1.9.2", + "gulp-livereload": "^3.7.0", + "gulp-load-plugins": "^0.8.0", + "gulp-clean-css": "^2.0.11", + "gulp-nodemon": "^2.0.0", + "gulp-order": "^1.1.1", + "gulp-print": "^1.1.0", + "gulp-rename": "^1.2.0", + "gulp-replace": "^0.5.4", + "gulp-rsync": "^0.0.6", + "gulp-sass": "^2.0.3", + "gulp-sourcemaps": "^1.3.0", + "gulp-task-listing": "^1.0.1", + "gulp-uglify": "^1.2.0", + "imagemin-pngquant": "*", + "jshint-stylish": "^1.0.0", + "karma": "^0.10", + "karma-junit-reporter": "^0.2.2", + "main-bower-files": "^2.5.0", + "method-override": "^2.1.2", + "protractor": "^1.1.1", + "q": "^1.1.2", + "shelljs": "^0.2.6", + "traceback": "^0.3.1", + "gulp-sym": "0.0.14", + "yargs":"5.0.0" + }, + "dependencies": { + "multer": "^1.1.0" + } +} |