add dependencies for offline use without a build step

This commit is contained in:
liamcottle
2024-07-24 20:51:23 +12:00
parent 4946a8a71a
commit 0fa7055b0a
10 changed files with 17826 additions and 9 deletions

View File

@@ -0,0 +1,760 @@
;(function (root, factory) {
if (typeof exports === "object") {
// CommonJS
module.exports = exports = factory();
}
else if (typeof define === "function" && define.amd) {
// AMD
define([], factory);
}
else {
// Global (browser)
root.CryptoJS = factory();
}
}(this, function () {
/**
* CryptoJS core components.
*/
var CryptoJS = CryptoJS || (function (Math, undefined) {
/*
* Local polyfil of Object.create
*/
var create = Object.create || (function () {
function F() {};
return function (obj) {
var subtype;
F.prototype = obj;
subtype = new F();
F.prototype = null;
return subtype;
};
}())
/**
* CryptoJS namespace.
*/
var C = {};
/**
* Library namespace.
*/
var C_lib = C.lib = {};
/**
* Base object for prototypal inheritance.
*/
var Base = C_lib.Base = (function () {
return {
/**
* Creates a new object that inherits from this object.
*
* @param {Object} overrides Properties to copy into the new object.
*
* @return {Object} The new object.
*
* @static
*
* @example
*
* var MyType = CryptoJS.lib.Base.extend({
* field: 'value',
*
* method: function () {
* }
* });
*/
extend: function (overrides) {
// Spawn
var subtype = create(this);
// Augment
if (overrides) {
subtype.mixIn(overrides);
}
// Create default initializer
if (!subtype.hasOwnProperty('init') || this.init === subtype.init) {
subtype.init = function () {
subtype.$super.init.apply(this, arguments);
};
}
// Initializer's prototype is the subtype object
subtype.init.prototype = subtype;
// Reference supertype
subtype.$super = this;
return subtype;
},
/**
* Extends this object and runs the init method.
* Arguments to create() will be passed to init().
*
* @return {Object} The new object.
*
* @static
*
* @example
*
* var instance = MyType.create();
*/
create: function () {
var instance = this.extend();
instance.init.apply(instance, arguments);
return instance;
},
/**
* Initializes a newly created object.
* Override this method to add some logic when your objects are created.
*
* @example
*
* var MyType = CryptoJS.lib.Base.extend({
* init: function () {
* // ...
* }
* });
*/
init: function () {
},
/**
* Copies properties into this object.
*
* @param {Object} properties The properties to mix in.
*
* @example
*
* MyType.mixIn({
* field: 'value'
* });
*/
mixIn: function (properties) {
for (var propertyName in properties) {
if (properties.hasOwnProperty(propertyName)) {
this[propertyName] = properties[propertyName];
}
}
// IE won't copy toString using the loop above
if (properties.hasOwnProperty('toString')) {
this.toString = properties.toString;
}
},
/**
* Creates a copy of this object.
*
* @return {Object} The clone.
*
* @example
*
* var clone = instance.clone();
*/
clone: function () {
return this.init.prototype.extend(this);
}
};
}());
/**
* An array of 32-bit words.
*
* @property {Array} words The array of 32-bit words.
* @property {number} sigBytes The number of significant bytes in this word array.
*/
var WordArray = C_lib.WordArray = Base.extend({
/**
* Initializes a newly created word array.
*
* @param {Array} words (Optional) An array of 32-bit words.
* @param {number} sigBytes (Optional) The number of significant bytes in the words.
*
* @example
*
* var wordArray = CryptoJS.lib.WordArray.create();
* var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]);
* var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6);
*/
init: function (words, sigBytes) {
words = this.words = words || [];
if (sigBytes != undefined) {
this.sigBytes = sigBytes;
} else {
this.sigBytes = words.length * 4;
}
},
/**
* Converts this word array to a string.
*
* @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex
*
* @return {string} The stringified word array.
*
* @example
*
* var string = wordArray + '';
* var string = wordArray.toString();
* var string = wordArray.toString(CryptoJS.enc.Utf8);
*/
toString: function (encoder) {
return (encoder || Hex).stringify(this);
},
/**
* Concatenates a word array to this word array.
*
* @param {WordArray} wordArray The word array to append.
*
* @return {WordArray} This word array.
*
* @example
*
* wordArray1.concat(wordArray2);
*/
concat: function (wordArray) {
// Shortcuts
var thisWords = this.words;
var thatWords = wordArray.words;
var thisSigBytes = this.sigBytes;
var thatSigBytes = wordArray.sigBytes;
// Clamp excess bits
this.clamp();
// Concat
if (thisSigBytes % 4) {
// Copy one byte at a time
for (var i = 0; i < thatSigBytes; i++) {
var thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8);
}
} else {
// Copy one word at a time
for (var i = 0; i < thatSigBytes; i += 4) {
thisWords[(thisSigBytes + i) >>> 2] = thatWords[i >>> 2];
}
}
this.sigBytes += thatSigBytes;
// Chainable
return this;
},
/**
* Removes insignificant bits.
*
* @example
*
* wordArray.clamp();
*/
clamp: function () {
// Shortcuts
var words = this.words;
var sigBytes = this.sigBytes;
// Clamp
words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8);
words.length = Math.ceil(sigBytes / 4);
},
/**
* Creates a copy of this word array.
*
* @return {WordArray} The clone.
*
* @example
*
* var clone = wordArray.clone();
*/
clone: function () {
var clone = Base.clone.call(this);
clone.words = this.words.slice(0);
return clone;
},
/**
* Creates a word array filled with random bytes.
*
* @param {number} nBytes The number of random bytes to generate.
*
* @return {WordArray} The random word array.
*
* @static
*
* @example
*
* var wordArray = CryptoJS.lib.WordArray.random(16);
*/
random: function (nBytes) {
var words = [];
var r = (function (m_w) {
var m_w = m_w;
var m_z = 0x3ade68b1;
var mask = 0xffffffff;
return function () {
m_z = (0x9069 * (m_z & 0xFFFF) + (m_z >> 0x10)) & mask;
m_w = (0x4650 * (m_w & 0xFFFF) + (m_w >> 0x10)) & mask;
var result = ((m_z << 0x10) + m_w) & mask;
result /= 0x100000000;
result += 0.5;
return result * (Math.random() > .5 ? 1 : -1);
}
});
for (var i = 0, rcache; i < nBytes; i += 4) {
var _r = r((rcache || Math.random()) * 0x100000000);
rcache = _r() * 0x3ade67b7;
words.push((_r() * 0x100000000) | 0);
}
return new WordArray.init(words, nBytes);
}
});
/**
* Encoder namespace.
*/
var C_enc = C.enc = {};
/**
* Hex encoding strategy.
*/
var Hex = C_enc.Hex = {
/**
* Converts a word array to a hex string.
*
* @param {WordArray} wordArray The word array.
*
* @return {string} The hex string.
*
* @static
*
* @example
*
* var hexString = CryptoJS.enc.Hex.stringify(wordArray);
*/
stringify: function (wordArray) {
// Shortcuts
var words = wordArray.words;
var sigBytes = wordArray.sigBytes;
// Convert
var hexChars = [];
for (var i = 0; i < sigBytes; i++) {
var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
hexChars.push((bite >>> 4).toString(16));
hexChars.push((bite & 0x0f).toString(16));
}
return hexChars.join('');
},
/**
* Converts a hex string to a word array.
*
* @param {string} hexStr The hex string.
*
* @return {WordArray} The word array.
*
* @static
*
* @example
*
* var wordArray = CryptoJS.enc.Hex.parse(hexString);
*/
parse: function (hexStr) {
// Shortcut
var hexStrLength = hexStr.length;
// Convert
var words = [];
for (var i = 0; i < hexStrLength; i += 2) {
words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4);
}
return new WordArray.init(words, hexStrLength / 2);
}
};
/**
* Latin1 encoding strategy.
*/
var Latin1 = C_enc.Latin1 = {
/**
* Converts a word array to a Latin1 string.
*
* @param {WordArray} wordArray The word array.
*
* @return {string} The Latin1 string.
*
* @static
*
* @example
*
* var latin1String = CryptoJS.enc.Latin1.stringify(wordArray);
*/
stringify: function (wordArray) {
// Shortcuts
var words = wordArray.words;
var sigBytes = wordArray.sigBytes;
// Convert
var latin1Chars = [];
for (var i = 0; i < sigBytes; i++) {
var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
latin1Chars.push(String.fromCharCode(bite));
}
return latin1Chars.join('');
},
/**
* Converts a Latin1 string to a word array.
*
* @param {string} latin1Str The Latin1 string.
*
* @return {WordArray} The word array.
*
* @static
*
* @example
*
* var wordArray = CryptoJS.enc.Latin1.parse(latin1String);
*/
parse: function (latin1Str) {
// Shortcut
var latin1StrLength = latin1Str.length;
// Convert
var words = [];
for (var i = 0; i < latin1StrLength; i++) {
words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8);
}
return new WordArray.init(words, latin1StrLength);
}
};
/**
* UTF-8 encoding strategy.
*/
var Utf8 = C_enc.Utf8 = {
/**
* Converts a word array to a UTF-8 string.
*
* @param {WordArray} wordArray The word array.
*
* @return {string} The UTF-8 string.
*
* @static
*
* @example
*
* var utf8String = CryptoJS.enc.Utf8.stringify(wordArray);
*/
stringify: function (wordArray) {
try {
return decodeURIComponent(escape(Latin1.stringify(wordArray)));
} catch (e) {
throw new Error('Malformed UTF-8 data');
}
},
/**
* Converts a UTF-8 string to a word array.
*
* @param {string} utf8Str The UTF-8 string.
*
* @return {WordArray} The word array.
*
* @static
*
* @example
*
* var wordArray = CryptoJS.enc.Utf8.parse(utf8String);
*/
parse: function (utf8Str) {
return Latin1.parse(unescape(encodeURIComponent(utf8Str)));
}
};
/**
* Abstract buffered block algorithm template.
*
* The property blockSize must be implemented in a concrete subtype.
*
* @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0
*/
var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({
/**
* Resets this block algorithm's data buffer to its initial state.
*
* @example
*
* bufferedBlockAlgorithm.reset();
*/
reset: function () {
// Initial values
this._data = new WordArray.init();
this._nDataBytes = 0;
},
/**
* Adds new data to this block algorithm's buffer.
*
* @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8.
*
* @example
*
* bufferedBlockAlgorithm._append('data');
* bufferedBlockAlgorithm._append(wordArray);
*/
_append: function (data) {
// Convert string to WordArray, else assume WordArray already
if (typeof data == 'string') {
data = Utf8.parse(data);
}
// Append
this._data.concat(data);
this._nDataBytes += data.sigBytes;
},
/**
* Processes available data blocks.
*
* This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype.
*
* @param {boolean} doFlush Whether all blocks and partial blocks should be processed.
*
* @return {WordArray} The processed data.
*
* @example
*
* var processedData = bufferedBlockAlgorithm._process();
* var processedData = bufferedBlockAlgorithm._process(!!'flush');
*/
_process: function (doFlush) {
// Shortcuts
var data = this._data;
var dataWords = data.words;
var dataSigBytes = data.sigBytes;
var blockSize = this.blockSize;
var blockSizeBytes = blockSize * 4;
// Count blocks ready
var nBlocksReady = dataSigBytes / blockSizeBytes;
if (doFlush) {
// Round up to include partial blocks
nBlocksReady = Math.ceil(nBlocksReady);
} else {
// Round down to include only full blocks,
// less the number of blocks that must remain in the buffer
nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0);
}
// Count words ready
var nWordsReady = nBlocksReady * blockSize;
// Count bytes ready
var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes);
// Process blocks
if (nWordsReady) {
for (var offset = 0; offset < nWordsReady; offset += blockSize) {
// Perform concrete-algorithm logic
this._doProcessBlock(dataWords, offset);
}
// Remove processed words
var processedWords = dataWords.splice(0, nWordsReady);
data.sigBytes -= nBytesReady;
}
// Return processed words
return new WordArray.init(processedWords, nBytesReady);
},
/**
* Creates a copy of this object.
*
* @return {Object} The clone.
*
* @example
*
* var clone = bufferedBlockAlgorithm.clone();
*/
clone: function () {
var clone = Base.clone.call(this);
clone._data = this._data.clone();
return clone;
},
_minBufferSize: 0
});
/**
* Abstract hasher template.
*
* @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits)
*/
var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({
/**
* Configuration options.
*/
cfg: Base.extend(),
/**
* Initializes a newly created hasher.
*
* @param {Object} cfg (Optional) The configuration options to use for this hash computation.
*
* @example
*
* var hasher = CryptoJS.algo.SHA256.create();
*/
init: function (cfg) {
// Apply config defaults
this.cfg = this.cfg.extend(cfg);
// Set initial values
this.reset();
},
/**
* Resets this hasher to its initial state.
*
* @example
*
* hasher.reset();
*/
reset: function () {
// Reset data buffer
BufferedBlockAlgorithm.reset.call(this);
// Perform concrete-hasher logic
this._doReset();
},
/**
* Updates this hasher with a message.
*
* @param {WordArray|string} messageUpdate The message to append.
*
* @return {Hasher} This hasher.
*
* @example
*
* hasher.update('message');
* hasher.update(wordArray);
*/
update: function (messageUpdate) {
// Append
this._append(messageUpdate);
// Update the hash
this._process();
// Chainable
return this;
},
/**
* Finalizes the hash computation.
* Note that the finalize operation is effectively a destructive, read-once operation.
*
* @param {WordArray|string} messageUpdate (Optional) A final message update.
*
* @return {WordArray} The hash.
*
* @example
*
* var hash = hasher.finalize();
* var hash = hasher.finalize('message');
* var hash = hasher.finalize(wordArray);
*/
finalize: function (messageUpdate) {
// Final message update
if (messageUpdate) {
this._append(messageUpdate);
}
// Perform concrete-hasher logic
var hash = this._doFinalize();
return hash;
},
blockSize: 512/32,
/**
* Creates a shortcut function to a hasher's object interface.
*
* @param {Hasher} hasher The hasher to create a helper for.
*
* @return {Function} The shortcut function.
*
* @static
*
* @example
*
* var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256);
*/
_createHelper: function (hasher) {
return function (message, cfg) {
return new hasher.init(cfg).finalize(message);
};
},
/**
* Creates a shortcut function to the HMAC's object interface.
*
* @param {Hasher} hasher The hasher to use in this HMAC helper.
*
* @return {Function} The shortcut function.
*
* @static
*
* @example
*
* var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256);
*/
_createHmacHelper: function (hasher) {
return function (message, key) {
return new C_algo.HMAC.init(hasher, key).finalize(message);
};
}
});
/**
* Algorithm namespace.
*/
var C_algo = C.algo = {};
return C;
}(Math));
return CryptoJS;
}));

