Added sendFile() function

This commit is contained in:
neiviv-ui 2021-08-06 13:06:21 +02:00
parent a64295504d
commit 3012c300f8
5 changed files with 548 additions and 246 deletions

View File

@ -4,12 +4,8 @@
## Usage
The buttons are actually diconnected, if you want to test, dive through the code.
## Things to change
- Have a more js-like code approach !
## Actual possibilities
- You can send files to flash memory (at least fls0, but maybe crd0 too), but only below ~1.5 ko (it freezes beyond, will patch this later)
- You can list files, make directories, remove directories etc...
- You can list files, make directories, remove directories, send files, etc...
- you can optimize your flash
- you can get your device infos
@ -18,7 +14,7 @@ The buttons are actually diconnected, if you want to test, dive through the code
- Make a user friendly interface
- Support all p7 protocol's commands
- Screen casting ? (not a usb but a graphic difficulty)
- other stuffs
- other stuffs (os update ?)
## Thanks to :

View File

@ -1,55 +1,286 @@
(function () {
/* ---------------------Single commands--------------------- */
p7.commands = {
/* ---------------------RAM filesystem commands--------------------- */
ram: {
/* ---------------------Single commands--------------------- */
/* Create a directory */
createDirectory: (name) =>
p7.send.singleCommand(ramCommandSubtype.createDirectory, 0, 0, [name, '', '', '', '', ''])
.catch((err) => {
err.message = "Couldn't create directory: " + err.message;
throw err;
}),
/* Create a directory */
p7.commands.createDirectory = (name, filesystem) => p7.send.singleCommand(flashCommandSubtype.createDirectory, 0, 0, [name, '', '', '', filesystem, '']);
/* Delete a directory */
deleteDirectory: (name) =>
p7.send.singleCommand(ramCommandSubtype.deleteDirectory, 0, 0, [name, '', '', '', '', ''])
.catch((err) => {
err.message = "Couldn't delete directory: " + err.message;
throw err;
}),
/* Rename a directory */
renameDirectory: (oldName, newName) =>
p7.send.singleCommand(ramCommandSubtype.renameDirectory, 0, 0, [oldName, newName, '', '', '', ''])
.catch((err) => {
err.message = "Couldn't rename directory: " + err.message;
throw err;
}),
/* Change working directory */
changeDirectory: (name) =>
p7.send.singleCommand(ramCommandSubtype.changeDirectory, 0, 0, [name, '', '', '', '', ''])
.catch((err) => {
err.message = "Couldn't change working directory: " + err.message;
throw err;
}),
/* Delete a file */
deleteFile: (datatype, fileSize, directory, name, groupName) =>
p7.send.singleCommand(ramCommandSubtype.deleteFile, datatype, fileSize, [directory, name, groupName, '', '', ''])
.catch((err) => {
err.message = "Couldn't delete file: " + err.message;
throw err;
}),
/* Rename a file */
renameFile: (datatype, directory, oldName, newName) =>
p7.send.singleCommand(ramCommandSubtype.renameFile, datatype, 0, [directory, oldName, newName, '', '', ''])
.catch((err) => {
err.message = "Couldn't rename file: " + err.message;
throw err;
}),
/* Copy a file */
copyFile: (datatype, oldDirectory, oldName, newDirectory, newName) =>
p7.send.singleCommand(ramCommandSubtype.copyFile, datatype, 0, [oldDirectory, oldName, newDirectory, newName, '', ''])
.catch((err) => {
err.message = "Couldn't copy file: " + err.message;
throw err;
}),
/* Reset */
reset: () =>
p7.send.packet(p7.make.basicPacket(p7PacketType.command, ramCommandSubtype.reset))
.catch((err) => {
err.message = "Couldn't reset RAM filesystem: " + err.message;
throw err;
}),
/* Delete a directory */
p7.commands.deleteDirectory = (name, filesystem) => p7.send.singleCommand(flashCommandSubtype.deleteDirectory, 0, 0, [name, '', '', '', filesystem, '']);
/* ---------------------Single command requests--------------------- */
/* Get free space */
getCapacity: () =>
p7.send.singleCommandRoleswap(ramCommandSubtype.capacityTransmitRequest, 0, 0, ['', '', '', '', '', ''],
(buffer) => buffer.commandPacketFileSize()
).then((filteredData) => filteredData[0])
.catch((err) => {
err.message = "Couldn't get the size of the free space: " + err.message;
throw err;
}),
/* List files */
list: () =>
p7.send.singleCommandRoleswap(ramCommandSubtype.fileInfoTransferAllRequest, 0, 0, ['', '', '', '', '', ''],
(buffer) => ({
datatype: buffer.commandPacketDataType(),
size: buffer.commandPacketFileSize(),
directoryName: buffer.commandPacketDataField(1),
name: buffer.commandPacketDataField(2),
groupName: buffer.commandPacketDataField(3)
})
).catch((err) => {
err.message = "Couldn't list files: " + err.message;
throw err;
}),
/* Rename a directory */
p7.commands.renameDirectory = (oldName, newName, filesystem) => p7.send.singleCommand(flashCommandSubtype.renameDirectory, 0, 0, [oldName, newName, '', '', filesystem, '']);
/* Transfer setup entry ? */
getSetupEntry: (setupEntry) =>
p7.send.singleCommandRoleswap(ramCommandSubtype.setupEntryTransferRequest, 0, 0, [setupEntry, '', '', '', '', ''],
(buffer) => ({
name: buffer.commandPacketDataField(1),
data: buffer.commandPacketDataField(2).asciiToHex()
})
).catch((err) => {
err.message = "Couldn't transfer setup entry: " + err.message;
throw err;
}),
/* Change working directory */
p7.commands.changeDirectory = (name, filesystem) => p7.send.singleCommand(flashCommandSubtype.changeDirectory, 0, 0, [name, '', '', '', filesystem, '']);
/* ---------------------Data commands--------------------- */
/* Delete a file */
p7.commands.deleteFile = (directory, name, filesystem) => p7.send.singleCommand(flashCommandSubtype.deleteFile, 0, 0, [directory, name, '', '', filesystem, '']);
/* ---------------------Data command requests--------------------- */
/* Rename a file */
p7.commands.renameFile = (directory, oldName, newName, filesystem) => p7.send.singleCommand(flashCommandSubtype.renameFile, 0, 0, [directory, oldName, newName, '', filesystem, '']);
/* Receive a file */
getFile: (dataType, directory, name, groupName) =>
p7.send.dataCommandRoleswap(ramCommandSubtype.fileTransferRequest, dataType, 0, [directory, name, groupName, '', '', ''],
(command, data) => ({
dataType: command.commandPacketDataType(),
size: command.commandPacketFileSize(),
directoryName: command.commandPacketDataField(1),
name: command.commandPacketDataField(2),
groupName: command.commandPacketDataField(3),
data: data
})
).catch((err) => {
err.message = "Couldn't receive file: " + err.message;
throw err;
})
},
/* Copy a file */
p7.commands.copyFile = (oldDirectory, oldName, newDirectory, newName, filesystem) => p7.send.singleCommand(flashCommandSubtype.copyFile, 0, 0, [oldDirectory, oldName, newDirectory, newName, filesystem, '']);
/* ---------------------Flash memory filesystem commands--------------------- */
/* Reset flash? */
p7.commands.resetFlash = (filesystem) => p7.send.singleCommand(flashCommandSubtype.resetFlash, 0, 0, ['', '', '', '', filesystem, '']);
flash: {
/* ---------------------Single commands--------------------- */
/* Optimize filesystem */
p7.commands.optimizeFilesystem = (filesystem) => p7.send.singleCommand(flashCommandSubtype.optimizeFileSystem, 0, 0, ['', '', '', '', filesystem, '']);
/* Create a directory */
createDirectory: (name, filesystem = 'fls0') =>
p7.send.singleCommand(flashCommandSubtype.createDirectory, 0, 0, [name, '', '', '', filesystem, ''])
.catch((err) => {
err.message = "Couldn't create directory: " + err.message;
throw err;
}),
/* Delete a directory */
deleteDirectory: (name, filesystem = 'fls0') =>
p7.send.singleCommand(flashCommandSubtype.deleteDirectory, 0, 0, [name, '', '', '', filesystem, ''])
.catch((err) => {
err.message = "Couldn't delete directory: " + err.message;
throw err;
}),
/* Rename a directory */
renameDirectory: (oldName, newName, filesystem = 'fls0') =>
p7.send.singleCommand(flashCommandSubtype.renameDirectory, 0, 0, [oldName, newName, '', '', filesystem, ''])
.catch((err) => {
err.message = "Couldn't rename directory: " + err.message;
throw err;
}),
/* Change working directory */
changeDirectory: (name, filesystem = 'fls0') =>
p7.send.singleCommand(flashCommandSubtype.changeDirectory, 0, 0, [name, '', '', '', filesystem, ''])
.catch((err) => {
err.message = "Couldn't change working directory: " + err.message;
throw err;
}),
/* Delete a file */
deleteFile: (directory, name, filesystem = 'fls0') =>
p7.send.singleCommand(flashCommandSubtype.deleteFile, 0, 0, [directory, name, '', '', filesystem, ''])
.catch((err) => {
err.message = "Couldn't delete file: " + err.message;
throw err;
}),
/* Rename a file */
renameFile: (directory, oldName, newName, filesystem = 'fls0') =>
p7.send.singleCommand(flashCommandSubtype.renameFile, 0, 0, [directory, oldName, newName, '', filesystem, ''])
.catch((err) => {
err.message = "Couldn't rename file: " + err.message;
throw err;
}),
/* Copy a file */
copyFile: (oldDirectory, oldName, newDirectory, newName, filesystem = 'fls0') =>
p7.send.singleCommand(flashCommandSubtype.copyFile, 0, 0, [oldDirectory, oldName, newDirectory, newName, filesystem, ''])
.catch((err) => {
err.message = "Couldn't copy file: " + err.message;
throw err;
}),
/* Reset */
reset: (filesystem = 'fls0') =>
p7.send.singleCommand(flashCommandSubtype.resetFlash, 0, 0, ['', '', '', '', filesystem, ''])
.catch((err) => {
err.message = "Couldn't reset flash: " + err.message;
throw err;
}),
/* Optimize filesystem */
optimize: (filesystem = 'fls0') =>
p7.send.singleCommand(flashCommandSubtype.optimizeFileSystem, 0, 0, ['', '', '', '', filesystem, ''])
.catch((err) => {
err.message = "Couldn't optimize flash: " + err.message;
throw err;
}),
/* ---------------------Single command requests--------------------- */
/* Get free space */
getCapacity: (filesystem = 'fls0') =>
p7.send.singleCommandRoleswap(flashCommandSubtype.capacityTransmitRequest, 0, 0, ['', '', '', '', filesystem, ''],
(buffer) => buffer.commandPacketFileSize()
).then((filteredData) => filteredData[0])
.catch((err) => {
err.message = "Couldn't get the size of the free space: " + err.message;
throw err;
}),
/* List files */
list: (filesystem = 'fls0') =>
p7.send.singleCommandRoleswap(flashCommandSubtype.fileInfoTransferAllRequest, 0, 0, ['', '', '', '', filesystem, ''],
(buffer) => ({
size: buffer.commandPacketFileSize(),
directoryName: buffer.commandPacketDataField(1),
name: buffer.commandPacketDataField(2)
})
).catch((err) => {
err.message = "Couldn't list files: " + err.message;
throw err;
}),
/* ---------------------Single command requests--------------------- */
/* ---------------------Data commands--------------------- */
/* Get free space */
p7.commands.getCapacity = (filesystem) =>
p7.send.singleCommandRoleswap(flashCommandSubtype.capacityTransmitRequest, 0, 0, ['', '', '', '', filesystem, ''],
() => p7.decode.commandPacketFileSize()
).then((filteredData) => filteredData[0])
.catch((err) => {
err.message = "Couldn't get the size of the free space: " + err.message;
throw err;
});
sendFile: (file, directory, filesystem = 'fls0') =>
file.arrayBuffer()
.then((fileContent) => p7.send.dataCommand(flashCommandSubtype.fileTransfer, 0, fileContent.length, [directory, file.name.substring(0, 12), "", "", filesystem, ""], fileContent))
.catch((err) => {
err.message = "Couldn't send file: " + err.message;
throw err;
}),
/* List files */
p7.commands.list = (filesystem) =>
p7.send.singleCommandRoleswap(flashCommandSubtype.fileInfoTransferAllRequest, 0, 0, ['', '', '', '', filesystem, ''],
() => ({
size: p7.decode.commandPacketFileSize(),
DirectoryName: p7.decode.commandPacketDataField(1),
name: p7.decode.commandPacketDataField(2)
})).catch((err) => {
err.message = "Couldn't list files: " + err.message;
throw err;
});
/* ---------------------Data command requests--------------------- */
getFile: (directory, name, filesystem = 'fls0') =>
p7.send.dataCommandRoleswap(flashCommandSubtype.fileTransferRequest, 0, 0, [directory, name, '', '', filesystem, ''],
(command, data) => ({
size: command.commandPacketFileSize(),
directory : command.commandPacketDataField(1),
name: command.commandPacketDataField(2),
filesystem: command.commandPacketDataField(5),
data: data
})
).then((filteredData) => filteredData[0])
.catch((err) => {
err.message = "Couldn't receive file: " + err.message;
throw err;
}),
getAllFiles: (filesystem = 'fls0') =>
p7.send.dataCommandRoleswap(flashCommandSubtype.fileTransferAllRequest, 0, 0, ['', '', '', '', filesystem, ''],
(command, data) => ({
size: command.commandPacketFileSize(),
directory : command.commandPacketDataField(1),
name: command.commandPacketDataField(2),
filesystem: command.commandPacketDataField(5),
data: data
})
).catch((err) => {
err.message = "Couldn't receive all files: " + err.message;
throw err;
}),
getFlashImage: (filesystem = 'fls0') =>
p7.send.dataCommandRoleswap(flashCommandSubtype.flashImageTransferRequest, 0, 0, ['', '', '', '', filesystem, ''],
(command, data)=> ({
filesystem: command.commandPacketDataField(5),
data: data
})
).catch((err) => {
err.message = "Couldn't dump flash image: " + err.message;
throw err;
})
}
};
}) ();

