///////////////////////////////////////////////////////////////////////// // Pages 6-7 unallocated ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// // // public methods // ///////////////////////////////////////////////////////////////////////// /// <summary> /// Save updated EEPROM fields to the device. /// </summary> /// <remarks> /// Only a handful of fields are recommended to be changed by users: /// /// - excitationNM /// - wavecalCoeffs /// - calibrationDate /// - calibrationBy /// - ROI /// - linearityCoeffs (not currently used) /// - userData /// - badPixels /// /// Note that the EEPROM isn't an SSD...it's not terribly fast, and there /// are a finite number of lifetime writes, so use sparingly. /// /// Due to the high risk of bricking a unit through a failed / bad EEPROM /// write, all internal calls bail at the first error in hopes of salvaging /// the unit if at all possible. /// /// That said, if you do frag your EEPROM, Wasatch has a "Model Configuration" /// utility to let you manually write EEPROM fields; contact your sales rep /// for a copy. /// </remarks> /// <returns>true on success, false on failure</returns> public bool write() { if (pages == null || pages.Count != MAX_PAGES) { logger.error("ModelConfig.write: need to perform a read first"); return(false); } if (!ParseData.writeString(model, pages[0], 0, 16)) { return(false); } if (!ParseData.writeString(serialNumber, pages[0], 16, 16)) { return(false); } if (!ParseData.writeUInt32(baudRate, pages[0], 32)) { return(false); } if (!ParseData.writeBool(hasCooling, pages[0], 36)) { return(false); } if (!ParseData.writeBool(hasBattery, pages[0], 37)) { return(false); } if (!ParseData.writeBool(hasLaser, pages[0], 38)) { return(false); } if (!ParseData.writeUInt16(excitationNM, pages[0], 39)) { return(false); } if (!ParseData.writeUInt16(slitSizeUM, pages[0], 41)) { return(false); } if (!ParseData.writeUInt16(startupIntegrationTimeMS, pages[0], 43)) { return(false); } if (!ParseData.writeInt16(startupDetectorTemperatureDegC, pages[0], 45)) { return(false); } if (!ParseData.writeByte(startupTriggeringMode, pages[0], 47)) { return(false); } if (!ParseData.writeFloat(detectorGain, pages[0], 48)) { return(false); } if (!ParseData.writeInt16(detectorOffset, pages[0], 52)) { return(false); } if (!ParseData.writeFloat(detectorGainOdd, pages[0], 54)) { return(false); } if (!ParseData.writeInt16(detectorOffsetOdd, pages[0], 58)) { return(false); } if (!ParseData.writeFloat(wavecalCoeffs[0], pages[1], 0)) { return(false); } if (!ParseData.writeFloat(wavecalCoeffs[1], pages[1], 4)) { return(false); } if (!ParseData.writeFloat(wavecalCoeffs[2], pages[1], 8)) { return(false); } if (!ParseData.writeFloat(wavecalCoeffs[3], pages[1], 12)) { return(false); } if (!ParseData.writeFloat(degCToDACCoeffs[0], pages[1], 16)) { return(false); } if (!ParseData.writeFloat(degCToDACCoeffs[1], pages[1], 20)) { return(false); } if (!ParseData.writeFloat(degCToDACCoeffs[2], pages[1], 24)) { return(false); } if (!ParseData.writeInt16(detectorTempMax, pages[1], 28)) { return(false); } if (!ParseData.writeInt16(detectorTempMin, pages[1], 30)) { return(false); } if (!ParseData.writeFloat(adcToDegCCoeffs[0], pages[1], 32)) { return(false); } if (!ParseData.writeFloat(adcToDegCCoeffs[1], pages[1], 36)) { return(false); } if (!ParseData.writeFloat(adcToDegCCoeffs[2], pages[1], 40)) { return(false); } if (!ParseData.writeInt16(thermistorResistanceAt298K, pages[1], 44)) { return(false); } if (!ParseData.writeInt16(thermistorBeta, pages[1], 46)) { return(false); } if (!ParseData.writeString(calibrationDate, pages[1], 48, 12)) { return(false); } if (!ParseData.writeString(calibrationBy, pages[1], 60, 3)) { return(false); } if (!ParseData.writeString(detectorName, pages[2], 0, 16)) { return(false); } if (!ParseData.writeUInt16(activePixelsHoriz, pages[2], 16)) { return(false); } // skip 18 if (!ParseData.writeUInt16(activePixelsVert, pages[2], 19)) { return(false); } if (!ParseData.writeUInt16((ushort)minIntegrationTimeMS, pages[2], 21)) { return(false); // for now } if (!ParseData.writeUInt16((ushort)maxIntegrationTimeMS, pages[2], 23)) { return(false); // for now } if (!ParseData.writeUInt16(actualPixelsHoriz, pages[2], 25)) { return(false); } if (!ParseData.writeUInt16(ROIHorizStart, pages[2], 27)) { return(false); } if (!ParseData.writeUInt16(ROIHorizEnd, pages[2], 29)) { return(false); } if (!ParseData.writeUInt16(ROIVertRegionStart[0], pages[2], 31)) { return(false); } if (!ParseData.writeUInt16(ROIVertRegionEnd [0], pages[2], 33)) { return(false); } if (!ParseData.writeUInt16(ROIVertRegionStart[1], pages[2], 35)) { return(false); } if (!ParseData.writeUInt16(ROIVertRegionEnd [1], pages[2], 37)) { return(false); } if (!ParseData.writeUInt16(ROIVertRegionStart[2], pages[2], 39)) { return(false); } if (!ParseData.writeUInt16(ROIVertRegionEnd [2], pages[2], 41)) { return(false); } if (!ParseData.writeFloat(linearityCoeffs[0], pages[2], 43)) { return(false); } if (!ParseData.writeFloat(linearityCoeffs[1], pages[2], 47)) { return(false); } if (!ParseData.writeFloat(linearityCoeffs[2], pages[2], 51)) { return(false); } if (!ParseData.writeFloat(linearityCoeffs[3], pages[2], 55)) { return(false); } if (!ParseData.writeFloat(linearityCoeffs[4], pages[2], 59)) { return(false); } if (!ParseData.writeFloat(laserPowerCoeffs[0], pages[3], 12)) { return(false); } if (!ParseData.writeFloat(laserPowerCoeffs[1], pages[3], 16)) { return(false); } if (!ParseData.writeFloat(laserPowerCoeffs[2], pages[3], 20)) { return(false); } if (!ParseData.writeFloat(laserPowerCoeffs[3], pages[3], 24)) { return(false); } if (!ParseData.writeFloat(maxLaserPowerMW, pages[3], 28)) { return(false); } if (!ParseData.writeFloat(minLaserPowerMW, pages[3], 32)) { return(false); } if (!ParseData.writeFloat(laserExcitationWavelengthNMFloat, pages[3], 36)) { return(false); } if (!ParseData.writeUInt32(minIntegrationTimeMS, pages[3], 40)) { return(false); } if (!ParseData.writeUInt32(maxIntegrationTimeMS, pages[3], 44)) { return(false); } Array.Copy(userData, pages[4], userData.Length); // note that we write the positional, error-prone array (which is // user -writable), not the List or SortedSet caches for (int i = 0; i < badPixels.Length; i++) { if (!ParseData.writeInt16(badPixels[i], pages[5], i * 2)) { return(false); } } if (!ParseData.writeString(productConfiguration, pages[5], 30, 16)) { return(false); } // regardless of what the "read" format was (this.format), we always WRITE the latest format version. pages[0][63] = FORMAT; for (short page = 0; page < pages.Count; page++) { bool ok = false; if (spectrometer.isARM) { logger.hexdump(pages[page], String.Format("writing page {0} [ARM]: ", page)); ok = spectrometer.sendCmd( opcode: Opcodes.SECOND_TIER_COMMAND, wValue: (ushort)Opcodes.SET_MODEL_CONFIG_ARM, wIndex: (ushort)page, buf: pages[page]); } else { const uint DATA_START = 0x3c00; // from Wasatch Stroker Console's EnhancedStroker.SetModelInformation() ushort pageOffset = (ushort)(DATA_START + page * 64); logger.hexdump(pages[page], String.Format("writing page {0} to offset {1} [FX2]: ", page, pageOffset)); ok = spectrometer.sendCmd( opcode: Opcodes.SET_MODEL_CONFIG_FX2, wValue: pageOffset, wIndex: 0, buf: pages[page]); } if (!ok) { logger.error("ModelConfig.write: failed to save page {0}", page); return(false); } logger.debug("ModelConfig: wrote EEPROM page {0}", page); } return(true); }