Desarrollo de la versión web del asistente de puerto serie
Demo: https://serial.wiki-power.com/
Repositorio del proyecto: linyuxuanlin/Serial_on_Web
Este proyecto se basa en web-serial-terminal y agrega la funcionalidad de imprimir registros y exportarlos utilizando debugout.js. A continuación se detallan los pasos:
Agregar el código debug.js
// guardar todos los console.logs
function debugout() {
var self = this;
// OPCIONES
self.realTimeLoggingOn = true; // registrar en tiempo real (se envía a console.log)
self.useTimestamps = false; // insertar una marca de tiempo al inicio de cada registro
self.useLocalStorage = false; // almacenar la salida utilizando window.localStorage() y agregar continuamente al mismo registro en cada sesión
self.recordLogs = true; // establecer en false una vez que haya terminado de depurar para evitar que el registro consuma memoria
self.autoTrim = true; // para evitar que el registro consuma memoria potencialmente infinita
self.maxLines = 2500; // si autoTrim es true, se guardan estas líneas más recientes
self.tailNumLines = 100; // cuántas líneas recuperará tail()
self.logFilename = "log.txt"; // nombre de archivo del registro descargado con downloadLog()
self.maxDepth = 25; // profundidad máxima de recursión para objetos registrados
// variables
self.depth = 0;
self.parentSizes = [0];
self.currentResult = "";
self.startTime = new Date();
self.output = "";
this.version = function () {
return "0.5.0";
};
/* MÉTODOS DEL USUARIO / this.getLog = function () { var retrievalTime = new Date(); // si la grabación está desactivada, para que el desarrollador sepa por qué no tiene ningún registro if (!self.recordLogs) { self.log("[debugout.js] la grabación de registros está desactivada."); } // si se utiliza el almacenamiento local, obtener los valores if (self.useLocalStorage) { var saved = window.localStorage.getItem("debugout.js"); if (saved) { saved = JSON.parse(saved); self.startTime = new Date(saved.startTime); self.output = saved.log; retrievalTime = new Date(saved.lastLog); } } return ( self.output + "\n---- Registro recuperado: " + retrievalTime + " ----\n" + self.formatSessionDuration(self.startTime, retrievalTime) ); }; // acepta un número opcional o utiliza el valor predeterminado para el número de líneas this.tail = function (numLines) { var numLines = numLines || self.tailLines; return self.trimLog(self.getLog(), numLines); }; // acepta una cadena para buscar this.search = function (string) { var lines = self.output.split("\n"); var rgx = new RegExp(string); var matched = []; // no se puede utilizar Array.prototype.filter() aquí // porque necesitamos agregar el número de línea for (var i = 0; i < lines.length; i++) { var addr = "[" + i + "] "; if (lines[i].match(rgx)) { matched.push(addr + lines[i]); } } var result = matched.join("\n"); if (result.length == 0) result = 'No se encontró nada para "' + string + '".'; return result; }; // acepta la línea de inicio y cuántas líneas después de la línea de inicio deseas this.getSlice = function (lineNumber, numLines) { var lines = self.output.split("\n"); var segment = lines.slice(lineNumber, lineNumber + numLines); return segment.join("\n"); }; // descarga inmediatamente el registro - para uso en el navegador de escritorio this.downloadLog = function () { var file = "data:text/plain;charset=utf-8,"; var logFile = self.getLog(); var encoded = encodeURIComponent(logFile); file += encoded; var a = document.createElement("a"); a.href = file; a.target = "_blank"; a.download = self.logFilename; document.body.appendChild(a); a.click(); a.remove(); }; // borra el registro this.clear = function () { var clearTime = new Date(); self.output = "---- Registro borrado: " + clearTime + " ----\n"; if (self.useLocalStorage) { // almacenamiento local var saveObject = { startTime: self.startTime, log: self.output, lastLog: clearTime, }; saveObject = JSON.stringify(saveObject); window.localStorage.setItem("debugout.js", saveObject); } if (self.realTimeLoggingOn) console.log("[debugout.js] clear()"); }; // registra un registro this.log = function (obj) { // registrar en tiempo real if (self.realTimeLoggingOn) console.log(obj); // registrar el registro var type = self.determineType(obj); if (type != null && self.recordLogs) { var addition = self.formatType(type, obj); // marca de tiempo, formateada para mayor brevedad if (self.useTimestamps) { var logTime = new Date(); self.output += self.formatTimestamp(logTime); } self.output += addition; if (self.autoTrim) self.output = self.trimLog(self.output, self.maxLines); // almacenamiento local if (self.useLocalStorage) { var last = new Date(); var saveObject = { startTime: self.startTime, log: self.output, lastLog: last, }; saveObject = JSON.stringify(saveObject); window.localStorage.setItem("debugout.js", saveObject); } } self.depth = 0; self.parentSizes = [0]; self.currentResult = ""; }; / MÉTODOS PARA CONSTRUIR EL REGISTRO */
// como typeof pero clasifica objetos de tipo 'object'
// se mantiene separado de formatType() para que puedas usarlo a tu conveniencia!
this.determineType = function (object) {
if (object != null) {
var typeResult;
var type = typeof object;
if (type == "object") {
var len = object.length;
if (len == null) {
if (typeof object.getTime == "function") {
typeResult = "Fecha";
} else if (typeof object.test == "function") {
typeResult = "Expresión regular";
} else {
typeResult = "Objeto";
}
} else {
typeResult = "Arreglo";
}
} else {
typeResult = type;
}
return typeResult;
} else {
return null;
}
};
// formatea el tipo correspondientemente, recursivamente si es necesario
this.formatType = function (type, obj) {
if (self.maxDepth && self.depth >= self.maxDepth) {
return "... (se alcanzó la máxima profundidad)";
}
switch (type) {
case "Object":
self.currentResult += "{\n";
self.depth++;
self.parentSizes.push(self.objectSize(obj));
var i = 0;
for (var prop in obj) {
self.currentResult += self.indentsForDepth(self.depth);
self.currentResult += prop + ": ";
var subtype = self.determineType(obj[prop]);
var subresult = self.formatType(subtype, obj[prop]);
if (subresult) {
self.currentResult += subresult;
if (i != self.parentSizes[self.depth] - 1)
self.currentResult += ",";
self.currentResult += "\n";
} else {
if (i != self.parentSizes[self.depth] - 1)
self.currentResult += ",";
self.currentResult += "\n";
}
i++;
}
self.depth--;
self.parentSizes.pop();
self.currentResult += self.indentsForDepth(self.depth);
self.currentResult += "}";
if (self.depth == 0) return self.currentResult;
break;
case "Array":
self.currentResult += "[";
self.depth++;
self.parentSizes.push(obj.length);
for (var i = 0; i < obj.length; i++) {
var subtype = self.determineType(obj[i]);
if (subtype == "Object" || subtype == "Array")
self.currentResult += "\n" + self.indentsForDepth(self.depth);
var subresult = self.formatType(subtype, obj[i]);
if (subresult) {
self.currentResult += subresult;
if (i != self.parentSizes[self.depth] - 1)
self.currentResult += ", ";
if (subtype == "Array") self.currentResult += "\n";
} else {
if (i != self.parentSizes[self.depth] - 1)
self.currentResult += ", ";
if (subtype != "Object") self.currentResult += "\n";
else if (i == self.parentSizes[self.depth] - 1)
self.currentResult += "\n";
}
}
self.depth--;
self.parentSizes.pop();
self.currentResult += "]";
if (self.depth == 0) return self.currentResult;
break;
case "function":
obj += "";
var lines = obj.split("\n");
for (var i = 0; i < lines.length; i++) {
if (lines[i].match(/\}/)) self.depth--;
self.currentResult += self.indentsForDepth(self.depth);
if (lines[i].match(/\{/)) self.depth++;
self.currentResult += lines[i] + "\n";
}
return self.currentResult;
break;
case "RegExp":
return "/" + obj.source + "/";
break;
case "Date":
case "string":
if (self.depth > 0 || obj.length == 0) {
return '"' + obj + '"';
} else {
return obj;
}
case "boolean":
if (obj) return "true";
else return "false";
case "number":
return obj + "";
break;
}
};
this.indentsForDepth = function (depth) {
var str = "";
for (var i = 0; i < depth; i++) {
str += "\t";
}
return str;
};
this.trimLog = function (log, maxLines) {
var lines = log.split("\n");
if (lines.length > maxLines) {
lines = lines.slice(lines.length - maxLines);
}
return lines.join("\n");
};
this.lines = function () {
return self.output.split("\n").length;
};
// calculate testing time
this.formatSessionDuration = function (startTime, endTime) {
var msec = endTime - startTime;
var hh = Math.floor(msec / 1000 / 60 / 60);
var hrs = ("0" + hh).slice(-2);
msec -= hh * 1000 * 60 * 60;
var mm = Math.floor(msec / 1000 / 60);
var mins = ("0" + mm).slice(-2);
msec -= mm * 1000 * 60;
var ss = Math.floor(msec / 1000);
var secs = ("0" + ss).slice(-2);
msec -= ss * 1000;
return "---- Duración de la sesión: " + hrs + ":" + mins + ":" + secs + " ----";
};
this.formatTimestamp = function (timestamp) {
var year = timestamp.getFullYear();
var date = timestamp.getDate();
var month = ("0" + (timestamp.getMonth() + 1)).slice(-2);
var hrs = Number(timestamp.getHours());
var mins = ("0" + timestamp.getMinutes()).slice(-2);
var secs = ("0" + timestamp.getSeconds()).slice(-2);
return (
"[" +
year +
"-" +
month +
"-" +
date +
" " +
hrs +
":" +
mins +
":" +
secs +
"]: "
);
};
this.objectSize = function (obj) {
var size = 0,
key;
for (key in obj) {
if (obj.hasOwnProperty(key)) size++;
}
return size;
};
/*
INICIAR/REANUDAR REGISTRO
*/
if (self.useLocalStorage) {
var saved = window.localStorage.getItem("debugout.js");
if (saved) {
saved = JSON.parse(saved);
self.output = saved.log;
var start = new Date(saved.startTime);
var end = new Date(saved.lastLog);
self.output += "\n---- Fin de la sesión: " + saved.lastLog + " ----\n";
self.output += self.formatSessionDuration(start, end);
self.output += "\n\n";
}
}
self.output += "---- Inicio de la sesión: " + self.startTime + " ----\n\n";
}
Agregar botón para descargar el registro
Después de la línea <button id="SerialConnectButton" type="button" disabled>Connect</button>
, agregar:
Llamar al objeto
Agregar en la etiqueta <script>
:
Registrar la salida
Después de la línea term.write(chunk);
, agregar:
Referencias y agradecimientos
- rafaelaroca/web-serial-terminal
- inorganik/debugout.js
- Evento onclick
- ¿Cómo leer y escribir archivos de texto en JavaScript? (Parte de solución alternativa)
- ¡Finalmente te encontré! ¿Cómo guardar los registros de console.log en un archivo en el frontend?
Dirección original del artículo: https://wiki-power.com/
Este artículo está protegido por la licencia CC BY-NC-SA 4.0. Si desea reproducirlo, por favor indique la fuente.Este post está traducido usando ChatGPT, por favor feedback si hay alguna omisión.