Skip to content
Open
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
80 changes: 34 additions & 46 deletions .github/workflows/sonarcloud.yml
Original file line number Diff line number Diff line change
@@ -1,30 +1,12 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.

# This workflow helps you trigger a SonarCloud analysis of your code and populates
# GitHub Code Scanning alerts with the vulnerabilities found.
# Free for open source project.

# 1. Login to SonarCloud.io using your GitHub account

# 2. Import your project on SonarCloud
# * Add your GitHub organization first, then add your repository as a new project.
# * Please note that many languages are eligible for automatic analysis,
# which means that the analysis will start automatically without the need to set up GitHub Actions.
# * This behavior can be changed in Administration > Analysis Method.
# SonarCloud аналіз для NetSdrClient (.NET 8)
#
# 3. Follow the SonarCloud in-product tutorial
# * a. Copy/paste the Project Key and the Organization Key into the args parameter below
# (You'll find this information in SonarCloud. Click on "Information" at the bottom left)
#
# * b. Generate a new token and add it to your Github repository's secrets using the name SONAR_TOKEN
# (On SonarCloud, click on your avatar on top-right > My account > Security
# or go directly to https://sonarcloud.io/account/security/)

# Feel free to take a look at our documentation (https://docs.sonarcloud.io/getting-started/github/)
# or reach out to our community forum if you need some help (https://community.sonarsource.com/c/help/sc/9)
# Перед першим запуском обов'язково:
# 1. Створити проект у SonarCloud (Analyze new project) для цього репозиторію.
# 2. У SonarCloud вимкнути Automatic Analysis (Administration -> Analysis Method).
# 3. Згенерувати User Token у SonarCloud та додати його у GitHub Secrets форку
# під іменем SONAR_TOKEN (Repo Settings -> Secrets and variables -> Actions).
# 4. Замінити нижче змінні `SONAR_PROJECT_KEY` і `SONAR_ORGANIZATION` на власні
# значення з SonarCloud (вкладка Information знизу зліва у проєкті Sonar).

name: SonarCloud analysis

Expand All @@ -36,12 +18,16 @@ on:
workflow_dispatch:

permissions:
pull-requests: read # allows SonarCloud to decorate PRs with analysis results
pull-requests: read

env:
SONAR_PROJECT_KEY: nik-bykoff_ReengineeringCourse
SONAR_ORGANIZATION: nik-bykoff

jobs:
sonar-check:
name: Sonar Check
runs-on: windows-latest # безпечно для будь-яких .NET проектів
runs-on: windows-latest
steps:
- uses: actions/checkout@v4
with: { fetch-depth: 0 }
Expand All @@ -50,34 +36,36 @@ jobs:
with:
dotnet-version: '8.0.x'

# 1) BEGIN: SonarScanner for .NET
- name: SonarScanner Begin
run: |
dotnet tool install --global dotnet-sonarscanner
echo "$env:USERPROFILE\.dotnet\tools" >> $env:GITHUB_PATH
dotnet sonarscanner begin `
/k:"ppanchen_NetSdrClient" `
/o:"ppanchen" `
/d:sonar.token="${{ secrets.SONAR_TOKEN }}" `
/d:sonar.cs.opencover.reportsPaths="**/coverage.xml" `
/d:sonar.cpd.cs.minimumTokens=40 `
/d:sonar.cpd.cs.minimumLines=5 `
/d:sonar.exclusions=**/bin/**,**/obj/**,**/sonarcloud.yml `
/d:sonar.qualitygate.wait=true
/k:"${{ env.SONAR_PROJECT_KEY }}" `
/o:"${{ env.SONAR_ORGANIZATION }}" `
/d:sonar.token="${{ secrets.SONAR_TOKEN }}" `
/d:sonar.cs.opencover.reportsPaths="**/coverage.xml" `
/d:sonar.cpd.cs.minimumTokens=40 `
/d:sonar.cpd.cs.minimumLines=5 `
/d:sonar.exclusions=**/bin/**,**/obj/**,**/sonarcloud.yml `
/d:sonar.qualitygate.wait=true
shell: pwsh
# 2) BUILD & TEST

- name: Restore
run: dotnet restore NetSdrClient.sln

- name: Build
run: dotnet build NetSdrClient.sln -c Release --no-restore
#- name: Tests with coverage (OpenCover)
# run: |
# dotnet test NetSdrClientAppTests/NetSdrClientAppTests.csproj -c Release --no-build `
# /p:CollectCoverage=true `
# /p:CoverletOutput=TestResults/coverage.xml `
# /p:CoverletOutputFormat=opencover
# shell: pwsh
# 3) END: SonarScanner

