Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 23 additions & 9 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,13 +170,25 @@ catch (Exception ex)
## Device Communication

The application communicates with DAQiFi devices using:
- UDP for device discovery
- TCP for data streaming and commands
- Protocol Buffers for message serialization

Key classes:
- `DaqifiDeviceFinder.cs` - Handles device discovery
- `WiFiDevice` - Manages WiFi device connections
- **UDP for device discovery**: Port 30303 (broadcast queries and responses)
- **TCP for data streaming**: Port varies by device (extracted from discovery response)
- **Protocol Buffers**: Message serialization for both UDP and TCP

### Port Configuration
- **UDP Discovery Port**: 30303 (used in `DaqifiDeviceFinder` and firewall rules)
- **TCP Data Port**: Device-specific (e.g., 9760) - discovered from `message.DevicePort` in protobuf response
- **Manual IP connections**: Must use the same TCP port as discovered devices

### Network Requirements
- **Firewall Rule**: UDP port 30303 must be allowed for device discovery
- **Admin Privileges**: Required for automatic firewall configuration
- **Network Interface**: Application and device must be on same subnet for UDP broadcast discovery
- **Virtual Machines**: Use bridged networking mode, not NAT/shared network

### Key Classes
- `DaqifiDeviceFinder.cs` - Handles UDP device discovery on port 30303
- `DaqifiStreamingDevice.cs` - Manages TCP connections to devices
- `FirewallManager.cs` - Configures Windows Firewall for UDP port 30303
- Protocol buffer messages defined in `.proto` files

## Database
Expand Down Expand Up @@ -219,11 +231,13 @@ public void InitializeFirewallRules()
## Common Tasks

When working on:
- **Device connectivity**: Check `/Device/` directory
- **Device connectivity**: Check `/Device/` directory and ensure network configuration
- **UI changes**: Update both View and ViewModel following MVVM
- **Data persistence**: Use Entity Framework patterns
- **Protocol changes**: Update `.proto` files and regenerate
- **Firewall/Network**: Ensure admin privileges handled properly
- **Firewall/Network**: Ensure admin privileges handled properly, verify ports match
- **WiFi Discovery Issues**: Check network interface detection and port configuration
- **Manual IP Connections**: Ensure TCP port matches what device discovery reports
- **New features**: Add unit tests with 80% coverage minimum

## Performance Considerations
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ public void InitializeFirewallRules_WhenRuleDoesNotExist_CreatesNewRule()
FirewallConfiguration.InitializeFirewallRules();

// Assert
_mockFirewallHelper.Verify(f => f.CreateUdpRule(It.IsAny<string>(), It.IsAny<string>(), 21234), Times.Once);
_mockFirewallHelper.Verify(f => f.CreateUdpRule(It.IsAny<string>(), It.IsAny<string>(), 30303), Times.Once);
_mockMessageBoxService.Verify(m => m.Show(It.IsAny<string>(), It.IsAny<string>(), It.IsAny<MessageBoxButton>(), It.IsAny<MessageBoxImage>()), Times.Never);
}

Expand Down Expand Up @@ -81,7 +81,7 @@ public void InitializeFirewallRules_WhenCreatingRuleThrowsException_ShowsErrorMe
// Arrange
_mockAdminChecker.Setup(c => c.IsCurrentUserAdmin()).Returns(true);
_mockFirewallHelper.Setup(f => f.RuleExists("DAQiFi Desktop")).Returns(false);
_mockFirewallHelper.Setup(f => f.CreateUdpRule(It.IsAny<string>(), It.IsAny<string>(), 21234))
_mockFirewallHelper.Setup(f => f.CreateUdpRule(It.IsAny<string>(), It.IsAny<string>(), 30303))
.Throws(new InvalidOperationException("Test exception"));

// Act
Expand Down
4 changes: 2 additions & 2 deletions Daqifi.Desktop/Configuration/FirewallManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ public static void InitializeFirewallRules()
return;
}

