webP7/internal.js

385 lines
15 KiB
JavaScript

"use strict";
var p7 = {
device: {},
make: {},
decode: {},
receive: {},
send: {}
};
(function() {
/* ---------------------Utilitaries--------------------- */
/* Sum individual bytes
* NOT + 1, as defined in fxReverse documentation.
* Be sure it's under 256! */
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))
}
/* Convert an hex number into an array of ascii values
* Use the uppercase representation of the number */
Number.prototype.hexToAscii = function (padding) {
return this.toString(16).toUpperCase().padStart(padding, 0).toAscii();
}
/* Convert an ascii array into a string */
p7.asciiToString = (array) => String.fromCharCode.apply(null, array);
/* Convert an ascii array representing an hex number into a number */
//Uint8Array.prototype.fromAsc
p7.asciiToHex = (array) => Number('0x' + p7.asciiToString(array));
p7.sendBuffer = new Uint8Array(1032);
p7.receiveBuffer = undefined;//new Uint8Array(1032 + 1);
/* ---------------------Packet making--------------------- */
/* Create a basic (Non-Extended) packet and push it to p7.sendBuffer */
/* return it's length (6) */
p7.make.basicPacket = (type, subtype) => {
//Set the Type (T), Subtype (ST) and Extended (EX) fields
p7.sendBuffer.set([type]
.concat(subtype.hexToAscii(2))
.concat([0x30])
, 0);
//Set the Checksum (CS) field
p7.sendBuffer.set(p7.sendBuffer.slice(1, 4).p7Checksum().hexToAscii(2), 4);
//Return the packet length
return 6;
}
/* Fill the Data (D) field of a command packet in p7.sendBuffer */
/* return the Data (D) field length */
p7.make.commandPacketDataField = function (dataType, fileSize, commandArguments) {
//Set Overwrite (OW), Data type (DT) and File size (FS) fields
p7.sendBuffer.set([0x30, 0x30, /* Overwrite */
0x30, 0x30] /* Data type field ?? */
.concat(fileSize.hexToAscii(8)) /* File size field */
, 8);
let index = 18;
//Set Size of Data {1-6} (SD{1-6}) fields
commandArguments.forEach(element => p7.sendBuffer.set(element.length.hexToAscii(2), (index += 2)));
//Set Data {1-6} (D{1-6}) fields
let data = commandArguments.join('');
p7.sendBuffer.set(data.toAscii(), 32);
return data.length + 24; /* Overwrite (OW), Data type (DT), File size (FS) and Data size (DS) subfields of the Data (D) field of the packet */;
}
/* Create an extended command packet and push it to p7.sendBuffer */
/* return it's length */
p7.make.extendedCommandPacket = function (subtype, dataType, fileSize, commandArguments) {
let dataSize = p7.make.commandPacketDataField(dataType, fileSize, commandArguments); /* Data field */
//Set Type (T), Subtype (ST), Extended (EX) and Data size (DT) fields
p7.sendBuffer.set([0x01] /* Type field */
.concat(subtype.hexToAscii(2)) /* Subtype field */
.concat([0x31]) /* Extended field */
.concat(dataSize.hexToAscii(4)) /* Data size field */
, 0);
//Set Checksum (CS) field
p7.sendBuffer.set(p7.sendBuffer.slice(1, dataSize + 8).p7Checksum().hexToAscii(2), dataSize + 8);
//Return it's length
return dataSize + 10 /* Type (T), Subtype (ST), Extended (EX), Data size (DT) and Checksum (CS) fields */;
}
/* Create a data packet and push it to p7.sendBuffer */
/* return it's length */
p7.make.dataPacket = function (subType, totalNumber, currentNumber, data) {
/* Set Type (T), Subtype (ST), Extended (EX), Data size (DS),
* Data (D) fields and Data (D) subfields :
* Total Number (TN), Current Number (CN), and Data (DD) */
p7.sendBuffer.set([0x02] /* Type field */
.concat(subType.hexToAscii(2)) /* Subtype (ST) field */
.concat([0x31]) /* Extended (EX) field */
.concat( /* Data size (DS) field */
(data.length + 8 /* Total number (TN) and Current number (CN) subfields */ ).hexToAscii(4))
.concat(totalNumber.hexToAscii(4)) /* Total number (TN) subfield */
.concat(currentNumber.hexToAscii(4)) /* Current number (CN) subfield */
.concat(data) /* Data (DD) subfield */
, 0);
//Set Checksum (CS) field
p7.sendBuffer.set(p7.sendBuffer.slice(1, data.length + 16).p7Checksum().hexToAscii(2), data.length + 16);
//Return it's length
return data.length + 18 /* All other fields and subfields */;
}
/* ---------------------Packet decoding--------------------- */
/* Return all the informations of the device, and trim string's overage (255) */
p7.decode.extendedAckPacket = () => {
return {
hardwareIdentifier : p7.asciiToString(p7ReceiveBuffer.slice(8, 16)),
processorIdentifier : p7.asciiToString(p7ReceiveBuffer.slice(16, 32)),
preprogrammedROMCapacity : p7.asciiToString(p7ReceiveBuffer.slice(32, 40)),
flashROMCapacity : p7.asciiToString(p7ReceiveBuffer.slice(40, 48)),
ramCapacity : p7.asciiToString(p7ReceiveBuffer.slice(48, 56)),
prepogrammedROMVersion : p7.asciiToString(p7ReceiveBuffer.slice(56, 72).filter(number => number !== 255)),
bootCodeVersion : p7.asciiToString(p7ReceiveBuffer.slice(72, 88).filter(number => number !== 255)),
bootCodeOffset : p7.asciiToString(p7ReceiveBuffer.slice(88, 96).filter(number => number !== 255)),
bootCodeSize : p7.asciiToString(p7ReceiveBuffer.slice(96, 104).filter(number => number !== 255)),
osCodeVersion : p7.asciiToString(p7ReceiveBuffer.slice(104, 120).filter(number => number !== 255)),
osCodeOffset : p7.asciiToString(p7ReceiveBuffer.slice(120, 128)),
osCodeSize : p7.asciiToString(p7ReceiveBuffer.slice(128, 136)),
protocolVersion : p7.asciiToString(p7ReceiveBuffer.slice(136, 140)),
productID : p7.asciiToString(p7ReceiveBuffer.slice(140, 156).filter(number => number !== 255)),
username : p7.asciiToString(p7ReceiveBuffer.slice(156, 172).filter(number => number !== 255))
}
};
/* 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.asciiToHex(p7.receiveBuffer.slice(12, 20));
/* ---------------------Packet receiving--------------------- */
/* Doesn't work for now on */
p7.receive.packet = async function () {
/*try {
let array = undefined;
do {
array = await p7.device.transferIn(2, 64);
console.log(array);
} while (array.data.byteLength == 0)
p7.receiveBuffer = Uint8Array(await p7.device.transferIn(2, 64).data.buffer);
} catch (err) {
throw new Error("Couldn't receive the first 64 bytes of the packet : " + err.message);
}
let packetInfo = {};
//Set Type (T) field
packetInfo.type = p7.receiveBuffer[0];
//Set Subtype (ST) field
packetInfo.subtype = p7.asciiToHex(p7.receiveBuffer.slice(1, 2));
//Set Extended (EX) field
packetInfo.extended = (p7.receiveBuffer[3] === 0x31);
console.log(packetInfo);
*/
let transferInResult = 0;
let err = 0;
//Recieve and parse the packet
do {
transferInResult = await p7.device.transferIn(2, 64).then(
(result) => {
return result;
}, (error) => {
err = error;
});
if (err)
return "Couldn't receive the first 64 bytes of the packet : " + err;
console.log('retrying');
} while(!transferInResult.data.byteLength);
//p7ReceivedPacketInfo.packetSize = 4; /*Type, Subtype and Extended field*/
//Copy the received buffer to p7ReceiveBuffer
p7.receiveBuffer.set(new Uint8Array(transferInResult.data.buffer), 0);
console.log(p7.receiveBuffer.slice(0, 25));
}
/* ---------------------Packet sending--------------------- */
/* Doesn't work for now on */
p7.send.packet = async function (length) {
/*try {
await p7.device.transferOut(1, p7.sendBuffer.slice(0, length));
} catch (err) {
throw new Error("Couldn't send the packet : " + err.message);
}*/
let err = 0;
//Send the packet and return the error on failure
if (err = await p7.device.transferOut(1, p7.sendBuffer.slice(0, length)).then((success) => 0, (failure) => failure))
return "Couldn't send the packet : " + err;
};
/* ---------------------Initialization and exiting--------------------- */
/* Initiate the connexion with the calculator */
p7.init = async function () {
try {
p7.device = await navigator.usb.requestDevice({filters:[
{'vendorId': 0x07cf , 'productId': 0x6101}, /* fx-9750gII */
{'vendorId': 0x07cf , 'productId': 0x6102}] /* fx-CP400 */
});
} catch (err) {
throw new Error("Couldn't find the calculator : " + err.message);
}
await p7.device.open();
if (p7.device.configuration === null)
await p7.device.selectConfiguration(1); /* Only existing one so it should be selected by default, just checking */
if (p7.device.configuration.interfaces[0].claimed === false)
await p7.device.claimInterface(0); /* Same as for the configuration */
console.log(p7.device);
/* Everything went right */
return 0;
}
/* End the connexion with the calculator */
p7.exit = async function () {
}
document.getElementById('connect').addEventListener('click', async function () {
try {
await p7.init();
} catch (err) {
console.error(err);
return err;
}
/* Receive and send some usb control message, as defined in fxReverse documentation
*
* Adapted version (some parameters changed since fxReverse's writing) of usb_control_msg() function's protoype
* from linux-manual : https://manpages.debian.org/jessie-backports/linux-manual-4.8/usb_control_msg.9.en.html
*
* int usb_control_msg(struct usb_device * dev,
* uint8_t requesttype,
* uint8_t request,
* uint16_t value,
* uint16_t index,
* void * data,
* uint16_t size,
* int timeout);
*
* fxReverse2:13:
*
* int init_connection() {
* char *buffer = calloc(0x29, sizeof(char));
*
* //Receive 0x12 bytes of data
* usb_control_message(usb_handle,
* 0x80, = 0b10000000
* - D7 = 1 -> Data transfer direction: Device-to-host
* - D6...D5 = 0 -> Type: Standard
* - D4...D0 = 0 -> Recipient: Device
* 0x6,
* 0x0100,
* 0x0,
* buffer,
* 0x12,
* 200);
*
* //Same arguments (except timeout), but value is 0x200 and it receives 0x29 bytes of data
* usb_control_message(usb_handle, 0x80, 0x6, 0x200, 0, buffer, 0x29, 250);
*
*
* usb_control_message(usb_handle,
* 0x41, = 0b01000001
* - D7 = 0 -> Data transfer direction: Host-to-device
* - D6...D5 = 2 -> Type: Vendor
* - D4...D0 = 1 -> Interface: Interface
* 0x1,
* 0x0,
* 0,
* buffer,
* 0x0,
* 250);
*
* free(buffer);
* return 0;
* }
****************************************************************
let transferInResult = undefined;
let controlData = undefined;
try {
transferInResult = await p7.device.controlTransferIn({
requestType: 'standard',
recipient: 'device',
request: 0x06, // GET_DESCRIPTOR
value: 0x0100, // Descriptor Type and Descriptor Index
index: 0x0000
}, 0x12); // Length
} catch (err) {
console.log(err);
}
controlData = new Uint8Array(transferInResult.data.buffer);
console.log('vendor id : 0x' + controlData[9].toString(16).padStart(2, 0) + controlData[8].toString(16).padStart(2,0));
console.log('product id : 0x' + controlData[11].toString(16).padStart(2, 0) + controlData[10].toString(16).padStart(2,0));
try {
transferInResult = await p7.device.controlTransferIn({
requestType: 'standard',
recipient: 'device',
request: 0x06, // GET_DESCRIPTOR
value: 0x0200, // Descriptor Type and Descriptor Index
index: 0x0000
}, 0x29); // Length
} catch (err) {
console.log(err);
}
controlData = new Uint8Array(transferInResult.data.buffer);
console.log(controlData);
try {
await p7.device.controlTransferOut({
requestType: 'vendor',
recipient: 'interface',
request: 0x01,
value: 0x0000,
index: 0x0000
}, controlData);
} catch (err) {
console.log(err);
} */
p7.make.basicPacket(0x06, 0x00);
console.log(p7.sendBuffer.slice(0, 8));
/*
try {
await p7.send.packet(6);
} catch (err) {
console.log('err');
}*/
let err = 0;
if (err = await p7.send.packet(6))
console.log('err' + err);
/* Error: Stay in an endless loop */
await p7.receive.packet();
});
})();