View
@@ -12,7 +12,7 @@ enum OsType
Linux64,
MacOs32,
MacOs64,
- Armv6HardFloat,
+ Armv6HardFloat, //Raspberry Pi 1. Has a library, but probably won't update.
Armv7HardFloat,
Android,
RoboRio//RoboRIO is Armv7 Soft Float
@@ -92,6 +92,7 @@ internal static bool CheckOsValid(OsType type)
case OsType.MacOs64:
return false;
case OsType.Armv6HardFloat:
+ Console.WriteLine("Raspberry Pi 1 does work, however the library will not be often updated and will probably be out of date.");
return true;
case OsType.Armv7HardFloat:
return true;
@@ -136,54 +137,54 @@ internal static void GetLibraryName(OsType type, out string embeddedResourceLoca
{
case OsType.Windows32:
embeddedResourceLocation = "NetworkTables.NativeLibraries.x86.ntcore.dll";
- extractLocation = "ntcore.dll";
+ //extractLocation = "ntcore.dll";
break;
case OsType.Windows64:
embeddedResourceLocation = "NetworkTables.NativeLibraries.amd64.ntcore.dll";
- extractLocation = "ntcore.dll";
+ //extractLocation = "ntcore.dll";
break;
case OsType.Linux32:
embeddedResourceLocation = "NetworkTables.NativeLibraries.x86.libntcore.so";
- extractLocation = "libntcore.so";
+ //extractLocation = "libntcore.so";
break;
case OsType.Linux64:
embeddedResourceLocation = "NetworkTables.NativeLibraries.amd64.libntcore.so";
- extractLocation = "libntcore.so";
+ //extractLocation = "libntcore.so";
break;
case OsType.MacOs32:
embeddedResourceLocation = "NetworkTables.NativeLibraries.x86.libntcore.dylib";
- extractLocation = "libntcore.dylib";
+ //extractLocation = "libntcore.dylib";
break;
case OsType.MacOs64:
embeddedResourceLocation = "NetworkTables.NativeLibraries.amd64.libntcore.dylib";
- extractLocation = "libntcore.dylib";
+ //extractLocation = "libntcore.dylib";
break;
case OsType.RoboRio:
embeddedResourceLocation = "NetworkTables.NativeLibraries.roborio.libntcore.so";
- extractLocation = "libntcore.so";
+ //extractLocation = "libntcore.so";
break;
case OsType.Armv6HardFloat:
embeddedResourceLocation = "NetworkTables.NativeLibraries.armv6.libntcore.so";
- extractLocation = "libntcore.so";
+ //extractLocation = "libntcore.so";
break;
// Android is only Arm Android. Don't currently have a way to detect otherwise.
case OsType.Android:
embeddedResourceLocation = "NetworkTables.NativeLibraries.android.libntcore.so";
- extractLocation = "libntcore.so";
+ //extractLocation = "libntcore.so";
break;
case OsType.Armv7HardFloat:
embeddedResourceLocation = "NetworkTables.NativeLibraries.armv7.libntcore.so";
- extractLocation = "libntcore.so";
+ //extractLocation = "libntcore.so";
break;
default:
throw new ArgumentOutOfRangeException(nameof(type), type, null);
}
- extractLocation = Path.GetTempPath() + extractLocation;
+ extractLocation = Path.GetTempFileName();
}
- internal static bool ExtractLibrary(string embeddedResourceLocation, string extractLocation)
- {
+ internal static bool ExtractLibrary(string embeddedResourceLocation, ref string extractLocation)
+ {
byte[] bytes;
//Load our resource file into memory
using (Stream s = Assembly.GetExecutingAssembly().GetManifestResourceStream(embeddedResourceLocation))
@@ -193,45 +194,56 @@ internal static bool ExtractLibrary(string embeddedResourceLocation, string extr
bytes = new byte[(int)s.Length];
s.Read(bytes, 0, (int)s.Length);
}
+ File.WriteAllBytes(extractLocation, bytes);
+ /*
bool isFileSame = true;
-
- //If file exists
- if (File.Exists(extractLocation))
+ try
{
- //Load existing file into memory
- byte[] existingFile = File.ReadAllBytes(extractLocation);
- //If files are different length they are different,
- //and we can automatically assume they are different.
- if (existingFile.Length != bytes.Length)
- {
- isFileSame = false;
- }
- else
+ //If file exists
+ if (File.Exists(extractLocation))
{
- //Otherwise directly compare the files
- //I first tried hashing, but that took 1.5-2.0 seconds,
- //wheras this took 0.3 seconds.
- for (int i = 0; i < existingFile.Length; i++)
+ //Load existing file into memory
+ byte[] existingFile = File.ReadAllBytes(extractLocation);
+ //If files are different length they are different,
+ //and we can automatically assume they are different.
+ if (existingFile.Length != bytes.Length)
+ {
+ isFileSame = false;
+ }
+ else
{
- if (bytes[i] != existingFile[i])
+ //Otherwise directly compare the files
+ //I first tried hashing, but that took 1.5-2.0 seconds,
+ //wheras this took 0.3 seconds.
+ for (int i = 0; i < existingFile.Length; i++)
{
- isFileSame = false;
+ if (bytes[i] != existingFile[i])
+ {
+ isFileSame = false;
+ }
}
}
}
- }
- else
- {
- isFileSame = false;
- }
+ else
+ {
+ isFileSame = false;
+ }
- //If file is different write the new file
- if (!isFileSame)
+ //If file is different write the new file
+ if (!isFileSame)
+ {
+ if (File.Exists(extractLocation))
+ File.Delete(extractLocation);
+ File.WriteAllBytes(extractLocation, bytes);
+ }
+
+ }
+ //If IO exception, means something else is using ntcore. Write to unique file.
+ catch (IOException)
{
- if (File.Exists(extractLocation))
- File.Delete(extractLocation);
+ extractLocation = Path.GetTempFileName();
File.WriteAllBytes(extractLocation, bytes);
- }
+ }*/
//Force a garbage collection, since we just wasted about 12 MB of RAM.
GC.Collect();
View
Binary file not shown.
View
Binary file not shown.
View
@@ -81,6 +81,8 @@ public class NetworkTable : ITable, IRemote
/// <summary>The default port NetworkTables listens on.</summary>
public const uint DefaultPort = 1735;
+ private static object s_lockObject = new object();
+
/// <summary>
/// The default file name used for Persistent Storage.
/// </summary>
@@ -94,8 +96,11 @@ public class NetworkTable : ITable, IRemote
private static void CheckInit()
{
- if (Running)
- throw new InvalidOperationException("Network Tables has already been initialized");
+ lock (s_lockObject)
+ {
+ if (Running)
+ throw new InvalidOperationException("Network Tables has already been initialized");
+ }
}
/// <summary>
@@ -108,35 +113,41 @@ private static void CheckInit()
/// </remarks>
public static void Initialize()
{
- if (Running)
- Shutdown();
- if (Client)
- {
- CoreMethods.StartClient(IPAddress, Port);
- }
- else
+ lock (s_lockObject)
{
- CoreMethods.StartServer(PersistentFilename, "", Port);
+ if (Running)
+ Shutdown();
+ if (Client)
+ {
+ CoreMethods.StartClient(IPAddress, Port);
+ }
+ else
+ {
+ CoreMethods.StartServer(PersistentFilename, "", Port);
+ }
+ Running = true;
}
- Running = true;
}
/// <summary>
/// Shuts down NetworkTables.
/// </summary>
public static void Shutdown()
{
- if (!Running)
- return;
- if (Client)
- {
- CoreMethods.StopClient();
- }
- else
+ lock (s_lockObject)
{
- CoreMethods.StopServer();
+ if (!Running)
+ return;
+ if (Client)
+ {
+ CoreMethods.StopClient();
+ }
+ else
+ {
+ CoreMethods.StopServer();
+ }
+ Running = false;
}
- Running = false;
}
/// <summary>
@@ -148,10 +159,13 @@ public static void Shutdown()
/// before <see cref="Initialize"/> or <see cref="GetTable(string)"/>.</remarks>
public static void SetClientMode()
{
- if (Client)
- return;
- CheckInit();
- Client = true;
+ lock (s_lockObject)
+ {
+ if (Client)
+ return;
+ CheckInit();
+ Client = true;
+ }
}
/// <summary>
@@ -163,10 +177,13 @@ public static void SetClientMode()
/// before <see cref="Initialize"/> or <see cref="GetTable(string)"/></remarks>
public static void SetServerMode()
{
- if (!Client)
- return;
- CheckInit();
- Client = false;
+ lock (s_lockObject)
+ {
+ if (!Client)
+ return;
+ CheckInit();
+ Client = false;
+ }
}
/// <summary>
@@ -178,7 +195,10 @@ public static void SetServerMode()
/// <see cref="GetTable(string)"/> if the system is a client.</remarks>
public static void SetTeam(int team)
{
- SetIPAddress($"roboRIO-{team}-FRC.local");
+ lock (s_lockObject)
+ {
+ SetIPAddress($"roboRIO-{team}-FRC.local");
+ }
}
/// <summary>
@@ -187,10 +207,13 @@ public static void SetTeam(int team)
/// <param name="address">The IP address to connect to in client mode</param>
public static void SetIPAddress(string address)
{
- if (IPAddress == address)
- return;
- CheckInit();
- IPAddress = address;
+ lock (s_lockObject)
+ {
+ if (IPAddress == address)
+ return;
+ CheckInit();
+ IPAddress = address;
+ }
}
/// <summary>
@@ -202,10 +225,13 @@ public static void SetIPAddress(string address)
/// <returns>The <see cref="NetworkTable"/> requested.</returns>
public static NetworkTable GetTable(string key)
{
- if (!Running) Initialize();
- if (key == "")
- return new NetworkTable(key);
- return new NetworkTable(PathSeperatorChar + key);
+ lock (s_lockObject)
+ {
+ if (!Running) Initialize();
+ if (key == "" || key[0] == PathSeperatorChar)
+ return new NetworkTable(key);
+ return new NetworkTable(PathSeperatorChar + key);
+ }
}
/// <summary>
@@ -912,6 +938,9 @@ public void RemoveTableListener(Action<ITable, string, object, NotifyFlags> list
private readonly Dictionary<IRemoteConnectionListener, int> m_connectionListenerMap =
new Dictionary<IRemoteConnectionListener, int>();
+ private readonly Dictionary<Action<IRemote, ConnectionInfo, bool>, int> m_actionConnectionListenerMap
+ = new Dictionary<Action<IRemote, ConnectionInfo, bool>, int>();
+
///<inheritdoc/>
public void AddConnectionListener(IRemoteConnectionListener listener, bool immediateNotify)
{
@@ -923,8 +952,8 @@ public void AddConnectionListener(IRemoteConnectionListener listener, bool immed
ConnectionListenerFunction func = (uid, connected, conn) =>
{
- if (connected) listener.Connected(this);
- else listener.Disconnected(this);
+ if (connected) listener.Connected(this, conn);
+ else listener.Disconnected(this, conn);
};
int id = CoreMethods.AddConnectionListener(func, immediateNotify);
@@ -943,6 +972,34 @@ public void RemoveConnectionListener(IRemoteConnectionListener listener)
}
}
+ /// <inheritdoc/>
+ public void AddConnectionListener(Action<IRemote, ConnectionInfo, bool> listener, bool immediateNotify)
+ {
+ if (m_actionConnectionListenerMap.ContainsKey(listener))
+ {
+ throw new ArgumentException("Cannot add the same listener twice", nameof(listener));
+ }
+
+ ConnectionListenerFunction func = (uid, connected, conn) =>
+ {
+ listener(this, conn, connected);
+ };
+
+ int id = CoreMethods.AddConnectionListener(func, immediateNotify);
+
+ m_actionConnectionListenerMap.Add(listener, id);
+ }
+
+ /// <inheritdoc/>
+ public void RemoveConnectionListener(Action<IRemote, ConnectionInfo, bool> listener)
+ {
+ int val;
+ if (m_actionConnectionListenerMap.TryGetValue(listener, out val))
+ {
+ CoreMethods.RemoveConnectionListener(val);
+ }
+ }
+
/// <summary>
/// Gets if the NetworkTables is connected to a client or server.
/// </summary>
View
@@ -91,6 +91,7 @@
<EmbeddedResource Condition=" '$(Configuration)' != 'ArmStandalone' " Include="NativeLibraries\amd64\libntcore.dylib" />
<EmbeddedResource Condition=" '$(Configuration)' != 'ArmStandalone' " Include="NativeLibraries\x86\libntcore.dylib" />
<EmbeddedResource Condition=" '$(Configuration)' == 'ArmStandalone' " Include="NativeLibraries\armv7\libntcore.so" />
+ <EmbeddedResource Condition=" '$(Configuration)' == 'ArmStandalone' " Include="NativeLibraries\armv7\libstdc++.so" />
<EmbeddedResource Condition=" '$(Configuration)' == 'ArmStandalone' " Include="NativeLibraries\armv6\libntcore.so" />
<EmbeddedResource Condition=" '$(Configuration)' == 'ArmStandalone' " Include="NativeLibraries\android\libntcore.so" />
</ItemGroup>
View
@@ -1,4 +1,6 @@
-namespace NetworkTables.Tables
+using System;
+
+namespace NetworkTables.Tables
{
/// <summary>
/// Represents an object that has a remote connection.
@@ -20,6 +22,25 @@ public interface IRemote
void RemoveConnectionListener(IRemoteConnectionListener listener);
/// <summary>
+ /// Register a delegate to listen for connection and disconnection events.
+ /// </summary>
+ /// <param name="listener">The listener to be registered.</param>
+ /// <param name="immediateNotify">True if the listener object should be notified of the current
+ /// connection state immediately.</param>
+ /// <remarks>
+ /// The <see cref="IRemote"/> of the action is the current table, the <see cref="ConnectionInfo"/>
+ /// is the info of the connected or disconnected target, and the bool is true if the event is
+ /// a connect, otherwise false.
+ /// </remarks>
+ void AddConnectionListener(Action<IRemote, ConnectionInfo, bool> listener, bool immediateNotify);
+
+ /// <summary>
+ /// Unregister a listener delegate from connection events.
+ /// </summary>
+ /// <param name="listener">The listener to be unregistered.</param>
+ void RemoveConnectionListener(Action<IRemote, ConnectionInfo, bool> listener);
+
+ /// <summary>
/// Gets if the current object is connected.
/// </summary>
bool IsConnected { get; }
View
@@ -9,12 +9,16 @@ public interface IRemoteConnectionListener
/// Called when an <see cref="IRemote"/> is connected
/// </summary>
/// <param name="remote">The object that connected.</param>
- void Connected(IRemote remote);
+ /// <param name="info">An object containing information about the
+ /// connected remote.</param>
+ void Connected(IRemote remote, ConnectionInfo info);
/// <summary>
/// Called when an <see cref="IRemote"/> is disconnected.
/// </summary>
/// <param name="remote">The object that disconnected.</param>
- void Disconnected(IRemote remote);
+ /// <param name="info">An object containing information about the
+ /// disconnected remote.</param>
+ void Disconnected(IRemote remote, ConnectionInfo info);
}
}
View
@@ -1,4 +1,4 @@
-version: 2016.0.0.{build}
+version: 2016.0.1.{build}
skip_tags: true
os: Visual Studio 2015