// Create new rule with specific UDP port (21234 is DAQiFi's discovery port)
_firewallHelper.CreateUdpRule(RuleName, appPath, 21234);
// Create new rule with specific UDP port (30303 is DAQiFi's UDP discovery port)
_firewallHelper.CreateUdpRule(RuleName, appPath, 30303);
}
catch (Exception ex)
{
Expand Down
20 changes: 13 additions & 7 deletions Daqifi.Desktop/Device/WiFiDevice/DaqifiDeviceFinder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ public override void Run()
}
catch (SocketException sockEx)
{
AppLogger.Warning($"Error sending broadcast to {endpoint}, {sockEx}");
AppLogger.Warning($"Error sending broadcast to {endpoint} (SocketError={sockEx.SocketErrorCode}): {sockEx.Message}");
}
}
Thread.Sleep(1000);
Expand Down Expand Up @@ -194,6 +194,7 @@ public void NotifyDeviceRemoved(object sender, IDevice device)
private List<IPEndPoint> GetAllBroadcastEndpoints(int port)
{
var endpoints = new List<IPEndPoint>();

foreach (var networkInterface in NetworkInterface.GetAllNetworkInterfaces())
{
if (networkInterface.OperationalStatus != OperationalStatus.Up ||
Expand Down Expand Up @@ -233,16 +234,21 @@ private List<IPEndPoint> GetAllBroadcastEndpoints(int port)
}

var broadcastAddress = new IPAddress(broadcastBytes);

endpoints.Add(new IPEndPoint(broadcastAddress, port));

var endpoint = new IPEndPoint(broadcastAddress, port);
endpoints.Add(endpoint);
break;
}
}

AppLogger.Information(endpoints.Count == 0
? "Could not find any suitable network interfaces for DAQiFi discovery broadcast."
: $"DAQiFi Discovery broadcasting to: {string.Join(", ", endpoints.Select(ep => ep.Address.ToString()))}");
if (endpoints.Count == 0)
{
AppLogger.Warning("Could not find any suitable network interfaces for DAQiFi discovery broadcast.");
}
else
{
AppLogger.Information($"DAQiFi discovery will broadcast to {endpoints.Count} network endpoint(s)");
}

return endpoints;
}
Expand Down
32 changes: 27 additions & 5 deletions Daqifi.Desktop/Device/WiFiDevice/DaqifiStreamingDevice.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,34 @@ public override bool Connect()
{
Client = new TcpClient();
var result = Client.BeginConnect(IpAddress, Port, null, null);
var success = result.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(5));

if (!success)
var waitHandle = result.AsyncWaitHandle;

try
{
var success = waitHandle.WaitOne(TimeSpan.FromSeconds(5));

if (!success)
{
AppLogger.Error($"Timeout connecting to DAQiFi device at {IpAddress}:{Port}");
Client?.Close();
return false;
}

// Complete the asynchronous connection
try
{
Client.EndConnect(result);
}
catch (SocketException ex)
{
AppLogger.Error(ex, $"Failed to connect to DAQiFi device at {IpAddress}:{Port}");
Client?.Close();
return false;
}
}
finally
{
AppLogger.Error("Timeout connecting to DAQiFi Device.");
return false;
waitHandle?.Close();
}

MessageProducer = new MessageProducer(Client.GetStream());
Expand Down
3 changes: 2 additions & 1 deletion Daqifi.Desktop/ViewModels/ConnectionDialogViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,8 @@ private async Task ConnectManualWifiAsync()
var deviceInfo = new DeviceInfo
{
IpAddress = ManualIpAddress,
DeviceName = "Manual IP Device"
DeviceName = "Manual IP Device",
Port = 9760 // Common DAQiFi TCP data port - TODO: make configurable or discover dynamically
};

var device = new DaqifiStreamingDevice(deviceInfo);
Expand Down
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,25 @@ DatabaseLogger->>Database:Bulk Insert Buffer
- Uses [Wix Toolset](https://wixtoolset.org/)
- Separate solution `Daqifi.Desktop.Setup`

## WiFi Device Connectivity

DAQiFi Desktop discovers and connects to DAQiFi devices over WiFi using UDP broadcasts and TCP connections.

### Network Requirements
- **Same Network**: Computer and DAQiFi device must be on the same network/subnet
- **Firewall**: UDP port 30303 must be allowed (configured automatically with admin privileges)
- **Virtual Machines**: Use bridged networking mode for VM environments

### Troubleshooting WiFi Discovery
1. **Run as Administrator** - Required for automatic firewall configuration
2. **Check Network Connection** - Ensure computer and device are on same WiFi network
3. **Verify Connectivity** - Test with `ping <device-ip>` from command prompt
4. **Manual Connection** - Use manual IP connection if discovery fails

### Port Configuration
- **UDP Discovery**: Port 30303 (device discovery broadcasts)
- **TCP Data**: Device-specific port (varies by device, typically 9760)

## Contribution

Please read [Contributing Guidelines](CONTRIBUTING.md) before contributing.
Loading