// Server setup and main loop public void Run() { Console.WriteLine("Starting Windows-BACnetServerExampleProprietaryPropertyCSharp version {0}.{1}", APPLICATION_VERSION, CIBuildVersion.CIBUILDNUMBER); Console.WriteLine("https://github.com/chipkin/BACnetServerExampleProprietaryPropertyCSharp"); Console.WriteLine("FYI: BACnet Stack version: {0}.{1}.{2}.{3}", CASBACnetStackAdapter.GetAPIMajorVersion(), CASBACnetStackAdapter.GetAPIMinorVersion(), CASBACnetStackAdapter.GetAPIPatchVersion(), CASBACnetStackAdapter.GetAPIBuildVersion()); // 1. Setup the callbacks // --------------------------------------------------------------------------- // Send/Recv callbacks. CASBACnetStackAdapter.RegisterCallbackSendMessage(SendMessage); CASBACnetStackAdapter.RegisterCallbackReceiveMessage(RecvMessage); CASBACnetStackAdapter.RegisterCallbackGetSystemTime(CallbackGetSystemTime); // Get Datatype Callbacks CASBACnetStackAdapter.RegisterCallbackGetPropertyCharacterString(CallbackGetPropertyCharString); // Set Datatype Callbacks CASBACnetStackAdapter.RegisterCallbackSetPropertyCharacterString(CallbackSetPropertyCharacterString); // 2. Setup the BACnet device // --------------------------------------------------------------------------- // Initialize database this.database.Setup(); // Add the device CASBACnetStackAdapter.AddDevice(this.database.Device.instance); CASBACnetStackAdapter.SetProprietaryProperty(this.database.Device.instance, CASBACnetStackAdapter.OBJECT_TYPE_DEVICE, this.database.Device.instance, 512 + 1, false, false, CASBACnetStackAdapter.DATA_TYPE_CHARACTER_STRING, false, false, false); CASBACnetStackAdapter.SetProprietaryProperty(this.database.Device.instance, CASBACnetStackAdapter.OBJECT_TYPE_DEVICE, this.database.Device.instance, 512 + 2, true, true, CASBACnetStackAdapter.DATA_TYPE_CHARACTER_STRING, false, false, false); // Enable optional services CASBACnetStackAdapter.SetServiceEnabled(database.Device.instance, CASBACnetStackAdapter.SERVICE_READ_PROPERTY_MULTIPLE, true); CASBACnetStackAdapter.SetServiceEnabled(database.Device.instance, CASBACnetStackAdapter.SERVICE_WRITE_PROPERTY, true); CASBACnetStackAdapter.SetServiceEnabled(database.Device.instance, CASBACnetStackAdapter.SERVICE_WRITE_PROPERTY_MULTIPLE, true); // All done with the BACnet setup Console.WriteLine("FYI: CAS BACnet Stack Setup, successfuly"); // 3. Open the BACnet port to receive messages // --------------------------------------------------------------------------- this.udpServer = new UdpClient(SETTING_BACNET_PORT); this.RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0); // 4. Main loop // --------------------------------------------------------------------------- Console.WriteLine("FYI: Starting main loop"); for (; ;) { CASBACnetStackAdapter.Loop(); // CAS BACnet stack loop database.Loop(); // Update database values } }
// Send readproperty service request private void ReadProperty() { byte[] connectionStringAsBytes = CreateConnectionString(new IPEndPoint(IPAddress.Parse(SETTING_BACNET_SERVER_IP_ADDRESS), SETTING_BACNET_PORT)); byte * connectionStringPointer = PointerData(connectionStringAsBytes); Console.WriteLine("FYI: Sending ReadProperty message"); CASBACnetStackAdapter.BuildReadProperty(CASBACnetStackAdapter.OBJECT_TYPE_ANALOG_INPUT, 0, CASBACnetStackAdapter.PROPERTY_IDENTIFIER_PRESENT_VALUE, false, 0); CASBACnetStackAdapter.SendReadProperty(null, connectionStringPointer, (byte)connectionStringAsBytes.Length, CASBACnetStackAdapter.NETWORK_TYPE_IP, 0, null, 0); }
// Handle user input private void DoUserInput() { if (Console.KeyAvailable) { ConsoleKeyInfo key = Console.ReadKey(true); switch (key.Key) { case ConsoleKey.F1: Console.WriteLine("FYI: BACnet Stack version: {0}.{1}.{2}.{3}", CASBACnetStackAdapter.GetAPIMajorVersion(), CASBACnetStackAdapter.GetAPIMinorVersion(), CASBACnetStackAdapter.GetAPIPatchVersion(), CASBACnetStackAdapter.GetAPIBuildVersion()); break; case ConsoleKey.UpArrow: database.AnalogInputManualIncrement.PresentValue += 0.01f; Console.WriteLine("FYI: Increment Analog input {0} present value to {1:0.00}", 0, database.AnalogInputManualIncrement.PresentValue); // Notify the CAS BACnet stack that this value has been updated. // If there are any subscribers to this value, they will be sent be sent the updated value. CASBACnetStackAdapter.ValueUpdated(database.Device.Instance, CASBACnetStackAdapter.OBJECT_TYPE_ANALOG_INPUT, database.AnalogInputManualIncrement.Instance, CASBACnetStackAdapter.PROPERTY_IDENTIFIER_PRESENT_VALUE); break; case ConsoleKey.DownArrow: database.AnalogInputManualIncrement.PresentValue -= 0.01f; Console.WriteLine("FYI: Decrement Analog input {0} present value to {1:0.00}", 0, database.AnalogInputManualIncrement.PresentValue); CASBACnetStackAdapter.ValueUpdated(database.Device.Instance, CASBACnetStackAdapter.OBJECT_TYPE_ANALOG_INPUT, database.AnalogInputManualIncrement.Instance, CASBACnetStackAdapter.PROPERTY_IDENTIFIER_PRESENT_VALUE); break; case ConsoleKey.B: // BackUp Trend Log Console.WriteLine("Backing up the Trend Log contents..."); BackupTrendLogToFile(); Console.WriteLine("Back up complete"); break; case ConsoleKey.S: // Save Trend Log Multiple Console.WriteLine("Backing up the Trend Log Multiple contents..."); BackupTrendLogMultipleToFile(); Console.WriteLine("Back up complete"); break; case ConsoleKey.Q: Console.WriteLine("Exiting program"); System.Environment.Exit(1); break; case ConsoleKey.H: default: PrintHelp(); break; } } }
private void CheckUserSubOption(ConsoleKey input) { byte[] connectionStringAsBytes = CreateConnectionString(new IPEndPoint(IPAddress.Parse(SETTING_BACNET_SERVER_IP_ADDRESS), SETTING_BACNET_PORT)); byte * connectionStringPointer = PointerData(connectionStringAsBytes); switch (subOption) { case ConsoleKey.D: switch (input) { case ConsoleKey.L: Console.WriteLine("FYI: Sending a Local Broadcast WhoIs message"); CASBACnetStackAdapter.SendWhoIs(connectionStringPointer, (byte)connectionStringAsBytes.Length, CASBACnetStackAdapter.NETWORK_TYPE_IP, true, 0, null, 0); break; case ConsoleKey.W: Console.WriteLine("FYI: Sending a Local Broadcast WhoIs message with limits of devices with device instances between 389900 and 389999"); CASBACnetStackAdapter.SendWhoIsWithLimits(389900, 389999, connectionStringPointer, (byte)connectionStringAsBytes.Length, CASBACnetStackAdapter.NETWORK_TYPE_IP, true, 0, null, 0); break; case ConsoleKey.R: Console.WriteLine("FYI: Sending a Remote Broadcast WhoIs message to DNET 7"); CASBACnetStackAdapter.SendWhoIs(connectionStringPointer, (byte)connectionStringAsBytes.Length, CASBACnetStackAdapter.NETWORK_TYPE_IP, true, 7, null, 0); break; case ConsoleKey.G: Console.WriteLine("FYI: Sending a Global Broadcast WhoIs message"); CASBACnetStackAdapter.SendWhoIs(connectionStringPointer, (byte)connectionStringAsBytes.Length, CASBACnetStackAdapter.NETWORK_TYPE_IP, true, 0xFFFF, null, 0); break; case ConsoleKey.Q: Console.WriteLine("FYI: Exiting the WhoIs menu"); subOption = ConsoleKey.NoName; break; default: Console.WriteLine("You pressed the '{0}' key. Not an assigned WhoIs option", input); Console.WriteLine("\nHelp:"); Console.WriteLine(" L - Send a Local Broadcast WhoIs message"); Console.WriteLine(" W - Send a Local Broadcast WhoIs message with Limits"); Console.WriteLine(" R - Send a Remote Broadcast WhoIs message"); Console.WriteLine(" G - Send a Global Broadcast WhoIs message"); Console.WriteLine(" Q - Exit WhoIs menu"); break; } break; default: break; } }
// Callback used by the BACnet Stack to send a BACnet message public UInt16 SendMessage(System.Byte *message, UInt16 messageLength, System.Byte *connectionString, System.Byte connectionStringLength, System.Byte networkType, Boolean broadcast) { if (connectionStringLength < 6 || messageLength <= 0) { return(0); } // Extract the connection string into a IP address and port. IPAddress ipAddress; if (broadcast) { // Note: for the sake of this example, simply setting the last octet if the message should be sent as a broadcast. ipAddress = new IPAddress(new byte[] { connectionString[0], connectionString[1], connectionString[2], 0xFF }); } else { ipAddress = new IPAddress(new byte[] { connectionString[0], connectionString[1], connectionString[2], connectionString[3] }); } IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, (connectionString[4] + connectionString[5] * 256)); // Debug Console.WriteLine("FYI: Sending {0} bytes to {1}", messageLength, ipEndPoint.ToString()); // XML decode (debug) IntPtr xmlBuffer = Marshal.AllocHGlobal(1024 * 5); int bufferLength = CASBACnetStackAdapter.DecodeAsXML(message, messageLength, xmlBuffer, 1024 * 5); string xmlStringBuffer = Marshal.PtrToStringAnsi(xmlBuffer, bufferLength); Marshal.FreeHGlobal(xmlBuffer);// Free HGlobal memory Console.WriteLine(xmlStringBuffer); Console.WriteLine(""); // Copy from the unsafe pointer to a Byte array. byte[] sendBytes = new byte[messageLength]; Marshal.Copy((IntPtr)message, sendBytes, 0, messageLength); try { this.udpServer.Send(sendBytes, sendBytes.Length, ipEndPoint); return((UInt16)sendBytes.Length); } catch (Exception e) { Console.WriteLine(e.ToString()); } return(0); }
// Not used private void DoUserInput() { if (Console.KeyAvailable) { ConsoleKeyInfo key = Console.ReadKey(true); switch (key.Key) { case ConsoleKey.F1: Console.WriteLine("FYI: BACnet Stack version: {0}.{1}.{2}.{3}", CASBACnetStackAdapter.GetAPIMajorVersion(), CASBACnetStackAdapter.GetAPIMinorVersion(), CASBACnetStackAdapter.GetAPIPatchVersion(), CASBACnetStackAdapter.GetAPIBuildVersion()); break; default: break; } } }
// Load TrendLogMultiple initial data points private bool LoadTrendLogMultipleFromFile(string filename) { string line; StreamReader file = new StreamReader(filename); while ((line = file.ReadLine()) != null) { if (line.StartsWith("#")) { // Ignore comments, lines that start with # continue; } int start = 0; int index = line.IndexOf(','); string number = line.Substring(start, index); start = index + 1; index = line.IndexOf(',', start); string timestampStr = line.Substring(start, index - start); start = index + 1; index = line.IndexOf(',', start); string dataTypeStr = line.Substring(start, index - start); string data = line.Substring(index + 1); // Insert TrendLog entry ulong timestamp = Convert.ToUInt64(timestampStr); byte dataType = Convert.ToByte(dataTypeStr); byte[] dataAsString = Encoding.ASCII.GetBytes(data); fixed(byte *ptr = dataAsString) { if (!CASBACnetStackAdapter.InsertTrendLogMultipleRecord(database.Device.Instance, database.TrendLogMultiple.Instance, timestamp, dataType, ptr, (uint)dataAsString.Length)) { Console.WriteLine("Error - failed to insert record in TrendLogMultiple for line: {0}", line); continue; } } } return(true); }
// Callback used by the BACnet Stack to check if there is a message to process public UInt16 RecvMessage(System.Byte *message, UInt16 maxMessageLength, System.Byte *receivedConnectionString, System.Byte maxConnectionStringLength, System.Byte *receivedConnectionStringLength, System.Byte *networkType) { try { if (this.udpServer.Available > 0) { // Data buffer for incoming data. byte[] receiveBytes = this.udpServer.Receive(ref this.RemoteIpEndPoint); byte[] ipAddress = RemoteIpEndPoint.Address.GetAddressBytes(); byte[] port = BitConverter.GetBytes(UInt16.Parse(RemoteIpEndPoint.Port.ToString())); // Copy from the unsafe pointer to a Byte array. Marshal.Copy(receiveBytes, 0, (IntPtr)message, receiveBytes.Length); // Copy the Connection string Marshal.Copy(ipAddress, 0, (IntPtr)receivedConnectionString, 4); Marshal.Copy(port, 0, (IntPtr)receivedConnectionString + 4, 2); *receivedConnectionStringLength = 6; // Debug Console.WriteLine("FYI: Recving {0} bytes from {1}", receiveBytes.Length, RemoteIpEndPoint.ToString()); // XML decode (debug) IntPtr xmlBuffer = Marshal.AllocHGlobal(1024 * 5); int bufferLength = CASBACnetStackAdapter.DecodeAsXML(message, (ushort)receiveBytes.Length, xmlBuffer, 1024 * 5); string xmlStringBuffer = Marshal.PtrToStringAnsi(xmlBuffer, bufferLength); Marshal.FreeHGlobal(xmlBuffer);// Free HGlobal memory Console.WriteLine(xmlStringBuffer); Console.WriteLine(""); // Return length return((ushort)receiveBytes.Length); } } catch (Exception e) { Console.WriteLine(e.ToString()); } return(0); }
// Backup trendlog multiple data points to txt file private bool BackupTrendLogMultipleToFile() { string currentDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); string format = "yyyyMMMdHHmm"; string suffix = DateTime.Now.ToString(format); string output = Path.Combine(currentDirectory, "trendLogMultipleBackupExample_" + suffix + ".txt"); StreamWriter file = new StreamWriter(output); uint offset = 0; bool more = true; file.WriteLine("# Backup generated on {0}", DateTime.Now.ToString("o")); file.WriteLine("#"); file.WriteLine("# Number, Timestamp (Epoch), DataType, DataAsString"); while (more) { ulong timestamp = 0; byte dataType = 0; byte[] dataAsString = new byte[256]; uint dataLength = 0; fixed(byte *ptr = dataAsString) { if (!CASBACnetStackAdapter.ReadTrendLogMultipleRecord(database.Device.Instance, database.TrendLogMultiple.Instance, offset, ×tamp, &dataType, ptr, &dataLength, 256, &more)) { Console.WriteLine("Error - failed to read record from TrendLogMultiple"); return(false); } offset++; string data = Encoding.ASCII.GetString(dataAsString); file.WriteLine("{0},{1},{2},{3}", offset, timestamp, dataType, data); } } file.Close(); return(true); }
// Load TrendLog initial data points private bool LoadTrendLogFromFile(string filename) { string line; StreamReader file = new StreamReader(filename); while ((line = file.ReadLine()) != null) { if (line.StartsWith("#")) { // Ignore comments, lines that start with # continue; } // Split on , string[] elements = line.Split(','); if (elements.Length != 4) { Console.WriteLine("Error - invalid data line: {0}", line); continue; } // Insert TrendLog entry ulong timestamp = Convert.ToUInt64(elements[1]); byte datumType = Convert.ToByte(elements[2]); byte[] datumAsString = Encoding.ASCII.GetBytes(elements[3]); fixed(byte *ptr = datumAsString) { if (!CASBACnetStackAdapter.InsertTrendLogRecord(database.Device.Instance, database.TrendLog.Instance, timestamp, datumType, ptr, (uint)datumAsString.Length, null, 0)) { Console.WriteLine("Error - failed to insert record in TrendLog for line: {0}", line); continue; } } } return(true); }
// Server setup and main loop public void Run() { Console.WriteLine("Starting Windows BACnetServer TrendLog Example CSharp version: {0}.{1}", APPLICATION_VERSION, CIBuildVersion.CIBUILDNUMBER); Console.WriteLine("https://github.com/chipkin/BACnetServerTrendLogExampleCSharp"); Console.WriteLine("FYI: BACnet Stack version: {0}.{1}.{2}.{3}", CASBACnetStackAdapter.GetAPIMajorVersion(), CASBACnetStackAdapter.GetAPIMinorVersion(), CASBACnetStackAdapter.GetAPIPatchVersion(), CASBACnetStackAdapter.GetAPIBuildVersion()); // 1. Setup the callbacks // --------------------------------------------------------------------------- // Send/Recv Callbacks CASBACnetStackAdapter.RegisterCallbackSendMessage(SendMessage); CASBACnetStackAdapter.RegisterCallbackReceiveMessage(RecvMessage); // System Callbacks CASBACnetStackAdapter.RegisterCallbackGetSystemTime(CallbackGetSystemTime); // Get Property Callbacks CASBACnetStackAdapter.RegisterCallbackGetPropertyCharacterString(CallbackGetPropertyCharString); CASBACnetStackAdapter.RegisterCallbackGetPropertyEnumerated(CallbackGetEnumerated); CASBACnetStackAdapter.RegisterCallbackGetPropertyReal(CallbackGetPropertyReal); CASBACnetStackAdapter.RegisterCallbackGetPropertyUnsignedInteger(CallbackGetUnsignedInteger); // 2. Setup the BACnet device // --------------------------------------------------------------------------- // Setup database database.Setup(); // Add Objects // --------------------------------------------------------------------------- // Add the device CASBACnetStackAdapter.AddDevice(database.Device.Instance); CASBACnetStackAdapter.SetPropertyEnabled(database.Device.Instance, CASBACnetStackAdapter.OBJECT_TYPE_DEVICE, database.Device.Instance, CASBACnetStackAdapter.PROPERTY_IDENTIFIER_DESCRIPTION, true); // Add analog inputs CASBACnetStackAdapter.AddObject(database.Device.Instance, CASBACnetStackAdapter.OBJECT_TYPE_ANALOG_INPUT, database.AnalogInputAutoIncrement.Instance); CASBACnetStackAdapter.AddObject(database.Device.Instance, CASBACnetStackAdapter.OBJECT_TYPE_ANALOG_INPUT, database.AnalogInputManualIncrement.Instance); // Add binary input CASBACnetStackAdapter.AddObject(database.Device.Instance, CASBACnetStackAdapter.OBJECT_TYPE_BINARY_INPUT, database.BinaryInput.Instance); // Add multi-state input CASBACnetStackAdapter.AddObject(database.Device.Instance, CASBACnetStackAdapter.OBJECT_TYPE_MULTI_STATE_INPUT, database.MultiStateInput.Instance); // Add Trend Log CASBACnetStackAdapter.AddTrendLogObject(database.Device.Instance, database.TrendLog.Instance, CASBACnetStackAdapter.OBJECT_TYPE_ANALOG_INPUT, database.AnalogInputAutoIncrement.Instance, CASBACnetStackAdapter.PROPERTY_IDENTIFIER_PRESENT_VALUE, 100, false, 0); CASBACnetStackAdapter.SetTrendLogTypeToPolled(database.Device.Instance, CASBACnetStackAdapter.OBJECT_TYPE_TREND_LOG, database.TrendLog.Instance, true, false, 3000); // Add Trend Log Multiple CASBACnetStackAdapter.AddTrendLogMultipleObject(database.Device.Instance, database.TrendLogMultiple.Instance, 100); CASBACnetStackAdapter.AddLoggedObjectToTrendLogMultiple(database.Device.Instance, database.TrendLogMultiple.Instance, CASBACnetStackAdapter.OBJECT_TYPE_ANALOG_INPUT, database.AnalogInputAutoIncrement.Instance, CASBACnetStackAdapter.PROPERTY_IDENTIFIER_PRESENT_VALUE, false, 0, false, 0); CASBACnetStackAdapter.AddLoggedObjectToTrendLogMultiple(database.Device.Instance, database.TrendLogMultiple.Instance, CASBACnetStackAdapter.OBJECT_TYPE_ANALOG_INPUT, database.AnalogInputManualIncrement.Instance, CASBACnetStackAdapter.PROPERTY_IDENTIFIER_PRESENT_VALUE, false, 0, false, 0); CASBACnetStackAdapter.AddLoggedObjectToTrendLogMultiple(database.Device.Instance, database.TrendLogMultiple.Instance, CASBACnetStackAdapter.OBJECT_TYPE_BINARY_INPUT, database.BinaryInput.Instance, CASBACnetStackAdapter.PROPERTY_IDENTIFIER_PRESENT_VALUE, false, 0, false, 0); CASBACnetStackAdapter.AddLoggedObjectToTrendLogMultiple(database.Device.Instance, database.TrendLogMultiple.Instance, CASBACnetStackAdapter.OBJECT_TYPE_MULTI_STATE_INPUT, database.MultiStateInput.Instance, CASBACnetStackAdapter.PROPERTY_IDENTIFIER_PRESENT_VALUE, false, 0, false, 0); CASBACnetStackAdapter.SetTrendLogTypeToPolled(database.Device.Instance, CASBACnetStackAdapter.OBJECT_TYPE_TREND_LOG_MULTIPLE, database.TrendLogMultiple.Instance, true, false, 3000); // 3. Enable Services // --------------------------------------------------------------------------- // Enable Optional Properties CASBACnetStackAdapter.SetServiceEnabled(database.Device.Instance, CASBACnetStackAdapter.SERVICES_SUPPORTED_READ_PROPERTY_MULTIPLE, true); CASBACnetStackAdapter.SetServiceEnabled(database.Device.Instance, CASBACnetStackAdapter.SERVICES_SUPPORTED_WRITE_PROPERTY, true); CASBACnetStackAdapter.SetServiceEnabled(database.Device.Instance, CASBACnetStackAdapter.SERVICES_SUPPORTED_READ_RANGE, true); // All done with the BACnet Setup Console.WriteLine("FYI: CAS BACnet Stack Setup, successfully"); // 4. Setup Trend Log objects // --------------------------------------------------------------------------- Console.WriteLine("FYI: Loading initial data points to Trend Log and Trend Log Multiple objects"); // Preload Trend Log and Trend Log Multiple from file string currentDirectory = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location); _trendLogBackupPath = Path.Combine(currentDirectory, "trendLogBackupExample.txt"); _trendLogMultipleBackupPath = Path.Combine(currentDirectory, "trendLogMultipleBackupExample.txt"); if (!LoadTrendLogFromFile(_trendLogBackupPath)) { Console.WriteLine("Failed to load trendLog from {0}", _trendLogBackupPath); return; } if (!LoadTrendLogMultipleFromFile(_trendLogMultipleBackupPath)) { Console.WriteLine("Failed to load trendLogMultiple from {0}", _trendLogMultipleBackupPath); return; } Console.WriteLine("FYI: Initial data load complete"); // 5. Open the BACnet port to receive messages // --------------------------------------------------------------------------- udpServer = new UdpClient(SETTING_BACNET_PORT); remoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0); // 6. Main loop // --------------------------------------------------------------------------- Console.WriteLine("FYI: Starting main loop"); for (; ;) { CASBACnetStackAdapter.Loop(); // BACnet Stack adapter update loop database.Loop(); // Update values in the example database DoUserInput(); // Handle user input } }
// Callback used by the BACnet Stack to set Charstring property values to the user public bool CallbackGetPropertyCharString(UInt32 deviceInstance, UInt16 objectType, UInt32 objectInstance, UInt32 propertyIdentifier, System.Byte *value, UInt32 *valueElementCount, UInt32 maxElementCount, System.Byte encodingType, bool useArrayIndex, UInt32 propertyArrayIndex) { Console.WriteLine("FYI: Request for CallbackGetPropertyCharString. objectType={0}, objectInstance={1}, propertyIdentifier={2}, propertyArrayIndex={3}", objectType, objectInstance, propertyIdentifier, propertyArrayIndex); switch (objectType) { case CASBACnetStackAdapter.OBJECT_TYPE_DEVICE: if (deviceInstance == database.Device.Instance && objectInstance == database.Device.Instance) { if (propertyIdentifier == CASBACnetStackAdapter.PROPERTY_IDENTIFIER_OBJECT_NAME) { *valueElementCount = CASBACnetStackAdapter.UpdateStringAndReturnSize(value, maxElementCount, database.Device.Name); return(true); } else if (propertyIdentifier == CASBACnetStackAdapter.PROPERTY_IDENTIFIER_MODEL_NAME) { *valueElementCount = CASBACnetStackAdapter.UpdateStringAndReturnSize(value, maxElementCount, database.Device.ModelName); return(true); } else if (propertyIdentifier == CASBACnetStackAdapter.PROPERTY_IDENTIFIER_VENDOR_NAME) { *valueElementCount = CASBACnetStackAdapter.UpdateStringAndReturnSize(value, maxElementCount, database.Device.VendorName); return(true); } else if (propertyIdentifier == CASBACnetStackAdapter.PROPERTY_IDENTIFIER_DESCRIPTION) { *valueElementCount = CASBACnetStackAdapter.UpdateStringAndReturnSize(value, maxElementCount, database.Device.Description); return(true); } else if (propertyIdentifier == CASBACnetStackAdapter.PROPERTY_IDENTIFIER_APPLICATIONSOFTWAREVERSION) { string version = APPLICATION_VERSION + "." + CIBuildVersion.CIBUILDNUMBER; * valueElementCount = CASBACnetStackAdapter.UpdateStringAndReturnSize(value, maxElementCount, version); return(true); } } break; case CASBACnetStackAdapter.OBJECT_TYPE_ANALOG_INPUT: if (objectInstance == database.AnalogInputAutoIncrement.Instance) { if (propertyIdentifier == CASBACnetStackAdapter.PROPERTY_IDENTIFIER_OBJECT_NAME) { *valueElementCount = CASBACnetStackAdapter.UpdateStringAndReturnSize(value, maxElementCount, database.AnalogInputAutoIncrement.Name); return(true); } } else if (objectInstance == database.AnalogInputManualIncrement.Instance) { if (propertyIdentifier == CASBACnetStackAdapter.PROPERTY_IDENTIFIER_OBJECT_NAME) { *valueElementCount = CASBACnetStackAdapter.UpdateStringAndReturnSize(value, maxElementCount, database.AnalogInputManualIncrement.Name); return(true); } } break; case CASBACnetStackAdapter.OBJECT_TYPE_BINARY_INPUT: if (objectInstance == database.BinaryInput.Instance) { if (propertyIdentifier == CASBACnetStackAdapter.PROPERTY_IDENTIFIER_OBJECT_NAME) { *valueElementCount = CASBACnetStackAdapter.UpdateStringAndReturnSize(value, maxElementCount, database.BinaryInput.Name); return(true); } } break; case CASBACnetStackAdapter.OBJECT_TYPE_MULTI_STATE_INPUT: if (objectInstance == database.MultiStateInput.Instance) { if (propertyIdentifier == CASBACnetStackAdapter.PROPERTY_IDENTIFIER_OBJECT_NAME) { *valueElementCount = CASBACnetStackAdapter.UpdateStringAndReturnSize(value, maxElementCount, database.MultiStateInput.Name); return(true); } else if (propertyIdentifier == CASBACnetStackAdapter.PROPERTY_IDENTIFIER_STATETEXT && useArrayIndex) { if (propertyArrayIndex <= database.MultiStateInput.StateText.Length) { *valueElementCount = CASBACnetStackAdapter.UpdateStringAndReturnSize(value, maxElementCount, database.MultiStateInput.StateText[propertyArrayIndex - 1]); return(true); } } } break; case CASBACnetStackAdapter.OBJECT_TYPE_TREND_LOG: if (objectInstance == database.TrendLog.Instance) { if (propertyIdentifier == CASBACnetStackAdapter.PROPERTY_IDENTIFIER_OBJECT_NAME) { *valueElementCount = CASBACnetStackAdapter.UpdateStringAndReturnSize(value, maxElementCount, database.TrendLog.Name); return(true); } } break; case CASBACnetStackAdapter.OBJECT_TYPE_TREND_LOG_MULTIPLE: if (objectInstance == database.TrendLogMultiple.Instance) { if (propertyIdentifier == CASBACnetStackAdapter.PROPERTY_IDENTIFIER_OBJECT_NAME) { *valueElementCount = CASBACnetStackAdapter.UpdateStringAndReturnSize(value, maxElementCount, database.TrendLogMultiple.Name); return(true); } } break; default: break; } Console.WriteLine(" FYI: Not implmented. propertyIdentifier={0}", propertyIdentifier); return(false); // Could not handle this request. }
ConsoleKey subOption = ConsoleKey.NoName; // If set to NoName, no suboption. See CheckUserInput for more info // Server setup and main loop public void Run() { Console.WriteLine("Starting BACnet Client Example CSharp version {0}.{1}", APPLICATION_VERSION, CIBuildVersion.CIBUILDNUMBER); Console.WriteLine("https://github.com/chipkin/BACnetClientExampleCSharp"); Console.WriteLine("FYI: BACnet Stack version: {0}.{1}.{2}.{3}", CASBACnetStackAdapter.GetAPIMajorVersion(), CASBACnetStackAdapter.GetAPIMinorVersion(), CASBACnetStackAdapter.GetAPIPatchVersion(), CASBACnetStackAdapter.GetAPIBuildVersion()); // 1. Setup the hooks and callbacks // --------------------------------------------------------------------------- // Send/Recv callbacks CASBACnetStackAdapter.RegisterCallbackSendMessage(SendMessage); CASBACnetStackAdapter.RegisterCallbackReceiveMessage(RecvMessage); CASBACnetStackAdapter.RegisterCallbackGetSystemTime(CallbackGetSystemTime); CASBACnetStackAdapter.RegisterCallbackGetPropertyUnsignedInteger(CallbackGetUnsignedInteger); // Data type hooks CASBACnetStackAdapter.BACnetStack_RegisterHookIAm(CallbackHookIAm); CASBACnetStackAdapter.BACnetStack_RegisterHookIHave(CallbackHookIHave); CASBACnetStackAdapter.BACnetStack_RegisterHookError(CallbackHookError); CASBACnetStackAdapter.BACnetStack_RegisterHookReject(CallbackHookReject); CASBACnetStackAdapter.BACnetStack_RegisterHookAbort(CallbackHookAbort); CASBACnetStackAdapter.BACnetStack_RegisterHookSimpleAck(CallbackHookSimpleAck); CASBACnetStackAdapter.BACnetStack_RegisterHookTimeout(CallbackHookTimeout); CASBACnetStackAdapter.BACnetStack_RegisterHookPropertyBitString(CallbackHookPropertyBitString); CASBACnetStackAdapter.BACnetStack_RegisterHookPropertyBool(CallbackHookPropertyBool); CASBACnetStackAdapter.BACnetStack_RegisterHookPropertyCharString(CallbackHookPropertyCharString); CASBACnetStackAdapter.BACnetStack_RegisterHookPropertyDate(CallbackHookPropertyDate); CASBACnetStackAdapter.BACnetStack_RegisterHookPropertyDouble(CallbackHookPropertyDouble); CASBACnetStackAdapter.BACnetStack_RegisterHookPropertyEnum(CallbackHookPropertyEnum); CASBACnetStackAdapter.BACnetStack_RegisterHookPropertyNull(CallbackHookPropertyNull); CASBACnetStackAdapter.BACnetStack_RegisterHookPropertyObjectIdentifier(CallbackHookPropertyObjectIdentifier); CASBACnetStackAdapter.BACnetStack_RegisterHookPropertyOctString(CallbackHookPropertyOctString); CASBACnetStackAdapter.BACnetStack_RegisterHookPropertyInt(CallbackHookPropertyInt); CASBACnetStackAdapter.BACnetStack_RegisterHookPropertyReal(CallbackHookPropertyReal); CASBACnetStackAdapter.BACnetStack_RegisterHookPropertyTime(CallbackHookPropertyTime); CASBACnetStackAdapter.BACnetStack_RegisterHookPropertyUInt(CallbackHookPropertyUInt); // 2. Setup the BACnet device // --------------------------------------------------------------------------- CASBACnetStackAdapter.AddDevice(SETTING_BACNET_DEVICE_INSTANCE); // 3. Enable Services // --------------------------------------------------------------------------- // Enable I-Am Service CASBACnetStackAdapter.SetServiceEnabled(SETTING_BACNET_DEVICE_INSTANCE, CASBACnetStackAdapter.SERVICES_SUPPORTED_I_AM, true); // Disabling WhoIs processing so this example does not respond to the WhoIs message it sends CASBACnetStackAdapter.SetServiceEnabled(SETTING_BACNET_DEVICE_INSTANCE, CASBACnetStackAdapter.SERVICES_SUPPORTED_WHO_IS, false); // All done with the BACnet setup. Console.WriteLine("FYI: CAS BACnet Stack Setup, successfuly"); // 4. Open the BACnet port to receive messages // --------------------------------------------------------------------------- this.udpServer = new UdpClient(SETTING_BACNET_PORT); this.RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0); // 5. Start the main loop // --------------------------------------------------------------------------- Console.WriteLine("FYI: Starting main loop"); PrintHelp(); for (; ;) { // Main BACnet stack loop CASBACnetStackAdapter.Loop(); // Exit program if Q is hit on main menu if (!CheckUserInput()) { break; } } }
// Handle user input private bool CheckUserInput() { if (!Console.KeyAvailable) { return(true); // Nothing to do. } ConsoleKeyInfo inputKey = Console.ReadKey(true); Console.WriteLine(">{0}", inputKey.Key); // Check if in a subOption if (subOption != ConsoleKey.NoName) { CheckUserSubOption(inputKey.Key); return(true); } byte[] connectionStringAsBytes = CreateConnectionString(new IPEndPoint(IPAddress.Parse(SETTING_BACNET_SERVER_IP_ADDRESS), SETTING_BACNET_PORT)); byte * connectionStringPointer = PointerData(connectionStringAsBytes); const UInt16 timeToLive = 60 * 5; // 5 Min switch (inputKey.Key) { case ConsoleKey.D: Console.WriteLine("\nWhoIs Menu:"); Console.WriteLine(" L - Send a Local Broadcast WhoIs message"); Console.WriteLine(" W - Send a Local Broadcast WhoIs message with Limits"); Console.WriteLine(" R - Send a Remote Broadcast WhoIs message"); Console.WriteLine(" G - Send a Global Broadcast WhoIs message"); Console.WriteLine(" Q - Exit WhoIs menu"); subOption = inputKey.Key;; break; case ConsoleKey.F: Console.WriteLine("FYI: Sending RegisterForeignDevice message"); CASBACnetStackAdapter.SendRegisterForeignDevice(timeToLive, connectionStringPointer, (byte)connectionStringAsBytes.Length); break; case ConsoleKey.C: Console.WriteLine("FYI: Sending SubscribeCOV message"); CASBACnetStackAdapter.SendSubscribeCOV(null, 500, CASBACnetStackAdapter.OBJECT_TYPE_ANALOG_INPUT, 0, false, timeToLive, connectionStringPointer, (byte)connectionStringAsBytes.Length, CASBACnetStackAdapter.NETWORK_TYPE_IP, 0, null, 0); break; case ConsoleKey.R: Console.WriteLine("FYI: Sending ReadProperty message"); CASBACnetStackAdapter.BuildReadProperty(CASBACnetStackAdapter.OBJECT_TYPE_ANALOG_INPUT, 0, CASBACnetStackAdapter.PROPERTY_IDENTIFIER_PRESENT_VALUE, false, 0); CASBACnetStackAdapter.SendReadProperty(null, connectionStringPointer, (byte)connectionStringAsBytes.Length, CASBACnetStackAdapter.NETWORK_TYPE_IP, 0, null, 0); break; case ConsoleKey.A: Console.WriteLine("FYI: Sending ReadProperty All message"); CASBACnetStackAdapter.BuildReadProperty(CASBACnetStackAdapter.OBJECT_TYPE_DEVICE, 389999, CASBACnetStackAdapter.PROPERTY_IDENTIFIER_ALL, false, 0); CASBACnetStackAdapter.SendReadProperty(null, connectionStringPointer, (byte)connectionStringAsBytes.Length, CASBACnetStackAdapter.NETWORK_TYPE_IP, 0, null, 0); break; case ConsoleKey.W: Console.WriteLine("FYI: Sending WriteProperty message"); String valueString = "99.6"; IntPtr ptS = Marshal.StringToHGlobalAnsi(valueString); CASBACnetStackAdapter.BuildWriteProperty(CASBACnetStackAdapter.DATA_TYPE_REAL, ptS, (uint)valueString.Length, CASBACnetStackAdapter.OBJECT_TYPE_ANALOG_OUTPUT, 1, CASBACnetStackAdapter.PROPERTY_IDENTIFIER_PRESENT_VALUE, false, 0, true, 8); CASBACnetStackAdapter.SendWriteProperty(null, connectionStringPointer, (byte)connectionStringAsBytes.Length, CASBACnetStackAdapter.NETWORK_TYPE_IP, 0, null, 0); break; case ConsoleKey.M: Console.WriteLine("FYI: Sending ReadProperty Multiple Asynch message"); CASBACnetStackAdapter.ReadPropertyAsync[] readPropertyValues = new CASBACnetStackAdapter.ReadPropertyAsync[3]; readPropertyValues[0] = new CASBACnetStackAdapter.ReadPropertyAsync() { flags = 0x00, objectInstance = 0, objectType = CASBACnetStackAdapter.OBJECT_TYPE_ANALOG_INPUT, propertyIdentifier = CASBACnetStackAdapter.PROPERTY_IDENTIFIER_PRESENT_VALUE, propertyArrayIndex = 0 }; readPropertyValues[1] = new CASBACnetStackAdapter.ReadPropertyAsync() { flags = 0x00, objectInstance = 3, objectType = CASBACnetStackAdapter.OBJECT_TYPE_BINARY_INPUT, propertyIdentifier = CASBACnetStackAdapter.PROPERTY_IDENTIFIER_PRESENT_VALUE, propertyArrayIndex = 0 }; readPropertyValues[2] = new CASBACnetStackAdapter.ReadPropertyAsync() { flags = 0x01, // Use array index objectInstance = 13, objectType = CASBACnetStackAdapter.OBJECT_TYPE_MULTI_STATE_INPUT, propertyIdentifier = CASBACnetStackAdapter.PROPERTY_IDENTIFIER_PRESENT_VALUE, propertyArrayIndex = 5 }; CASBACnetStackAdapter.SendReadPropertyAsync(null, connectionStringPointer, (byte)connectionStringAsBytes.Length, CASBACnetStackAdapter.NETWORK_TYPE_IP, 0, null, 0, readPropertyValues); break; case ConsoleKey.E: Console.WriteLine("FYI: Sending WriteProperty Multiple Asynch message"); CASBACnetStackAdapter.WritePropertyAsync[] writePropertyValues = new CASBACnetStackAdapter.WritePropertyAsync[3]; writePropertyValues[0] = new CASBACnetStackAdapter.WritePropertyAsync() { flags = 0x00, objectInstance = 1, objectType = CASBACnetStackAdapter.OBJECT_TYPE_ANALOG_OUTPUT, propertyIdentifier = CASBACnetStackAdapter.PROPERTY_IDENTIFIER_PRESENT_VALUE, propertyArrayIndex = 0, dataType = CASBACnetStackAdapter.DATA_TYPE_REAL, priority = 0, valueAsString = "1.19" }; writePropertyValues[1] = new CASBACnetStackAdapter.WritePropertyAsync() { flags = 0x00, objectInstance = 1, objectType = CASBACnetStackAdapter.OBJECT_TYPE_BINARY_OUTPUT, propertyIdentifier = CASBACnetStackAdapter.PROPERTY_IDENTIFIER_PRESENT_VALUE, propertyArrayIndex = 0, dataType = CASBACnetStackAdapter.DATA_TYPE_ENUMERATED, priority = 0, valueAsString = "1" }; writePropertyValues[2] = new CASBACnetStackAdapter.WritePropertyAsync() { flags = 0x01 | 0x02, // 0x01 = use propertyArrayIndex, 0x02 = use priority objectInstance = 14, objectType = CASBACnetStackAdapter.OBJECT_TYPE_MULTI_STATE_OUTPUT, propertyIdentifier = CASBACnetStackAdapter.PROPERTY_IDENTIFIER_PRESENT_VALUE, propertyArrayIndex = 0, dataType = CASBACnetStackAdapter.DATA_TYPE_ENUMERATED, priority = 8, valueAsString = "7" }; CASBACnetStackAdapter.SendWritePropertyAsync(null, connectionStringPointer, (byte)connectionStringAsBytes.Length, CASBACnetStackAdapter.NETWORK_TYPE_IP, 0, null, 0, writePropertyValues); break; case ConsoleKey.X: Console.WriteLine("FYI: Debug test for ConfirmedRequest"); String testA_IPAddress = "192.168.1.26"; byte[] testA_ConnectionStringAsBytes = CreateConnectionString(new IPEndPoint(IPAddress.Parse(testA_IPAddress), SETTING_BACNET_PORT)); byte * testA_ConnectionStringPointer = PointerData(testA_ConnectionStringAsBytes); CASBACnetStackAdapter.BuildReadProperty(CASBACnetStackAdapter.OBJECT_TYPE_DEVICE, 389999, CASBACnetStackAdapter.PROPERTY_IDENTIFIER_OBJECT_NAME, false, 0); CASBACnetStackAdapter.SendReadProperty(null, testA_ConnectionStringPointer, (byte)testA_ConnectionStringAsBytes.Length, CASBACnetStackAdapter.NETWORK_TYPE_IP, 0, null, 0); String testB_IPAddress = "192.168.1.111"; byte[] testB_ConnectionStringAsBytes = CreateConnectionString(new IPEndPoint(IPAddress.Parse(testB_IPAddress), SETTING_BACNET_PORT)); byte * testB_ConnectionStringPointer = PointerData(testB_ConnectionStringAsBytes); CASBACnetStackAdapter.BuildReadProperty(CASBACnetStackAdapter.OBJECT_TYPE_DEVICE, 389001, CASBACnetStackAdapter.PROPERTY_IDENTIFIER_OBJECT_NAME, false, 0); CASBACnetStackAdapter.SendReadProperty(null, testB_ConnectionStringPointer, (byte)testB_ConnectionStringAsBytes.Length, CASBACnetStackAdapter.NETWORK_TYPE_IP, 0, null, 0); /* * String testC_IPAddress = "192.168.1.26"; * byte[] testC_ConnectionStringAsBytes = CreateConnectionString(new IPEndPoint(IPAddress.Parse(testC_IPAddress), SETTING_BACNET_PORT)); * byte* testC_ConnectionStringPointer = PointerData(testC_ConnectionStringAsBytes); * * CASBACnetStackAdapter.BuildReadProperty(CASBACnetStackAdapter.OBJECT_TYPE_DEVICE, 189999, CASBACnetStackAdapter.PROPERTY_IDENTIFIER_OBJECT_NAME, false, 0); * CASBACnetStackAdapter.SendReadProperty(null, testC_ConnectionStringPointer, (byte)testC_ConnectionStringAsBytes.Length, CASBACnetStackAdapter.NETWORK_TYPE_IP, 0, null, 0); */ break; // Quit the server case ConsoleKey.Q: Console.WriteLine("\nQuitting..."); return(false); default: Console.WriteLine("You pressed the '{0}' key. Not assigned", inputKey.Key); PrintHelp(); break; } // Switch return(true); }