268
js/crypto-js@3.9.1-1/md5.js Normal file
View File

@@ -0,0 +1,268 @@
;(function (root, factory) {
if (typeof exports === "object") {
// CommonJS
module.exports = exports = factory(require("./core"));
}
else if (typeof define === "function" && define.amd) {
// AMD
define(["./core"], factory);
}
else {
// Global (browser)
factory(root.CryptoJS);
}
}(this, function (CryptoJS) {
(function (Math) {
// Shortcuts
var C = CryptoJS;
var C_lib = C.lib;
var WordArray = C_lib.WordArray;
var Hasher = C_lib.Hasher;
var C_algo = C.algo;
// Constants table
var T = [];
// Compute constants
(function () {
for (var i = 0; i < 64; i++) {
T[i] = (Math.abs(Math.sin(i + 1)) * 0x100000000) | 0;
}
}());
/**
* MD5 hash algorithm.
*/
var MD5 = C_algo.MD5 = Hasher.extend({
_doReset: function () {
this._hash = new WordArray.init([
0x67452301, 0xefcdab89,
0x98badcfe, 0x10325476
]);
},
_doProcessBlock: function (M, offset) {
// Swap endian
for (var i = 0; i < 16; i++) {
// Shortcuts
var offset_i = offset + i;
var M_offset_i = M[offset_i];
M[offset_i] = (
(((M_offset_i << 8) | (M_offset_i >>> 24)) & 0x00ff00ff) |
(((M_offset_i << 24) | (M_offset_i >>> 8)) & 0xff00ff00)
);
}
// Shortcuts
var H = this._hash.words;
var M_offset_0 = M[offset + 0];
var M_offset_1 = M[offset + 1];
var M_offset_2 = M[offset + 2];
var M_offset_3 = M[offset + 3];
var M_offset_4 = M[offset + 4];
var M_offset_5 = M[offset + 5];
var M_offset_6 = M[offset + 6];
var M_offset_7 = M[offset + 7];
var M_offset_8 = M[offset + 8];
var M_offset_9 = M[offset + 9];
var M_offset_10 = M[offset + 10];
var M_offset_11 = M[offset + 11];
var M_offset_12 = M[offset + 12];
var M_offset_13 = M[offset + 13];
var M_offset_14 = M[offset + 14];
var M_offset_15 = M[offset + 15];
// Working varialbes
var a = H[0];
var b = H[1];
var c = H[2];
var d = H[3];
// Computation
a = FF(a, b, c, d, M_offset_0, 7, T[0]);
d = FF(d, a, b, c, M_offset_1, 12, T[1]);
c = FF(c, d, a, b, M_offset_2, 17, T[2]);
b = FF(b, c, d, a, M_offset_3, 22, T[3]);
a = FF(a, b, c, d, M_offset_4, 7, T[4]);
d = FF(d, a, b, c, M_offset_5, 12, T[5]);
c = FF(c, d, a, b, M_offset_6, 17, T[6]);
b = FF(b, c, d, a, M_offset_7, 22, T[7]);
a = FF(a, b, c, d, M_offset_8, 7, T[8]);
d = FF(d, a, b, c, M_offset_9, 12, T[9]);
c = FF(c, d, a, b, M_offset_10, 17, T[10]);
b = FF(b, c, d, a, M_offset_11, 22, T[11]);
a = FF(a, b, c, d, M_offset_12, 7, T[12]);
d = FF(d, a, b, c, M_offset_13, 12, T[13]);
c = FF(c, d, a, b, M_offset_14, 17, T[14]);
b = FF(b, c, d, a, M_offset_15, 22, T[15]);
a = GG(a, b, c, d, M_offset_1, 5, T[16]);
d = GG(d, a, b, c, M_offset_6, 9, T[17]);
c = GG(c, d, a, b, M_offset_11, 14, T[18]);
b = GG(b, c, d, a, M_offset_0, 20, T[19]);
a = GG(a, b, c, d, M_offset_5, 5, T[20]);
d = GG(d, a, b, c, M_offset_10, 9, T[21]);
c = GG(c, d, a, b, M_offset_15, 14, T[22]);
b = GG(b, c, d, a, M_offset_4, 20, T[23]);
a = GG(a, b, c, d, M_offset_9, 5, T[24]);
d = GG(d, a, b, c, M_offset_14, 9, T[25]);
c = GG(c, d, a, b, M_offset_3, 14, T[26]);
b = GG(b, c, d, a, M_offset_8, 20, T[27]);
a = GG(a, b, c, d, M_offset_13, 5, T[28]);
d = GG(d, a, b, c, M_offset_2, 9, T[29]);
c = GG(c, d, a, b, M_offset_7, 14, T[30]);
b = GG(b, c, d, a, M_offset_12, 20, T[31]);
a = HH(a, b, c, d, M_offset_5, 4, T[32]);
d = HH(d, a, b, c, M_offset_8, 11, T[33]);
c = HH(c, d, a, b, M_offset_11, 16, T[34]);
b = HH(b, c, d, a, M_offset_14, 23, T[35]);
a = HH(a, b, c, d, M_offset_1, 4, T[36]);
d = HH(d, a, b, c, M_offset_4, 11, T[37]);
c = HH(c, d, a, b, M_offset_7, 16, T[38]);
b = HH(b, c, d, a, M_offset_10, 23, T[39]);
a = HH(a, b, c, d, M_offset_13, 4, T[40]);
d = HH(d, a, b, c, M_offset_0, 11, T[41]);
c = HH(c, d, a, b, M_offset_3, 16, T[42]);
b = HH(b, c, d, a, M_offset_6, 23, T[43]);
a = HH(a, b, c, d, M_offset_9, 4, T[44]);
d = HH(d, a, b, c, M_offset_12, 11, T[45]);
c = HH(c, d, a, b, M_offset_15, 16, T[46]);
b = HH(b, c, d, a, M_offset_2, 23, T[47]);
a = II(a, b, c, d, M_offset_0, 6, T[48]);
d = II(d, a, b, c, M_offset_7, 10, T[49]);
c = II(c, d, a, b, M_offset_14, 15, T[50]);
b = II(b, c, d, a, M_offset_5, 21, T[51]);
a = II(a, b, c, d, M_offset_12, 6, T[52]);
d = II(d, a, b, c, M_offset_3, 10, T[53]);
c = II(c, d, a, b, M_offset_10, 15, T[54]);
b = II(b, c, d, a, M_offset_1, 21, T[55]);
a = II(a, b, c, d, M_offset_8, 6, T[56]);
d = II(d, a, b, c, M_offset_15, 10, T[57]);
c = II(c, d, a, b, M_offset_6, 15, T[58]);
b = II(b, c, d, a, M_offset_13, 21, T[59]);
a = II(a, b, c, d, M_offset_4, 6, T[60]);
d = II(d, a, b, c, M_offset_11, 10, T[61]);
c = II(c, d, a, b, M_offset_2, 15, T[62]);
b = II(b, c, d, a, M_offset_9, 21, T[63]);
// Intermediate hash value
H[0] = (H[0] + a) | 0;
H[1] = (H[1] + b) | 0;
H[2] = (H[2] + c) | 0;
H[3] = (H[3] + d) | 0;
},
_doFinalize: function () {
// Shortcuts
var data = this._data;
var dataWords = data.words;
var nBitsTotal = this._nDataBytes * 8;
var nBitsLeft = data.sigBytes * 8;
// Add padding
dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);
var nBitsTotalH = Math.floor(nBitsTotal / 0x100000000);
var nBitsTotalL = nBitsTotal;
dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = (
(((nBitsTotalH << 8) | (nBitsTotalH >>> 24)) & 0x00ff00ff) |
(((nBitsTotalH << 24) | (nBitsTotalH >>> 8)) & 0xff00ff00)
);
dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = (
(((nBitsTotalL << 8) | (nBitsTotalL >>> 24)) & 0x00ff00ff) |
(((nBitsTotalL << 24) | (nBitsTotalL >>> 8)) & 0xff00ff00)
);
data.sigBytes = (dataWords.length + 1) * 4;
// Hash final blocks
this._process();
// Shortcuts
var hash = this._hash;
var H = hash.words;
// Swap endian
for (var i = 0; i < 4; i++) {
// Shortcut
var H_i = H[i];
H[i] = (((H_i << 8) | (H_i >>> 24)) & 0x00ff00ff) |
(((H_i << 24) | (H_i >>> 8)) & 0xff00ff00);
}
// Return final computed hash
return hash;
},
clone: function () {
var clone = Hasher.clone.call(this);
clone._hash = this._hash.clone();
return clone;
}
});
function FF(a, b, c, d, x, s, t) {
var n = a + ((b & c) | (~b & d)) + x + t;
return ((n << s) | (n >>> (32 - s))) + b;
}
function GG(a, b, c, d, x, s, t) {
var n = a + ((b & d) | (c & ~d)) + x + t;
return ((n << s) | (n >>> (32 - s))) + b;
}
function HH(a, b, c, d, x, s, t) {
var n = a + (b ^ c ^ d) + x + t;
return ((n << s) | (n >>> (32 - s))) + b;
}
function II(a, b, c, d, x, s, t) {
var n = a + (c ^ (b | ~d)) + x + t;
return ((n << s) | (n >>> (32 - s))) + b;
}
/**
* Shortcut function to the hasher's object interface.
*
* @param {WordArray|string} message The message to hash.
*
* @return {WordArray} The hash.
*
* @static
*
* @example
*
* var hash = CryptoJS.MD5('message');
* var hash = CryptoJS.MD5(wordArray);
*/
C.MD5 = Hasher._createHelper(MD5);
/**
* Shortcut function to the HMAC's object interface.
*
* @param {WordArray|string} message The message to hash.
* @param {WordArray|string} key The secret key.
*
* @return {WordArray} The HMAC.
*
* @static
*
* @example
*
* var hmac = CryptoJS.HmacMD5(message, key);
*/
C.HmacMD5 = Hasher._createHmacHelper(MD5);
}(Math));
return CryptoJS.MD5;
}));

