diff --git a/constants.js b/constants.js index 461451a..af0d86c 100644 --- a/constants.js +++ b/constants.js @@ -147,13 +147,45 @@ exports.packetLengthVersions = [{ packetLength: 62 }]; +const FIRMWARE_OFFICIAL_RELEASE = 0; +const FIRMWARE_OFFICIAL_RELEASE_CANDIDATE = 1; +const FIRMWARE_CUSTOM_EQUIVALENT = 2; +const FIRMWARE_UNSUPPORTED = 3; +exports.FIRMWARE_OFFICIAL_RELEASE = FIRMWARE_OFFICIAL_RELEASE; +exports.FIRMWARE_OFFICIAL_RELEASE_CANDIDATE = FIRMWARE_OFFICIAL_RELEASE_CANDIDATE; +exports.FIRMWARE_CUSTOM_EQUIVALENT = FIRMWARE_CUSTOM_EQUIVALENT; +exports.FIRMWARE_UNSUPPORTED = FIRMWARE_UNSUPPORTED; + +const EQUIVALENCE_REGEX = /E[0-9]+\.[0-9]+\.[0-9]+/g; +exports.EQUIVALENCE_REGEX = EQUIVALENCE_REGEX; + /* Remove trailing digit and check if description is in list of supported firmware descriptions */ -exports.isSupportedFirmwareDescription = (desc) => { +exports.getFirmwareClassification = (desc) => { + + /* If official firmware or a release candidate of the official firmware */ + + if (desc === 'AudioMoth-Firmware-Basic') { + + return FIRMWARE_OFFICIAL_RELEASE; + + } + + if (desc.replace(/-RC\d+$/, '-RC') === 'AudioMoth-Firmware-Basic-RC') { + + return FIRMWARE_OFFICIAL_RELEASE_CANDIDATE; + + } + + const foundEquivalence = desc.match(EQUIVALENCE_REGEX); + + if (foundEquivalence) { + + return FIRMWARE_CUSTOM_EQUIVALENT; - const supportedFirmwareDescs = ['AudioMoth-Firmware-Basic', 'AudioMoth-Firmware-Basic-RC']; + } - return supportedFirmwareDescs.includes(desc.replace(/\d+$/, '')); + return FIRMWARE_UNSUPPORTED; }; diff --git a/expansion/expansion.html b/expansion/expansion.html index 422dc4e..95827fb 100644 --- a/expansion/expansion.html +++ b/expansion/expansion.html @@ -28,7 +28,7 @@
-
+
@@ -106,7 +106,7 @@
-
+
diff --git a/expansion/uiExpansion.js b/expansion/uiExpansion.js index 5d09d87..1689220 100644 --- a/expansion/uiExpansion.js +++ b/expansion/uiExpansion.js @@ -159,8 +159,6 @@ function updateFileMaxLengthUI (elementClass, checkbox) { function expandFiles () { - let successCount, errorCount, cancelled, response, filePath, fileContent, maxLength, outputPath, prefix, errorFileLocation; - if (!files) { return; @@ -172,16 +170,20 @@ function expandFiles () { const maxLengthRadioName = expansionType === 'DURATION' ? 'duration-max-length-radio' : 'event-max-length-radio'; - successCount = 0; - errorCount = 0; + let successCount = 0; + let errorCount = 0; const errors = []; const errorFiles = []; + var errorFilePath; + + let maxLength = null; + for (let i = 0; i < files.length; i++) { /* If progress bar is closed, the expansion task is considered cancelled. This will contact the main thread and ask if that has happened */ - cancelled = electron.ipcRenderer.sendSync('poll-expansion-cancelled'); + const cancelled = electron.ipcRenderer.sendSync('poll-expansion-cancelled'); if (cancelled) { @@ -225,10 +227,10 @@ function expandFiles () { /* Check if the optional prefix/output directory setttings are being used. If left as null, expander will put expanded file(s) in the same directory as the input with no prefix */ - outputPath = outputCheckbox.checked ? outputDir : null; - prefix = (prefixCheckbox.checked && prefixInput.value !== '') ? prefixInput.value : null; + const outputPath = outputCheckbox.checked ? outputDir : null; + const prefix = (prefixCheckbox.checked && prefixInput.value !== '') ? prefixInput.value : null; - response = audiomothUtils.expand(files[i], outputPath, prefix, expansionType, maxLength, generateSilentFiles, alignToSecondTransitions, (progress) => { + const response = audiomothUtils.expand(files[i], outputPath, prefix, expansionType, maxLength, generateSilentFiles, alignToSecondTransitions, (progress) => { electron.ipcRenderer.send('set-expansion-bar-progress', i, progress, path.basename(files[i])); @@ -240,7 +242,7 @@ function expandFiles () { } else { - /* Keep track of the errors to write to the log at the end */ + /* Add error to log file */ errorCount++; errors.push(response.error); @@ -248,42 +250,40 @@ function expandFiles () { electron.ipcRenderer.send('set-expansion-bar-error', path.basename(files[i])); - ui.sleep(3000); + if (errorCount === 1) { - } + const errorFileLocation = outputCheckbox.checked ? outputDir : path.dirname(errorFiles[0]); - } + errorFilePath = path.join(errorFileLocation, 'ERRORS.TXT'); - /* Build error file */ + } - if (errorCount > 0) { + let fileContent = ''; - errorFileLocation = outputCheckbox.checked ? outputDir : path.dirname(errorFiles[0]); + for (let j = 0; j < errorCount; j++) { - filePath = path.join(errorFileLocation, 'ERRORS.TXT'); + fileContent += path.basename(errorFiles[j]) + ' - ' + errors[j] + '\n'; - fileContent = ''; + } - for (let j = 0; j < errorCount; j++) { + try { - fileContent += path.basename(errorFiles[j]) + ' - ' + errors[j] + '\n'; + fs.writeFileSync(errorFilePath, fileContent); - } + console.log('Error summary written to ' + errorFilePath); - try { + } catch (err) { - fs.writeFileSync(filePath, fileContent); + console.error(err); + electron.ipcRenderer.send('set-expansion-bar-completed', successCount, errorCount, true); + return; - } catch (err) { + } - console.error(err); - electron.ipcRenderer.send('set-expansion-bar-completed', successCount, errorCount, true); - return; + ui.sleep(3000); } - console.log('Error summary written to ' + filePath); - } /* Notify main thread that expansion is complete so progress bar is closed */ @@ -300,7 +300,7 @@ electron.ipcRenderer.on('expansion-summary-closed', enableUI); function updateInputDirectoryDisplay (directoryArray) { - if (directoryArray.length === 0 || !directoryArray) { + if (!directoryArray || directoryArray.length === 0) { fileLabel.innerHTML = 'No AudioMoth T.WAV files selected.'; expandButton.disabled = true; diff --git a/expansion/uiSplit.js b/expansion/uiSplit.js index ba54b13..5c587f9 100644 --- a/expansion/uiSplit.js +++ b/expansion/uiSplit.js @@ -100,24 +100,24 @@ function enableUI () { function splitFiles () { - let successCount, errorCount, cancelled, response, filePath, fileContent, maxLength, outputPath, prefix, errorFileLocation; - if (!files) { return; } - successCount = 0; - errorCount = 0; + let successCount = 0; + let errorCount = 0; const errors = []; const errorFiles = []; + let errorFilePath; + for (let i = 0; i < files.length; i++) { /* If progress bar is closed, the split task is considered cancelled. This will contact the main thread and ask if that has happened */ - cancelled = electron.ipcRenderer.sendSync('poll-split-cancelled'); + const cancelled = electron.ipcRenderer.sendSync('poll-split-cancelled'); if (cancelled) { @@ -131,7 +131,7 @@ function splitFiles () { electron.ipcRenderer.send('set-split-bar-progress', i, 0, path.basename(files[i])); - maxLength = MAX_LENGTHS[ui.getSelectedRadioValue('max-length-radio')]; + const maxLength = MAX_LENGTHS[ui.getSelectedRadioValue('max-length-radio')]; console.log('Splitting:', files[i]); console.log('Maximum file length:', maxLength); @@ -140,10 +140,10 @@ function splitFiles () { /* Check if the optional prefix/output directory setttings are being used. If left as null, splitter will put file(s) in the same directory as the input with no prefix */ - outputPath = outputCheckbox.checked ? outputDir : null; - prefix = (prefixCheckbox.checked && prefixInput.value !== '') ? prefixInput.value : null; + const outputPath = outputCheckbox.checked ? outputDir : null; + const prefix = (prefixCheckbox.checked && prefixInput.value !== '') ? prefixInput.value : null; - response = audiomothUtils.split(files[i], outputPath, prefix, maxLength, (progress) => { + const response = audiomothUtils.split(files[i], outputPath, prefix, maxLength, (progress) => { electron.ipcRenderer.send('set-split-bar-progress', i, progress, path.basename(files[i])); @@ -155,7 +155,7 @@ function splitFiles () { } else { - /* Keep track of the errors to write to the log at the end */ + /* Add error to log file */ errorCount++; errors.push(response.error); @@ -163,42 +163,40 @@ function splitFiles () { electron.ipcRenderer.send('set-split-bar-error', path.basename(files[i])); - ui.sleep(3000); + if (errorCount === 1) { - } + const errorFileLocation = outputCheckbox.checked ? outputDir : path.dirname(errorFiles[0]); - } + errorFilePath = path.join(errorFileLocation, 'ERRORS.TXT'); - /* Build error file */ + } - if (errorCount > 0) { + let fileContent = ''; - errorFileLocation = outputCheckbox.checked ? outputDir : path.dirname(errorFiles[0]); + for (let j = 0; j < errorCount; j++) { - filePath = path.join(errorFileLocation, 'ERRORS.TXT'); + fileContent += path.basename(errorFiles[j]) + ' - ' + errors[j] + '\n'; - fileContent = ''; + } - for (let j = 0; j < errorCount; j++) { + try { - fileContent += path.basename(errorFiles[j]) + ' - ' + errors[j] + '\n'; + fs.writeFileSync(errorFilePath, fileContent); - } + console.log('Error summary written to ' + errorFilePath); - try { + } catch (err) { - fs.writeFileSync(filePath, fileContent); + console.error(err); + electron.ipcRenderer.send('set-split-bar-completed', successCount, errorCount, true); + return; - } catch (err) { + } - console.error(err); - electron.ipcRenderer.send('set-split-bar-completed', successCount, errorCount, true); - return; + ui.sleep(3000); } - console.log('Error summary written to ' + filePath); - } /* Notify main thread that split is complete so progress bar is closed */ diff --git a/package.json b/package.json index 75824f2..2eb1b79 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "AudioMoth-Config", - "version": "1.5.0", + "version": "1.5.1", "description": "The configuration app for the AudioMoth acoustic monitoring device.", "main": "main.js", "author": "openacousticdevices.info", @@ -45,6 +45,8 @@ }, "nsis": { "createDesktopShortcut": true, + "oneClick": false, + "allowToChangeInstallationDirectory": true, "artifactName": "AudioMothConfigurationAppSetup${version}.exe", "shortcutName": "AudioMoth Configuration App", "uninstallDisplayName": "AudioMoth Configuration App ${version}" @@ -56,17 +58,17 @@ }, "devDependencies": { "electron": "8.5.2", - "electron-builder": "^22.9.1", - "eslint": "^6.8.0", + "electron-builder": "^22.11.7", + "eslint": "^7.27.0", "eslint-config-standard": "^14.1.0", "eslint-plugin-import": "^2.22.1", "eslint-plugin-node": "^10.0.0", - "eslint-plugin-promise": "^4.2.1", + "eslint-plugin-promise": "^4.3.1", "eslint-plugin-standard": "^4.0.2" }, "dependencies": { "audiomoth-hid": "^2.1.0", - "audiomoth-utils": "^1.0.0", + "audiomoth-utils": "^1.0.3", "bootstrap": "4.3.1", "bootstrap-slider": "^10.6.2", "electron-debug": "3.0.1", diff --git a/settings/filtering.html b/settings/filtering.html index 9a0ee58..92f6c9c 100644 --- a/settings/filtering.html +++ b/settings/filtering.html @@ -106,43 +106,43 @@
- +
- - - - - - - - + + + + + + + +
012510153060012510153060
Minimum trigger duration (s): - + - + - + - + - + - + - + - +
diff --git a/settings/uiFiltering.js b/settings/uiFiltering.js index 93cc6dc..bd68452 100644 --- a/settings/uiFiltering.js +++ b/settings/uiFiltering.js @@ -42,8 +42,8 @@ const amplitudeThresholdingMinLabel = document.getElementById('amplitude-thresho const amplitudeThresholdingCheckbox = document.getElementById('amplitude-thresholding-checkbox'); const amplitudeThresholdingSlider = new Slider('#amplitude-thresholding-slider', {}); const amplitudeThresholdingLabel = document.getElementById('amplitude-thresholding-label'); -const amplitudeThresholdingTimeTable = document.getElementById('trigger-time-table'); -const amplitudeThresholdingRadioButtons = document.getElementsByName('trigger-time-radio'); +const amplitudeThresholdingDurationTable = document.getElementById('amplitude-thresholding-duration-table'); +const amplitudeThresholdingRadioButtons = document.getElementsByName('amplitude-thresholding-duration-radio'); const VALID_AMPLITUDE_VALUES = [0, 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 36, 40, 44, 48, 52, 56, 60, 64, 72, 80, 88, 96, 104, 112, 120, 128, 144, 160, 176, 192, 208, 224, 240, 256, 288, 320, 352, 384, 416, 448, 480, 512, 576, 640, 704, 768, 832, 896, 960, 1024, 1152, 1280, 1408, 1536, 1664, 1792, 1920, 2048, 2304, 2560, 2816, 3072, 3328, 3584, 3840, 4096, 4608, 5120, 5632, 6144, 6656, 7168, 7680, 8192, 9216, 10240, 11264, 12288, 13312, 14336, 15360, 16384, 18432, 20480, 22528, 24576, 26624, 28672, 30720, 32768]; @@ -51,6 +51,9 @@ const VALID_AMPLITUDE_VALUES = [0, 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24 var displayDurationWarning = true; +/* Only scale filter sliders if the filter has been enabled this session */ +var filterHasBeenEnabled = false; + const FILTER_LOW = 0; const FILTER_BAND = 1; const FILTER_HIGH = 2; @@ -163,6 +166,12 @@ function updateFilterSliders () { function updateFilterLabel () { + if (!filterCheckbox.checked) { + + return; + + } + let currentBandPassLower, currentBandPassHigher, currentHighPass, currentLowPass; const filterIndex = getSelectedRadioValue('filter-radio'); @@ -356,6 +365,8 @@ exports.setFilters = (enabled, lowerSliderValue, higherSliderValue, filterType) filterCheckbox.checked = enabled; + filterHasBeenEnabled = enabled; + if (enabled) { switch (filterType) { @@ -527,7 +538,7 @@ exports.getAmplitudeThresholdScaleIndex = () => { function getMinimumAmplitudeThresholdDuration () { - return parseInt(getSelectedRadioValue('trigger-time-radio')); + return parseInt(getSelectedRadioValue('amplitude-thresholding-duration-radio')); } @@ -546,7 +557,7 @@ function updateAmplitudeThresholdingUI () { amplitudeThresholdingLabel.style.color = ''; updateAmplitudeThresholdingLabel(); - amplitudeThresholdingTimeTable.style.color = ''; + amplitudeThresholdingDurationTable.style.color = ''; for (let i = 0; i < amplitudeThresholdingRadioButtons.length; i++) { @@ -563,7 +574,7 @@ function updateAmplitudeThresholdingUI () { amplitudeThresholdingLabel.style.color = 'grey'; amplitudeThresholdingLabel.textContent = 'All audio will be written to a .WAV file.'; - amplitudeThresholdingTimeTable.style.color = 'grey'; + amplitudeThresholdingDurationTable.style.color = 'grey'; for (let i = 0; i < amplitudeThresholdingRadioButtons.length; i++) { @@ -670,7 +681,7 @@ function roundToSliderStep (value, step) { /* Update UI according to new sample rate selection */ -exports.sampleRateChange = () => { +function sampleRateChange () { const sampleRateIndex = getSelectedRadioValue('sample-rate-radio'); @@ -691,32 +702,57 @@ exports.sampleRateChange = () => { lowPassFilterSlider.setAttribute('step', FILTER_SLIDER_STEPS[sampleRateIndex]); bandPassFilterSlider.setAttribute('step', FILTER_SLIDER_STEPS[sampleRateIndex]); - /* Validate current band-pass filter values */ + /* Get current slider values */ const currentBandPassHigher = Math.max(...bandPassFilterSlider.getValue()); const currentBandPassLower = Math.min(...bandPassFilterSlider.getValue()); + const currentLowPass = lowPassFilterSlider.getValue(); + const currentHighPass = highPassFilterSlider.getValue(); - const newBandPassLower = currentBandPassLower > maxFreq ? 0 : currentBandPassLower; + if (filterHasBeenEnabled) { - const newBandPassHigher = currentBandPassHigher > maxFreq ? maxFreq : currentBandPassHigher; + /* Validate current band-pass filter values */ - setBandPass(roundToSliderStep(Math.max(newBandPassHigher, newBandPassLower), FILTER_SLIDER_STEPS[sampleRateIndex]), roundToSliderStep(Math.min(newBandPassHigher, newBandPassLower), FILTER_SLIDER_STEPS[sampleRateIndex])); + const newBandPassLower = currentBandPassLower > maxFreq ? 0 : currentBandPassLower; + const newBandPassHigher = currentBandPassHigher > maxFreq ? maxFreq : currentBandPassHigher; + setBandPass(roundToSliderStep(Math.max(newBandPassHigher, newBandPassLower), FILTER_SLIDER_STEPS[sampleRateIndex]), roundToSliderStep(Math.min(newBandPassHigher, newBandPassLower), FILTER_SLIDER_STEPS[sampleRateIndex])); - /* Validate current low-pass filter value */ + /* Validate current low-pass filter value */ - const currentLowPass = lowPassFilterSlider.getValue(); - const newLowPass = currentLowPass > maxFreq ? maxFreq : currentLowPass; - setLowPassSliderValue(roundToSliderStep(newLowPass, FILTER_SLIDER_STEPS[sampleRateIndex])); + const newLowPass = currentLowPass > maxFreq ? maxFreq : currentLowPass; + setLowPassSliderValue(roundToSliderStep(newLowPass, FILTER_SLIDER_STEPS[sampleRateIndex])); - /* Validate current high-pass filter value */ + /* Validate current high-pass filter value */ - const currentHighPass = highPassFilterSlider.getValue(); - const newHighPass = currentHighPass > maxFreq ? maxFreq : currentHighPass; - setHighPassSliderValue(roundToSliderStep(newHighPass, FILTER_SLIDER_STEPS[sampleRateIndex])); + const newHighPass = currentHighPass > maxFreq ? maxFreq : currentHighPass; + setHighPassSliderValue(roundToSliderStep(newHighPass, FILTER_SLIDER_STEPS[sampleRateIndex])); + + } else { + + /* Set high/low-pass sliders to 1/4 and 3/4 of the bar if filtering has not yet been enabled */ + + const newLowPassFreq = maxFreq / 4; + const newHighPassFreq = 3 * maxFreq / 4; + + /* Set band-pass filter values */ + + setBandPass(roundToSliderStep(newHighPassFreq, FILTER_SLIDER_STEPS[sampleRateIndex]), roundToSliderStep(newLowPassFreq, FILTER_SLIDER_STEPS[sampleRateIndex])); + + /* Set low-pass filter value */ + + setLowPassSliderValue(roundToSliderStep(newHighPassFreq, FILTER_SLIDER_STEPS[sampleRateIndex])); + + /* Set high-pass filter value */ + + setHighPassSliderValue(roundToSliderStep(newLowPassFreq, FILTER_SLIDER_STEPS[sampleRateIndex])); + + } updateFilterLabel(); -}; +} + +exports.sampleRateChange = sampleRateChange; /* Update the labels either side of the amplitude threshold scale */ @@ -815,6 +851,14 @@ exports.prepareUI = (changeFunction, checkRecordingDurationFunction) => { filterCheckbox.addEventListener('change', () => { updateFilterLabel(); + + if (filterCheckbox.checked) { + + filterHasBeenEnabled = true; + sampleRateChange(); + + } + updateFilterUI(); }); diff --git a/uiIndex.js b/uiIndex.js index 2b13024..3f1c4bb 100644 --- a/uiIndex.js +++ b/uiIndex.js @@ -133,6 +133,18 @@ function requestBatteryState () { } +function getEquivalentVersion (desc) { + + const foundEquivalence = desc.match(constants.EQUIVALENCE_REGEX)[0]; + + const regex1 = /[0-9]+/g; + const equivalentVersionStrArray = foundEquivalence.match(regex1); + const equivalentVersionArray = [parseInt(equivalentVersionStrArray[0]), parseInt(equivalentVersionStrArray[1]), parseInt(equivalentVersionStrArray[2])]; + + return equivalentVersionArray; + +} + /* Request, receive and handle packet containing the current firmware version and check the version/description to see if a warning message should be shown */ function requestFirmwareVersion () { @@ -152,32 +164,6 @@ function requestFirmwareVersion () { firmwareVersion = versionArr[0] + '.' + versionArr[1] + '.' + versionArr[2]; - if (!versionWarningShown) { - - if (!constants.isSupportedFirmwareDescription(firmwareDescription)) { - - versionWarningShown = true; - - dialog.showMessageBoxSync(BrowserWindow.getFocusedWindow(), { - type: 'warning', - title: 'Unsupported firmware', - message: 'The firmware installed on your AudioMoth may not be supported by this version of the AudioMoth Configuration App.' - }); - - } else if (isOlderSemanticVersion(versionArr, constants.latestFirmwareVersionArray)) { - - versionWarningShown = true; - - dialog.showMessageBoxSync(BrowserWindow.getFocusedWindow(), { - type: 'warning', - title: 'Firmware update recommended', - message: 'Update to at least version ' + constants.latestFirmwareVersionString + ' of AudioMoth-Firmware-Basic to use all the features of this version of the AudioMoth Configuration App.' - }); - - } - - } - requestBatteryState(); } @@ -282,6 +268,70 @@ function getAudioMothPacket () { } +/* Check the version and description to see if the firmware is compatible or equivalent to an equivalent version of firmware */ + +function checkVersionCompatibilty () { + + /* This version array may be replaced if the firmware is custom with an equivalent official version */ + + let trueVersionArr = firmwareVersion.split('.'); + + const classification = constants.getFirmwareClassification(firmwareDescription); + + let versionWarningText, versionWarningTitle; + + switch (classification) { + + case constants.FIRMWARE_OFFICIAL_RELEASE: + case constants.FIRMWARE_OFFICIAL_RELEASE_CANDIDATE: + versionWarningTitle = 'Firmware update recommended'; + versionWarningText = 'Update to at least version ' + constants.latestFirmwareVersionString + ' of AudioMoth-Firmware-Basic to use all the features of this version of the AudioMoth Configuration App.'; + break; + + case constants.FIRMWARE_CUSTOM_EQUIVALENT: + trueVersionArr = getEquivalentVersion(firmwareDescription); + + versionWarningTitle = 'Unsupported features'; + versionWarningText = 'This firmware does not allow you to use all the features of this version of the AudioMoth Configuration App.'; + break; + + case constants.FIRMWARE_UNSUPPORTED: + if (!versionWarningShown) { + + versionWarningShown = true; + + dialog.showMessageBoxSync(BrowserWindow.getFocusedWindow(), { + type: 'warning', + title: 'Unsupported firmware', + message: 'The firmware installed on your AudioMoth may not be supported by this version of the AudioMoth Configuration App.' + }); + + } + + return; + + } + + /* If OFFICIAL_RELEASE, OFFICIAL_RELEASE_CANDIDATE or CUSTOM_EQUIVALENT */ + + if (!versionWarningShown) { + + if (isOlderSemanticVersion(trueVersionArr, constants.latestFirmwareVersionArray)) { + + versionWarningShown = true; + + dialog.showMessageBoxSync(BrowserWindow.getFocusedWindow(), { + type: 'warning', + title: versionWarningTitle, + message: versionWarningText + }); + + } + + } + +} + /* Fill in time/date, ID, battery state, firmware version */ function usePacketValues () { @@ -310,6 +360,8 @@ function usePacketValues () { updateBatteryDisplay(batteryState); + setTimeout(checkVersionCompatibilty, 100); + } } @@ -326,6 +378,34 @@ function writeLittleEndianBytes (buffer, start, byteCount, value) { } +function getTrueFirmwareVersion () { + + let trueFirmwareVersion = firmwareVersion.split('.'); + + /* Check for equivalent if using custom firmware */ + + const classification = constants.getFirmwareClassification(firmwareDescription); + + if (classification === constants.FIRMWARE_CUSTOM_EQUIVALENT) { + + trueFirmwareVersion = getEquivalentVersion(firmwareDescription); + console.log('Treating firmware as equivalent version: ' + trueFirmwareVersion[0] + '.' + trueFirmwareVersion[1] + '.' + trueFirmwareVersion[2]); + + } + + /* Use latest version if custom */ + + if (classification === constants.FIRMWARE_UNSUPPORTED) { + + trueFirmwareVersion = constants.latestFirmwareVersionArray; + console.log('Unsupported firmware, treating firmware as latest version'); + + } + + return trueFirmwareVersion; + +} + /* Send configuration packet to AudioMoth */ function sendPacket (packet) { @@ -357,13 +437,14 @@ function sendPacket (packet) { let packetLength = Math.min(packet.length, data.length - 1); + const trueFirmwareVersion = getTrueFirmwareVersion(); + for (let k = 0; k < constants.packetLengthVersions.length; k++) { const possibleFirmwareVersion = constants.packetLengthVersions[k].firmwareVersion; - if (isOlderSemanticVersion(firmwareVersion.split('.'), possibleFirmwareVersion.split('.'))) { + if (isOlderSemanticVersion(trueFirmwareVersion, possibleFirmwareVersion.split('.'))) { - console.log('Using packet length', packetLength); break; } @@ -372,6 +453,8 @@ function sendPacket (packet) { } + console.log('Using packet length', packetLength); + /* Verify the packet sent was read correctly by the device by comparing it to the returned packet */ for (let j = 0; j < packetLength; j++) { @@ -451,7 +534,11 @@ function configureDevice () { packet[index++] = settings.gain; - const configurations = (isOlderSemanticVersion(firmwareVersion.split('.'), ['1', '4', '4']) && settings.sampleRateIndex < 3) ? constants.oldConfigurations : constants.configurations; + /* If equivalent firmware or unsupported firmware is present, use correct firmware version */ + + const trueFirmwareVersion = getTrueFirmwareVersion(); + + const configurations = (isOlderSemanticVersion(trueFirmwareVersion, ['1', '4', '4']) && settings.sampleRateIndex < 3) ? constants.oldConfigurations : constants.configurations; const sampleRateConfiguration = configurations[settings.sampleRateIndex];