/*
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.ANTFS;
using ANT_Managed_Library;
namespace ANTFS_Demo
{
///
/// This demo shows how to configure a basic ANT-FS client
/// For a more featured demo, please refer to the source code of the ANT-FS PC tools
///
class ClientDemo
{
// ANT-FS Client Configuration Parameters
readonly AuthenticationType ClientAuthenticationType = AuthenticationType.None; // Allow pairing, passkey and passthru
readonly byte BeaconTimeout = 60; // The client will drop back to link state if no messages from the host are received within this timeout
readonly byte PairingTimeout = 5; // Time to wait for the user to provide a response to a pairing request. Use a short value here since demo accepts pairing automatically
readonly bool DataAvailable = true; // Indicate in beacon there is data available for download
readonly bool PairingEnabled = true; // Indicate in beacon that pairing is enabled
readonly bool UploadEnabled = false; // Indicate in beacon that pairing is not supported
readonly byte[] PassKey = { 1, 2, 3, 1, 2, 3, 1, 2 }; // Authentication passkey
readonly string ClientFriendlyName = "ConsoleClient"; // ANT-FS Client friendly name
readonly uint TestFileSize = 512; // Size of file listed in the directory. This demo does not
// access the file system; it just creates a file of the configured size
ANT_Channel channel0; // ANT channel to use
ANTFS_ClientChannel antfsClient; // ANT-FS client
ANTFS_Directory dirFS; // ANT-FS directory
bool demoDone = false; // Flag to allow demo to exit
byte[] txBuffer = {0,0,0,0,0,0,0,0}; // Tx buffer to use while in broadcast mode
int cursorIndex = 0; // index to handle cursor display while transmitting in broadcast mode
///
/// Setup ANT-FS client to process messages from connected device
///
public void Start(ANT_Device antDevice)
{
PrintMenu();
try
{
// Create the ANT-FS client and attach it to a channel (in this case, 0)
channel0 = antDevice.getChannel(0);
antfsClient = new ANTFS_ClientChannel(channel0);
// Setup callback to handle ANT-FS response events
antfsClient.OnResponse += new Action(HandleClientResponses);
// Configure the client, and begin beaconing
ConfigureClient(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);
Console.ReadLine();
}
finally
{
Console.WriteLine("Disconnecting module...");
antDevice.Dispose(); // Close down the device completely and completely shut down all communication
antfsClient.Dispose(); // Release all native resources used by the client
Console.WriteLine("Demo has completed successfully!");
}
}
///
/// Configure the client beacon parameters, and start transmitting/beaconing
///
/// ANT USB device
public void ConfigureClient(ANT_Device antDevice)
{
// Configure ANT Channel parameters
antfsClient.SetClientNetworkKey(0, Demo.NetworkKey);
antfsClient.SetChannelID(Demo.DeviceType, Demo.TransmissionType);
antfsClient.SetChannelPeriod(Demo.ChannelPeriod);
// Setup client configuration parameters.
// ANTFS_ClientParameters is a struct, so make sure to initialize ALL parameters
ANTFS_ClientParameters clientConfig = new ANTFS_ClientParameters();
clientConfig.BeaconDeviceType = Demo.ClientDeviceType;
clientConfig.BeaconManufacturerID = Demo.ClientManufacturerID;
clientConfig.BeaconRadioFrequency = Demo.SearchRF;
clientConfig.LinkPeriod = Demo.LinkPeriod;
clientConfig.AuthenticationType = ClientAuthenticationType;
clientConfig.IsDataAvailable = DataAvailable;
clientConfig.IsPairingEnabled = PairingEnabled;
clientConfig.IsUploadEnabled = UploadEnabled;
clientConfig.BeaconTimeout = BeaconTimeout;
clientConfig.PairingTimeout = PairingTimeout;
clientConfig.SerialNumber = antDevice.getSerialNumber(); // Use the serial number of the USB stick to identify the client
// Apply configuration
antfsClient.Configure(clientConfig);
// Configure friendly name and passkey (optional)
antfsClient.SetFriendlyName(ClientFriendlyName);
antfsClient.SetPassKey(PassKey);
// Create directory, an add a single entry, of the configured size
dirFS = new ANTFS_Directory();
ANTFS_Directory.Entry fileEntry;
fileEntry.FileIndex = 1;
fileEntry.FileSize = TestFileSize;
fileEntry.FileDataType = 1;
fileEntry.FileNumber = 1;
fileEntry.FileSubType = 0;
fileEntry.GeneralFlags = (byte) (ANTFS_Directory.GeneralFlags.Read | ANTFS_Directory.GeneralFlags.Write | ANTFS_Directory.GeneralFlags.Erase);
fileEntry.SpecificFlags = 0;
fileEntry.TimeStamp = 0; // TODO: Encode the timestamp properly
dirFS.AddEntry(fileEntry);
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 master, and look for the request message in the channel callback
// to switch to ANT-FS mode
if (!antDevice.setNetworkKey(Demo.NetworkNumber, Demo.NetworkKey, 500))
throw new Exception("Error configuring network key");
if (!channel0.assignChannel(ANT_ReferenceLibrary.ChannelType.BASE_Master_Transmit_0x10, Demo.NetworkNumber, 500))
throw new Exception("Error assigning channel");
if (!channel0.setChannelID((ushort)clientConfig.SerialNumber, 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
{
// If we want to start in ANT-FS mode, just open the beacon
antfsClient.OpenBeacon();
}
}
///
/// Create a test file, of the specified size
///
/// File size, in bytes
///
public byte[] ReadFile(uint fileSize)
{
byte[] testFile = new byte[fileSize];
for (uint i = 0; i < fileSize; i++)
testFile[i] = (byte)i;
return testFile;
}
///
/// Handle ANT-FS response events
///
public void HandleClientResponses(ANTFS_ClientChannel.Response response)
{
Console.WriteLine(Print.AsString(response)); // Display response
switch (response)
{
case ANTFS_ClientChannel.Response.ConnectionLost:
case ANTFS_ClientChannel.Response.DisconnectPass:
// Close the channel
if (antfsClient.GetDisconnectParameters().CommandType == (byte)DisconnectType.Broadcast)
{
channel0.closeChannel();
}
else
{
antfsClient.CloseBeacon();
}
break;
case ANTFS_ClientChannel.Response.BeaconClosed:
demoDone = true;
Console.WriteLine("Press enter to exit");
break;
case ANTFS_ClientChannel.Response.PairingRequest:
Console.WriteLine("Pairing request from " + antfsClient.GetHostName());
antfsClient.SendPairingResponse(true);
break;
case ANTFS_ClientChannel.Response.DownloadRequest:
try
{
ushort index = antfsClient.GetRequestedFileIndex();
if(index == 0)
antfsClient.SendDownloadResponse(DownloadResponse.Ok, index, dirFS.ToByteArray());
else
antfsClient.SendDownloadResponse(DownloadResponse.Ok, index, ReadFile(dirFS.GetFileSize(index)));
}
catch(ANTFS_Exception)
{
antfsClient.SendDownloadResponse(DownloadResponse.InvalidIndex, 0, null);
}
break;
default:
break;
}
}
///
/// Handle channel responses, while in broadcast mode
///
/// ANT channel events
public void HandleChannelResponses(ANT_Response response)
{
// Make sure we are not processing responses if ANT-FS is active
if(antfsClient.GetStatus() != ANTFS_ClientChannel.State.Idle)
return;
if ((response.responseID == (byte)ANT_ReferenceLibrary.ANTMessageID.RESPONSE_EVENT_0x40))
{
if(response.getChannelEventCode() == ANT_ReferenceLibrary.ANTEventID.EVENT_TX_0x03)
{
channel0.sendBroadcastData(txBuffer);
txBuffer[7]++;
Console.Write("Tx: " + Demo.CursorStrings[cursorIndex++] + "\r");
cursorIndex &= 3;
}
else if(response.getChannelEventCode() == ANT_ReferenceLibrary.ANTEventID.EVENT_CHANNEL_CLOSED_0x07)
{
Console.WriteLine("Channel Closed");
Console.WriteLine("Unassigning Channel...");
if (channel0.unassignChannel(500))
{
Console.WriteLine("Unassigned Channel");
Console.WriteLine("Press enter to exit");
demoDone = true;
}
}
}
else if (response.responseID == (byte)ANT_ReferenceLibrary.ANTMessageID.ACKNOWLEDGED_DATA_0x4F)
{
// Look for request page
if (response.messageContents[1] == 0x46)
{
if (response.messageContents[6] == 0 &&
response.messageContents[7] == 0x43 &&
response.messageContents[8] == 0x02)
Console.WriteLine("Remote device requesting ANT-FS session");
antfsClient.OpenBeacon();
}
}
}
///
/// Display user menu
///
public void PrintMenu()
{
Console.WriteLine(Environment.NewLine);
Console.WriteLine("M - Print this menu");
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 "V":
case "v":
Console.WriteLine("ANT-FS Library Version " + ANTFS_ClientChannel.GetLibraryVersion());
break;
case "S":
case "s":
Console.WriteLine("Status: " + Print.AsString(antfsClient.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);
}
}
}
}