diff --git a/config/sitemap.json b/config/sitemap.json
index 8a7eab16f..b52ccb041 100644
--- a/config/sitemap.json
+++ b/config/sitemap.json
@@ -9913,6 +9913,10 @@
"reference/device-os/libraries/q/QuectelTowerRK.md": {
"hash": "8fc4b68ee55fa303089c3158f990a73461be550ea335770fabfc8a8e147a4a7a",
"date": "2025-11-03"
+ },
+ "tools/developer-tools/module-version.md": {
+ "hash": "b6061154a3413973f4e1451c2bf16b5215017fcc431c640507218b64701ec50b",
+ "date": "2025-11-04"
}
}
}
\ No newline at end of file
diff --git a/src/assets/js/api-helper-extras.js b/src/assets/js/api-helper-extras.js
index 9cc320c09..6e31e2ab2 100644
--- a/src/assets/js/api-helper-extras.js
+++ b/src/assets/js/api-helper-extras.js
@@ -3476,6 +3476,210 @@ $(document).ready(function() {
}
+ $('.apiHelperModuleVersion').each(function() {
+ const thisPartial = $(this);
+
+ const moduleVersionHelper = {
+ outputWidth: '440px',
+ };
+
+ const moduleVersionPlatformElem = $(thisPartial).find('.moduleVersionPlatform');
+ const moduleVersion1Elem = $(thisPartial).find('.moduleVersion1');
+ const moduleVersion2Elem = $(thisPartial).find('.moduleVersion2');
+ const moduleVersionBodyElem = $(thisPartial).find('.moduleVersionBody');
+
+ const updateOutput = async function() {
+ const platformName = $(moduleVersionPlatformElem).val();
+ const ver1 = $(moduleVersion1Elem).val();
+ const ver2 = $(moduleVersion2Elem).val();
+
+ let verInfo1;
+ try {
+ const fetchRes = await fetch('/assets/files/device-restore/' + ver1 + '/' + platformName + '.json');
+ verInfo1 = await fetchRes.json();
+ }
+ catch(e) {
+ }
+
+ let verInfo2;
+ if (ver2 != '-') {
+ try {
+ let fetchRes = await fetch('/assets/files/device-restore/' + ver2 + '/' + platformName + '.json');
+ verInfo2 = await fetchRes.json();
+ }
+ catch(e) {
+ }
+ }
+
+ $(thisPartial).find('.moduleVersionHead1').text(ver1);
+ if (verInfo2) {
+ $(thisPartial).find('.moduleVersionHead2').text(ver2);
+ }
+ else {
+ $(thisPartial).find('.moduleVersionHead2').text('');
+ }
+
+ let moduleFunctions = [];
+ for(const key in verInfo1) {
+ const prefixInfo = verInfo1[key].prefixInfo;
+
+ moduleFunctions.push({
+ moduleFunction: prefixInfo.moduleFunction,
+ moduleIndex: prefixInfo.moduleIndex,
+ key,
+ });
+ }
+ console.log('moduleFunctions', moduleFunctions);
+
+ $(moduleVersionBodyElem).empty();
+
+ const fields = [
+ {
+ title: 'Module Version',
+ key: 'moduleVersion'
+ },
+ ];
+
+ const columnWidths = {
+ module: '150px',
+ fieldTitle: '150px',
+ value: '100px',
+ };
+
+
+ for(const key in verInfo1) {
+ let trElem = document.createElement('tr');
+
+ let tdElem;
+ tdElem = document.createElement('td');
+ $(tdElem).css('width', columnWidths.module);
+ $(tdElem).text(key);
+ $(trElem).append(tdElem);
+ $(moduleVersionBodyElem).append(trElem);
+
+ for(const fieldObj of fields) {
+ trElem = document.createElement('tr');
+
+ // Spacer below module name
+ tdElem = document.createElement('td');
+ $(tdElem).css('width', columnWidths.module);
+ $(trElem).append(tdElem);
+
+ tdElem = document.createElement('td');
+ $(tdElem).css('width', columnWidths.fieldTitle);
+ $(tdElem).text(fieldObj.title);
+ $(trElem).append(tdElem);
+
+ for(const values of [verInfo1, verInfo2]) {
+ if (!values || !values[key].prefixInfo) {
+ continue;
+ }
+
+ tdElem = document.createElement('td');
+ $(tdElem).css('width', columnWidths.value);
+ $(tdElem).text(values[key].prefixInfo[fieldObj.key]);
+ $(trElem).append(tdElem);
+ }
+
+ $(moduleVersionBodyElem).append(trElem);
+ }
+
+
+ }
+
+ if (verInfo2) {
+ }
+
+
+ }
+
+ const updateVersionSelect = async function() {
+ $(moduleVersion1Elem).empty();
+ $(moduleVersion2Elem).empty();
+
+ {
+ const optionElem = document.createElement('option');
+ $(optionElem).text('None');
+ $(optionElem).val('-');
+
+ $(moduleVersion2Elem).append(optionElem);
+ }
+
+ const platformName = $(moduleVersionPlatformElem).val();
+
+ for(const verString of moduleVersionHelper.deviceRestore.versionsZipByPlatform[platformName]) {
+ const optionElem = document.createElement('option');
+ $(optionElem).text(verString);
+ $(optionElem).val(verString);
+
+ $(moduleVersion1Elem).append(optionElem);
+ $(moduleVersion2Elem).append(optionElem.cloneNode(true));
+ }
+
+
+ $(moduleVersion1Elem).on('change', updateOutput);
+ $(moduleVersion2Elem).on('change', updateOutput);
+ updateOutput();
+ }
+
+ const run = async function() {
+
+ const promises = [];
+
+ /*
+ promises.push(new Promise(function(resolve, reject) {
+ apiHelper.getCarriersJson().then(function(carriersJson) {
+ moduleVersionHelper.carriersJson = carriersJson;
+
+ resolve();
+ });
+ }));
+ */
+
+ promises.push(new Promise(function(resolve, reject) {
+ fetch('/assets/files/deviceRestore.json')
+ .then(response => response.json())
+ .then(function(data) {
+
+ moduleVersionHelper.deviceRestore = data;
+
+ resolve();
+ });
+ }));
+
+ await Promise.all(promises);
+
+ console.log('moduleVersionHelper', moduleVersionHelper);
+
+ moduleVersionHelper.devicePlatformNames = [];
+ for(const platformObj of moduleVersionHelper.deviceRestore.platforms) {
+ if (!platformObj.discontinued) {
+ moduleVersionHelper.devicePlatformNames.push(platformObj.name);
+ }
+ }
+ moduleVersionHelper.devicePlatformNames.sort(function(a, b) {
+ const aObj = moduleVersionHelper.deviceRestore.platforms.find(e => e.name == a);
+ const bObj = moduleVersionHelper.deviceRestore.platforms.find(e => e.name == b);
+
+ return aObj.title.localeCompare(bObj.title);
+ })
+
+ // Load platform popup
+ for(const name of moduleVersionHelper.devicePlatformNames) {
+ const platformObj = moduleVersionHelper.deviceRestore.platforms.find(e => e.name == name)
+
+ const optionElem = document.createElement('option');
+ $(optionElem).text(platformObj.title + ' (' + platformObj.id + ')');
+ $(optionElem).val(name);
+
+ $(moduleVersionPlatformElem).append(optionElem);
+ }
+ $(moduleVersionPlatformElem).on('change', updateVersionSelect)
+ await updateVersionSelect();
+ };
+ run();
+ })
+
});
diff --git a/src/content/tools/developer-tools/module-version.md b/src/content/tools/developer-tools/module-version.md
new file mode 100644
index 000000000..1231f9ce9
--- /dev/null
+++ b/src/content/tools/developer-tools/module-version.md
@@ -0,0 +1,11 @@
+---
+title: Module version tool
+columns: two
+layout: commonTwo.hbs
+description: Tools for comparing module version numbers
+includeDefinitions: [api-helper, api-helper-extras]
+---
+
+# {{title}}
+
+{{> module-version}}
\ No newline at end of file
diff --git a/src/content/tools/newMenu.json b/src/content/tools/newMenu.json
index 39d34501e..a27a6af2e 100644
--- a/src/content/tools/newMenu.json
+++ b/src/content/tools/newMenu.json
@@ -100,6 +100,10 @@
{
"dir": "file-to-code",
"title": "File to code generator"
+ },
+ {
+ "dir": "module-version",
+ "title": "Module version tool"
}
]
},
diff --git a/templates/partials/module-version.hbs b/templates/partials/module-version.hbs
new file mode 100644
index 000000000..ceea1e515
--- /dev/null
+++ b/templates/partials/module-version.hbs
@@ -0,0 +1,40 @@
+
+
+
+
+
+
+ | Platform |
+
+ |
+ |
+
+
+ | Version |
+ |
+ |
+
+
+ | Version to compare to |
+ |
+ |
+
+
+
+
+
+
+
+
+