Skip to content

Commit

Permalink
Merge pull request #43 from David032/SkullOSReintegration
Browse files Browse the repository at this point in the history
Adding working parts from Haro sub-project to the core program
  • Loading branch information
David032 authored Feb 12, 2024
2 parents 25e51c8 + 2dc29a5 commit e8f5c18
Show file tree
Hide file tree
Showing 38 changed files with 418 additions and 120 deletions.
4 changes: 4 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[*.cs]

# CS8600: Converting null literal or possible null value to non-nullable type.
dotnet_diagnostic.CS8600.severity = none
27 changes: 27 additions & 0 deletions ServoSkull.sln
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{B50B951E
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{EE38A10C-F0BB-40B5-B1E6-8CB16C6E452C}"
ProjectSection(SolutionItems) = preProject
.editorconfig = .editorconfig
Pinout.md = Pinout.md
EndProjectSection
EndProject
Expand All @@ -38,33 +39,59 @@ EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|ARM64 = Debug|ARM64
Release|Any CPU = Release|Any CPU
Release|ARM64 = Release|ARM64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{464B162B-62FC-49CC-A6AB-72DBE959DD8C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{464B162B-62FC-49CC-A6AB-72DBE959DD8C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{464B162B-62FC-49CC-A6AB-72DBE959DD8C}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{464B162B-62FC-49CC-A6AB-72DBE959DD8C}.Debug|ARM64.Build.0 = Debug|Any CPU
{464B162B-62FC-49CC-A6AB-72DBE959DD8C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{464B162B-62FC-49CC-A6AB-72DBE959DD8C}.Release|Any CPU.Build.0 = Release|Any CPU
{464B162B-62FC-49CC-A6AB-72DBE959DD8C}.Release|ARM64.ActiveCfg = Release|Any CPU
{464B162B-62FC-49CC-A6AB-72DBE959DD8C}.Release|ARM64.Build.0 = Release|Any CPU
{6D3C5D36-0002-4EFD-A3B9-0924D6D3CCD8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6D3C5D36-0002-4EFD-A3B9-0924D6D3CCD8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6D3C5D36-0002-4EFD-A3B9-0924D6D3CCD8}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{6D3C5D36-0002-4EFD-A3B9-0924D6D3CCD8}.Debug|ARM64.Build.0 = Debug|Any CPU
{6D3C5D36-0002-4EFD-A3B9-0924D6D3CCD8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6D3C5D36-0002-4EFD-A3B9-0924D6D3CCD8}.Release|Any CPU.Build.0 = Release|Any CPU
{6D3C5D36-0002-4EFD-A3B9-0924D6D3CCD8}.Release|ARM64.ActiveCfg = Release|Any CPU
{6D3C5D36-0002-4EFD-A3B9-0924D6D3CCD8}.Release|ARM64.Build.0 = Release|Any CPU
{5E1EC385-4B61-4E8C-82C7-46695A33AC72}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5E1EC385-4B61-4E8C-82C7-46695A33AC72}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5E1EC385-4B61-4E8C-82C7-46695A33AC72}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{5E1EC385-4B61-4E8C-82C7-46695A33AC72}.Debug|ARM64.Build.0 = Debug|Any CPU
{5E1EC385-4B61-4E8C-82C7-46695A33AC72}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5E1EC385-4B61-4E8C-82C7-46695A33AC72}.Release|Any CPU.Build.0 = Release|Any CPU
{5E1EC385-4B61-4E8C-82C7-46695A33AC72}.Release|ARM64.ActiveCfg = Release|Any CPU
{5E1EC385-4B61-4E8C-82C7-46695A33AC72}.Release|ARM64.Build.0 = Release|Any CPU
{DE800E5A-E68B-4BCA-AC99-4BC9DB44FD56}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DE800E5A-E68B-4BCA-AC99-4BC9DB44FD56}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DE800E5A-E68B-4BCA-AC99-4BC9DB44FD56}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{DE800E5A-E68B-4BCA-AC99-4BC9DB44FD56}.Debug|ARM64.Build.0 = Debug|Any CPU
{DE800E5A-E68B-4BCA-AC99-4BC9DB44FD56}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DE800E5A-E68B-4BCA-AC99-4BC9DB44FD56}.Release|Any CPU.Build.0 = Release|Any CPU
{DE800E5A-E68B-4BCA-AC99-4BC9DB44FD56}.Release|ARM64.ActiveCfg = Release|Any CPU
{DE800E5A-E68B-4BCA-AC99-4BC9DB44FD56}.Release|ARM64.Build.0 = Release|Any CPU
{3CBE1B63-957B-43B6-939D-070EAC517C7C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3CBE1B63-957B-43B6-939D-070EAC517C7C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3CBE1B63-957B-43B6-939D-070EAC517C7C}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{3CBE1B63-957B-43B6-939D-070EAC517C7C}.Debug|ARM64.Build.0 = Debug|Any CPU
{3CBE1B63-957B-43B6-939D-070EAC517C7C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3CBE1B63-957B-43B6-939D-070EAC517C7C}.Release|Any CPU.Build.0 = Release|Any CPU
{3CBE1B63-957B-43B6-939D-070EAC517C7C}.Release|ARM64.ActiveCfg = Release|Any CPU
{3CBE1B63-957B-43B6-939D-070EAC517C7C}.Release|ARM64.Build.0 = Release|Any CPU
{0B0F89D7-32B6-4E20-B676-44F70E7B5352}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0B0F89D7-32B6-4E20-B676-44F70E7B5352}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0B0F89D7-32B6-4E20-B676-44F70E7B5352}.Debug|ARM64.ActiveCfg = Debug|Any CPU
{0B0F89D7-32B6-4E20-B676-44F70E7B5352}.Debug|ARM64.Build.0 = Debug|Any CPU
{0B0F89D7-32B6-4E20-B676-44F70E7B5352}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0B0F89D7-32B6-4E20-B676-44F70E7B5352}.Release|Any CPU.Build.0 = Release|Any CPU
{0B0F89D7-32B6-4E20-B676-44F70E7B5352}.Release|ARM64.ActiveCfg = Release|Any CPU
{0B0F89D7-32B6-4E20-B676-44F70E7B5352}.Release|ARM64.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
11 changes: 7 additions & 4 deletions skullOS.API/Controllers/CapturesController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ public string GetDirectory()
[HttpGet("MostRecent")]
public IActionResult GetNewest()
{
var mostRecentImage = capturesDirectoryInfo.GetFiles().Where(f => f.Extension == ".jpg").OrderByDescending(f => f.LastAccessTime).FirstOrDefault();
var mostRecentImage = capturesDirectoryInfo.GetFiles().Where(f => f.Extension == ".jpg").OrderByDescending(f => f.LastAccessTime).FirstOrDefault()
?? throw new Exception("Failed to find file!"); ;
var image = System.IO.File.OpenRead(mostRecentImage.FullName);
return File(image, "image/jpeg");
}
Expand Down Expand Up @@ -85,15 +86,17 @@ public List<Capture> GetAllVideos()
[HttpGet("Image")]
public IActionResult GetImage(string fileId)
{
var file = capturesDirectoryInfo.GetFiles().Where(f => f.Name == fileId).FirstOrDefault();
var file = capturesDirectoryInfo.GetFiles().Where(f => f.Name == fileId).FirstOrDefault()
?? throw new Exception("Failed to find file!");
var image = System.IO.File.OpenRead(file.FullName);
return File(image, "image/jpeg");
}

