Commit 98cde58f authored by Vincent's avatar Vincent 💩

Added diveSelector and better way of working with the async writer

parent aeca1a4e
......@@ -55,9 +55,9 @@
<ItemGroup>
<Compile Include="Dive.cs" />
<Compile Include="DiveBundle.cs" />
<Compile Include="DiveReader.cs" />
<Compile Include="Readers\DiveReader.cs" />
<Compile Include="Request.cs" />
<Compile Include="DiveSelector\SelectDive.cs" />
<Compile Include="DiveSelector\SelectDiveRow.cs" />
<Compile Include="DiveSelector\DiveSelector.cs">
<SubType>Form</SubType>
</Compile>
......@@ -77,6 +77,7 @@
<Compile Include="Writers\DiveWriter.cs" />
<Compile Include="Writers\FileDiveWriter.cs" />
<Compile Include="Writers\LittleLogDiveWriter.cs" />
<Compile Include="Writers\SelectDiveWriter.cs" />
<EmbeddedResource Include="Form1.resx">
<DependentUpon>Form1.cs</DependentUpon>
</EmbeddedResource>
......@@ -94,6 +95,7 @@
<DependentUpon>DiveSelector.cs</DependentUpon>
</EmbeddedResource>
<None Include="packages.config" />
<None Include="Properties\DataSources\DiveLogUploader.DiveSelector.DiveSelectorRow.datasource" />
<None Include="Properties\DataSources\SelectDive.datasource" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
......
......@@ -9,29 +9,62 @@ using System.Threading.Tasks;
using System.Windows.Forms;
namespace DiveLogUploader.DiveSelector {
public partial class DiveSelector : Form {
public partial class DiveSelectorForm : Form {
public delegate void DoneDelegate(object source, DoneEventArgs eventArgs);
public event DoneDelegate OnDone;
public List<DiveSelectorRow> availableDives = new List<DiveSelectorRow>();
public BindingList<DiveSelectorRow> AvailableDives = new BindingList<DiveSelectorRow>();
public DiveSelector() {
public DiveSelectorForm() {
InitializeComponent();
gridDives.DataSource = availableDives;
diveSelectorRowBindingSource.DataSource = AvailableDives;
}
public void SetDives(List<Dive> dives) {
availableDives.Clear();
availableDives.Capacity = dives.Count;
gridDives.CurrentCell = null;
AvailableDives.Clear();
foreach(var d in dives) {
availableDives.Add(new DiveSelectorRow {
AvailableDives.Add(new DiveSelectorRow {
IsSelected = true,
Dive = d
});
}
}
private void gridDives_CurrentCellChanged(object sender, EventArgs e) {
if (gridDives.CurrentRow != null) {
var rowIndex = gridDives.CurrentRow.Index;
AvailableDives[rowIndex].IsSelected = !AvailableDives[rowIndex].IsSelected;
gridDives.UpdateCellValue(0, rowIndex);
gridDives.Rows[rowIndex].Selected = true;
}
}
private void gridDives_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e) {
gridDives.CurrentCell = null;
AvailableDives[0].IsSelected = true;
}
private void buttonSelectAll_Click(object sender, EventArgs e) {
foreach(var d in AvailableDives) {
d.IsSelected = true;
}
gridDives.Invalidate();
gridDives.Update();
}
private void buttonDeselectAll_Click(object sender, EventArgs e) {
foreach (var d in AvailableDives) {
d.IsSelected = false;
}
gridDives.Invalidate();
gridDives.Update();
}
private void ButtonDone_Click(object sender, EventArgs e) {
OnDone?.Invoke(this, new DoneEventArgs { dives = new Dive[] { } });
Hide();
var dives = AvailableDives.Where((d) => d.IsSelected).Select((d) => d.Dive).ToArray();
OnDone?.Invoke(this, new DoneEventArgs { dives = dives });
Close();
}
}
......
......@@ -120,13 +120,7 @@
<metadata name="IsSelected.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="Date.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="DiveTime.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
</metadata>
<metadata name="MaxDepth.UserAddedColumn" type="System.Boolean, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>True</value>
<metadata name="diveSelectorRowBindingSource.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root>
\ No newline at end of file
......@@ -4,12 +4,17 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DiveLogUploader {
namespace DiveLogUploader.DiveSelector {
public class DiveSelectorRow {
public bool IsSelected;
public Dive Dive;
public bool IsSelected;
public bool IIsSelected {
get { return IsSelected; }
}
public string DiveTime {
get {
var ts = new TimeSpan(0, 0, (int)Dive.DiveTime);
......@@ -19,7 +24,12 @@ namespace DiveLogUploader {
public string MaxDepth {
get {
return Dive.MaxDepth.ToString() + "m";
if (Dive.MaxDepth != null) {
var depth = (double)Dive.MaxDepth;
return depth.ToString("n2") + "m";
} else {
return null;
}
}
}
......
......@@ -13,16 +13,14 @@ using System.Linq;
using System.Windows.Forms;
using static LibDiveComputer.Context;
using DiveLogUploader.Writers;
using DiveLogUploader.DiveSelector;
using DiveLogUploader.Readers;
namespace divecomputer_test {
public partial class Form1 : Form {
private SessionStore Session = new SessionStore();
private DiveSelector DiveSelector = new DiveSelector();
private DiveReader Reader = new DiveReader();
private IDiveWriter Writer;
public Form1() {
......@@ -35,28 +33,6 @@ namespace divecomputer_test {
AuthErrLabel.Text = err.GetException().Message;
};
Reader.OnProgress += (source, args) => {
SetReadProgress(args.Precent);
};
Reader.OnLogMessage += (source, args) => {
Log(args.Message);
};
Reader.OnDeviceInfo += (source, args) => {
Writer.SetDevice(args.Device);
Writer.Start();
};
Reader.OnDive += (source, args) => {
Writer.AddDive(args.Dive);
};
Reader.OnStateChange += (source, args) => {
if (args.State == ReadingState.Reading) {
SetState(string.Format("{0}; Device: {1}, firmware {2}", args.State.ToString(), args.Device.Serial, args.Device.Firmware));
} else {
SetState(args.State.ToString());
}
StartButton.Enabled = args.State == ReadingState.Complete;
};
}
......@@ -139,13 +115,11 @@ namespace divecomputer_test {
LabelAccountDiveCount.Text = data.DiveCount.ToString();
LabelAccountSince.Text = data.Inserted.ToString("yyyy-MM-dd hh:mm:ss");
LabelAccountComputerCount.Text = data.ComputerCount.ToString();
}
private void LogLevelSelector_SelectedValueChanged(object sender, EventArgs e) {
if (LogLevelSelector.SelectedItem == null) return;
var item = (KeyValuePair<dc_loglevel_t, string>)LogLevelSelector.SelectedItem;
Reader.Loglevel = item.Key;
}
private void StartButton_Click(object sender, EventArgs e) {
......@@ -169,114 +143,91 @@ namespace divecomputer_test {
StartButton.Enabled = false;
//DivecomputerWorker.RunWorkerAsync();
DoReadDiveComputer();
}
private void RefreshPortButton_Click(object sender, EventArgs e) {
LoadSerialPorts();
}
//private void StartReading(Descriptor descriptor, string port) {
// DivecomputerWorker.RunWorkerAsync();
//}
//private void DivecomputerWorker_DoWork(object sender, DoWorkEventArgs e) {
// SetReadProgress(0, true);
// SetWriteProgress(0, true);
// var writeAll = ReadAllRadio.Checked;
// var args = currentTask;
// args.ctx = CreateContext(args.logLevel);
// IDiveWriter writer = null;
// try {
// var allDives = new List<Dive>();
// writer = CreateWriter();
// writer.OnProgres += (_, total, processed) => {
// SetWriteProgress((int)((float)processed / total * 100), true);
// };
// writer.OnComplete += (_) => {
// SetWriteProgress(100, true);
// };
// args.device = new Device(args.ctx, args.descriptor, args.serialPort);
// args.device.OnWaiting += () => { SetState("Waiting..."); };
// args.device.OnProgess += (prog) => { SetReadProgress((int)((float)prog.current / prog.maximum * 100)); };
// args.device.OnDeviceInfo += (devInfo) => {
// SetState(string.Format("Device: {0}, firmware {1}", devInfo.serial, devInfo.firmware));
// writer.SetDevice(args.device);
// writer.Start();
// };
// args.device.OnClock += (clock) => {
// Console.WriteLine(string.Format("systime: {0}, devtime: {1}", clock.systime, clock.devtime));
// };
// Dive lastDive = null;
// args.device.OnDive += (data, size, fingerprint, fsize, udata) => {
// lastDive = Dive.Parse(args.device, data, fingerprint);
// allDives.Add(lastDive);
// if (writeAll) {
// writer.AddDive(lastDive);
// }
// };
// args.device.Start();
// SetReadProgress(100, true);
// if (!writeAll) {
// SelectDives(allDives);
// } else {
// writer.End();
// }
// writer.Dispose();
// SetState("Finished");
// } catch (Exception err) {
// SetState("Error while reading device: " + err.Message, Color.Red);
// if (writer != null) {
// writer.Dispose();
// }
// }
// SetReadProgress(100, false);
// SetWriteProgress(100, false);
//}
private void DoReadDiveComputer() {
var writer = CreateWriter();
var reader = CreateReader(writer);
reader.Start();
private void SelectDives(List<Dive> d) {
if (InvokeRequired) {
Invoke(new Action(() => { SelectDives(d); }));
} else {
DiveSelector.Show();
DiveSelector.SetDives(d);
DiveSelector.OnDone += (source, a) => {
Console.WriteLine(a);
};
}
writer.OnComplete += (_) => {
SetStartButtonEnabled(true);
writer.Dispose();
reader.Dispose();
};
}
//private void DivecomputerWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
// Invoke(new Action(() => {
// if (currentTask.ctx != null) currentTask.ctx.Dispose();
// if (currentTask.device != null) currentTask.device.Dispose();
// currentTask.bundle = null;
// currentTask = null;
// StartButton.Enabled = true;
// }));
//}
private DiveReader CreateReader(IDiveWriter writer) {
var reader = new DiveReader();
if (LogLevelSelector.SelectedItem != null) {
var kvp = (KeyValuePair<dc_loglevel_t, string>)LogLevelSelector.SelectedItem;
reader.Loglevel = kvp.Key;
}
if (PortSelector.SelectedItem != null) {
var kvp = (KeyValuePair<string, string>)PortSelector.SelectedItem;
reader.SerialPort = kvp.Key;
}
if (ComputerSelector.SelectedItem != null) {
var kvp = (KeyValuePair<Descriptor, string>)ComputerSelector.SelectedItem;
reader.DeviceDescriptor = kvp.Key;
}
reader.OnProgress += (source, args) => {
SetReadProgress(args.Precent);
};
reader.OnLogMessage += (source, args) => {
Log(args.Message);
};
reader.OnDeviceInfo += (source, args) => {
writer.SetDevice(args.Device);
writer.Start();
};
reader.OnDive += (source, args) => {
writer.AddDive(args.Dive);
};
reader.OnStateChange += (source, args) => {
if (args.State == ReadingState.Reading) {
SetState(string.Format("{0}; Device: {1}, firmware {2}", args.State.ToString(), args.Device.Serial, args.Device.Firmware));
} else {
SetState(args.State.ToString());
}
};
reader.OnComplete += (_, __) => {
writer.End();
};
reader.OnError += (source, args) => {
SetState(args.Error.Message, Color.Red);
writer.Dispose();
SetStartButtonEnabled(true);
};
return reader;
}
private IDiveWriter CreateWriter() {
IDiveWriter writer;
if (FileRadio.Checked) {
writer = new FileDiveWriter(SaveFileText.Text);
} else if(LogRadio.Checked) {
writer = new LittleLogDiveWriter(Session.WebAppSession.Token);
writer = new LittleLogDiveWriter(Session.WebAppSession.Token, CheckboxReadSinceLast.Checked);
} else {
throw new Exception("No target type selected");
}
writer.OnProgres += (_, total, processed) => {
SetWriteProgress((int)((float)processed / total * 100), true);
if(ReadSelectRadio.Checked) {
writer = new SelectDiveWriter(writer, this);
}
writer.OnProgres += (_, args) => {
SetWriteProgress((int)((float)args.Current / args.Maximum * 100), true);
};
writer.OnComplete += (_) => {
SetWriteProgress(100, true);
......@@ -285,6 +236,14 @@ namespace divecomputer_test {
return writer;
}
private void SetStartButtonEnabled(bool enabled) {
if (InvokeRequired) {
Invoke(new Action(() => { SetStartButtonEnabled(enabled); }));
} else {
StartButton.Enabled = enabled;
}
}
private void SetState(string text, Color? color = null) {
Color c = color == null ? Color.Black : (Color)color;
if (InvokeRequired) {
......
<?xml version="1.0" encoding="utf-8"?>
<!--
This file is automatically generated by Visual Studio .Net. It is
used to store generic object data source configuration information.
Renaming the file extension or editing the content of this file may
cause the file to be unrecognizable by the program.
-->
<GenericObjectDataSource DisplayName="DiveSelectorRow" Version="1.0" xmlns="urn:schemas-microsoft-com:xml-msdatasource">
<TypeInfo>DiveLogUploader.DiveSelector.DiveSelectorRow, DiveLogUploader, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null</TypeInfo>
</GenericObjectDataSource>
\ No newline at end of file
......@@ -2,61 +2,67 @@
using LibDiveComputer;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static LibDiveComputer.Context;
public class DeviceEventArgs : EventArgs {
public Device Device;
public Context Context;
public enum ReadingState {
Started,
Waiting,
Reading,
Complete,
}
public class ProgressEventArgs : DeviceEventArgs {
public uint Maximum;
public uint Current;
public float Ratio { get { return (float)Current / Maximum; } }
public int Precent { get { return (int)Math.Round(Ratio * 100); } }
}
namespace DiveLogUploader.Readers {
public class DeviceInfoEventArgs : DeviceEventArgs {
public uint Model;
public uint Firmware;
public uint Serial;
}
public class DeviceEventArgs : EventArgs {
public Device Device;
public Context Context;
}
public class DeviceClockEventArgs : DeviceEventArgs {
public uint DevTime;
public long SysTime;
}
public class ProgressEventArgs : DeviceEventArgs {
public uint Maximum;
public uint Current;
public float Ratio { get { return (float)Current / Maximum; } }
public int Precent { get { return (int)Math.Round(Ratio * 100); } }
}
public class DiveEventArgs : DeviceEventArgs {
public Dive Dive;
}
public class DeviceInfoEventArgs : DeviceEventArgs {
public uint Model;
public uint Firmware;
public uint Serial;
}
public class CompleteEventArgs : DeviceEventArgs {
}
public class DeviceClockEventArgs : DeviceEventArgs {
public uint DevTime;
public long SysTime;
}
public class StateChangedEventArgs : DeviceEventArgs {
public ReadingState State;
}
public class DiveEventArgs : DeviceEventArgs {
public Dive Dive;
}
public class LogEntryEventArgs : DeviceEventArgs {
public dc_loglevel_t Loglevel;
public string File;
public uint Line;
public string Function;
public string Message;
}
public class CompleteEventArgs : DeviceEventArgs {
}
public enum ReadingState {
Started,
Waiting,
Reading,
Complete,
}
public class StateChangedEventArgs : DeviceEventArgs {
public ReadingState State;
}
public class LogEntryEventArgs : DeviceEventArgs {
public dc_loglevel_t Loglevel;
public string File;
public uint Line;
public string Function;
public string Message;
}
public class ErrorEventArgs : EventArgs {
public Exception Error;
}
namespace DiveLogUploader {
public delegate void ProgressHandle(object source, ProgressEventArgs args);
public delegate void DeviceInfoHandle(object source, DeviceInfoEventArgs args);
public delegate void ClockInfoHandle(object source, DeviceClockEventArgs args);
......@@ -64,8 +70,9 @@ namespace DiveLogUploader {
public delegate void CompleteHandle(object source, CompleteEventArgs args);
public delegate void LogMessageHandle(object source, LogEntryEventArgs args);
public delegate void StateChangeHandle(object source, StateChangedEventArgs args);
public delegate void ErrorHandle(object source, ErrorEventArgs args);
public class DiveReader {
public class DiveReader : IDisposable {
public const dc_loglevel_t DefaultLogLevel = dc_loglevel_t.DC_LOGLEVEL_ERROR;
public event ProgressHandle OnProgress;
public event DeviceInfoHandle OnDeviceInfo;
......@@ -74,10 +81,17 @@ namespace DiveLogUploader {
public event CompleteHandle OnComplete;
public event LogMessageHandle OnLogMessage;
public event StateChangeHandle OnStateChange;
public event ErrorHandle OnError;
public dc_loglevel_t Loglevel = DefaultLogLevel;
public string SerialPort;
public Descriptor deviceDescriptor;
public Descriptor DeviceDescriptor;
protected BackgroundWorker worker = new BackgroundWorker();
public DiveReader() {
worker.DoWork += (_, __) => DoWork();
}
private Context CreateContext() {
var ctx = new Context();
......@@ -94,70 +108,92 @@ namespace DiveLogUploader {
return ctx;
}
public void Read() {
var ctx = CreateContext();
var device = new Device(ctx, deviceDescriptor, SerialPort);
device.OnWaiting += () => {
public void Start() {
if(worker.IsBusy) {
throw new Exception("Dive Reader is already busy");
}
worker.RunWorkerAsync();
}
protected void DoWork() {
try {
var ctx = CreateContext();
var device = new Device(ctx, DeviceDescriptor, SerialPort);
device.OnWaiting += () => {
OnStateChange?.Invoke(this, new StateChangedEventArgs {
Context = ctx,
Device = device,
State = ReadingState.Waiting,
});
};
device.OnDeviceInfo += (devInfo) => {
OnDeviceInfo?.Invoke(this, new DeviceInfoEventArgs {
Context = ctx,
Device = device,
Firmware = devInfo.firmware,
Model = devInfo.model,
Serial = devInfo.serial,
});
};
device.OnClock += (clock) => {
OnStateChange?.Invoke(this, new StateChangedEventArgs {
Context = ctx,
Device = device,
State = ReadingState.Reading,
});
OnDeviceClock?.Invoke(this, new DeviceClockEventArgs {
Context = ctx,
Device = device,
DevTime = clock.devtime,
SysTime = clock.systime
});
};
device.OnProgess += (prog) => {
OnProgress?.Invoke(this, new ProgressEventArgs {
Context = ctx,
Device = device,
Current = prog.current,
Maximum = prog.maximum
});
};
device.OnDive += (data, size, fingerprint, fsize, udata) => {
OnDive?.Invoke(this, new DiveEventArgs {
Dive = Dive.Parse(device, data, fingerprint)
});
};
OnStateChange?.Invoke(this, new StateChangedEventArgs {
Context = ctx,
Device = device,
State = ReadingState.Waiting,
State = ReadingState.Started,
});
};
device.OnDeviceInfo += (devInfo) => {
OnDeviceInfo?.Invoke(this, new DeviceInfoEventArgs {
device.Start();
OnComplete?.Invoke(this, new CompleteEventArgs {
Context = ctx,
Device = device,
Firmware = devInfo.firmware,
Model = devInfo.model,
Serial = devInfo.serial,
});
};
device.OnClock += (clock) => {
OnStateChange?.Invoke(this, new StateChangedEventArgs {
Context = ctx,
Device = device,
State = ReadingState.Reading,
State = ReadingState.Complete,
});
OnDeviceClock?.Invoke(this, new DeviceClockEventArgs {
Context = ctx,
Device = device,
DevTime = clock.devtime,
SysTime = clock.systime
});
};
device.OnProgess += (prog) => {
OnProgress?.Invoke(this, new ProgressEventArgs {
Context = ctx,
Device = device,
Current = prog.current,
Maximum = prog.maximum
});
};
device.OnDive += (data, size, fingerprint, fsize, udata) => {
OnDive?.Invoke(this, new DiveEventArgs {
Dive = Dive.Parse(device, data, fingerprint)
});
};
OnStateChange?.Invoke(this, new StateChangedEventArgs {
Context = ctx,
Device = device,
State = ReadingState.Started,
});
device.Start();
OnComplete?.Invoke(this, new CompleteEventArgs {
Context = ctx,
Device = device,
});
OnStateChange?.Invoke(this, new StateChangedEventArgs {
Context = ctx,
Device = device,
State = ReadingState.Complete,
});
device.Dispose();
ctx.Dispose();
} catch(Exception ex) {
OnError?.Invoke(this, new ErrorEventArgs {
Error = ex
});
}
}
public void Dispose() {
}
}
......
......@@ -6,33 +6,34 @@ using System.Threading;
namespace DiveLogUploader.Writers {
public class ProgresEventArgs : EventArgs {
public uint Maximum;
public uint Current;
public float Ratio { get { return (float)Current / Maximum; } }
public int Precent { get { return (int)Math.Round(Ratio * 100); } }
}
public delegate void OnCompleteHandler(object sender);
public delegate void OnProgresHandler(object sender, int total, int processed);
public delegate void OnProgresHandler(object sender, ProgresEventArgs args);