app.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. "use strict";
  2. /**
  3. * Constants for application
  4. *
  5. * manifestList is the url that contains all possible manifests
  6. * pollTime is used to check for changes in the serial ports
  7. *
  8. * @type {{manifestList: string, pollTime: number}}
  9. */
  10. const CONSTANTS = {
  11. manifestList: "http://flasher.thingssdk.com/v1/manifest-list.json",
  12. pollTime: 1000
  13. };
  14. var last_notification = "";
  15. /************************
  16. * Backend dependencies.
  17. * Note: Paths are relative to index.html not app.js
  18. ************************/
  19. const SerialScanner = require("../back-end/serial_scanner");
  20. const PortSelect = require("./js/port_select");
  21. const prepareBinaries = require("../back-end/prepare_binaries");
  22. const log = require("../back-end/logger");
  23. const RomComm = require("../back-end/rom_comm");
  24. const serialScanner = new SerialScanner();
  25. /************************
  26. * UI Elements
  27. ************************/
  28. const flashButton = $("flash-button");
  29. const appStatus = $("status");
  30. const portsSelect = new PortSelect($("ports"));
  31. const manifestsSelect = $("manifests");
  32. /************************
  33. * Utility Functions
  34. ************************/
  35. /**
  36. * Simple helper returns HTML element from an element's id
  37. *
  38. * @param id a string of the id of an HTML element
  39. * @returns {Element}
  40. */
  41. function $(id) { return document.getElementById(id); }
  42. /**
  43. * Processes the response from an HTTP fetch and returns the JSON promise.
  44. *
  45. * @param response from a fetch call
  46. * @returns {Promise}
  47. */
  48. function processJSON(response) {
  49. return response.json();
  50. }
  51. /************************
  52. * Handle UI
  53. ************************/
  54. flashButton.addEventListener("click", (event) => {
  55. disableInputs();
  56. fetch(manifestsSelect.value)
  57. .then(processJSON)
  58. .then(flashWithManifest);
  59. });
  60. /************************
  61. * Manage serial port events
  62. ************************/
  63. serialScanner.on("ports", (ports) => {
  64. portsSelect.addAll(ports);
  65. readyToFlash();
  66. });
  67. serialScanner.on("deviceAdded", (port) => {
  68. portsSelect.add(port);
  69. new Notification(`Added: ${port}!`);
  70. });
  71. serialScanner.on("deviceRemoved", (port) => {
  72. portsSelect.remove(port);
  73. new Notification(`Removed: ${port}!`);
  74. });
  75. serialScanner.on("error", onError);
  76. /**
  77. * Updates UI to say it's ready
  78. */
  79. function readyToFlash() {
  80. appStatus.textContent = "Ready";
  81. enableInputs();
  82. }
  83. /**
  84. * Enabled the serial port SELECT and flash BUTTON elements.
  85. */
  86. function enableInputs() {
  87. portsSelect.disabled = false;
  88. manifestsSelect.disabled = false;
  89. flashButton.disabled = false;
  90. }
  91. function disableInputs() {
  92. portsSelect.disabled = true;
  93. manifestsSelect.disabled = true;
  94. flashButton.disabled = true;
  95. }
  96. /**
  97. * Generic catch all error. Shows notification at the moment.
  98. * @param error
  99. */
  100. function onError(error){
  101. if(last_notification !== error.message) {
  102. last_notification = error.message;
  103. new Notification(last_notification);
  104. }
  105. appStatus.textContent = error.message;
  106. }
  107. function generateManifestList(manifestsJSON) {
  108. manifestsJSON.options.forEach((option) => {
  109. option.versions.forEach((version) => {
  110. const optionElement = document.createElement("option");
  111. optionElement.textContent = `${option.name} - ${version.version}`;
  112. optionElement.value = version.manifest;
  113. manifestsSelect.appendChild(optionElement);
  114. manifestsSelect.disabled = false;
  115. });
  116. });
  117. }
  118. function getManifests() {
  119. appStatus.textContent = "Getting latest manifests.";
  120. fetch(CONSTANTS.manifestList)
  121. .then(processJSON)
  122. .then(generateManifestList).catch(error => {
  123. setTimeout(getManifests, pollTime);
  124. });
  125. }
  126. function flashWithManifest(manifest) {
  127. appStatus.textContent = `Flashing ${portsSelect.value}`;
  128. prepareBinaries(manifest, (err, flashSpec) => {
  129. if(err) throw err;
  130. const esp = new RomComm({
  131. portName: portsSelect.value,
  132. baudRate: 115200,
  133. progress: progressHandler
  134. });
  135. esp.open().then((result) => {
  136. appStatus.textContent = `Flashing ${portsSelect.value}...Openned Port.`; let promise = Promise.resolve();
  137. flashSpec.forEach(createProgressBars);
  138. flashSpec.forEach((spec, index) => {
  139. promise = promise.then(()=> {
  140. appStatus.textContent = `Flashing ${index+1}/${flashSpec.length} binaries.`;
  141. return esp.flashAddress(Number.parseInt(spec.address), spec.buffer)
  142. });
  143. });
  144. return promise.then(() => esp.close())
  145. .then((result) => {
  146. new Notification("Flash Finished!");
  147. readyToFlash();
  148. log.info("Flashed to latest Espruino build!", result);
  149. });
  150. }).catch((error) => {
  151. log.error("Oh noes!", error);
  152. });
  153. });
  154. }
  155. function createProgressBars(spec) {
  156. }
  157. function progressHandler(spec) {
  158. }
  159. /**
  160. * Get's manifest list for possibilities for flashing,
  161. * scans serial ports and sets up timer for checking for changes.
  162. */
  163. function start() {
  164. getManifests();
  165. serialScanner.scan();
  166. setInterval(serialScanner.checkForChanges.bind(serialScanner), CONSTANTS.pollTime);
  167. }
  168. /**
  169. * Start Application
  170. */
  171. start();