[HttpGet("Video")]
public IActionResult GetVideo(string fileId)
{
var file = capturesDirectoryInfo.GetFiles().Where(f => f.Name == fileId).FirstOrDefault();
var file = capturesDirectoryInfo.GetFiles().Where(f => f.Name == fileId).FirstOrDefault()
?? throw new Exception("Failed to find file!");
var image = System.IO.File.OpenRead(file.FullName);
return File(image, "video/mp4");
}
Expand All @@ -116,7 +119,7 @@ public bool DeleteCapture(string filePath)
public void DeleteMostRecent()
{
var mostRecentImage = capturesDirectoryInfo.GetFiles().Where(f => f.Extension == ".jpg")
.OrderByDescending(f => f.LastAccessTime).FirstOrDefault();
.OrderByDescending(f => f.LastAccessTime).FirstOrDefault() ?? throw new Exception("Failed to find file!"); ;
mostRecentImage.Delete();
}
}
Expand Down
16 changes: 13 additions & 3 deletions skullOS.API/Data Objects/Capture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
public class Capture
{
private string filename;
private string date;
private string? date;
private string time;

public Capture(string Name, string time, string date = null)
public Capture(string Name, string time, string? date = null)
{
filename = Name;
this.date = date;
Expand All @@ -27,7 +27,17 @@ public string Filename

public string Date
{
get { return date; }
get
{
if (date != null)
{
return date;
}
else
{
return "No date";
}
}
set { date = value; }
}
}
Expand Down
2 changes: 1 addition & 1 deletion skullOS.API/skullOS.API.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
Expand Down
22 changes: 17 additions & 5 deletions skullOS.Core/FileManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ public static class FileManager

public static void CreateSkullDirectory(bool usePersonalDir = true)
{
DirectoryInfo rootDirectory = null;
DirectoryInfo? rootDirectory = null;
string pathToDir;
if (usePersonalDir)
{
pathToDir = @Environment.GetFolderPath(Environment.SpecialFolder.Personal);
//pathToDir = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
pathToDir = Environment.GetEnvironmentVariable("HOME");
Console.WriteLine("Path to personal dir is " + pathToDir);
}
else
{
Expand All @@ -23,14 +25,21 @@ public static void CreateSkullDirectory(bool usePersonalDir = true)
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
rootDirectory = Directory.CreateDirectory(pathToDir + @"/skullOS",
unixCreateMode: UnixFileMode.OtherRead | UnixFileMode.OtherWrite | UnixFileMode.OtherExecute);
unixCreateMode: UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute |
UnixFileMode.GroupRead | UnixFileMode.GroupWrite | UnixFileMode.GroupExecute |
UnixFileMode.OtherRead | UnixFileMode.OtherWrite | UnixFileMode.OtherExecute);
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
if (rootDirectory == null)
{
throw new Exception("Root directory not defined!");
}
rootDirectoryPath = rootDirectory.FullName;
Console.WriteLine("Root directory is: " + rootDirectoryPath);
}

public static string GetSkullDirectory()
Expand All @@ -40,9 +49,12 @@ public static string GetSkullDirectory()

public static void CreateSubDirectory(string directoryName)
{
if (rootDirectoryPath != string.Empty)
if (rootDirectoryPath != string.Empty && RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
Directory.CreateDirectory(@rootDirectoryPath + "/" + directoryName);
Directory.CreateDirectory(rootDirectoryPath + @"/" + directoryName,
unixCreateMode: UnixFileMode.UserRead | UnixFileMode.UserWrite | UnixFileMode.UserExecute |
UnixFileMode.GroupRead | UnixFileMode.GroupWrite | UnixFileMode.GroupExecute |
UnixFileMode.OtherRead | UnixFileMode.OtherWrite | UnixFileMode.OtherExecute);
}
}
}
Expand Down
6 changes: 5 additions & 1 deletion skullOS.Core/skullOS.Core.csproj
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<None Include="..\.editorconfig" Link=".editorconfig" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Iot.Device.Bindings" Version="3.0.0" />
<PackageReference Include="System.Device.Gpio" Version="3.0.0" />
Expand Down
68 changes: 3 additions & 65 deletions skullOS.HardwareServices/CameraService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,17 @@
using Iot.Device.Common;
using Iot.Device.Media;
using skullOS.HardwareServices.Interfaces;
using System.Diagnostics;