- name: Tests with coverage (OpenCover)
run: |
dotnet test NetSdrClientAppTests/NetSdrClientAppTests.csproj -c Release --no-build `
/p:CollectCoverage=true `
/p:CoverletOutput=TestResults/coverage.xml `
/p:CoverletOutputFormat=opencover `
/p:Exclude="[NetSdrClientApp]NetSdrClientApp.Program"
shell: pwsh

- name: SonarScanner End
run: dotnet sonarscanner end /d:sonar.token="${{ secrets.SONAR_TOKEN }}"
shell: pwsh
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -360,4 +360,9 @@ MigrationBackup/
.ionide/

# Fody - auto-generated XML schema
FodyWeavers.xsd
FodyWeavers.xsd

# Local environment / secrets
.env
.env.*
!.env.example
29 changes: 13 additions & 16 deletions NetSdrClientApp/Messages/NetSdrMessageHelper.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection.PortableExecutable;
using System.Text;
using System.Threading.Tasks;

namespace NetSdrClientApp.Messages
{
Expand Down Expand Up @@ -83,7 +80,7 @@ public static bool TranslateMessage(byte[] msg, out MsgTypes type, out ControlIt
msgEnumarable = msgEnumarable.Skip(_msgControlItemLength);
msgLength -= _msgControlItemLength;

if (Enum.IsDefined(typeof(ControlItemCodes), value))
if (Enum.IsDefined(typeof(ControlItemCodes), (int)value))
{
itemCode = (ControlItemCodes)value;
}
Expand All @@ -108,23 +105,23 @@ public static bool TranslateMessage(byte[] msg, out MsgTypes type, out ControlIt

public static IEnumerable<int> GetSamples(ushort sampleSize, byte[] body)
{
sampleSize /= 8; //to bytes
if (sampleSize > 4)
int sampleSizeBytes = sampleSize / 8;
if (sampleSizeBytes > 4)
{
throw new ArgumentOutOfRangeException();
throw new ArgumentOutOfRangeException(nameof(sampleSize));
}

var bodyEnumerable = body as IEnumerable<byte>;
var prefixBytes = Enumerable.Range(0, 4 - sampleSize)
.Select(b => (byte)0);
if (sampleSizeBytes == 0)
{
yield break;
}

while (bodyEnumerable.Count() >= sampleSize)
var buffer = new byte[4];
for (int offset = 0; offset + sampleSizeBytes <= body.Length; offset += sampleSizeBytes)
{
yield return BitConverter.ToInt32(bodyEnumerable
.Take(sampleSize)
.Concat(prefixBytes)
.ToArray());
bodyEnumerable = bodyEnumerable.Skip(sampleSize);
Array.Clear(buffer, 0, buffer.Length);
Array.Copy(body, offset, buffer, 0, sampleSizeBytes);
yield return BitConverter.ToInt32(buffer);
}
}

Expand Down
43 changes: 17 additions & 26 deletions NetSdrClientApp/NetSdrClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,19 @@
using NetSdrClientApp.Networking;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;
using static NetSdrClientApp.Messages.NetSdrMessageHelper;
using static System.Runtime.InteropServices.JavaScript.JSType;

namespace NetSdrClientApp
{
public class NetSdrClient
{
private ITcpClient _tcpClient;
private IUdpClient _udpClient;
private readonly ITcpClient _tcpClient;
private readonly IUdpClient _udpClient;
private TaskCompletionSource<byte[]>? _responseTaskSource;

public bool IQStarted { get; set; }

Expand All @@ -38,7 +37,6 @@ public async Task ConnectAsync()
var automaticFilterMode = BitConverter.GetBytes((ushort)0).ToArray();
var adMode = new byte[] { 0x00, 0x03 };

//Host pre setup
var msgs = new List<byte[]>
{
NetSdrMessageHelper.GetControlItemMessage(MsgTypes.SetControlItem, ControlItemCodes.IQOutputDataSampleRate, sampleRate),
Expand All @@ -53,7 +51,7 @@ public async Task ConnectAsync()
}
}

public void Disconect()
public void Disconnect()
{
_tcpClient.Disconnect();
}
Expand All @@ -66,15 +64,15 @@ public async Task StartIQAsync()
return;
}

; var iqDataMode = (byte)0x80;
var iqDataMode = (byte)0x80;
var start = (byte)0x02;
var fifo16bitCaptureMode = (byte)0x01;
var n = (byte)1;

var args = new[] { iqDataMode, start, fifo16bitCaptureMode, n };

var msg = NetSdrMessageHelper.GetControlItemMessage(MsgTypes.SetControlItem, ControlItemCodes.ReceiverState, args);

await SendTcpRequest(msg);

IQStarted = true;
Expand Down Expand Up @@ -119,47 +117,40 @@ private void _udpClient_MessageReceived(object? sender, byte[] e)
NetSdrMessageHelper.TranslateMessage(e, out MsgTypes type, out ControlItemCodes code, out ushort sequenceNum, out byte[] body);
var samples = NetSdrMessageHelper.GetSamples(16, body);

Console.WriteLine($"Samples recieved: " + body.Select(b => Convert.ToString(b, toBase: 16)).Aggregate((l, r) => $"{l} {r}"));
Console.WriteLine("Samples recieved: " + string.Join(" ", body.Select(b => Convert.ToString(b, toBase: 16))));

using (FileStream fs = new FileStream("samples.bin", FileMode.Append, FileAccess.Write, FileShare.Read))
using (BinaryWriter sw = new BinaryWriter(fs))
{
foreach (var sample in samples)
{
sw.Write((short)sample); //write 16 bit per sample as configured
sw.Write((short)sample);
}
}
}

private TaskCompletionSource<byte[]> responseTaskSource;

private async Task<byte[]> SendTcpRequest(byte[] msg)
private async Task<byte[]?> SendTcpRequest(byte[] msg)
{
if (!_tcpClient.Connected)
{
Console.WriteLine("No active connection.");
return null;
}

responseTaskSource = new TaskCompletionSource<byte[]>(TaskCreationOptions.RunContinuationsAsynchronously);
var responseTask = responseTaskSource.Task;
var tcs = new TaskCompletionSource<byte[]>(TaskCreationOptions.RunContinuationsAsynchronously);
Interlocked.Exchange(ref _responseTaskSource, tcs);

await _tcpClient.SendMessageAsync(msg);

var resp = await responseTask;

return resp;
return await tcs.Task;
}

private void _tcpClient_MessageReceived(object? sender, byte[] e)
{
//TODO: add Unsolicited messages handling here
if (responseTaskSource != null)
{
responseTaskSource.SetResult(e);
responseTaskSource = null;
}
Console.WriteLine("Response recieved: " + e.Select(b => Convert.ToString(b, toBase: 16)).Aggregate((l, r) => $"{l} {r}"));
var tcs = Interlocked.Exchange(ref _responseTaskSource, null);
tcs?.TrySetResult(e);

Console.WriteLine("Response recieved: " + string.Join(" ", e.Select(b => Convert.ToString(b, toBase: 16))));
}
}
}
4 changes: 0 additions & 4 deletions NetSdrClientApp/Networking/ITcpClient.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Runtime.InteropServices.JavaScript.JSType;

