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
6 changes: 6 additions & 0 deletions .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,9 @@ jobs:
- name: Build
run: msbuild.exe NINASonyCameraPlugin.sln /nologo /nr:false /p:DeployOnBuild=true /p:DeployDefaultTarget=WebPublish /p:WebPublishMethod=FileSystem /p:DeleteExistingFiles=True /p:platform="Any CPU" /p:configuration="Release" /p:PublishUrl="../_build"

- name: Upload SonyCamera DLL
uses: actions/upload-artifact@v4
with:
name: SonyCamera-DLL
path: |
**/bin/Release/**/NINA.RetroKiwi.Plugin.SonyCamera.dll
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Sony Camera Plugin

## 1.0.0.4
* Added the `UpdateSubSampleArea` implementation and bumped the minimum NINA version so the plugin loads in 3.2.
* Restored the ISO/Gain UI by notifying NINA whenever the camera connection updates ISO data and by handling cameras without ISO option lists.
* Probed the registry ISO property (`0xFFFE`) so older Sony bodies still populate the gain dropdown.
* Logged clearer errors when gain min/max cannot be determined and improved the GitHub workflow to publish the release DLL artifact.

Comment thread
dougforpres marked this conversation as resolved.
## 1.0.0.3
Updated to support new device property "DisplayName" required in NINA 3

