/*
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);
}
}
}
}