namespace NetSdrClientApp.Networking
{
Expand Down
18 changes: 9 additions & 9 deletions NetSdrClientApp/Networking/TcpClientWrapper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ namespace NetSdrClientApp.Networking
{
public class TcpClientWrapper : ITcpClient
{
private string _host;
private int _port;
private readonly string _host;
private readonly int _port;
private TcpClient? _tcpClient;
private NetworkStream? _stream;
private CancellationTokenSource _cts;
private CancellationTokenSource? _cts;

public bool Connected => _tcpClient != null && _tcpClient.Connected && _stream != null;

Expand Down Expand Up @@ -75,7 +75,7 @@ public async Task SendMessageAsync(byte[] data)
{
if (Connected && _stream != null && _stream.CanWrite)
{
Console.WriteLine($"Message sent: " + data.Select(b => Convert.ToString(b, toBase: 16)).Aggregate((l, r) => $"{l} {r}"));
Console.WriteLine("Message sent: " + string.Join(" ", data.Select(b => Convert.ToString(b, toBase: 16))));
await _stream.WriteAsync(data, 0, data.Length);
}
else
Expand All @@ -89,7 +89,7 @@ public async Task SendMessageAsync(string str)
var data = Encoding.UTF8.GetBytes(str);
if (Connected && _stream != null && _stream.CanWrite)
{
Console.WriteLine($"Message sent: " + data.Select(b => Convert.ToString(b, toBase: 16)).Aggregate((l, r) => $"{l} {r}"));
Console.WriteLine("Message sent: " + string.Join(" ", data.Select(b => Convert.ToString(b, toBase: 16))));
await _stream.WriteAsync(data, 0, data.Length);
}
else
Expand All @@ -100,11 +100,11 @@ public async Task SendMessageAsync(string str)

private async Task StartListeningAsync()
{
if (Connected && _stream != null && _stream.CanRead)
if (Connected && _stream != null && _stream.CanRead && _cts != null)
{
try
{
Console.WriteLine($"Starting listening for incomming messages.");
Console.WriteLine("Starting listening for incomming messages.");

while (!_cts.Token.IsCancellationRequested)
{
Expand All @@ -117,9 +117,9 @@ private async Task StartListeningAsync()
}
}
}
catch (OperationCanceledException ex)
catch (OperationCanceledException)
{
//empty
// graceful shutdown initiated by Disconnect()
}
catch (Exception ex)
{
Expand Down
Loading