Expand Down
149 changes: 96 additions & 53 deletions Drivers/CameraDriver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,9 @@
namespace NINA.RetroKiwi.Plugin.SonyCamera.Drivers {
public class CameraDriver : BaseINPC, ICamera {
// Some camera settings we are interested in
private const uint PROPID_BATTERY = 53784;
private const uint PROPID_ISO = 53790; // Actual ISO currently set
private const uint PROPID_ISOS = 65534; // List of learnt ISOs this camera supports
private const uint PROPID_BATTERY = 53784;
private const uint PROPID_ISO = 0xD21E; // Actual ISO currently set
private const uint PROPID_ISOS = 0xFFFE; // Registry-backed list of learnt ISOs (may be empty until learnt)

// Capture Status
private const uint CAPTURE_CREATED = 0x0000;
Expand Down Expand Up @@ -60,6 +60,37 @@ private PropertyValue GetPropertyValue(uint id) {
return SonyDriver.GetInstance().GetProperty(_camera.Handle, id);
}

private IReadOnlyList<PropertyValueOption> GetAvailableIsoOptions() {
if (_camera == null) {
return Array.Empty<PropertyValueOption>();
}

uint[] propertyCandidates = { PROPID_ISOS, PROPID_ISO };

foreach (var propertyId in propertyCandidates) {
try {
var options = _camera.GetPropertyInfo(propertyId)?.Options()?.Where(o => o.Value <= 0x00FFFFFF).ToList();
if (options != null && options.Count > 0) {
return options;
}
} catch (Exception ex) {
Logger.Warning($"Unable to enumerate ISO options for property 0x{propertyId:X}: {ex.Message}");
}
}

Logger.Warning("Camera did not report any ISO options via known properties (registry ISO list may be empty until the camera learns it).");
return Array.Empty<PropertyValueOption>();
}

private void NotifyGainPropertiesChanged() {
RaisePropertyChanged(nameof(CanGetGain));
RaisePropertyChanged(nameof(CanSetGain));
RaisePropertyChanged(nameof(GainMin));
RaisePropertyChanged(nameof(GainMax));
RaisePropertyChanged(nameof(Gain));
RaisePropertyChanged(nameof(Gains));
}

#endregion

#region Supported Properties
Expand Down Expand Up @@ -211,45 +242,35 @@ public int BitDepth {
}
}

public bool CanGetGain {
get {
if (_camera != null) {
PropertyInfo gainInfo = _camera.GetPropertyInfo(PROPID_ISOS);

if (gainInfo != null && gainInfo.Options().Any()) {
return true;
} else {
return false;
}
} else {
return false;
}
}
}
public bool CanGetGain => GetAvailableIsoOptions().Any();

public bool CanSetGain => CanGetGain;

public int GainMax {
get {
if (_camera != null) {
PropertyInfo gainInfo = _camera.GetPropertyInfo(PROPID_ISOS);

return (int)gainInfo.Options().Last().Value;
} else {
return 0;
var isoOptions = GetAvailableIsoOptions();
if (!isoOptions.Any()) {
if (_camera != null) {
Logger.Error("Problem getting gain max: camera did not report ISO options.");
}
return -1;
}

return (int)isoOptions.Last().Value;
}
}

public int GainMin {
get {
if (_camera != null) {
PropertyInfo gainInfo = _camera.GetPropertyInfo(PROPID_ISOS);

return (int)gainInfo.Options().Min(o => o.Value);
} else {
var isoOptions = GetAvailableIsoOptions();
if (!isoOptions.Any()) {
if (_camera != null) {
Logger.Error("Problem getting gain min: camera did not report ISO options.");
}
return -1;
}

return (int)isoOptions.Min(o => o.Value);
}
}

Expand All @@ -258,7 +279,6 @@ public int Gain {
if (_camera != null) {
try {
PropertyValue value = GetPropertyValue(PROPID_ISO);
PropertyInfo gainInfo = _camera.GetPropertyInfo(PROPID_ISOS);

return (int)(value.Value == 0xffffff ? 0 : value.Value);
} catch (Exception ex) {
Expand All @@ -274,6 +294,7 @@ public int Gain {
if (_camera != null) {
try {
SonyDriver.GetInstance().SetProperty(_camera.Handle, PROPID_ISO, (uint)value);
RaisePropertyChanged(nameof(Gain));
} catch (Exception ex) {
Logger.Error($"Problem setting gain to {value}", ex);
}
Expand All @@ -285,17 +306,11 @@ public IList<int> Gains {
get {
List<int> gains = new List<int>();

if (_camera != null) {
PropertyInfo gainInfo = _camera.GetPropertyInfo(PROPID_ISOS);

foreach (var iso in gainInfo.Options()) {
if (iso.Value == 0xffffff) {
// AUTO
gains.Add(0);
}
else {
gains.Add((int)iso.Value);
}
foreach (var iso in GetAvailableIsoOptions()) {
if (iso.Value == 0xffffff) {
gains.Add(0); // AUTO
} else {
gains.Add((int)iso.Value);
}
}

Expand Down Expand Up @@ -343,6 +358,7 @@ public double TemperatureSetPoint {
set {
}
}

public bool CanSubSample => false;

public bool EnableSubSample { get; set; }
Expand Down Expand Up @@ -441,12 +457,12 @@ public Task<bool> Connect(CancellationToken token) {
return Task.Run<bool>(() => {
try {
_camera = SonyDriver.GetInstance().OpenCamera(_device.Id);
}
catch (Exception ex) {
} catch (Exception ex) {
Logger.Error(ex);
_camera = null;
}

NotifyGainPropertiesChanged();
return _camera != null;
});
}
Expand All @@ -460,6 +476,7 @@ public void Disconnect() {
}

_camera = null;
NotifyGainPropertiesChanged();
}
}

Expand All @@ -468,7 +485,8 @@ public Task<IExposureData> DownloadLiveView(CancellationToken token) {
using (var memStream = new MemoryStream(SonyDriver.GetInstance().GetLiveView(_camera.Handle))) {
memStream.Position = 0;

JpegBitmapDecoder decoder = new JpegBitmapDecoder(memStream, BitmapCreateOptions.IgnoreColorProfile, BitmapCacheOption.OnLoad);
JpegBitmapDecoder decoder =
new JpegBitmapDecoder(memStream, BitmapCreateOptions.IgnoreColorProfile, BitmapCacheOption.OnLoad);

FormatConvertedBitmap bitmap = new FormatConvertedBitmap();
bitmap.BeginInit();
Expand All @@ -482,15 +500,16 @@ public Task<IExposureData> DownloadLiveView(CancellationToken token) {
var metaData = new ImageMetaData();

return _exposureDataFactory.CreateImageArrayExposureData(
input: outArray,
width: bitmap.PixelWidth,
height: bitmap.PixelHeight,
bitDepth: 16,
isBayered: false,
metaData: metaData);
input: outArray,
width: bitmap.PixelWidth,
height: bitmap.PixelHeight,
bitDepth: 16,
isBayered: false,
metaData: metaData);
}
});
}

public void SetupDialog() {
throw new NotImplementedException();
}
Expand All @@ -500,15 +519,16 @@ public void StartExposure(CaptureSequence sequence) {
SonyDriver driver = SonyDriver.GetInstance();
uint captureStatus = driver.GetCaptureStatus(_camera.Handle);

if (captureStatus == CAPTURE_CAPTURING || captureStatus == CAPTURE_PROCESSING || captureStatus == CAPTURE_STARTING || captureStatus == CAPTURE_READING || captureStatus == CAPTURE_PROCESSING) {
if (captureStatus == CAPTURE_CAPTURING || captureStatus == CAPTURE_PROCESSING || captureStatus == CAPTURE_STARTING ||
captureStatus == CAPTURE_READING || captureStatus == CAPTURE_PROCESSING) {
Notification.ShowWarning("Another exposure still in progress. Cancelling it to start another.");
}

// Tell the camera to cancel capture, we do this every time regardless - this will reset the status to be non-complete
driver.CancelCapture(_camera.Handle);

double exposureTime = sequence.ExposureTime;
driver.StartCapture(_camera.Handle, (float)exposureTime);//);
driver.StartCapture(_camera.Handle, (float)exposureTime); //);
}
}

Expand All @@ -530,7 +550,8 @@ public async Task WaitUntilExposureIsReady(CancellationToken token) {

try {
uint captureStatus = driver.GetCaptureStatus(_camera.Handle);
Logger.Info($"Waiting for image to be ready, current state is {captureStatus}, completion states are {String.Join(", ", completionStates)}");
Logger.Info(
$"Waiting for image to be ready, current state is {captureStatus}, completion states are {String.Join(", ", completionStates)}");

while (!completionStates.Contains(captureStatus)) {
await CoreUtil.Wait(TimeSpan.FromMilliseconds(100), token);
Expand Down Expand Up @@ -583,6 +604,28 @@ public string SendCommandString(string command, bool raw = true) {
public void SetBinning(short x, short y) {
// Ignore
}

public void UpdateSubSampleArea() {
if (_camera == null) {
EnableSubSample = false;
SubSampleX = 0;
SubSampleY = 0;
SubSampleWidth = 0;
SubSampleHeight = 0;
return;
}

if (EnableSubSample && !CanSubSample) {
Logger.Warning("Sub-sampling requested but not supported for Sony cameras. Falling back to full frame.");
EnableSubSample = false;
}

// Sony cameras currently expose the entire frame, so always reset to the sensor dimensions.
SubSampleX = 0;
SubSampleY = 0;
SubSampleWidth = _camera.ImageSize.Width;
SubSampleHeight = _camera.ImageSize.Height;
}

#endregion

Expand Down
36 changes: 3 additions & 33 deletions NINASonyCameraPlugin.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<Reference Include="ReachFramework" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="NINA.Plugin" Version="3.0.0.3001-rc" />
<PackageReference Include="NINA.Plugin" Version="3.2.0.3001-rc" />
<PackageReference Include="System.ComponentModel.Composition" Version="8.0.0" />
<PackageReference Include="System.Data.DataSetExtensions" Version="4.6.0-preview3.19128.7" />
<PackageReference Include="EntityFramework" Version="6.4.4" />
Expand All @@ -21,51 +21,21 @@
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="System.Collections.Immutable" Version="8.0.0" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
<PackageReference Include="System.Configuration.ConfigurationManager" Version="8.0.0" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Accord" Version="3.8.2-alpha" />
<PackageReference Include="Accord.Imaging" Version="3.8.2-alpha" />
<PackageReference Include="Accord.Math" Version="3.8.2-alpha" />
<PackageReference Include="Accord.Statistics" Version="3.8.2-alpha" />
<PackageReference Include="AsyncEnumerator" Version="4.0.2" />
<PackageReference Include="Castle.Core" Version="5.1.1" />
<PackageReference Include="Castle.Core.AsyncInterceptor" Version="2.1.0" />
<PackageReference Include="CommonServiceLocator" Version="2.0.7" />
<PackageReference Include="CSharpFITS" Version="1.1.0" />
<PackageReference Include="CsvHelper" Version="30.0.1" />
<PackageReference Include="Dirkster.AvalonDock" Version="4.72.1" />
<PackageReference Include="DotNetProjects.Extended.Wpf.Toolkit" Version="5.0.113" />
<PackageReference Include="Fastenshtein" Version="1.0.0.8" />
<PackageReference Include="Google.Protobuf" Version="3.25.1" />
<PackageReference Include="Google.Protobuf.Tools" Version="3.25.1" />
<PackageReference Include="Grpc.Core.Api" Version="2.60.0" />
<PackageReference Include="GrpcDotNetNamedPipes" Version="3.0.0" />
<PackageReference Include="K4os.Compression.LZ4" Version="1.3.7-beta" />
<PackageReference Include="Microsoft.Xaml.Behaviors.Wpf" Version="1.1.77" />
<PackageReference Include="Namotion.Reflection" Version="3.1.1" />
<PackageReference Include="Nito.AsyncEx" Version="5.1.2" />
<PackageReference Include="Nito.AsyncEx.Context" Version="5.1.2" />
<PackageReference Include="Nito.AsyncEx.Coordination" Version="5.1.2" />
<PackageReference Include="Nito.AsyncEx.Interop.WaitHandles" Version="5.1.2" />
<PackageReference Include="Nito.AsyncEx.Oop" Version="5.1.2" />
<PackageReference Include="Nito.AsyncEx.Tasks" Version="5.1.2" />
<PackageReference Include="Nito.Cancellation" Version="1.2.0" />
<PackageReference Include="Nito.Collections.Deque" Version="1.2.1" />
<PackageReference Include="Nito.Disposables" Version="2.5.0" />
<PackageReference Include="Nito.Mvvm.Async" Version="1.0.0-pre-04" />
<PackageReference Include="Nito.Mvvm.Core" Version="1.3.1" />
<PackageReference Include="NJsonSchema" Version="11.0.0" />
<PackageReference Include="OxyPlot.Core" Version="2.1.2" />
<PackageReference Include="OxyPlot.Wpf" Version="2.1.2" />
<PackageReference Include="SHA3" Version="1.0.0" />
<PackageReference Include="SharpGIS.NmeaParser" Version="2.2.2" />
<PackageReference Include="System.Data.SQLite" Version="1.0.118" />
<PackageReference Include="System.Data.SQLite.Core" Version="1.0.118" />
<PackageReference Include="System.Data.SQLite.EF6" Version="1.0.118" />
<PackageReference Include="System.Windows.Interactivity.WPF" Version="2.0.20525" />
<PackageReference Include="ToggleSwitch" Version="1.2.0" />
<PackageReference Include="Trinet.Core.IO.Ntfs" Version="4.1.1" />
<PackageReference Include="VVVV.FreeImage" Version="3.15.1.1" />
<PackageReference Include="Zlib.Portable.Signed" Version="1.11.0" />
</ItemGroup>
Expand Down Expand Up @@ -99,6 +69,6 @@
</ItemGroup>
<PropertyGroup />
<Target Name="PostBuild" AfterTargets="PostBuildEvent">
<Exec Command="if not exist &quot;%25localappdata%25\NINA\Plugins&quot; (&#xD;&#xA; echo &quot;Creating $(PlatformName) Plugins folder&quot;&#xD;&#xA; mkdir &quot;%25localappdata%25\NINA\Plugins&quot;&#xD;&#xA;)&#xD;&#xA;if not exist &quot;%25localappdata%25\NINA\Plugin\3.0.0\$(TargetName)&quot; (&#xD;&#xA; echo &quot;Creating $(PlatformName) Plugins\3.0.0\$(TargetName) folder&quot;&#xD;&#xA; mkdir &quot;%25localappdata%25\NINA\Plugins\$(TargetName)&quot;&#xD;&#xA;)&#xD;&#xA;&#xD;&#xA;echo &quot;Copying $(PlatformName) $(TargetFileName)&quot;&#xD;&#xA;xcopy &quot;$(TargetPath)&quot; &quot;%25localappdata%25\NINA\Plugins\3.0.0\$(TargetName)&quot; /h/i/c/k/e/r/y" />
<Exec Command="if not exist &quot;%25localappdata%25\NINA\Plugins\3.0.0&quot; (&#xA; echo &quot;Creating $(PlatformName) Plugins folder&quot;&#xA; mkdir &quot;%25localappdata%25\NINA\Plugins\3.0.0&quot;&#xA;)&#xA;if not exist &quot;%25localappdata%25\NINA\Plugins\3.0.0\$(TargetName)&quot; (&#xA; echo &quot;Creating $(PlatformName) Plugins $(TargetName) folder&quot;&#xA; mkdir &quot;%25localappdata%25\NINA\Plugins\3.0.0\$(TargetName)&quot;&#xA;)&#xA;&#xA;echo &quot;Copying $(PlatformName) $(TargetFileName)&quot;&#xA;xcopy &quot;$(TargetPath)&quot; &quot;%25localappdata%25\NINA\Plugins\3.0.0\$(TargetName)&quot; /h/i/c/k/e/r/y" />
</Target>
</Project>
</Project>
9 changes: 6 additions & 3 deletions Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@

// [MANDATORY] The assembly versioning
//Should be incremented for each new release build of a plugin
[assembly: AssemblyVersion("1.0.0.3")]
[assembly: AssemblyFileVersion("1.0.0.3")]
[assembly: AssemblyVersion("1.0.0.4")]
[assembly: AssemblyFileVersion("1.0.0.4")]

// [MANDATORY] The name of your plugin
[assembly: AssemblyTitle("Sony Camera Plugin")]
Expand All @@ -25,7 +25,7 @@
[assembly: AssemblyCopyright("Copyright © 2023-2024 Doug Henderson")]

// The minimum Version of N.I.N.A. that this plugin is compatible with
[assembly: AssemblyMetadata("MinimumApplicationVersion", "3.0.0.2001")]
[assembly: AssemblyMetadata("MinimumApplicationVersion", "3.2.0.3001")]

// The license your plugin code is using
[assembly: AssemblyMetadata("License", "MPL-2.0")]
Expand Down Expand Up @@ -72,6 +72,9 @@
* [My camera is not supported](https://github.com/dougforpres/ASCOMSonyCameraDriver/wiki/Installation#if-you-dont-have-a-supported-camera-model)
* [List of supported cameras](https://github.com/dougforpres/ASCOMSonyCameraDriver/wiki/Supported-Cameras)
* [Other known issues](https://github.com/dougforpres/ASCOMSonyCameraDriver/wiki/Troubleshooting)

## Contributors
* Lucas Lepski [@ShurkanTwo](https://github.com/shurkanTwo)
")]

// Setting ComVisible to false makes the types in this assembly not visible
Expand Down
Loading