File diff suppressed because one or more lines are too long

446
js/nrf52_dfu_flasher.js Normal file
View File

@@ -0,0 +1,446 @@
/**
* A Web Serial based nRF52 flasher written by liam@liamcottle.com based on dfu_transport.serial.py
* https://github.com/adafruit/Adafruit_nRF52_nrfutil/blob/master/nordicsemi/dfu/dfu_transport_serial.py
*/
class Nrf52DfuFlasher {
DFU_TOUCH_BAUD = 1200;
SERIAL_PORT_OPEN_WAIT_TIME = 0.1;
TOUCH_RESET_WAIT_TIME = 1.5;
FLASH_BAUD = 115200;
HEX_TYPE_APPLICATION = 4;
DFU_INIT_PACKET = 1;
DFU_START_PACKET = 3;
DFU_DATA_PACKET = 4;
DFU_STOP_DATA_PACKET = 5;
DATA_INTEGRITY_CHECK_PRESENT = 1;
RELIABLE_PACKET = 1;
HCI_PACKET_TYPE = 14;
FLASH_PAGE_SIZE = 4096;
FLASH_PAGE_ERASE_TIME = 0.0897;
FLASH_WORD_WRITE_TIME = 0.000100;
FLASH_PAGE_WRITE_TIME = (this.FLASH_PAGE_SIZE/4) * this.FLASH_WORD_WRITE_TIME;
// The DFU packet max size
DFU_PACKET_MAX_SIZE = 512;
constructor(serialPort) {
this.serialPort = serialPort;
this.sequenceNumber = 0;
this.sd_size = 0;
this.total_size = 0;
}
/**
* Waits for the provided milliseconds, and then resolves.
* @param millis
* @returns {Promise<void>}
*/
async sleepMillis(millis) {
await new Promise((resolve) => {
setTimeout(resolve, millis);
});
}
/**
* Writes the provided data to the Serial Port.
* @param data
* @returns {Promise<void>}
*/
async sendPacket(data) {
const writer = this.serialPort.writable.getWriter();
try {
await writer.write(new Uint8Array(data));
} finally {
writer.releaseLock();
}
}
/**
* Puts an nRF52 board into DFU mode by quickly opening and closing a serial port.
* @returns {Promise<void>}
*/
async enterDfuMode() {
// open port
await this.serialPort.open({
baudRate: this.DFU_TOUCH_BAUD,
});
// wait SERIAL_PORT_OPEN_WAIT_TIME before closing port
await this.sleepMillis(this.SERIAL_PORT_OPEN_WAIT_TIME * 1000);
// close port
await this.serialPort.close();
// wait TOUCH_RESET_WAIT_TIME for device to enter into DFU mode
await this.sleepMillis(this.TOUCH_RESET_WAIT_TIME * 1000);
}
/**
* Flashes the provided firmware zip.
* @param firmwareZipBlob
* @param progressCallback
* @returns {Promise<void>}
*/
async flash(firmwareZipBlob, progressCallback) {
// read zip file
const blobReader = new window.zip.BlobReader(firmwareZipBlob);
const zipReader = new window.zip.ZipReader(blobReader);
const zipEntries = await zipReader.getEntries();
// find manifest file
const manifestFile = zipEntries.find((zipEntry) => zipEntry.filename === "manifest.json");
if(!manifestFile){
throw "manifest.json not found in firmware file!";
}
// read manifest file as text
const text = await manifestFile.getData(new window.zip.TextWriter());
// parse manifest json
const json = JSON.parse(text);
const manifest = json.manifest;
// todo softdevice_bootloader
// if self.manifest.softdevice_bootloader:
// self._dfu_send_image(HexType.SD_BL, self.manifest.softdevice_bootloader)
// todo softdevice
// if self.manifest.softdevice:
// self._dfu_send_image(HexType.SOFTDEVICE, self.manifest.softdevice)
// todo bootloader
// if self.manifest.bootloader:
// self._dfu_send_image(HexType.BOOTLOADER, self.manifest.bootloader)
// flash application image
if(manifest.application){
await this.dfuSendImage(this.HEX_TYPE_APPLICATION, zipEntries, manifest.application, progressCallback);
}
}
/**
* Sends the firmware image to the device in DFU mode.
* @param programMode
* @param zipEntries
* @param firmwareManifest
* @param progressCallback
* @returns {Promise<void>}
*/
async dfuSendImage(programMode, zipEntries, firmwareManifest, progressCallback) {
// open port
await this.serialPort.open({
baudRate: this.FLASH_BAUD,
});
// wait SERIAL_PORT_OPEN_WAIT_TIME
await this.sleepMillis(this.SERIAL_PORT_OPEN_WAIT_TIME * 1000);
// file sizes
var softdeviceSize = 0
var bootloaderSize = 0
var applicationSize = 0
// read bin file (firmware)
const binFile = zipEntries.find((zipEntry) => zipEntry.filename === firmwareManifest.bin_file);
const firmware = await binFile.getData(new window.zip.Uint8ArrayWriter());
// read dat file (init packet)
const datFile = zipEntries.find((zipEntry) => zipEntry.filename === firmwareManifest.dat_file);
const init_packet = await datFile.getData(new window.zip.Uint8ArrayWriter());
// only support flashing application for now
if(programMode !== this.HEX_TYPE_APPLICATION){
throw "not implemented";
}
// determine application size
if(programMode === this.HEX_TYPE_APPLICATION){
applicationSize = firmware.length;
}
console.log("Sending DFU start packet");
await this.sendStartDfu(programMode, softdeviceSize, bootloaderSize, applicationSize);
console.log("Sending DFU init packet");
await this.sendInitPacket(init_packet);
console.log("Sending firmware");
await this.sendFirmware(firmware, progressCallback);
// todo
// sleep(self.dfu_transport.get_activate_wait_time())
}
/**
* Calculates CRC16 on the provided binaryData
* @param {Uint8Array} binaryData - Array with data to run CRC16 calculation on
* @param {number} crc - CRC value to start calculation with
* @return {number} - Calculated CRC value of binaryData
*/
calcCrc16(binaryData, crc = 0xffff) {
if(!(binaryData instanceof Uint8Array)){
throw new Error("calcCrc16 requires Uint8Array input");
}
for(let b of binaryData){
crc = (crc >> 8 & 0x00FF) | (crc << 8 & 0xFF00);
crc ^= b;
crc ^= (crc & 0x00FF) >> 4;
crc ^= (crc << 8) << 4;
crc ^= ((crc & 0x00FF) << 4) << 1;
}
return crc & 0xFFFF;
}
/**
* Encode esc characters in a SLIP package.
* Replace 0xC0 with 0xDBDC and 0xDB with 0xDBDD.
* @param dataIn
* @returns {*[]}
*/
slipEncodeEscChars(dataIn) {
let result = [];
for(let i = 0; i < dataIn.length; i++){
let char = dataIn[i];
if(char === 0xC0){
result.push(0xDB);
result.push(0xDC);
} else if(char === 0xDB) {
result.push(0xDB);
result.push(0xDD);
} else {
result.push(char);
}
}
return result;
}
/**
* Creates an HCI packet from the provided frame data.
* https://github.com/adafruit/Adafruit_nRF52_nrfutil/blob/master/nordicsemi/dfu/dfu_transport_serial.py#L332
* @param frame
* @returns {*[]}
*/
createHciPacketFromFrame(frame) {
// increase sequence number, but roll over at 8
this.sequenceNumber = (this.sequenceNumber + 1) % 8;
// create slip header
const slipHeaderBytes = this.createSlipHeader(
this.sequenceNumber,
this.DATA_INTEGRITY_CHECK_PRESENT,
this.RELIABLE_PACKET,
this.HCI_PACKET_TYPE,
frame.length,
);
// create packet data
let data = [
...slipHeaderBytes,
...frame,
];
// add crc of data
const crc = this.calcCrc16(new Uint8Array(data), 0xffff);
data.push(crc & 0xFF);
data.push((crc & 0xFF00) >> 8);
// add escape characters
return [
0xc0,
...this.slipEncodeEscChars(data),
0xc0,
];
}
/**
* Calculate how long we should wait for erasing data.
* @returns {number}
*/
getEraseWaitTime() {
// always wait at least 0.5 seconds
return Math.max(0.5, ((this.total_size / this.FLASH_PAGE_SIZE) + 1) * this.FLASH_PAGE_ERASE_TIME);
}
/**
* Constructs the image size packet sent in the DFU Start packet.
* @param softdeviceSize
* @param bootloaderSize
* @param appSize
* @returns {number[]}
*/
createImageSizePacket(softdeviceSize = 0, bootloaderSize = 0, appSize = 0) {
return [
...this.int32ToBytes(softdeviceSize),
...this.int32ToBytes(bootloaderSize),
...this.int32ToBytes(appSize),
];
}
/**
* Sends the DFU Start packet to the device.
* @param mode
* @param softdevice_size
* @param bootloader_size
* @param app_size
* @returns {Promise<void>}
*/
async sendStartDfu(mode, softdevice_size = 0, bootloader_size = 0, app_size = 0){
// create frame
const frame = [
...this.int32ToBytes(this.DFU_START_PACKET),
...this.int32ToBytes(mode),
...this.createImageSizePacket(softdevice_size, bootloader_size, app_size),
];
// send hci packet
await this.sendPacket(this.createHciPacketFromFrame(frame));
// remember file sizes for calculating erase wait time
this.sd_size = softdevice_size;
this.total_size = softdevice_size + bootloader_size + app_size;
// wait for initial erase
await this.sleepMillis(this.getEraseWaitTime() * 1000);
}
/**
* Sends the DFU Init packet to the device.
* @param initPacket
* @returns {Promise<void>}
*/
async sendInitPacket(initPacket){
// create frame
const frame = [
...this.int32ToBytes(this.DFU_INIT_PACKET),
...initPacket,
...this.int16ToBytes(0x0000), // padding required
];
// send hci packet
await this.sendPacket(this.createHciPacketFromFrame(frame));
}
/**
* Sends the firmware file to the device in multiple chunks.
* @param firmware
* @param progressCallback
* @returns {Promise<void>}
*/
async sendFirmware(firmware, progressCallback) {
const packets = [];
var packetsSent = 0;
// chunk firmware into separate packets
for(let i = 0; i < firmware.length; i += this.DFU_PACKET_MAX_SIZE){
packets.push(this.createHciPacketFromFrame([
...this.int32ToBytes(this.DFU_DATA_PACKET),
...firmware.slice(i, i + this.DFU_PACKET_MAX_SIZE),
]));
}
// send initial progress
if(progressCallback){
progressCallback(0);
}
// send each packet one after the other
for(var i = 0; i < packets.length; i++){
// send packet
await this.sendPacket(packets[i]);
// wait a bit to allow device to write before sending next packet
await this.sleepMillis(this.FLASH_PAGE_WRITE_TIME * 1000);
// update progress
packetsSent++;
if(progressCallback){
const progress = Math.floor((packetsSent / packets.length) * 100);
progressCallback(progress);
}
}
// finished sending firmware, send DFU Stop Data packet
await this.sendPacket(this.createHciPacketFromFrame([
...this.int32ToBytes(this.DFU_STOP_DATA_PACKET),
]));
}
/**
* Creates a SLIP header.
*
* For a description of the SLIP header go to:
* http://developer.nordicsemi.com/nRF51_SDK/doc/7.2.0/s110/html/a00093.html
*
* @param {number} seq - Packet sequence number
* @param {number} dip - Data integrity check
* @param {number} rp - Reliable packet
* @param {number} pktType - Payload packet
* @param {number} pktLen - Packet length
* @return {Uint8Array} - SLIP header
*/
createSlipHeader(seq, dip, rp, pktType, pktLen) {
let ints = [0, 0, 0, 0];
ints[0] = seq | (((seq + 1) % 8) << 3) | (dip << 6) | (rp << 7);
ints[1] = pktType | ((pktLen & 0x000F) << 4);
ints[2] = (pktLen & 0x0FF0) >> 4;
ints[3] = (~(ints[0] + ints[1] + ints[2]) + 1) & 0xFF;
return new Uint8Array(ints);
}
/**
* Converts the provided int32 to 4 bytes.
* @param num
* @returns {number[]}
*/
int32ToBytes(num){
return [
(num & 0x000000ff),
(num & 0x0000ff00) >> 8,
(num & 0x00ff0000) >> 16,
(num & 0xff000000) >> 24,
];
}
/**
* Converts the provided int16 to 2 bytes.
* @param num
* @returns {number[]}
*/
int16ToBytes(num){
return [
(num & 0x00FF),
(num & 0xFF00) >> 8,
];
}
}

