/* This software is subject to the license described in the License.txt file included with this software distribution. You may not use this file except in compliance with this license. Copyright (c) Dynastream Innovations Inc. 2016 All rights reserved. */ ////////////////////////////////////////////////////////////////////////// // To use the ANT-FS functionality in the managed library, you must: // 1. Import ANT_NET.dll as a reference // 2. Reference the ANT_Managed_Library and ANT_Managed_Library.ANTFS namespaces // 3. Include the following files in the working directory of your application: // - DSI_CP310xManufacturing_3_1.dll // - DSI_SiUSBXp_3_1.dll // - ANT_WrappedLib.dll // - ANT_NET.dll // 4. You will also need to copy ANT_NET.xml into your project for // Intellisense to work properly ////////////////////////////////////////////////////////////////////////// using System; using System.Text; using System.IO; using System.Collections.Generic; using System.Threading; using ANT_Managed_Library; using ANT_Managed_Library.ANTFS; namespace ANTFS_Demo { /// /// This demo shows how to configure a basic ANT-FS host /// For a more featured demo, please refer to the source code of the ANT-FS PC tools (however, the host source code is in C++) /// public class HostDemo { // ANT-FS Configuration Parameters readonly string HostFriendlyName = "ConsoleHost"; // ANT-FS Host Friendly Name readonly byte ConnectRF = (byte)ANT_Managed_Library.ANTFS.RadioFrequency.Auto; // Radio Frequency to use once a connection is established (set by host) readonly uint ClientDeviceID = 0; // ANT-FS Client Device ID (Serial Number): Wildcard to match any client ID readonly ushort DeviceNumber = 0; // Device Number (ANT Channel ID): Wildcard to match any client Device Number readonly byte SearchTimeout = 60; // How long to search for a client device, in seconds ANT_Channel channel0; // ANT channel to use ANTFS_HostChannel antfsHost; // ANT-FS host ANTFS_Directory dirFS; // ANT-FS directory byte[] clientPassKey; // Used to store pass key retrieved from the client during pairing bool demoDone = false; // Signal when the demo is done to exit int cursorIndex = 0; // Index to handle cursor display while transmitting in broadcast mode ushort currentDownloadIndex = 0; // Current index being downloaded. Start with directory (0) Timer searchTimer; // Timer to limit search time, in case there are no client devices around /// /// Setup ANT-FS host to process messages from connected USB device /// public void Start(ANT_Device antDevice) { PrintMenu(); try { // Create the ANT-FS host and attach it to a channel (in this case, 0) channel0 = antDevice.getChannel(0); antfsHost = new ANTFS_HostChannel(channel0); // Setup callback to handle ANT-FS response events antfsHost.OnResponse += new Action(HandleHostResponses); // Configure the host, and begin searching ConfigureHost(antDevice); while (!demoDone) { string command = Console.ReadLine(); HandleUserInput(command); Thread.Sleep(0); } } catch(ANTFS_Exception antEx) // Handle exceptions thrown by ANT Managed library { Console.WriteLine("ANT-FS Exception: " + antEx.Message); } catch (Exception ex) // Handle other exceptions { Console.WriteLine("Demo failed: " + ex.Message); } finally { Console.WriteLine("Disconnecting module..."); antDevice.Dispose(); // Close down the device completely and completely shut down all communication antfsHost.Dispose(); // Release all native resources used by the host Console.WriteLine("Demo has completed successfully!"); } } /// /// Configure the host search parameters, and begin the search /// /// ANT USB device public void ConfigureHost(ANT_Device antDevice) { // Configure ANT channel parameters antfsHost.SetNetworkKey(Demo.NetworkNumber, Demo.NetworkKey); antfsHost.SetChannelID(Demo.DeviceType, Demo.TransmissionType); antfsHost.SetChannelPeriod(Demo.ChannelPeriod); // Configure search parameters if (antfsHost.AddSearchDevice(ClientDeviceID, Demo.ClientManufacturerID, Demo.ClientDeviceType) == 0) throw new Exception("Error adding search device: "); if (Demo.AntfsBroadcast) { // If we want to use ANT-FS broadcast mode, and start the channel in broadcast mode, // setup callback to handle responses for channel 0 while in broadcast mode channel0.channelResponse += new dChannelResponseHandler(HandleChannelResponses); // Configure the channel as a slave, and look for messages from the master in the channel callback // This demo will automatically switch to ANT-FS mode after a few seconds if (!antDevice.setNetworkKey(Demo.NetworkNumber, Demo.NetworkKey, 500)) throw new Exception("Error configuring network key"); if (!channel0.assignChannel(ANT_ReferenceLibrary.ChannelType.BASE_Slave_Receive_0x00, Demo.NetworkNumber, 500)) throw new Exception("Error assigning channel"); if (!channel0.setChannelID(DeviceNumber, false, Demo.DeviceType, Demo.TransmissionType, 500)) throw new Exception("Error configuring Channel ID"); if (!channel0.setChannelFreq(Demo.SearchRF, 500)) throw new Exception("Error configuring radio frequency"); if (!channel0.setChannelPeriod(Demo.ChannelPeriod, 500)) throw new Exception("Error configuring channel period"); if (!channel0.openChannel(500)) throw new Exception("Error opening channel"); } else { // Start searching directly for an ANT-FS client matching the search criteria // NOTE: If not interested in the payload while in broadcast mode and intend to start a session right away, // you can specify useRequestPage = true to search for broadcast devices, and automatically request them // to switch to ANT-FS mode antfsHost.SearchForDevice(Demo.SearchRF, ConnectRF, DeviceNumber); } Console.WriteLine("Searching for devices..."); // Setup a timer, so that we can cancel the search if no device is found searchTimer = new Timer(SearchExpired, null, SearchTimeout * 1000, Timeout.Infinite); // convert time to milliseconds } /// /// Handle ANT-FS response events /// public void HandleHostResponses(ANTFS_HostChannel.Response response) { Console.WriteLine(Print.AsString(response)); // Display response switch (response) { case ANTFS_HostChannel.Response.ConnectPass: // A device matching the search criteria was found // Disable the search timeout searchTimer.Change(Timeout.Infinite, Timeout.Infinite); // Obtain and display the device parameters ANTFS_SearchResults foundDevice = antfsHost.GetFoundDeviceParameters(); if (foundDevice != null) Console.WriteLine(foundDevice.ToString()); else Console.WriteLine("Error obtaining device parameters"); break; case ANTFS_HostChannel.Response.AuthenticatePass: // The authentication request was accepted // If using Pairing authentication mode, the client will send a Passkey after accepting the request byte[] authString = antfsHost.GetAuthResponse(); if (authString.Length > 0) { Console.WriteLine("Received Passkey: Stored for use in next session"); clientPassKey = authString; // Store Passkey for future use } break; case ANTFS_HostChannel.Response.DownloadPass: // Download completed successfully // Retrieve downloaded data byte[] dlData = antfsHost.GetTransferData(); if ((dlData.Length > 0)) { if (currentDownloadIndex == 0) // Directory { // Parse downloaded directory Console.WriteLine("Received Directory"); dirFS = new ANTFS_Directory(dlData); Console.WriteLine(dirFS.ToString()); } else { // Store downloaded file Console.WriteLine("Downloaded file " + currentDownloadIndex + ", Download size: " + antfsHost.GetDownloadSize()); if (dlData != null) { File.WriteAllBytes("rawdataout.txt", dlData); Console.WriteLine("Saved to: rawdataout.txt"); } else { Console.WriteLine("No data available"); } } } else { Console.WriteLine("No data available"); } break; case ANTFS_HostChannel.Response.DisconnectPass: case ANTFS_HostChannel.Response.ConnectionLost: case ANTFS_HostChannel.Response.CancelDone: Console.WriteLine("Press any key to exit"); demoDone = true; break; default: break; } } /// /// Handle ANT channel responses, while in broadcast mode /// /// ANT channel event public void HandleChannelResponses(ANT_Response response) { // Make sure we are not processing responses if ANT-FS is active if (antfsHost.GetStatus() != ANTFS_HostChannel.State.Idle) return; if (response.responseID == (byte) ANT_ReferenceLibrary.ANTMessageID.BROADCAST_DATA_0x4E) { Console.Write("Rx: " + Demo.CursorStrings[cursorIndex++] + "\r"); cursorIndex &= 3; if (response.getDataPayload()[7] >= 40) // Receive data for about 10 seconds { antfsHost.RequestSession(Demo.SearchRF, ConnectRF); // Request ANT-FS session } } } /// /// Cancel the search after the timeout has expired /// /// timer param private void SearchExpired(Object state) { lock (this) { ANTFS_HostChannel.State currentState = antfsHost.GetStatus(); if (currentState == ANTFS_HostChannel.State.Searching) { Console.WriteLine("No devices found..."); antfsHost.Cancel(); } } } /// /// Display user menu /// public void PrintMenu() { Console.WriteLine(Environment.NewLine); Console.WriteLine("M - Print this menu"); Console.WriteLine("A - Authenticate"); Console.WriteLine("D - Download"); Console.WriteLine("U - Upload"); Console.WriteLine("E - Erase"); Console.WriteLine("X - Disconnect"); Console.WriteLine("C - Cancel"); Console.WriteLine("P - Print directory"); Console.WriteLine("V - Request version"); Console.WriteLine("S - Request status"); Console.WriteLine("Q - Quit"); Console.WriteLine(Environment.NewLine); } /// /// Process user input and execute requested commands /// /// User command public void HandleUserInput(string command) { try { switch (command) { case "M": case "m": PrintMenu(); break; case "A": case "a": // Send authentication request based on user selection // The library will wait for the configured timeout to receive a response to the request Console.WriteLine("Select authentication mode:"); Console.WriteLine("1 - Skip authentication"); Console.WriteLine("2 - Request pairing"); Console.WriteLine("3 - Send passkey"); string authChoice = Console.ReadLine(); switch (authChoice) { case "1": antfsHost.Authenticate(AuthenticationType.None, 60000); // Passthru authentication. Timeout = 60 sec break; case "2": antfsHost.Authenticate(AuthenticationType.Pairing, HostFriendlyName, 60000); // Request pairing. Timeout = 60 sec break; case "3": if (clientPassKey != null) antfsHost.Authenticate(AuthenticationType.PassKey, clientPassKey, 60000); // Use passkey, if we have one. Timeout = 60 sec else Console.WriteLine("Try pairing first"); break; default: Console.WriteLine("Invalid authentication type."); break; } break; case "D": case "d": // Send a download request based on user selection Console.WriteLine("Select the file index to download."); Console.WriteLine("Choose 0 for the directory"); string downloadChoice = Console.ReadLine(); currentDownloadIndex = Demo.ParseInput(downloadChoice); antfsHost.Download(currentDownloadIndex, 0, 0); // Start download from the beginning, and do not limit size break; case "U": case "u": // Send an upload request based on user selection Console.WriteLine("Select the file index to upload."); string uploadChoice = Console.ReadLine(); byte[] ulData; if (File.Exists("rawdataout.txt")) ulData = File.ReadAllBytes("rawdataout.txt"); else ulData = new byte[200]; antfsHost.Upload(Demo.ParseInput(uploadChoice), ulData); Console.WriteLine("Uploading: {0} bytes", ulData.Length); break; case "E": case "e": // Send an erase request depending on user selection Console.WriteLine("Select the file index to erase"); string eraseChoice = Console.ReadLine(); antfsHost.EraseData(Demo.ParseInput(eraseChoice)); break; case "X": case "x": // Disconnect from the remote device antfsHost.Disconnect(); break; case "C": case "c": // Cancel pending operations antfsHost.Cancel(); break; case "P": case "p": if (dirFS != null) Console.WriteLine(dirFS.ToString()); else Console.WriteLine("Try requesting the directory first"); break; case "V": case "v": Console.WriteLine("ANT-FS Library Version " + antfsHost.GetLibraryVersion()); break; case "S": case "s": Console.WriteLine("Status: " + Print.AsString(antfsHost.GetStatus())); break; case "Q": case "q": demoDone = true; break; default: break; } } catch (ANTFS_RequestFailed_Exception antEx) { // Inform the user that the operation requested failed, and resume operation Console.WriteLine(antEx.Message); } catch (System.ArgumentException argEx) { // Inform the user about the invalid input, and resume operation Console.WriteLine(argEx.Message); } } } }