namespace skullOS.HardwareServices
{
public class CameraService : ICameraService
{
public VideoDevice Camera { get; private set; }
private Process? cameraCommand;
private TaskCompletionSource<bool> eventHandled;

private readonly ProcessSettings _processSettings;


public CameraService(VideoConnectionSettings cameraSettings = null)
public CameraService(VideoConnectionSettings? cameraSettings = null)
{
cameraSettings ??= new(busId: 0, captureSize: (2592, 1944), pixelFormat: VideoPixelFormat.JPEG);
Camera = VideoDevice.Create(cameraSettings);
Expand All @@ -25,14 +22,14 @@ public CameraService(VideoConnectionSettings cameraSettings = null)
_processSettings = ProcessSettingsFactory.CreateForLibcamerastill();
}

public async Task<string> TakePictureAsync(string fileLocation)
public async Task<string> TakePictureAsync(string fileLocation, int x = 2592, int y = 1944)
{
var builder = new CommandOptionsBuilder()
.WithTimeout(1)
.WithVflip()
.WithHflip()
.WithPictureOptions(quality: 100)
.WithResolution(2592, 1944);
.WithResolution(x, y);
var args = builder.GetArguments();

using var proc = new ProcessRunner(_processSettings);
Expand All @@ -55,64 +52,5 @@ public async Task<string> TakePictureAsync(string fileLocation)

return filename;
}

#region SharpCamera code(https://github.com/David032/sharpCamera) for recording video
public void RecordVideo(string outputDirectory, int duration)
{
try
{
using (cameraCommand = new Process())
{
string args = "-o " + outputDirectory + "/" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".h264 -t " + (duration * 1000);
cameraCommand.StartInfo.UseShellExecute = false;
cameraCommand.StartInfo.FileName = "raspivid";
cameraCommand.StartInfo.Arguments = args;

#if DEBUG
Console.Out.WriteLine(cameraCommand.StartInfo.Arguments);
#endif

cameraCommand.Start();
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}

public async Task RecordVideoAsync(string outputDirectory, int duration)
{
eventHandled = new TaskCompletionSource<bool>();
using (cameraCommand = new Process())
{
try
{
string args = "-o " + outputDirectory + "/" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".h264 -t " + (duration * 1000);
cameraCommand.StartInfo.UseShellExecute = false;
cameraCommand.StartInfo.FileName = "raspivid";
cameraCommand.StartInfo.Arguments = args;
cameraCommand.EnableRaisingEvents = true;
cameraCommand.Exited += new EventHandler(VideoRecorded);
#if DEBUG
Console.Out.WriteLine(cameraCommand.StartInfo.Arguments);
#endif
cameraCommand.Start();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
return;
}

await Task.WhenAny(eventHandled.Task, Task.Delay(duration * 1000));
}
}

private void VideoRecorded(object sender, EventArgs e)
{
eventHandled.TrySetResult(true);
}
#endregion
}
}
4 changes: 3 additions & 1 deletion skullOS.HardwareServices/Interfaces/ICameraService.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
namespace skullOS.HardwareServices.Interfaces

namespace skullOS.HardwareServices.Interfaces
{
public interface ICameraService
{
Task<string> TakePictureAsync(string fileLocation, int x = 2592, int y = 1944);
}
}
4 changes: 4 additions & 0 deletions skullOS.HardwareServices/Interfaces/ILedService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,9 @@
{
public interface ILedService
{
void BlinkLight(string light);
void TurnOff(int Pin);
void TurnOn(int Pin);
Dictionary<string, int> GetLeds();
}
}
4 changes: 3 additions & 1 deletion skullOS.HardwareServices/Interfaces/ISpeakerService.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
namespace skullOS.HardwareServices.Interfaces

namespace skullOS.HardwareServices.Interfaces
{
public interface ISpeakerService
{
Task PlayAudio(string filepath);
}
}
5 changes: 5 additions & 0 deletions skullOS.HardwareServices/LedService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,10 @@ public void TurnOff(int Pin)
}
controller.Write(Pin, PinValue.Low);
}

public Dictionary<string, int> GetLeds()
{
return LEDs;
}
}
}
2 changes: 1 addition & 1 deletion skullOS.HardwareServices/MicrophoneService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public class MicrophoneService : IMicrophoneService
{
public SoundDevice Microphone { get; private set; }

public MicrophoneService(SoundConnectionSettings micSettings = null)
public MicrophoneService(SoundConnectionSettings? micSettings = null)
{
micSettings ??= new SoundConnectionSettings();
Microphone = SoundDevice.Create(micSettings); //Can't create a microphone if there's no mic!
Expand Down
Loading

0 comments on commit e8f5c18

Please sign in to comment.