883
js/rnode.js Normal file
View File

@@ -0,0 +1,883 @@
class Utils {
/**
* Waits for the provided milliseconds, and then resolves.
* @param millis
* @returns {Promise<void>}
*/
static async sleepMillis(millis) {
await new Promise((resolve) => {
setTimeout(resolve, millis);
});
}
static bytesToHex(bytes) {
for(var hex = [], i = 0; i < bytes.length; i++){
var current = bytes[i] < 0 ? bytes[i] + 256 : bytes[i];
hex.push((current >>> 4).toString(16));
hex.push((current & 0xF).toString(16));
}
return hex.join("");
}
static md5(data) {
var bytes = [];
const hash = CryptoJS.MD5(CryptoJS.enc.Hex.parse(this.bytesToHex(data)));
for(var i = 0; i < hash.sigBytes; i++){
bytes.push((hash.words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff);
}
return bytes;
}
static packUInt32BE(value) {
const buffer = new ArrayBuffer(4);
const view = new DataView(buffer);
view.setUint32(0, value, false);
return new Uint8Array(buffer);
}
static unpackUInt32BE(byteArray) {
const buffer = new Uint8Array(byteArray).buffer;
const view = new DataView(buffer);
return view.getUint32(0, false);
}
}
class RNode {
KISS_FEND = 0xC0;
KISS_FESC = 0xDB;
KISS_TFEND = 0xDC;
KISS_TFESC = 0xDD;
CMD_FREQUENCY = 0x01;
CMD_BANDWIDTH = 0x02;
CMD_TXPOWER = 0x03;
CMD_SF = 0x04;
CMD_CR = 0x05;
CMD_RADIO_STATE = 0x06;
CMD_STAT_RX = 0x21;
CMD_STAT_TX = 0x22
CMD_STAT_RSSI = 0x23;
CMD_STAT_SNR = 0x24;
CMD_BOARD = 0x47;
CMD_PLATFORM = 0x48;
CMD_MCU = 0x49;
CMD_RESET = 0x55;
CMD_RESET_BYTE = 0xF8;
CMD_DEV_HASH = 0x56;
CMD_FW_VERSION = 0x50;
CMD_ROM_READ = 0x51;
CMD_ROM_WRITE = 0x52;
CMD_CONF_SAVE = 0x53;
CMD_CONF_DELETE = 0x54;
CMD_FW_HASH = 0x58;
CMD_UNLOCK_ROM = 0x59;
ROM_UNLOCK_BYTE = 0xF8;
CMD_HASHES = 0x60;
CMD_FW_UPD = 0x61;
CMD_BT_CTRL = 0x46;
CMD_BT_PIN = 0x62;
CMD_DETECT = 0x08;
DETECT_REQ = 0x73;
DETECT_RESP = 0x46;
RADIO_STATE_OFF = 0x00;
RADIO_STATE_ON = 0x01;
RADIO_STATE_ASK = 0xFF;
CMD_ERROR = 0x90
ERROR_INITRADIO = 0x01
ERROR_TXFAILED = 0x02
ERROR_EEPROM_LOCKED = 0x03
PLATFORM_AVR = 0x90;
PLATFORM_ESP32 = 0x80;
PLATFORM_NRF52 = 0x70;
MCU_1284P = 0x91;
MCU_2560 = 0x92;
MCU_ESP32 = 0x81;
MCU_NRF52 = 0x71;
BOARD_RNODE = 0x31;
BOARD_HMBRW = 0x32;
BOARD_TBEAM = 0x33;
BOARD_HUZZAH32 = 0x34;
BOARD_GENERIC_ESP32 = 0x35;
BOARD_LORA32_V2_0 = 0x36;
BOARD_LORA32_V2_1 = 0x37;
BOARD_RAK4631 = 0x51;
HASH_TYPE_TARGET_FIRMWARE = 0x01;
HASH_TYPE_FIRMWARE = 0x02;
constructor(serialPort) {
this.serialPort = serialPort;
this.readable = serialPort.readable;
this.writable = serialPort.writable;
}
static async fromSerialPort(serialPort) {
// open port
await serialPort.open({
baudRate: 115200,
});
return new RNode(serialPort);
}
async close() {
await this.serialPort.close();
}
async write(bytes) {
const writer = this.writable.getWriter();
try {
await writer.write(new Uint8Array(bytes));
} finally {
writer.releaseLock();
}
}
async readFromSerialPort() {
const reader = this.readable.getReader();
try {
let buffer = [];
while(true){
const { value, done } = await reader.read();
if(done){
break;
}
if(value){
for(let byte of value){
buffer.push(byte);
if(byte === this.KISS_FEND){
if(buffer.length > 1){
return this.handleKISSFrame(buffer);
}
buffer = [this.KISS_FEND]; // Start new frame
}
}
}
}
} catch (error) {
console.error('Error reading from serial port: ', error);
} finally {
reader.releaseLock();
}
}
handleKISSFrame(frame) {
let data = [];
let escaping = false;
// Skip the initial 0xC0 and process the rest
for(let i = 1; i < frame.length; i++){
let byte = frame[i];
if (escaping) {
if (byte === this.KISS_TFEND) {
data.push(this.KISS_FEND);
} else if (byte === this.KISS_TFESC) {
data.push(this.KISS_FESC);
}
escaping = false;
} else {
if (byte === this.KISS_FESC) {
escaping = true;
} else if (byte === this.KISS_FEND) {
// Ignore the end frame delimiter
break;
} else {
data.push(byte);
}
}
}
//console.log('Received KISS frame data:', new Uint8Array(data));
return data;
}
createKissFrame(data) {
let frame = [this.KISS_FEND];
for(let byte of data){
if(byte === this.KISS_FEND){
frame.push(this.KISS_FESC, this.KISS_TFEND);
} else if(byte === this.KISS_FESC){
frame.push(this.KISS_FESC, this.KISS_TFESC);
} else {
frame.push(byte);
}
}
frame.push(this.KISS_FEND);
return new Uint8Array(frame);
}
async sendKissCommand(data) {
await this.write(this.createKissFrame(data));
}
async reset() {
await this.sendKissCommand([
this.CMD_RESET,
this.CMD_RESET_BYTE,
]);
}
async detect() {
// ask if device is rnode
await this.sendKissCommand([
this.CMD_DETECT,
this.DETECT_REQ,
]);
// read response from device
const [ command, responseByte ] = await this.readFromSerialPort();
// device is an rnode if response is as expected
return command === this.CMD_DETECT && responseByte === this.DETECT_RESP;
}
async getFirmwareVersion() {
await this.sendKissCommand([
this.CMD_FW_VERSION,
0x00,
]);
// read response from device
var [ command, majorVersion, minorVersion ] = await this.readFromSerialPort();
if(minorVersion.length === 1){
minorVersion = "0" + minorVersion;
}
// 1.23
return majorVersion + "." + minorVersion;
}
async getPlatform() {
await this.sendKissCommand([
this.CMD_PLATFORM,
0x00,
]);
// read response from device
const [ command, platformByte ] = await this.readFromSerialPort();
return platformByte;
}
async getMcu() {
await this.sendKissCommand([
this.CMD_MCU,
0x00,
]);
// read response from device
const [ command, mcuByte ] = await this.readFromSerialPort();
return mcuByte;
}
async getBoard() {
await this.sendKissCommand([
this.CMD_BOARD,
0x00,
]);
// read response from device
const [ command, boardByte ] = await this.readFromSerialPort();
return boardByte;
}
async getDeviceHash() {
await this.sendKissCommand([
this.CMD_DEV_HASH,
0x01, // anything != 0x00
]);
// read response from device
const [ command, ...deviceHash ] = await this.readFromSerialPort();
return deviceHash;
}
async getTargetFirmwareHash() {
await this.sendKissCommand([
this.CMD_HASHES,
this.HASH_TYPE_TARGET_FIRMWARE,
]);
// read response from device
const [ command, hashType, ...targetFirmwareHash ] = await this.readFromSerialPort();
return targetFirmwareHash;
}
async getFirmwareHash() {
await this.sendKissCommand([
this.CMD_HASHES,
this.HASH_TYPE_FIRMWARE,
]);
// read response from device
const [ command, hashType, ...firmwareHash ] = await this.readFromSerialPort();
return firmwareHash;
}
async getRom() {
await this.sendKissCommand([
this.CMD_ROM_READ,
0x00,
]);
// read response from device
const [ command, ...eepromBytes ] = await this.readFromSerialPort();
return eepromBytes;
}
async getFrequency() {
await this.sendKissCommand([
this.CMD_FREQUENCY,
// request frequency by sending zero as 4 bytes
0x00,
0x00,
0x00,
0x00,
]);
// read response from device
const [ command, ...frequencyBytes ] = await this.readFromSerialPort();
// convert 4 bytes to 32bit integer representing frequency in hertz
const frequencyInHz = frequencyBytes[0] << 24 | frequencyBytes[1] << 16 | frequencyBytes[2] << 8 | frequencyBytes[3];
return frequencyInHz;
}
async getBandwidth() {
await this.sendKissCommand([
this.CMD_BANDWIDTH,
// request bandwidth by sending zero as 4 bytes
0x00,
0x00,
0x00,
0x00,
]);
// read response from device
const [ command, ...bandwidthBytes ] = await this.readFromSerialPort();
// convert 4 bytes to 32bit integer representing bandwidth in hertz
const bandwidthInHz = bandwidthBytes[0] << 24 | bandwidthBytes[1] << 16 | bandwidthBytes[2] << 8 | bandwidthBytes[3];
return bandwidthInHz;
}
async getTxPower() {
await this.sendKissCommand([
this.CMD_TXPOWER,
0xFF, // request tx power
]);
// read response from device
const [ command, txPower ] = await this.readFromSerialPort();
return txPower;
}
async getSpreadingFactor() {
await this.sendKissCommand([
this.CMD_SF,
0xFF, // request spreading factor
]);
// read response from device
const [ command, spreadingFactor ] = await this.readFromSerialPort();
return spreadingFactor;
}
async getCodingRate() {
await this.sendKissCommand([
this.CMD_CR,
0xFF, // request coding rate
]);
// read response from device
const [ command, codingRate ] = await this.readFromSerialPort();
return codingRate;
}
async getRadioState() {
await this.sendKissCommand([
this.CMD_RADIO_STATE,
0xFF, // request radio state
]);
// read response from device
const [ command, radioState ] = await this.readFromSerialPort();
return radioState;
}
async getRxStat() {
await this.sendKissCommand([
this.CMD_STAT_RX,
0x00,
]);
// read response from device
const [ command, ...statBytes ] = await this.readFromSerialPort();
// convert 4 bytes to 32bit integer
const stat = statBytes[0] << 24 | statBytes[1] << 16 | statBytes[2] << 8 | statBytes[3];
return stat;
}
async getTxStat() {
await this.sendKissCommand([
this.CMD_STAT_TX,
0x00,
]);
// read response from device
const [ command, ...statBytes ] = await this.readFromSerialPort();
// convert 4 bytes to 32bit integer
const stat = statBytes[0] << 24 | statBytes[1] << 16 | statBytes[2] << 8 | statBytes[3];
return stat;
}
async getRssiStat() {
await this.sendKissCommand([
this.CMD_STAT_RSSI,
0x00,
]);
// read response from device
const [ command, rssi ] = await this.readFromSerialPort();
return rssi;
}
async disableBluetooth() {
await this.sendKissCommand([
this.CMD_BT_CTRL,
0x00, // stop
]);
}
async enableBluetooth() {
await this.sendKissCommand([
this.CMD_BT_CTRL,
0x01, // start
]);
}
async startBluetoothPairing() {
await this.sendKissCommand([
this.CMD_BT_CTRL,
0x02, // enable pairing
]);
}
async setFrequency(frequencyInHz) {
const c1 = frequencyInHz >> 24;
const c2 = frequencyInHz >> 16 & 0xFF;
const c3 = frequencyInHz >> 8 & 0xFF;
const c4 = frequencyInHz & 0xFF;
await this.sendKissCommand([
this.CMD_FREQUENCY,
c1,
c2,
c3,
c4,
]);
}
async setBandwidth(bandwidthInHz) {
const c1 = bandwidthInHz >> 24;
const c2 = bandwidthInHz >> 16 & 0xFF;
const c3 = bandwidthInHz >> 8 & 0xFF;
const c4 = bandwidthInHz & 0xFF;
await this.sendKissCommand([
this.CMD_BANDWIDTH,
c1,
c2,
c3,
c4,
]);
}
async setTxPower(db) {
await this.sendKissCommand([
this.CMD_TXPOWER,
db,
]);
}
async setSpreadingFactor(spreadingFactor) {
await this.sendKissCommand([
this.CMD_SF,
spreadingFactor,
]);
}
async setCodingRate(codingRate) {
await this.sendKissCommand([
this.CMD_CR,
codingRate,
]);
}
async setRadioStateOn() {
await this.sendKissCommand([
this.CMD_RADIO_STATE,
this.RADIO_STATE_ON,
]);
}
async setRadioStateOff() {
await this.sendKissCommand([
this.CMD_RADIO_STATE,
this.RADIO_STATE_OFF,
]);
}
// setTNCMode
async saveConfig() {
await this.sendKissCommand([
this.CMD_CONF_SAVE,
0x00,
]);
}
// setNormalMode
async deleteConfig() {
await this.sendKissCommand([
this.CMD_CONF_DELETE,
0x00,
]);
}
async indicateFirmwareUpdate() {
await this.sendKissCommand([
this.CMD_FW_UPD,
0x01,
]);
}
async setFirmwareHash(hash) {
await this.sendKissCommand([
this.CMD_FW_HASH,
...hash,
]);
}
async writeRom(address, value) {
// write to rom
await this.sendKissCommand([
this.CMD_ROM_WRITE,
address,
value,
]);
// wait a bit to allow device to write to rom
await Utils.sleepMillis(85);
}
async wipeRom() {
await this.sendKissCommand([
this.CMD_UNLOCK_ROM,
this.ROM_UNLOCK_BYTE,
]);
// wiping can take up to 30 seconds
await Utils.sleepMillis(30000);
}
async getRomAsObject() {
const rom = await this.getRom();
return new ROM(rom);
}
}
class ROM {
static PLATFORM_AVR = 0x90
static PLATFORM_ESP32 = 0x80
static PLATFORM_NRF52 = 0x70
static MCU_1284P = 0x91
static MCU_2560 = 0x92
static MCU_ESP32 = 0x81
static MCU_NRF52 = 0x71
static PRODUCT_RAK4631 = 0x10
static MODEL_11 = 0x11
static MODEL_12 = 0x12
static PRODUCT_RNODE = 0x03
static MODEL_A1 = 0xA1
static MODEL_A6 = 0xA6
static MODEL_A4 = 0xA4
static MODEL_A9 = 0xA9
static MODEL_A3 = 0xA3
static MODEL_A8 = 0xA8
static MODEL_A2 = 0xA2
static MODEL_A7 = 0xA7
static PRODUCT_T32_10 = 0xB2
static MODEL_BA = 0xBA
static MODEL_BB = 0xBB
static PRODUCT_T32_20 = 0xB0
static MODEL_B3 = 0xB3
static MODEL_B8 = 0xB8
static PRODUCT_T32_21 = 0xB1
static MODEL_B4 = 0xB4
static MODEL_B9 = 0xB9
static MODEL_B4_TCXO = 0x04 // The TCXO model codes are only used here to select the
static MODEL_B9_TCXO = 0x09 // correct firmware, actual model codes in firmware is still 0xB4 and 0xB9.
static PRODUCT_H32_V2 = 0xC0
static MODEL_C4 = 0xC4
static MODEL_C9 = 0xC9
static PRODUCT_H32_V3 = 0xC1
static MODEL_C5 = 0xC5
static MODEL_CA = 0xCA
static PRODUCT_TBEAM = 0xE0
static MODEL_E4 = 0xE4
static MODEL_E9 = 0xE9
static MODEL_E3 = 0xE3
static MODEL_E8 = 0xE8
static PRODUCT_HMBRW = 0xF0
static MODEL_FF = 0xFF
static MODEL_FE = 0xFE
static ADDR_PRODUCT = 0x00
static ADDR_MODEL = 0x01
static ADDR_HW_REV = 0x02
static ADDR_SERIAL = 0x03
static ADDR_MADE = 0x07
static ADDR_CHKSUM = 0x0B
static ADDR_SIGNATURE = 0x1B
static ADDR_INFO_LOCK = 0x9B
static ADDR_CONF_SF = 0x9C
static ADDR_CONF_CR = 0x9D
static ADDR_CONF_TXP = 0x9E
static ADDR_CONF_BW = 0x9F
static ADDR_CONF_FREQ = 0xA3
static ADDR_CONF_OK = 0xA7
static INFO_LOCK_BYTE = 0x73
static CONF_OK_BYTE = 0x73
static BOARD_RNODE = 0x31
static BOARD_HMBRW = 0x32
static BOARD_TBEAM = 0x33
static BOARD_HUZZAH32 = 0x34
static BOARD_GENERIC_ESP32 = 0x35
static BOARD_LORA32_V2_0 = 0x36
static BOARD_LORA32_V2_1 = 0x37
static BOARD_RAK4631 = 0x51
static MANUAL_FLASH_MODELS = [ROM.MODEL_A1, ROM.MODEL_A6]
constructor(eeprom) {
this.eeprom = eeprom;
}
getProduct() {
return this.eeprom[ROM.ADDR_PRODUCT];
}
getModel() {
return this.eeprom[ROM.ADDR_MODEL];
}
getHardwareRevision() {
return this.eeprom[ROM.ADDR_HW_REV];
}
getSerialNumber() {
return [
this.eeprom[ROM.ADDR_SERIAL],
this.eeprom[ROM.ADDR_SERIAL + 1],
this.eeprom[ROM.ADDR_SERIAL + 2],
this.eeprom[ROM.ADDR_SERIAL + 3],
];
}
getMade() {
return [
this.eeprom[ROM.ADDR_MADE],
this.eeprom[ROM.ADDR_MADE + 1],
this.eeprom[ROM.ADDR_MADE + 2],
this.eeprom[ROM.ADDR_MADE + 3],
];
}
getChecksum() {
const checksum = [];
for(var i = 0; i < 16; i++){
checksum.push(this.eeprom[ROM.ADDR_CHKSUM + i]);
}
return checksum;
}
getSignature() {
const signature = [];
for(var i = 0; i < 128; i++){
signature.push(this.eeprom[ROM.ADDR_SIGNATURE + i]);
}
return signature;
}
getCalculatedChecksum() {
return Utils.md5([
this.getProduct(),
this.getModel(),
this.getHardwareRevision(),
...this.getSerialNumber(),
...this.getMade(),
]);
}
getConfiguredSpreadingFactor() {
return this.eeprom[ROM.ADDR_CONF_SF];
}
getConfiguredCodingRate() {
return this.eeprom[ROM.ADDR_CONF_CR];
}
getConfiguredTxPower() {
return this.eeprom[ROM.ADDR_CONF_TXP];
}
getConfiguredFrequency() {
return this.eeprom[ROM.ADDR_CONF_FREQ] << 24
| this.eeprom[ROM.ADDR_CONF_FREQ + 1] << 16
| this.eeprom[ROM.ADDR_CONF_FREQ + 2] << 8
| this.eeprom[ROM.ADDR_CONF_FREQ + 3];
}
getConfiguredBandwidth() {
return this.eeprom[ROM.ADDR_CONF_BW] << 24
| this.eeprom[ROM.ADDR_CONF_BW + 1] << 16
| this.eeprom[ROM.ADDR_CONF_BW + 2] << 8
| this.eeprom[ROM.ADDR_CONF_BW + 3];
}
isInfoLocked() {
return this.eeprom[ROM.ADDR_INFO_LOCK] === ROM.INFO_LOCK_BYTE;
}
isConfigured() {
return this.eeprom[ROM.ADDR_CONF_OK] === ROM.CONF_OK_BYTE;
}
parse() {
// ensure info lock byte is set
if(!this.isInfoLocked()){
return null;
}
// convert to hex
const checksumHex = Utils.bytesToHex(this.getChecksum());
const calculatedChecksumHex = Utils.bytesToHex(this.getCalculatedChecksum());
const signatureHex = Utils.bytesToHex(this.getSignature());
// add details
var details = {
is_provisioned: true,
is_configured: this.isConfigured(),
product: this.getProduct(),
model: this.getModel(),
hardware_revision: this.getHardwareRevision(),
serial_number: Utils.unpackUInt32BE(this.getSerialNumber()),
made: Utils.unpackUInt32BE(this.getMade()),
checksum: checksumHex,
calculated_checksum: calculatedChecksumHex,
signature: signatureHex,
}
// if configured, add configuration to details
if(details.is_configured){
details = {
...details,
configured_spreading_factor: this.getConfiguredSpreadingFactor(),
configured_coding_rate: this.getConfiguredCodingRate(),
configured_tx_power: this.getConfiguredTxPower(),
configured_frequency: this.getConfiguredFrequency(),
configured_bandwidth: this.getConfiguredBandwidth(),
};
}
// if checksum in eeprom does not match checksum calculated from info, it is not provisioned
if(details.checksum !== details.calculated_checksum){
details.is_provisioned = false;
}
return details;
}
}

File diff suppressed because one or more lines are too long

16725
js/vue@3.4.26/dist/vue.global.js vendored Normal file

File diff suppressed because it is too large Load Diff

1
js/zip.min.js vendored Normal file

File diff suppressed because one or more lines are too long