using System; using System.Text; namespace NKH.MindSqualls { /// /// Abstract class representing the NXT communication protocol. /// /// /// The communication protocol for the NXT brick is specified in the documents: /// /// Lego Mindstorms NXT,
/// Bluetooth Developer Kit,
/// Appendix 1: LEGO MINDSTORMS NXT Communication protocol
/// - and:
/// Appendix 2: LEGO MINDSTORMS NXT Direct commands
/// /// - which can be downloaded at:
/// http://mindstorms.lego.com/overview/NXTreme.aspx
/// /// A special thanks goes to Bram Fokke for his NXT# project:
/// http://nxtsharp.fokke.net/
/// /// Without his work, I doubt very much if my own work would have gotten off the ground. I have even st... ehem... borrowed a bit of his code here and there. However the major part of the code is my own. ///
public abstract class NxtCommunicationProtocol { /// /// Constructor. /// public NxtCommunicationProtocol() : base() { } #region Communication. /// /// Flag indicating if a reply should always be recieved. /// public bool ReplyRequired = false; /// /// Connect to the NXT brick. /// public abstract void Connect(); /// /// Disconnect from the NXT brick. /// public abstract void Disconnect(); /// /// Returns a boolean indicating if the NXT brick is connected. /// public abstract bool IsConnected { get; } /// /// Send a request to the NXT brick, and return a reply. /// /// The request to the NXT brick /// The reply from the NXT brick, or null protected abstract byte[] Send(byte[] request); #endregion #region Protocol. /// /// STARTPROGRAM /// /// /// Reference: BDK, Appendix 2, p. 5. /// /// File name public void StartProgram(string fileName) { ValidateFilename(fileName); byte[] fileNameByteArr = Encoding.ASCII.GetBytes(fileName); byte[] request = new byte[22]; request[0] = (byte) (ReplyRequired ? 0x00 : 0x80); request[1] = (byte) NxtCommand.StartProgram; fileNameByteArr.CopyTo(request, 2); Send(request); } /// /// STOPPROGRAM /// /// /// Reference: BDK, Appendix 2, p. 5. /// public void StopProgram() { byte[] request = new byte[] { (byte) (ReplyRequired ? 0x00 : 0x80), (byte) NxtCommand.StopProgram }; Send(request); } /// /// PLAYSOUNDFILE /// /// /// Reference: BDK, Appendix 2, p. 5. /// /// Loop sound file indefinately? /// File name public void PlaySoundfile(bool loop, string fileName) { ValidateFilename(fileName); byte[] request = new byte[23]; request[0] = (byte) (ReplyRequired ? 0x00 : 0x80); request[1] = (byte) NxtCommand.PlaySoundfile; request[2] = (byte) (loop ? 0xFF : 0x00); Encoding.ASCII.GetBytes(fileName).CopyTo(request, 3); Send(request); } /// /// PLAYTONE /// /// /// Reference: BDK, Appendix 2, p. 6. /// /// Frequency for the tone, Hz /// Duration of the tone, ms public void PlayTone(UInt16 frequency, UInt16 duration) { if (frequency < 200) frequency = 200; if (frequency > 14000) frequency = 14000; byte[] request = new byte[6]; request[0] = (byte) (ReplyRequired ? 0x00 : 0x80); request[1] = (byte) NxtCommand.PlayTone; Util.SetUInt16(frequency, request, 2); Util.SetUInt16(duration, request, 4); Send(request); } /// /// SETOUTPUTSTATE /// /// /// Reference: BDK, Appendix 2, p. 6. /// /// Motor port /// Power set point /// Mode /// Regulation mode /// Turn ratio /// Run state /// Tacho limit, 0: run forever public void SetOutputState(NxtMotorPort motorPort, sbyte power, NxtMotorMode mode, NxtMotorRegulationMode regulationMode, sbyte turnRatio, NxtMotorRunState runState, UInt32 tachoLimit) { TraceUtil.MethodEnter(); if (power < -100) power = -100; if (power > 100) power = 100; if (turnRatio < -100) turnRatio = -100; if (turnRatio > 100) turnRatio = 100; byte[] request = new byte[12]; request[0] = (byte) (ReplyRequired ? 0x00 : 0x80); request[1] = (byte) NxtCommand.SetOutputState; request[2] = (byte) motorPort; request[3] = (byte) power; request[4] = (byte) mode; request[5] = (byte) regulationMode; request[6] = (byte) turnRatio; request[7] = (byte) runState; Util.SetUInt32(tachoLimit, request, 8); Send(request); TraceUtil.MethodExit(null); } /// /// SETINPUTMODE /// /// /// Reference: BDK, Appendix 2, p. 7. /// /// Input Port /// Sensor Type /// Sensor Mode public void SetInputMode(NxtSensorPort sensorPort, NxtSensorType sensorType, NxtSensorMode sensorMode) { TraceUtil.MethodEnter(); byte[] request = new byte[] { (byte) (ReplyRequired ? 0x00 : 0x80), (byte) NxtCommand.SetInputMode, (byte) sensorPort, (byte) sensorType, (byte) sensorMode }; Send(request); TraceUtil.MethodExit(null); } /// /// GETOUTPUTSTATE /// /// /// Reference: BDK, Appendix 2, p. 8. /// /// Ourput Port /// Returns a parsed NxtGetOutputStateReply with the reply public NxtGetOutputStateReply? GetOutputState(NxtMotorPort motorPort) { TraceUtil.MethodEnter(); byte[] request = new byte[] { 0x00, (byte) NxtCommand.GetOutputState, (byte) motorPort }; byte[] reply = Send(request); if (reply == null) { TraceUtil.MethodExit("return null"); return null; } byte motorPortOut = reply[3]; if (motorPortOut != (byte) motorPort) { TraceUtil.MethodExit("throw new NxtException"); throw new NxtException(string.Format("Output motor port, {0}, was different from input motor port, {1}.", motorPortOut, motorPort)); } NxtGetOutputStateReply result; result.power = (sbyte) reply[4]; result.mode = (NxtMotorMode) reply[5]; result.regulationMode = (NxtMotorRegulationMode) reply[6]; result.turnRatio = (sbyte) reply[7]; result.runState = (NxtMotorRunState) reply[8]; result.tachoLimit = Util.GetUInt32(reply, 9); result.tachoCount = Util.GetInt32(reply, 13); result.blockTachoCount = Util.GetInt32(reply, 17); result.rotationCount = Util.GetInt32(reply, 21); TraceUtil.MethodExit("return result"); return result; } /// /// GETINPUTVALUES /// /// /// Reference: BDK, Appendix 2, p. 8. /// Used with passive sensors like the Touch, Light and Sound sensors. /// /// Input Port /// Returns a NxtGetInputValues with the parsed reply public NxtGetInputValuesReply? GetInputValues(NxtSensorPort sensorPort) { TraceUtil.MethodEnter(); byte[] request = new byte[] { 0x00, (byte) NxtCommand.GetInputValues, (byte) sensorPort }; byte[] reply = Send(request); if (reply == null) { TraceUtil.MethodExit("return null"); return null; } byte sensorPortOut = reply[3]; if (sensorPortOut != (byte) sensorPort) { TraceUtil.MethodExit("throw new NxtException"); throw new NxtException(string.Format("Output sensor port, {0}, was different from input sensor port, {1}.", sensorPortOut, sensorPort)); } NxtGetInputValuesReply result; result.valid = (reply[4] != 0x00); result.calibrated = (reply[5] != 0x00); result.sensorType = (NxtSensorType) reply[6]; result.sensorMode = (NxtSensorMode) reply[7]; result.rawAdValue = Util.GetUInt16(reply, 8); result.normalizedAdValue = Util.GetUInt16(reply, 10); result.scaledValue = Util.GetInt16(reply, 12); result.calibratedValue = Util.GetInt16(reply, 14); TraceUtil.MethodExit("return result"); return result; } /// /// RESETINPUTSCALEDVALUE /// /// /// Reference: BDK, Appendix 2, p. 8. /// /// Input Port public void ResetInputScaledValue(NxtSensorPort sensorPort) { byte[] request = new byte[] { (byte) (ReplyRequired ? 0x00 : 0x80), (byte) NxtCommand.ResetInputScaledValue, (byte) sensorPort }; Send(request); } /// /// MESSAGEWRITE /// /// /// Reference: BDK, Appendix 2, p. 9. /// /// Inbox number /// Message data public void MessageWrite(NxtMailbox inBox, string messageData) { if (!messageData.EndsWith("\0")) messageData += '\0'; byte messageSize = (byte) messageData.Length; if (messageSize > 59) throw new ArgumentException("Message may not exceed 59 characters."); byte[] request = new byte[4 + messageSize]; request[0] = (byte) (ReplyRequired ? 0x00 : 0x80); request[1] = (byte) NxtCommand.MessageWrite; request[2] = (byte) inBox; request[3] = messageSize; Encoding.ASCII.GetBytes(messageData).CopyTo(request, 4); Send(request); } /// /// RESETMOTORPOSITION /// /// /// Reference: BDK, Appendix 2, p. 9. /// /// Output port /// Relative? True: position relative to last movement, False: absolute position public void ResetMotorPosition(NxtMotorPort motorPort, bool relative) { byte[] request = new byte[] { (byte) (ReplyRequired ? 0x00 : 0x80), (byte) NxtCommand.ResetMotorPosition, (byte) motorPort, (byte) (relative ? 0xFF : 0x00) }; Send(request); } /// /// GETBATTERYLEVEL /// /// /// Reference: BDK, Appendix 2, p. 9. /// /// Voltage in millivolts public UInt16? GetBatteryLevel() { byte[] request = new byte[] { 0x00, (byte) NxtCommand.GetBatteryLevel }; byte[] reply = Send(request); if (reply == null) return null; UInt16 voltage = Util.GetUInt16(reply, 3); return voltage; } /// /// STOPSOUNDPLAYBACK /// /// /// Reference: BDK, Appendix 2, p. 9. /// public void StopSoundPlayback() { byte[] request = new byte[] { (byte) (ReplyRequired ? 0x00 : 0x80), (byte) NxtCommand.StopSoundPlayback }; Send(request); } /// /// KEEPALIVE /// /// /// Reference: BDK, Appendix 2, p. 10. /// /// Current sleep time limit, ms public UInt32? KeepAlive() { TraceUtil.MethodEnter(); byte[] request = new byte[] { 0x00, (byte) NxtCommand.KeepAlive }; byte[] reply = Send(request); if (reply == null) { TraceUtil.MethodExit("return null"); return null; } UInt32 currentSleepLimit = Util.GetUInt32(reply, 3); TraceUtil.MethodExit("return currentSleepLimit"); return currentSleepLimit; } /// /// LSGETSTATUS /// /// /// Reference: BDK, Appendix 2, p. 10. /// Returns the number of bytes ready in the LowSpeed port. Used with digital sensors like the Ultrasonic sensor. /// /// Sensor port /// Bytes Ready (count of available bytes to read) /// /// public byte? LsGetStatus(NxtSensorPort sensorPort) { TraceUtil.MethodEnter(); byte[] request = new byte[] { 0x00, (byte) NxtCommand.LsGetStatus, (byte) sensorPort }; byte[] reply = Send(request); if (reply == null) { TraceUtil.MethodExit("return null"); return null; } byte bytesReady = reply[3]; TraceUtil.MethodExit("return bytesReady"); return bytesReady; } /// /// LSWRITE /// /// /// Reference: BDK, Appendix 2, p. 10. /// Writes data to the LowSpeed port. Used with digital sensors like the Ultrasonic sensor. /// /// Sensor port /// Rx Data Length /// Tx Data /// /// public void LsWrite(NxtSensorPort sensorPort, byte rxDataLength, byte[] txData) { TraceUtil.MethodEnter(); byte txDataLength = (byte) txData.Length; if (txDataLength == 0) { TraceUtil.MethodExit("throw new ArgumentException - 1"); throw new ArgumentException("No data to send."); } if (txDataLength > 16) { TraceUtil.MethodExit("throw new ArgumentException - 2"); throw new ArgumentException("Tx data may not exceed 16 bytes."); } if (rxDataLength < 0 || 16 < rxDataLength) { TraceUtil.MethodExit("throw new ArgumentException - 3"); throw new ArgumentException("Rx data length should be in the interval 0-16."); } byte[] request = new byte[5 + txDataLength]; request[0] = (byte) (ReplyRequired ? 0x00 : 0x80); request[1] = (byte) NxtCommand.LsWrite; request[2] = (byte) sensorPort; request[3] = txDataLength; request[4] = rxDataLength; txData.CopyTo(request, 5); Send(request); TraceUtil.MethodExit(null); } /// /// LSREAD /// /// /// Reference: BDK, Appendix 2, p. 10. /// Reads data from the LowSpeed port. Used with digital sensors like the Ultrasonic sensor. /// /// The sensor port /// The data read from the port /// /// public byte[] LsRead(NxtSensorPort sensorPort) { TraceUtil.MethodEnter(); byte[] request = new byte[] { 0x00, (byte) NxtCommand.LsRead, (byte) sensorPort }; byte[] reply = Send(request); if (reply == null) { TraceUtil.MethodExit("return null"); return null; } byte bytesRead = reply[3]; byte[] rxData = new byte[bytesRead]; Array.Copy(reply, 4, rxData, 0, bytesRead); TraceUtil.MethodExit("return rxData"); return rxData; } /// /// GETCURRENTPROGRAMNAME /// /// /// Reference: BDK, Appendix 2, p. 11. /// /// File name of the running program public string GetCurrentProgramName() { byte[] request = new byte[] { 0x00, (byte) NxtCommand.GetCurrentProgramName }; byte[] reply = Send(request); if (reply == null) return null; string fileName = Encoding.ASCII.GetString(reply, 3, 20).TrimEnd('\0'); return fileName; } /// /// MESSAGEREAD /// /// /// Reference: BDK, Appendix 2, p. 11. /// /// Remote Inbox number /// Local Inbox number /// Remove? True: clears message from Remote Inbox /// Message data public string MessageRead(NxtMailbox2 remoteInboxNo, NxtMailbox localInboxNo, bool remove) { byte[] request = new byte[] { 0x00, (byte) NxtCommand.MessageRead, (byte) remoteInboxNo, (byte) localInboxNo, (byte) (remove ? 0xFF : 0x00) }; byte[] reply = Send(request); if (reply == null) return null; byte localInboxNoOut = reply[3]; // TODO: Validate on this? byte messageSize = reply[4]; string message = Encoding.ASCII.GetString(reply, 5, messageSize).TrimEnd('\0'); return message; } /// /// OPEN READ COMMAND /// /// /// Reference: BDK, Appendix 1, p. 7. /// Close the handle after use. The handle is automatically closed if an error occurs. /// /// The name of the file /// A NxtOpenReadReply with the result of the request public NxtOpenReadReply? OpenRead(string fileName) { ValidateFilename(fileName); byte[] request = new byte[22]; request[0] = 0x01; request[1] = (byte) NxtCommand.OpenRead; Encoding.ASCII.GetBytes(fileName).CopyTo(request, 2); byte[] reply = Send(request); if (reply == null) return null; NxtOpenReadReply result; result.handle = reply[3]; result.fileSize = Util.GetUInt32(reply, 4); return result; } /// /// OPEN WRITE COMMAND /// /// /// Reference: BDK, Appendix 1, p. 7. /// Close the handle after use. The handle is automatically closed if an error occurs. /// /// The file name /// The file size /// A handle to the file public byte? OpenWrite(string fileName, UInt32 fileSize) { ValidateFilename(fileName); byte[] request = new byte[26]; request[0] = 0x01; request[1] = (byte) NxtCommand.OpenWrite; Encoding.ASCII.GetBytes(fileName).CopyTo(request, 2); Util.SetUInt32(fileSize, request, 22); byte[] reply = Send(request); if (reply == null) return null; return reply[3]; } /// /// READ COMMAND /// /// /// Reference: BDK, Appendix 1, p. 8. /// /// A handle to the file /// Number of data bytes to be read /// A byte array with the read data public byte[] Read(byte handle, UInt16 bytesToRead) { byte[] request = new byte[5]; request[0] = 0x01; request[1] = (byte) NxtCommand.Read; request[2] = handle; Util.SetUInt16(bytesToRead, request, 3); byte[] reply = Send(request); if (reply == null) return null; byte handleOut = reply[3]; if (handleOut != handle) throw new NxtException(string.Format("Output handle, {0}, was different from input handle, {1}.", handleOut, handle)); UInt16 bytesRead = Util.GetUInt16(reply, 4); byte[] respons = new byte[bytesRead]; Array.Copy(reply, 6, respons, 0, bytesRead); return respons; } /// /// WRITE COMMAND /// /// /// Reference: BDK, Appendix 1, p. 8. /// /// File handle to write to /// Data to write /// Number of bytes written public UInt16? Write(byte handle, byte[] data) { byte[] request = new byte[3 + data.Length]; request[0] = 0x01; request[1] = (byte) NxtCommand.Write; request[2] = handle; data.CopyTo(request, 3); byte[] reply = Send(request); if (reply == null) return null; byte handleOut = reply[3]; if (handleOut != handle) throw new NxtException(string.Format("Output handle, {0}, was different from input handle, {1}.", handleOut, handle)); UInt16 bytesWritten = Util.GetUInt16(reply, 4); return bytesWritten; } /// /// CLOSE COMMAND /// /// /// Reference: BDK, Appendix 1, p. 8. /// /// File handle to close public void Close(byte handle) { byte[] request = new byte[] { 0x01, (byte) NxtCommand.Close, handle }; byte[] reply = Send(request); if (reply == null) return; byte handleOut = reply[3]; if (handleOut != handle) throw new NxtException(string.Format("Output handle, {0}, was different from input handle, {1}.", handleOut, handle)); } /// /// DELETE COMMAND /// /// /// Reference: BDK, Appendix 1, p. 9. /// /// The file name public void Delete(string fileName) { ValidateFilename(fileName); byte[] request = new byte[22]; request[0] = 0x01; request[1] = (byte) NxtCommand.Delete; Encoding.ASCII.GetBytes(fileName).CopyTo(request, 2); byte[] reply = Send(request); if (reply == null) return; string fileNameOut = Encoding.ASCII.GetString(reply, 3, 20); if (fileNameOut != fileName) throw new NxtException(string.Format("The file reported as deleted, '{0}', was different from the file requested, '{1}'.", fileNameOut, fileName)); } /// /// FIND FIRST /// /// /// Reference: BDK, Appendix 1, p. 9. /// Close the handle after use. The handle is automatically closed if an error occurs. /// /// Filename or -mask to search /// A NxtFindFileReply containing the result for the search /// public NxtFindFileReply? FindFirst(string fileName) { ValidateFilename(fileName); byte[] request = new byte[22]; request[0] = 0x01; request[1] = (byte) NxtCommand.FindFirst; Encoding.ASCII.GetBytes(fileName).CopyTo(request, 2); return SendAndParseNxtFindFileReply(request); } /// /// FIND NEXT /// /// /// Reference: BDK, Appendix 1, p. 10. /// Close the handle after use. The handle is automatically closed if an error occurs. /// /// Handle from the previous found file or from the FindFirst command /// A NxtFindFileReply containing the result for the search /// public NxtFindFileReply? FindNext(byte handle) { byte[] request = new byte[] { 0x01, (byte) NxtCommand.FindNext, handle }; return SendAndParseNxtFindFileReply(request); } /// /// Sends a FindFirst- or FindNext-request and parses the result as a NxtFindFileReply. /// /// The request /// A NxtFindFileReply containing the parsed result /// /// private NxtFindFileReply? SendAndParseNxtFindFileReply(byte[] request) { byte[] reply; NxtFindFileReply result; try { reply = Send(request); if (reply == null) return null; } catch (NxtCommunicationProtocolException ex) { if (ex.errorMessage == NxtErrorMessage.FileNotFound) { result.FileFound = false; result.handle = 0; result.fileName = ""; result.fileSize = 0; return result; } // Rethrow if not a FileNotFound error. throw; } result.FileFound = true; result.handle = reply[3]; result.fileName = Encoding.ASCII.GetString(reply, 4, 20).TrimEnd('\0'); result.fileSize = Util.GetUInt32(reply, 24); return result; } /// /// GET FIRMWARE VERSION /// /// /// Reference: BDK, Appendix 1, p. 11. /// /// A NxtGetFirmwareVersionReply with the protocol-, and the firmware versions. public NxtGetFirmwareVersionReply? GetFirmwareVersion() { byte[] request = new byte[] { 0x01, (byte) NxtCommand.GetFirmwareVersion }; byte[] reply = Send(request); if (reply == null) return null; NxtGetFirmwareVersionReply result; result.protocolVersion = new Version(reply[4], reply[3]); result.firmwareVersion = new Version(reply[6], reply[5]); return result; } /// /// OPEN WRITE LINEAR COMMAND /// /// /// Reference: BDK, Appendix 1, p. 11. /// /// The file name /// The file size /// A handle to the file public byte? OpenWriteLinear(string fileName, UInt32 fileSize) { ValidateFilename(fileName); byte[] request = new byte[26]; request[0] = 0x01; request[1] = (byte) NxtCommand.OpenWriteLinear; Encoding.ASCII.GetBytes(fileName).CopyTo(request, 2); // NOTE: I'm not sure if the documentation is 100% Util.SetUInt32(fileSize, request, 22); // ... correct here, since it do not allow space for the null terminator. byte[] reply = Send(request); if (reply == null) return null; byte handle = reply[3]; return handle; } /// /// OPEN READ LINEAR COMMAND (INTERNAL COMMAND) /// /// /// Reference: BDK, Appendix 1, p. 12. /// /// The file name /// Pointer to linear memory segment public UInt32? OpenReadLinear(string fileName) { ValidateFilename(fileName); byte[] request = new byte[22]; request[0] = 0x01; request[1] = (byte) NxtCommand.OpenReadLinear; Encoding.ASCII.GetBytes(fileName).CopyTo(request, 2); byte[] reply = Send(request); if (reply == null) return null; UInt32 pointer = Util.GetUInt32(reply, 3); return pointer; } /// /// OPEN WRITE DATA COMMAND /// /// /// Reference: BDK, Appendix 1, p. 12. /// /// The file name /// The file size /// A handle to the file public byte? OpenWriteData(string fileName, UInt32 fileSize) { ValidateFilename(fileName); byte[] request = new byte[26]; request[0] = 0x01; request[1] = (byte) NxtCommand.OpenWriteData; Encoding.ASCII.GetBytes(fileName).CopyTo(request, 2); // NOTE: I'm not sure if the documentation is 100% Util.SetUInt32(fileSize, request, 22); // ... correct here, since it do not allow space for the null terminator. byte[] reply = Send(request); if (reply == null) return null; byte handle = reply[3]; return handle; } /// /// OPEN APPEND DATA COMMAND /// /// /// Reference: BDK, Appendix 1, p. 13. /// /// The file name /// A NxtOpenAppendDataReply withe the parsed reply public NxtOpenAppendDataReply? OpenAppendData(string fileName) { ValidateFilename(fileName); byte[] request = new byte[22]; request[0] = 0x01; request[1] = (byte) NxtCommand.OpenAppendData; Encoding.ASCII.GetBytes(fileName).CopyTo(request, 2); byte[] reply = Send(request); if (reply == null) return null; NxtOpenAppendDataReply result; result.handle = reply[3]; result.availableFilesize = Util.GetUInt32(reply, 4); return result; } /// /// REQUEST FIRST MODULE /// /// /// Reference: BDK, Appendix 1, p. 19. /// /// Modulename or -mask to search /// A NxtRequestModuleReply containing the result for the search /// /// public NxtRequestModuleReply? RequestFirstModule(string resourceName) { ValidateFilename(resourceName); byte[] request = new byte[22]; request[0] = 0x01; request[1] = (byte) NxtCommand.RequestFirstModule; Encoding.ASCII.GetBytes(resourceName).CopyTo(request, 2); return SendAndParseNxtRequestModuleReply(request); } /// /// REQUEST NEXT MODULE /// /// /// Reference: BDK, Appendix 1, p. 19. /// /// Handle number from the previous Request Next Module command or from the very first Request First Module command /// A NxtRequestModuleReply containing the result for the search /// /// public NxtRequestModuleReply? RequestNextModule(byte handle) { byte[] request = new byte[] { 0x01, (byte) NxtCommand.RequestNextModule, handle }; return SendAndParseNxtRequestModuleReply(request); } /// /// Sends a RequestFirstModule- or RequestNextModule-request and parses the result as a NxtRequestModule. /// /// The request /// A NxtRequestModuleReply containing the parsed result /// /// private NxtRequestModuleReply? SendAndParseNxtRequestModuleReply(byte[] request) { byte[] reply; NxtRequestModuleReply result; try { reply = Send(request); if (reply == null) return null; } catch (NxtCommunicationProtocolException ex) { if (ex.errorMessage == NxtErrorMessage.NoMoreHandles || ex.errorMessage == NxtErrorMessage.ModuleNotFound) { result.ModuleFound = false; result.handle = 0; result.moduleName = ""; result.moduleId = 0; result.moduleIdCC = 0; result.moduleIdFF = 0; result.moduleIdPP = 0; result.moduleIdTT = 0; result.moduleSize = 0; result.moduleIoMapSize = 0; return result; } // Rethrow if not a NoMoreHandles- or a ModuleNotFound error. throw; } result.ModuleFound = true; result.handle = reply[3]; result.moduleName = Encoding.ASCII.GetString(reply, 4, 20).TrimEnd('\0'); result.moduleId = Util.GetUInt32(reply, 24); // NOTE: There seems to be some inconsistency in the documentation about PP TT CC FF, Appendix 1, p. 18. result.moduleIdFF = 0; // reply[24]; result.moduleIdCC = 0; // reply[25]; result.moduleIdTT = reply[26]; // reply[26]; result.moduleIdPP = reply[24]; // reply[27] result.moduleSize = Util.GetUInt32(reply, 28); result.moduleIoMapSize = Util.GetUInt16(reply, 32); return result; } /// /// CLOSE MODULE HANDLE COMMAND /// /// /// Reference: BDK, Appendix 1, p. 20. /// /// Handle number /// /// public void CloseModuleHandle(byte handle) { byte[] request = new byte[] { 0x01, (byte) NxtCommand.CloseModuleHandle, handle }; Send(request); } /// /// READ IO MAP COMMAND /// /// /// Reference: BDK, Appendix 1, p. 20. /// /// The module ID /// The offset to read from /// Number of bytes to be read /// IO-map content public byte[] ReadIoMap(UInt32 moduleId, UInt16 offset, UInt16 bytesToRead) { byte[] request = new byte[10]; request[0] = 0x01; request[1] = (byte) NxtCommand.ReadIoMap; Util.SetUInt32(moduleId, request, 2); Util.SetUInt16(offset, request, 6); Util.SetUInt16(bytesToRead, request, 8); byte[] reply = Send(request); if (reply == null) return null; UInt32 moduleIdOut = Util.GetUInt32(reply, 3); if (moduleIdOut != moduleId) throw new NxtException(string.Format("Output module Id, {0}, was different from input module Id, {1}.", moduleIdOut, moduleId)); UInt16 bytesRead = Util.GetUInt16(reply, 7); byte[] ioMapContent = new byte[bytesRead]; Array.Copy(reply, 9, ioMapContent, 0, bytesRead); return ioMapContent; } /// /// WRITE IO MAP COMMAND /// /// /// Reference: BDK, Appendix 1, p. 21. /// /// The module ID /// The offset to write to /// IO-map content to be stored in IO-map[index]...IO-map[index+N] /// The number of data that have been written public UInt16? WriteIoMap(UInt32 moduleId, UInt16 offset, byte[] ioMapContent) { UInt16 bytesToWrite = (UInt16) ioMapContent.Length; byte[] request = new byte[10 + ioMapContent.Length]; request[0] = 0x01; request[1] = (byte) NxtCommand.WriteIoMap; Util.SetUInt32(moduleId, request, 2); Util.SetUInt16(offset, request, 6); Util.SetUInt16(bytesToWrite, request, 8); ioMapContent.CopyTo(request, 10); byte[] reply = Send(request); if (reply == null) return null; UInt32 moduleIdOut = Util.GetUInt32(reply, 3); if (moduleIdOut != moduleId) throw new NxtException(string.Format("Output module Id, {0}, was different from input module Id, {1}.", moduleIdOut, moduleId)); UInt16 bytesWritten = Util.GetUInt16(reply, 7); return bytesWritten; } /// /// BOOT COMMAND /// /// /// Reference: BDK, Appendix 1, p. 13. /// This command can only be accepted by USB. /// public void Boot() { byte[] request = new byte[21]; request[0] = 0x01; request[1] = (byte) NxtCommand.Boot; Encoding.ASCII.GetBytes("Let's dance: SAMBA").CopyTo(request, 2); byte[] reply = Send(request); if (reply == null) return; string result = Encoding.ASCII.GetString(reply, 3, 4).TrimEnd('\0'); if (result != "Yes") throw new NxtException("The reply, '{0}', was not the expected, 'Yes'."); } /// /// SET BRICK NAME COMMAND /// /// /// Reference: BDK, Appendix 1, p. 13. /// For some reason only the first 8 characters is remembered when the NXT is turned off. This is with version 1.4 of the firmware, and it may be fixed with newer versions. /// /// The new name of the NXT brick public void SetBrickName(string brickName) { if (brickName.Length > 15) brickName = brickName.Substring(0, 15); byte[] request = new byte[18]; request[0] = 0x01; request[1] = (byte) NxtCommand.SetBrickName; Encoding.ASCII.GetBytes(brickName).CopyTo(request, 2); Send(request); } /// /// GET DEVICE INFO /// /// /// Reference: BDK, Appendix 1, p. 14. /// For some reason only the first 8 characters of the BXT name is remembered when the NXT is turned off. This is with version 1.4 of the firmware, and it may be fixed with newer versions. /// /// A NxtGetDeviceInfoReply containing the parsed result public NxtGetDeviceInfoReply? GetDeviceInfo() { byte[] request = new byte[] { 0x01, (byte) NxtCommand.GetDeviceInfo }; byte[] reply = Send(request); if (reply == null) return null; NxtGetDeviceInfoReply result; result.nxtName = Encoding.ASCII.GetString(reply, 3, 15).TrimEnd('\0'); result.btAdress = new byte[7]; Array.Copy(reply, 18, result.btAdress, 0, 7); result.bluetoothSignalStrength = Util.GetUInt32(reply, 25); result.freeUserFlash = Util.GetUInt32(reply, 29); return result; } /// /// DELETE USER FLASH /// /// /// Reference: BDK, Appendix 1, p. 14. /// public void DeleteUserFlash() { byte[] request = new byte[] { 0x01, (byte) NxtCommand.DeleteUserFlash }; Send(request); } /// /// POLL COMMAND LENGTH /// /// /// Reference: BDK, Appendix 1, p. 15. /// /// Buffer Number: 0x00 = Poll Buffer, 0x01 = High Speed buffer /// Number of bytes for the command ready in the buffer public byte? PollCommandLength(byte bufferNo) { byte[] request = new byte[] { 0x01, (byte) NxtCommand.PollCommandLength, bufferNo }; byte[] reply = Send(request); if (reply == null) return null; // NOTE: My guess is that the documentation has switched meaning between bytes 2 and 3. byte bufferNoOut = reply[3]; if (bufferNoOut != bufferNo) throw new NxtException(string.Format("Output buffer no-, {0}, was different from input buffer no., {1}.", bufferNoOut, bufferNo)); byte bytesReady = reply[4]; return bytesReady; } /// /// POLL COMMAND /// /// /// Reference: BDK, Appendix 1, p. 15. /// /// Buffer Number: 0x00 = Poll Buffer, 0x01 = High Speed buffer /// Command length public void PollCommand(byte bufferNo, byte commandLength) { byte[] request = new byte[] { 0x01, (byte) NxtCommand.PollCommand, bufferNo, commandLength }; byte[] reply = Send(request); if (reply == null) return; // NOTE: My guess is that the documentathion has switched meaning between bytes 2 and 3. byte bufferNoOut = reply[3]; if (bufferNoOut != bufferNo) throw new NxtException(string.Format("Output buffer no-, {0}, was different from input buffer no., {1}.", bufferNoOut, bufferNo)); // TODO: Parse the reply, and return the result. } /// /// BLUETOOTH FACTORY RESET COMMAND /// /// /// Reference: BDK, Appendix 1, p. 15. /// This command cannot be transmitted via Bluetooth because all Bluetooth functionality is reset by this command! /// public void BluetoothFactoryReset() { byte[] request = new byte[] { 0x01, (byte) NxtCommand.BluetoothFactoryReset }; Send(request); } #endregion #region Utilities. /// /// This function validates that the filename is correct for the NXT brick. /// /// The file name private void ValidateFilename(string fileName) { if (fileName.Length > 19) throw new ArgumentException("File name is to long. Maximum length is 19 characters (15.3)."); } #endregion } #region Reply types. /// /// Reply type for the FindFirst() and FindNext() functions. /// /// /// public struct NxtFindFileReply { /// /// Boolean indicating if a file was found or not. /// public bool FileFound; /// /// The file handle. /// public byte handle; /// /// The file name. /// public string fileName; /// /// The filesize. /// public UInt32 fileSize; } /// /// Reply type for the FindFirst() and FindNext() functions. /// /// /// public struct CopyOfNxtFindFileReply { /// /// Boolean indicating if a file was found or not. /// public bool FileFound; /// /// The file handle. /// public byte handle; /// /// The file name. /// public string fileName; /// /// The filesize. /// public UInt32 fileSize; } /// /// Reply type for the GetDeviceInfo() function. /// /// public struct NxtGetDeviceInfoReply { /// /// The name of the NXT brick. /// public string nxtName; /// /// The bluetooth address. /// public byte[] btAdress; /// /// The bluetooth signal strength. /// public UInt32 bluetoothSignalStrength; /// /// The size of the free user flash. /// public UInt32 freeUserFlash; } /// /// Reply type for the GetFirmwareVersion() function. /// /// public struct NxtGetFirmwareVersionReply { /// /// The protocol version. /// public Version protocolVersion; /// /// The firmware version. /// public Version firmwareVersion; } /// /// Reply type for the GetInputValues() function. /// /// public struct NxtGetInputValuesReply { /// /// A boolean indicating if the returned result is valid or not. /// public bool valid; /// /// A boolean indicating if the returned result is calibrated or not. /// public bool calibrated; /// /// The sensor type. /// public NxtSensorType sensorType; /// /// The sensor mode. /// public NxtSensorMode sensorMode; /// /// The raw A/D value. /// public UInt16 rawAdValue; /// /// The normalized A/D value. /// public UInt16 normalizedAdValue; /// /// The scaled value. /// public Int16 scaledValue; /// /// The calibrated value. /// public Int16 calibratedValue; } /// /// Reply type for the GetOutputState() function. /// /// public struct CopyOfNxtGetOutputStateReply { /// /// The motor power. /// public sbyte power; /// /// The motor mode. /// public NxtMotorMode mode; /// /// The regulation mode. /// public NxtMotorRegulationMode regulationMode; /// /// The turn ratio. /// public sbyte turnRatio; /// /// The run state. /// public NxtMotorRunState runState; /// /// The tacho limit in degrees, 0 means unlimited. /// public UInt32 tachoLimit; /// /// The tacho count. /// public Int32 tachoCount; /// /// The block tacho count. /// public Int32 blockTachoCount; /// /// The rotation count. /// public Int32 rotationCount; /// /// ToString()-override. /// /// ... TBD ... public override string ToString() { return string.Format("[P:{0,4}|M:{1,25}|RM:{2,27}|TR:{3,4}|RS:{4,24}|TL:{5,3}|TC:{6,4}|BTC:{7,4}|RC:{8,4}]", power, mode, regulationMode, turnRatio, runState, tachoLimit, tachoCount, blockTachoCount, rotationCount); } } /// /// Reply type for the GetOutputState() function. /// /// public struct NxtGetOutputStateReply { /// /// The motor power. /// public sbyte power; /// /// The motor mode. /// public NxtMotorMode mode; /// /// The regulation mode. /// public NxtMotorRegulationMode regulationMode; /// /// The turn ratio. /// public sbyte turnRatio; /// /// The run state. /// public NxtMotorRunState runState; /// /// The tacho limit in degrees, 0 means unlimited. /// public UInt32 tachoLimit; /// /// The tacho count. /// public Int32 tachoCount; /// /// The block tacho count. /// public Int32 blockTachoCount; /// /// The rotation count. /// public Int32 rotationCount; /// /// ToString()-override. /// /// ... TBD ... public override string ToString() { return string.Format("[P:{0,4}|M:{1,25}|RM:{2,27}|TR:{3,4}|RS:{4,24}|TL:{5,3}|TC:{6,4}|BTC:{7,4}|RC:{8,4}]", power, mode, regulationMode, turnRatio, runState, tachoLimit, tachoCount, blockTachoCount, rotationCount); } } /// /// Reply type for the OpenAppendData() function. /// /// public struct NxtOpenAppendDataReply { /// /// File handle. /// public byte handle; /// /// Available file size. /// public UInt32 availableFilesize; } /// /// Reply type for the OpenRead() function. /// /// public struct NxtOpenReadReply { /// /// File handle. /// public byte handle; /// /// File size. /// public UInt32 fileSize; } /// /// Reply type for the RequestFirstModule() and RequestNextModule() functions. /// /// /// public struct NxtRequestModuleReply { /// /// Boolean indicating if a module was found, or not. /// public bool ModuleFound; /// /// Module handle. /// public byte handle; /// /// Module name. /// public string moduleName; /// /// Module ID. /// public UInt32 moduleId; /// /// Module ID, PP-value. /// public byte moduleIdPP; /// /// Module ID, TT-value. /// public byte moduleIdTT; /// /// Module ID, CC-value. /// public byte moduleIdCC; /// /// Module ID, FF-value. /// public byte moduleIdFF; /// /// Module size. /// public UInt32 moduleSize; /// /// Module IO-map size. /// public UInt16 moduleIoMapSize; } #endregion #region Enumerations. /// /// Commands to the NXT brick. /// /// /// Reference: BDK, Appendix 1 & 2. /// public enum NxtCommand: byte { /// /// BDK, Appendix 2, p. 5. /// StartProgram = 0x00, /// /// BDK, Appendix 2, p. 5. /// StopProgram = 0x01, /// /// BDK, Appendix 2, p. 5. /// PlaySoundfile = 0x02, /// /// BDK, Appendix 2, p. 6. /// PlayTone = 0x03, /// /// BDK, Appendix 2, p. 6. /// SetOutputState = 0x04, /// /// BDK, Appendix 2, p. 7. /// SetInputMode = 0x05, /// /// BDK, Appendix 2, p. 8. /// GetOutputState = 0x06, /// /// BDK, Appendix 2, p. 8. /// GetInputValues = 0x07, /// /// BDK, Appendix 2, p. 8. /// ResetInputScaledValue = 0x08, /// /// BDK, Appendix 2, p. 9. /// MessageWrite = 0x09, /// /// BDK, Appendix 2, p. 9. /// ResetMotorPosition = 0x0A, /// /// BDK, Appendix 2, p. 9. /// GetBatteryLevel = 0x0B, /// /// BDK, Appendix 2, p. 9. /// StopSoundPlayback = 0x0C, /// /// BDK, Appendix 2, p. 10. /// KeepAlive = 0x0D, /// /// BDK, Appendix 2, p. 10. /// LsGetStatus = 0x0E, /// /// BDK, Appendix 2, p. 10. /// LsWrite = 0x0F, /// /// BDK, Appendix 2, p. 10. /// LsRead = 0x10, /// /// BDK, Appendix 2, p. 11. /// GetCurrentProgramName = 0x11, /// /// BDK, Appendix 2, p. 11. /// MessageRead = 0x13, /// /// BDK, Appendix 1, p. 7. /// OpenRead = 0x80, /// /// BDK, Appendix 1, p. 7. /// OpenWrite = 0x81, /// /// BDK, Appendix 1, p. 8. /// Read = 0x82, /// /// BDK, Appendix 1, p. 8. /// Write = 0x83, /// /// BDK, Appendix 1, p. 8. /// Close = 0x84, /// /// BDK, Appendix 1, p. 9. /// Delete = 0x85, /// /// BDK, Appendix 1, p. 9. /// FindFirst = 0x86, /// /// BDK, Appendix 1, p. 10. /// FindNext = 0x87, /// /// BDK, Appendix 1, p. 11. /// GetFirmwareVersion = 0x88, /// /// BDK, Appendix 1, p. 11. /// OpenWriteLinear = 0x89, /// /// BDK, Appendix 1, p. 12. /// OpenReadLinear = 0x8A, /// /// BDK, Appendix 1, p. 12. /// OpenWriteData = 0x8B, /// /// BDK, Appendix 1, p. 13. /// OpenAppendData = 0x8C, /// /// BDK, Appendix 1, p. 19. /// RequestFirstModule = 0x90, /// /// BDK, Appendix 1, p. 19. /// RequestNextModule = 0x91, /// /// BDK, Appendix 1, p. 20. /// CloseModuleHandle = 0x92, /// /// BDK, Appendix 1, p. 20. /// ReadIoMap = 0x94, /// /// BDK, Appendix 1, p. 21. /// WriteIoMap = 0x95, /// /// BDK, Appendix 1, p. 13. /// Boot = 0x97, /// /// BDK, Appendix 1, p. 13. /// SetBrickName = 0x98, /// /// BDK, Appendix 1, p. 14. /// GetDeviceInfo = 0x9B, /// /// BDK, Appendix 1, p. 14. /// DeleteUserFlash = 0xA0, /// /// BDK, Appendix 1, p. 15. /// PollCommandLength = 0xA1, /// /// BDK, Appendix 1, p. 15. /// PollCommand = 0xA2, /// /// BDK, Appendix 1, p. 15. /// BluetoothFactoryReset = 0xA4 } /// /// ERROR MESSAGE BACK TO THE HOST /// /// /// Reference: BDK, Appendix 1, p. 16.
/// Reference: BDK, Appendix 2, p. 12.
///
public enum NxtErrorMessage: byte { /// /// BDK, Appendix 2, p. 12. /// Succes = 0x00, /// /// BDK, Appendix 2, p. 12. /// PendingCommunicationTransactionInProgress = 0x20, /// /// BDK, Appendix 2, p. 12. /// SpecifiedMailboxQueueIsEmpty = 0x40, /// /// BDK, Appendix 1, p. 16. /// NoMoreHandles = 0x81, /// /// BDK, Appendix 1, p. 16. /// NoSpace = 0x82, /// /// BDK, Appendix 1, p. 16. /// NoMoreFiles = 0x83, /// /// BDK, Appendix 1, p. 16. /// EndOfFileExpected = 0x84, /// /// BDK, Appendix 1, p. 16. /// EndOfFile = 0x85, /// /// BDK, Appendix 1, p. 16. /// NotALinearFile = 0x86, /// /// BDK, Appendix 1, p. 16. /// FileNotFound = 0x87, /// /// BDK, Appendix 1, p. 16. /// HandleAllReadyClosed = 0x88, /// /// BDK, Appendix 1, p. 16. /// NoLinearSpace = 0x89, /// /// BDK, Appendix 1, p. 16. /// UndefinedError = 0x8A, /// /// BDK, Appendix 1, p. 16. /// FileIsBusy = 0x8B, /// /// BDK, Appendix 1, p. 16. /// NoWriteBuffers = 0x8C, /// /// BDK, Appendix 1, p. 16. /// AppendNotPossible = 0x8D, /// /// BDK, Appendix 1, p. 16. /// FileIsFull = 0x8E, /// /// BDK, Appendix 1, p. 16. /// FileExists = 0x8F, /// /// BDK, Appendix 1, p. 16. /// ModuleNotFound = 0x90, /// /// BDK, Appendix 1, p. 16. /// OutIfBoundary = 0x91, /// /// BDK, Appendix 1, p. 16. /// IllegalFileName = 0x92, /// /// BDK, Appendix 1, p. 16. /// IllegalHandle = 0x93, /// /// BDK, Appendix 2, p. 12. /// RequestFailed = 0xBD, // i.e. specified file not found /// /// BDK, Appendix 2, p. 12. /// UnknownCommandOpcode = 0xBE, /// /// BDK, Appendix 2, p. 12. /// InsanePacket = 0xBF, /// /// BDK, Appendix 2, p. 12. /// DataContainsOutOfRangeValues = 0xC0, /// /// BDK, Appendix 2, p. 12. /// CommunicationBusError = 0xDD, /// /// BDK, Appendix 2, p. 12. /// NoFreeMemoryInCommunicationBuffer = 0xDE, /// /// BDK, Appendix 2, p. 12. /// SpecifiedChannelOrConnectionIsNotValid = 0xDF, /// /// BDK, Appendix 2, p. 12. /// SpecifiedChannelOrConnectionNotConfiguredOrBusy = 0xE0, /// /// BDK, Appendix 2, p. 12. /// NoActiveProgram = 0xEC, /// /// BDK, Appendix 2, p. 12. /// IllegalSizeSpecified = 0xED, /// /// BDK, Appendix 2, p. 12. /// IllegalMailboxQueueIdSpecified = 0xEE, /// /// BDK, Appendix 2, p. 12. /// AttemptedToAccessInvalidFieldOfAStructure = 0xEF, /// /// BDK, Appendix 2, p. 12. /// BadInputOrOutputSpecified = 0xF0, /// /// BDK, Appendix 2, p. 12. /// InsufficientMemoryAvailable = 0xFB, /// /// BDK, Appendix 2, p. 12. /// BadArguments = 0xFF } /// /// Reference: BDK, Appendix 2, p. 6. /// [Flags] public enum NxtMotorMode: byte { /// /// Turn on the specified motor. /// MOTORON = 0x01, /// /// Use run/break instead of run/float in PWM. /// BRAKE = 0x02, /// /// Turns on the regulation. /// REGULATED = 0x04 } /// /// Reference: BDK, Appendix 2, p. 6. /// public enum NxtMotorPort: byte { /// /// Motor port A. /// PortA, /// /// Motor port B. /// PortB, /// /// Motor port C. /// PortC, /// /// All motor ports. /// All = 0xFF } /// /// Reference: BDK, Appendix 2, p. 6. /// public enum NxtMotorRegulationMode: byte { /// /// No regulation will be enabled. /// REGULATION_MODE_IDLE = 0x00, /// /// Power control will be enabled on specified output. /// REGULATION_MODE_MOTOR_SPEED = 0x01, /// /// Syncronization will be enabled (Needs enabled on two output). /// REGULATION_MODE_MOTOR_SYNC = 0x02 } /// /// Reference: BDK, Appendix 2, p. 6. /// [Flags] public enum NxtMotorRunState: byte { /// /// Output will be idle. /// MOTOR_RUN_STATE_IDLE = 0x00, /// /// Output will ramp-up. /// MOTOR_RUN_STATE_RAMPUP = 0x10, /// /// Output will be running. /// MOTOR_RUN_STATE_RUNNING = 0x20, /// /// Output will ramp-down. /// MOTOR_RUN_STATE_RAMPDOWN = 0x40 } /// /// Reference: BDK, Appendix 2, p. 7. /// public enum NxtSensorMode: byte { /// /// ... TBD ... /// RAWMODE = 0x00, /// /// ... TBD ... /// BOOLEANMODE = 0x20, /// /// ... TBD ... /// TRANSITIONCNTMODE = 0x40, /// /// ... TBD ... /// PERIODCOUNTERMODE = 0x60, /// /// ... TBD ... /// PCTFULLSCALEMODE = 0x80, /// /// ... TBD ... /// CELSIUSMODE = 0xA0, /// /// ... TBD ... /// FAHRENHEITMODE = 0xC0, /// /// ... TBD ... /// ANGLESTEPMODE = 0xE0 // SLOPEMASK = 0x1F (?) // MODEMASK = 0xE0 (?) } /// /// Reference: BDK, Appendix 2, p. 7. /// public enum NxtSensorPort: byte { /// /// Sensor port 1. /// Port1, /// /// Sensor port 2. /// Port2, /// /// Sensor port 3. /// Port3, /// /// Sensor port 4. /// Port4 } /// /// Reference: BDK, Appendix 2, p. 7. /// /// /// Explantion of the values is found on p. 46 of the Executable File Specification document. /// public enum NxtSensorType: byte { /// /// No sensor configured. /// NO_SENSOR = 0x00, /// /// NXT or RCX touch sensor. /// SWITCH = 0x01, /// /// RCX temperature sensor. /// TEMPERATURE = 0x02, /// /// RCX light sensor. /// REFLECTION = 0x03, /// /// RCX rotation sensor. /// ANGLE = 0x04, /// /// NXT light sensor with floodlight enabled. /// LIGHT_ACTIVE = 0x05, /// /// NXT light sensor with floodlight disabled. /// LIGHT_INACTIVE = 0x06, /// /// NXT sound sensor; dB scaling. /// SOUND_DB = 0x07, /// /// NXT sound sensor; dBA scaling. /// SOUND_DBA = 0x08, /// /// Unused in NXT programs. /// CUSTOM = 0x09, /// /// I2C digital sensor. /// LOWSPEED = 0x0A, /// /// I2C digital sensor; 9V power. /// LOWSPEED_9V = 0x0B, /// /// "HIGHSPEED". Unused in NXT programs. /// NO_OF_SENSOR_TYPES = 0x0C, /// /// Nxt Colour Sensor /// COLOR_DETECTOR = 0x0D, COLOR_RED = 0x0E, COLOR_GREEN = 0x0F, COLOR_BLUE = 0x10, COLOR_NONE = 0x11, } /// /// Reference: BDK, Appendix 2, p. 9. /// public enum NxtMailbox: byte { /// /// ... TBD ... /// Box0, /// /// ... TBD ... /// Box1, /// /// ... TBD ... /// Box2, /// /// ... TBD ... /// Box3, /// /// ... TBD ... /// Box4, /// /// ... TBD ... /// Box5, /// /// ... TBD ... /// Box6, /// /// ... TBD ... /// Box7, /// /// ... TBD ... /// Box8, /// /// ... TBD ... /// Box9 } /// /// Reference: BDK, Appendix 2, p. 9.
/// Reference: BDK, Appendix 2, p. 11. (see MessageRead() function).
///
public enum NxtMailbox2: byte { /// /// ... TBD ... /// Box0, /// /// ... TBD ... /// Box1, /// /// ... TBD ... /// Box2, /// /// ... TBD ... /// Box3, /// /// ... TBD ... /// Box4, /// /// ... TBD ... /// Box5, /// /// ... TBD ... /// Box6, /// /// ... TBD ... /// Box7, /// /// ... TBD ... /// Box8, /// /// ... TBD ... /// Box9, /// /// ... TBD ... /// Box10, /// /// ... TBD ... /// Box11, /// /// ... TBD ... /// Box12, /// /// ... TBD ... /// Box13, /// /// ... TBD ... /// Box14, /// /// ... TBD ... /// Box15, /// /// ... TBD ... /// Box16, /// /// ... TBD ... /// Box17, /// /// ... TBD ... /// Box18, /// /// ... TBD ... /// Box19 } #endregion }