View File

@ -17,8 +17,8 @@ const sysCommandSubtype = {
'setLinkSettings': 0x02, /* Probably unavailable since we are using USB */
};
const mcsCommandSubtype = {
/* MCS commands */
const ramCommandSubtype = {
/* RAM filesystem commands */
'createDirectory': 0x20,
'deleteDirectory': 0x21,
'renameDirectory': 0x22,
@ -29,7 +29,7 @@ const mcsCommandSubtype = {
'renameFile': 0x27,
'copyFile': 0x28,
'fileTransferAllRequest': 0x29,
'unknownResetMCS': 0x2A, /* TODO: TEST */
'reset': 0x2A, /* TODO: TEST */
'capacityTransmitRequest': 0x2B,
'capacityTransmit': 0x2C,
'fileInfoTransferAllRequest': 0x2D,
@ -42,7 +42,7 @@ const mcsCommandSubtype = {
};
const flashCommandSubtype = {
/* Flash commands */
/* Flash memory filesystem commands */
'createDirectory': 0x40,
'deleteDirectory': 0x41,
'renameDirectory': 0x42,

View File

@ -1 +1,22 @@
'use strict'
'use strict'
document.getElementById('connect').addEventListener('click', async function () {
p7.device = {};
var time = performance.now();
await p7.init()
.catch((err) => {
console.error(err);
throw err;
}).then((deviceInfo) => console.log(deviceInfo));
await p7.commands.ram.getFile(254, "@EDIT", "EDIT.CFG", "@EDIT").then((file) => console.log(file));
await p7.commands.flash.getAllFiles().then((f) => console.log(f));
console.log('Done. (in ' + Math.round(performance.now() - time) + 'ms)');
});
let input = document.getElementById('input');
input.addEventListener('change', async () => {
await p7.commands.flash.sendFile(input.files[0], '');
console.log('Done.');
});

View File

@ -1,28 +1,11 @@
"use strict";
var p7 = {
device: {},
make: {},
send: {},
receive: {},
decode: {},
commands: {},
receiveBuffer : new Uint8Array(1032 + 1)
};
var p7 = {};
(function() {
/* ---------------------Utilitaries--------------------- */
/* Sum individual bytes
* NOT + 1, as defined in fxReverse documentation.
* Be sure it's under 256! */
Array.prototype.p7Checksum = Uint8Array.prototype.p7Checksum = function () {
return (((~(this.reduce((accumulator, currentValue) => accumulator + currentValue))) + 1) & 0xFF)
}
/* Convert a string into an array of ascii numbers */
String.prototype.toAscii = function () {
return this.split('').map((char) => char.charCodeAt(0))
@ -33,214 +16,307 @@ var p7 = {
Number.prototype.hexToAscii = function (padding) {
return this.toString(16).toUpperCase().padStart(padding, 0).toAscii();
}
/* Sum individual bytes
* NOT + 1, as defined in fxReverse documentation.
* Be sure it's under 256! */
Array.prototype.p7Checksum = function () {
return (((~(this.reduce((accumulator, currentValue) => accumulator + currentValue))) + 1) & 0xFF)
}
/* Add the Checksum (CS) field to a packet */
Array.prototype.addP7Checksum = function () {
return this.concat(this.slice(1, this.length).p7Checksum().hexToAscii(2));
}
/* Convert an ascii array into a string */
Array.prototype.asciiToString = Uint8Array.prototype.asciiToString = function () {
Array.prototype.asciiToString = function () {
let string = [];
this.forEach((element) => string.push(String.fromCharCode(element)));
return string.join('');
}
/* Convert an ascii array representing an hex number into a number */
Array.prototype.asciiToHex = Uint8Array.prototype.asciiToHex = function () {
Array.prototype.asciiToHex = function () {
return Number('0x' + this.asciiToString());
}
/* ---------------------Packet making--------------------- */
//Add the checksum to a packet
p7.make.checksum = (packet) => packet.concat(packet.slice(1, packet.length).p7Checksum().hexToAscii(2));
/* Create a basic (Non-Extended) packet */
/* Return the packet */
p7.make.basicPacket = (type, subtype) => p7.make.checksum([type, //Type (T)
...subtype.hexToAscii(2), //Subtype (ST)
0x30]); //Extended (EX)
/* Create an extended command packet */
/* Return the packet */
p7.make.extendedCommandPacket = (subtype, datatype, fileSize, commandArguments) => {
let data = [0x30, 0x30, //Overwrite (OW)
...[0x30, 0x30], //Data type (DT) ??
...fileSize.hexToAscii(8), //File size (FS)
...commandArguments.flatMap((element) => element.length.hexToAscii(2)), //Size of Data {1..6} (SD{1..6})
...commandArguments.join('').toAscii()]; //Data {1..6} (D{1..6})
return p7.make.checksum([0x01, //Type (T)
...subtype.hexToAscii(2), //Subtype (ST)
0x31, //Extended (EX)
...data.length.hexToAscii(4), //Data size (DS)
...data]); //Data (D)
/* Return the decoded Data (D) field */
Array.prototype.decodeDataField = function () {
let buffer = [...this]
buffer.forEach((element, index) => {
if (element === 0x5C)
buffer.splice(index, 2, buffer[index + 1] - (buffer[index + 1] !== 0x5C) * 0x20);
});
return buffer;
}
/* Create a data packet */
/* Return the packet */
p7.make.dataPacket = (subtype, totalNumber, currentNumber, data) =>
p7.make.checksum([0x02, //Type field
...subtype.hexToAscii(2), //Subtype (ST) field
0x31, //Extended (EX) field
...(data.length + 8).hexToAscii(4), //Data size (DS) field
...totalNumber.hexToAscii(4), //Total number (TN) subfield
...currentNumber.hexToAscii(4), //Current number (CN) subfield
...data]); //Data (DD) subfield
/* ---------------------Packet decoding--------------------- */
/* Return the encoded Data (D) field */
Array.prototype.encodeDataField = function () {
return this.flatMap((element) => (element < 0x20) ? [0x5C, (element + 0x20)] : (element === 0x5C) ? [0x5C, 0x5C] : element);
}
/* Return all the informations of the device, and trim string's overage (255) */
p7.decode.extendedAckPacket = () => {
Array.prototype.extendedAckPacket = function () {
return {
hardwareIdentifier : p7.receiveBuffer.slice(8, 16).asciiToString(),
processorIdentifier : p7.receiveBuffer.slice(16, 32).asciiToString(),
preprogrammedROMCapacity : p7.receiveBuffer.slice(32, 40).asciiToString(),
flashROMCapacity : p7.receiveBuffer.slice(40, 48).asciiToString(),
ramCapacity : p7.receiveBuffer.slice(48, 56).asciiToString(),
prepogrammedROMVersion : p7.receiveBuffer.slice(56, 72).filter(number => number !== 255).asciiToString(),
bootCodeVersion : p7.receiveBuffer.slice(72, 88).filter(number => number !== 255).asciiToString(),
bootCodeOffset : p7.receiveBuffer.slice(88, 96).filter(number => number !== 255).asciiToString(),
bootCodeSize : p7.receiveBuffer.slice(96, 104).filter(number => number !== 255).asciiToString(),
osCodeVersion : p7.receiveBuffer.slice(104, 120).filter(number => number !== 255).asciiToString(),
osCodeOffset : p7.receiveBuffer.slice(120, 128).asciiToString(),
osCodeSize : p7.receiveBuffer.slice(128, 136).asciiToString(),
protocolVersion : p7.receiveBuffer.slice(136, 140).asciiToString(),
productID : p7.receiveBuffer.slice(140, 156).filter(number => number !== 255).asciiToString(),
username : p7.receiveBuffer.slice(156, 172).filter(number => number !== 255).asciiToString()
hardwareIdentifier : this.slice(8, 16).asciiToString(),
processorIdentifier : this.slice(16, 32).asciiToString(),
preprogrammedROMCapacity : this.slice(32, 40).asciiToString(),
flashROMCapacity : this.slice(40, 48).asciiToString(),
ramCapacity : this.slice(48, 56).asciiToString(),
prepogrammedROMVersion : this.slice(56, 72).asciiToString(),
bootCodeVersion : this.slice(72, 88).asciiToString(),
bootCodeOffset : this.slice(88, 96).asciiToString(),
bootCodeSize : this.slice(96, 104).asciiToString(),
osCodeVersion : this.slice(104, 120).filter(number => number !== 0xFF).asciiToString(),
osCodeOffset : this.slice(120, 128).asciiToString(),
osCodeSize : this.slice(128, 136).asciiToString(),
protocolVersion : this.slice(136, 140).asciiToString(),
productID : this.slice(140, 156).filter(number => number !== 0xFF).asciiToString(),
username : this.slice(156, 172).filter(number => number !== 0xFF).asciiToString()
}
};
/* Return the value (as an number) of the Overwrite (OW) subfield of the Data (D) field of an extended command packet */
p7.decode.commandPacketOverWrite = () => p7.receiveBuffer.slice(8, 10).asciiToHex();
Array.prototype.commandPacketOverWrite = function () {
return this.slice(8, 10).asciiToHex();
}
/* Return the value (as an number) of the Data type (DT) subfield of the Data (D) field of an extended command packet */
p7.decode.commandPacketDataType = () => p7.receiveBuffer.slice(10, 12).asciiToHex();
Array.prototype.commandPacketDataType = function () {
return this.slice(10, 12).asciiToHex();
}
/* Return the value (as an number) of the FileSize (FS) subfield of the Data (D) field of an extended command packet */
p7.decode.commandPacketFileSize = () => p7.receiveBuffer.slice(12, 20).asciiToHex();
Array.prototype.commandPacketFileSize = function () {
return this.slice(12, 20).asciiToHex();
}
/* Return the value (as a string) of the requested Data (D) subfield of the Data (D) field of an extended command packet */
p7.decode.commandPacketDataField = function (field) {
Array.prototype.commandPacketDataField = function (field) {
let fieldSize = [];
/* Decode the length of Data {1 - ${length}} (D{1 - ${length}}) subfields */
for (let index = 20, i = 0; i < field ; i++)
fieldSize.push(p7.receiveBuffer.slice(index, (index += 2)).asciiToHex());
fieldSize.push(this.slice(index, (index += 2)).asciiToHex());
/* Get the requested field size */
let fieldLength = fieldSize.pop();
/* Get the index of the requested field */
let fieldIndex = (fieldSize.length) ? fieldSize.reduce((accumulator, currentValue) => accumulator + currentValue) + 32 : 32;
/* Return the ascii array as a string */
return p7.receiveBuffer.slice(fieldIndex, fieldIndex + fieldLength).asciiToString();
}
return this.slice(fieldIndex, fieldIndex + fieldLength).asciiToString();
};
p7.decode.commandPacketAllDataFields = function () {
/* Return an array containing the value (as a string) of all the Data (D) subfield of the Data (D) field of an extended command packet */
Array.prototype.commandPacketAllDataFields = function () {
let dataFieldSize = [];
let index = 20
while(index < 32)
dataFieldSize.push(p7.receiveBuffer.subarray(index, (index += 2)).asciiToHex());
dataFieldSize.push(this.slice(index, (index += 2)).asciiToHex());
return dataFieldSize.map((element) => p7.receiveBuffer.slice(index, (index += element)).asciiToString());
return dataFieldSize.map((element) => this.slice(index, (index += element)).asciiToString());
}
/* Return the value (as a number) of the Total number (CN) subfield of the Data (D) field of a data packet */
Array.prototype.dataPacketDataFieldGetTotalNumber = function () {
return this.slice(0, 4).asciiToHex();
}
/* Return the value (as a number) of the Current number (CN) subfield of the Data (D) field of a data packet */
Array.prototype.dataPacketDataFieldGetCurrentNumber = function () {
return this.slice(4, 8).asciiToHex();
}
/* Return the Data (D) subfield of the Data (D) field of a data packet */
Array.prototype.dataPacketDataFieldGetData = function () {
return this.slice(8, this.length);
}
/* ---------------------Packet making--------------------- */
p7.make = {
/* Create a basic (Non-Extended) packet
* Return the packet */
basicPacket: (type, subtype) =>
([type, //Type (T)
...subtype.hexToAscii(2), //Subtype (ST)
0x30].addP7Checksum()), //Extended (EX)
/* Create an Extended packet
* Return the packet */
extendedPacket: (type, subtype, dataField) =>
([type,
...subtype.hexToAscii(2),
0x31,
...(dataField = dataField.encodeDataField()).length.hexToAscii(4),
...dataField].addP7Checksum()),
/* Create a buffer containing the Data (D) field of a command packet
* Return the buffer */
commandPacketDataField: (datatype, fileSize, commandArguments) =>
([0x30, 0x30, //Overwrite (OW)
...datatype.hexToAscii(2), //Data type (DT) ??
...fileSize.hexToAscii(8), //File size (FS)
...commandArguments.flatMap((element) => element.length.hexToAscii(2)), //Size of Data {1..6} (SD{1..6})
...commandArguments.join('').toAscii()]), //Data {1..6} (D{1..6})
/* Create a buffer containing the Data (D) field of a data packet
* Return the buffer */
dataPacketDataField: (totalNumber, currentNumber, data) =>
([...totalNumber.hexToAscii(4), //Total number (TN) subfield
...currentNumber.hexToAscii(4), //Current number (CN) subfield
...data]), //Data (DD) subfield
};
/* ---------------------Packet receiving--------------------- */
p7.receive.packet = function () {
console.log("%cReceiving...", "color: orange");
var packetInfo = {};
var transfered = 0; //Already transfered bytes
return p7.device.transferIn(2, 64)
.then(function receive(transferInResult) {
if (!transferInResult.data.byteLength)
return p7.device.transferIn(2, 64).then(receive);
p7.receiveBuffer.set(new Uint8Array(transferInResult.data.buffer), 0);
packetInfo.length = 6; //Type (T), Subtype (S), Extended (EX) and Checksum (CS) fields
p7.receive = {
packet: function () {
console.log("%cReceiving...", "color: orange");
//Set Type (T) field
packetInfo.type = p7.receiveBuffer[0];
//Set Subtype (ST) field
packetInfo.subtype = p7.receiveBuffer.slice(1, 2).asciiToHex();
var packetInfo = {};
//Set Extended (EX) field
if ((packetInfo.extended = (p7.receiveBuffer[3] === 0x31))) {
//Set Data size (DS) field
packetInfo.dataSize = p7.receiveBuffer.slice(4, 8).asciiToHex();
return p7.device.transferIn(2, 64)
.then(function receive(transferInResult) {
if (!transferInResult.data.byteLength) {
console.log('buffer was empty, retrying');
return p7.device.transferIn(2, 64).then(receive);
}
packetInfo.receiveBuffer = Array.from(new Uint8Array(transferInResult.data.buffer));
packetInfo.length = 6; //Type (T), Subtype (S), Extended (EX) and Checksum (CS) fields
//Set Type (T) field
packetInfo.type = packetInfo.receiveBuffer[0];
//Set Subtype (ST) field
packetInfo.subtype = packetInfo.receiveBuffer.slice(1, 2).asciiToHex();
packetInfo.length += packetInfo.dataSize + 4; //Data size field
if ((transfered += 64) < packetInfo.length)
return p7.device.transferIn(2, 64)
.then(function receiveRemainingPackets(transferInResult) {
p7.receiveBuffer.set(new Uint8Array(transferInResult.data.buffer), transfered);
//Set Extended (EX) field
if ((packetInfo.extended = (packetInfo.receiveBuffer[3] === 0x31))) {
console.log('packet is extended');
//Set Data size (DS) field
packetInfo.dataSize = packetInfo.receiveBuffer.slice(4, 8).asciiToHex();
packetInfo.length += packetInfo.dataSize + 4; //Data size field
if (64 < packetInfo.length)
return p7.device.transferIn(2, packetInfo.length - 64)
.then((transferInResult) => packetInfo.receiveBuffer.push(...(new Uint8Array(transferInResult.data.buffer))));
}
}).then(() => {
if (packetInfo.extended)
packetInfo.data = packetInfo.receiveBuffer.slice(8, packetInfo.receiveBuffer.length - 2).decodeDataField();
if ((transfered += 64) < packetInfo.length)
return p7.device.transferIn(2, 64).then(receiveRemainingPackets);
});
}
}).then(() => {
//Compute checksum
let checksumError = ((packetInfo.checksum = p7.receiveBuffer.slice(packetInfo.length - 2, packetInfo.length).asciiToHex()) !== p7.receiveBuffer.slice(1, packetInfo.length - 2).p7Checksum());
//Compute checksum
let checksumError = ((packetInfo.checksum = packetInfo.receiveBuffer.slice(packetInfo.length - 2, packetInfo.length).asciiToHex()) !== packetInfo.receiveBuffer.slice(1, packetInfo.length - 2).p7Checksum());
/* TODO: handle checksum errors */
console.log(checksumError);
return packetInfo;
}).catch((err) => {
err.message = "Couldn't receive the packet: " + err.message;
throw err;
});
},
return packetInfo;
}).catch((err) => {
err.message = "Couldn't receive the " + transfered + " to " + (transfered + 64) + " bytes of the packet: " + err.message;
throw err;
});
}
data: function (responsePacketInfo) {
var data = [];
return p7.send.packet(p7.make.basicPacket(p7PacketType.ack, ackSubtype.default))
.then(function receiveData(responsePacketInfo) {
if (responsePacketInfo.type !== p7PacketType.data)
return [data.flat(), responsePacketInfo];
data.push(responsePacketInfo.data.dataPacketDataFieldGetData());
return p7.send.packet(p7.make.basicPacket(p7PacketType.ack, ackSubtype.default)).then(receiveData);
});
}
};
/* ---------------------Packet sending--------------------- */
p7.send.packet = function (buffer) {
console.log("%cSending packet...", "color: green");
return p7.device.transferOut(1, Uint8Array.from(buffer))
.catch((err) => {
err.message = "Couldn't send the packet: " + err.message;
throw err;
})
.then(() => p7.receive.packet())
.catch((err) => {
err.message = "Couldn't receive the response packet: " + err.message;
throw err;
});
}
p7.send = {
packet: function (buffer) {
console.log("%cSending packet...", "color: green");
return p7.device.transferOut(1, Uint8Array.from(buffer))
.catch((err) => {
err.message = "Couldn't send the packet: " + err.message;
throw err;
})
.then((transferOutResult) => p7.receive.packet())
.catch((err) => {
err.message = "Couldn't receive the response packet: " + err.message;
throw err;
});
},
/* Send a single command
* Return the informations about the response ack packet */
p7.send.singleCommand = (subtype, datatype, fileSize, commandArguments) =>
p7.send.packet(p7.make.extendedCommandPacket(subtype, datatype, fileSize, commandArguments))
.then((responsePacketInfo) => {
//Check if the packet is an ack packet
if (!(responsePacketInfo.type === p7PacketType.ack && responsePacketInfo.subtype === ackSubtype.default))
throw new Error("The calculator didn't send the expected ack packet!");
});
/* Send a single command
* Return the informations about the response ack packet */
singleCommand: (subtype, datatype, fileSize, commandArguments) =>
p7.send.packet(p7.make.extendedPacket(p7PacketType.command, subtype, p7.make.commandPacketDataField(datatype, fileSize, commandArguments)))
.then((responsePacketInfo) => {
if (!(responsePacketInfo.type === p7PacketType.ack && responsePacketInfo.subtype === ackSubtype.default))
throw new Error("The calculator didn't send the expected ack packet!:" +
"\t{Type: " + responsePacketInfo.type +
"\tSubtype: " + responsePacketInfo.subtype + "}");
/* Send a single command request
* Return an array containing the filtered (with `callbackFunction`) Data (D) field of each response command packet */
p7.send.singleCommandRoleswap = function (subtype, datatype, fileSize, commandArguments, callbackFunction) {
var filteredData = [];
return responsePacketInfo;
}),
/* Send a single command request
* Return an array containing the filtered (with `callbackFunction`) Data (D) field of each response command packet */
singleCommandRoleswap: function (subtype, datatype, fileSize, commandArguments, callbackFunction) {
var filteredData = [];
return p7.send.singleCommand(subtype, datatype, fileSize, commandArguments)
.then(() => p7.send.packet(p7.make.basicPacket(p7PacketType.roleswap, roleswapSubtype.default)))
.then(function receiveRequestedCommand(responsePacketInfo) {
if (responsePacketInfo.type !== p7PacketType.command)
return filteredData;
filteredData.push(callbackFunction(responsePacketInfo.receiveBuffer));
return p7.send.packet(p7.make.basicPacket(p7PacketType.ack, ackSubtype.default)).then(receiveRequestedCommand);
});
},
dataCommand: function (subtype, datatype, fileSize, commandArguments, data) {
var currentPacketNumber = 0;
var lastPacketSize = data.length & 0xFF; //Equivalent to data.length % 256, but way faster !
var totalPacketNumber = (data.length >> 8) + (lastPacketSize !== 0); //Equivalent to data.length / 256, but way way waaaaaay faster, and return an integer quotient, not a decimal one !!
return p7.send.singleCommand(subtype, datatype, fileSize, commandArguments)
.then((responsePacketInfo) => p7.send.packet(p7.make.basicPacket(p7PacketType.roleswap, roleswapSubtype.default)))
.then(function receiveRequestedCommand(responsePacketInfo) {
if (responsePacketInfo.type !== p7PacketType.command)
return filteredData;
filteredData.push(callbackFunction());
return p7.send.packet(p7.make.basicPacket(p7PacketType.ack, ackSubtype.default)).then(receiveRequestedCommand);
});
}
.then(function sendDataPackets(result) {
if ((currentPacketNumber += 1) === totalPacketNumber)
return p7.send.packet(p7.make.extendedPacket(p7PacketType.data, subtype, p7.make.dataPacketDataField(totalPacketNumber, currentPacketNumber, data.slice(data.length - lastPacketSize, data.length))))
return p7.send.packet(p7.make.extendedPacket(p7PacketType.data, subtype, p7.make.dataPacketDataField(totalPacketNumber, currentPacketNumber, data.slice(((currentPacketNumber - 1) << 8), (currentPacketNumber << 8))))).then(sendDataPackets);
});
},
dataCommandRoleswap: async function (subtype, datatype, fileSize, commandArguments, callbackFunction) {
var filteredData = [];
return p7.send.singleCommand(subtype, datatype, fileSize, commandArguments)
.then(() => p7.send.packet(p7.make.basicPacket(p7PacketType.roleswap, roleswapSubtype.default)))
.then(function receiveRequestedData(responsePacketInfo) {
if (responsePacketInfo.type === p7PacketType.roleswap)
return filteredData;
let command = responsePacketInfo.receiveBuffer;
return p7.receive.data()
.then((dataResponse) => {
filteredData.push(callbackFunction(command, dataResponse[0]));
return receiveRequestedData(dataResponse[1]);
});
});
}
};
/* ---------------------Initialization and exiting--------------------- */
/* Connect to the calculator */
@ -370,32 +446,10 @@ var p7 = {
}).then(() => p7.send.packet(p7.make.basicPacket(p7PacketType.command, sysCommandSubtype.getDeviceInfo))
.catch(() => {
throw new Error("Couldn't ask for the device infos!");
}).then(() => p7.decode.extendedAckPacket())));
}).then((responsePacketInfo) => responsePacketInfo.receiveBuffer.extendedAckPacket())));
/* End the connexion with the calculator */
p7.exit = async function () {
p7.exit = function () {
}
document.getElementById('connect').addEventListener('click',
async function () {
var time = performance.now();
return p7.init()
.catch((err) => {
console.error(err);
return err;
}).then((deviceInfo) => {
console.log(deviceInfo);
//Main commands
p7.commands.list('fls0')
.then((fileList) => console.log('The following files are in the flash memory: %o', fileList))
.then(() => p7.commands.getCapacity('fls0'))
.then((capacity) => console.log('Flash memory free space: ' + capacity + 'o'))
.then(() => console.log('Done. (in ' + Math.round(performance.now() - time) + 'ms)'));
})
});
})();