diff Radio/Tuner.cs @ 0:3ab940a0c7a0

Initial commit
author Ivo Smits <Ivo@UCIS.nl>
date Tue, 11 Sep 2012 16:28:53 +0200
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Radio/Tuner.cs	Tue Sep 11 16:28:53 2012 +0200
@@ -0,0 +1,262 @@
+using System;
+using System.Collections.Generic;
+
+namespace UCIS.Radio {
+	public struct TunerFrequencyRange {
+		public TunerFrequencyRange(ulong Begin, ulong End) {
+			this.Begin = Begin;
+			this.End = End;
+		}
+
+		public ulong Begin;
+		public ulong End;
+	}
+	public struct TunerMode {
+		public TunerMode(int Index, string Name) {
+			this.Index = Index;
+			this.Name = Name;
+		}
+
+		public int Index;
+		public string Name;
+	}
+	public struct TunerFilter {
+		public TunerFilter(int Index, string Name) {
+			this.Index = Index;
+			this.Name = Name;
+		}
+
+		public int Index;
+		public string Name;
+	}
+
+	public class TunerCapabilities {
+		public TunerFrequencyRange[] Bands = new TunerFrequencyRange[0];
+		public IDictionary<byte, string> Modes = new Dictionary<byte, string>();
+		public IDictionary<byte, string> Filters = new Dictionary<byte, string>();
+		public IList<TunerOption> Options = new List<TunerOption>();
+		public byte[] AvailableModes;
+		public byte[] AvailableFilters;
+	}
+
+	public enum TunerOption : byte {
+		//R/W 0-255 value
+		Volume = 1,
+		Squelch = 2,
+		IfShift = 3,
+
+		//Not accessible (feature indication only)
+		Frequency = 50,
+		Mode = 51,
+		Filter = 52,
+
+		//Read only
+		Signal = 70,
+		Online = 71,
+
+		//R/W On/Off
+		Attenuator = 100,
+		AGC = 101,
+		NoiseBlanker = 102,
+		VSC = 103,
+		StereoMono = 104,
+
+		//W Execute
+		Poll = 151,
+		RadioText = 200,
+
+		//200+: reserved for personal use
+	}
+
+	public class TunerOptionChangedEventArgs : EventArgs {
+		public TunerOptionChangedEventArgs(TunerOption option) { Option = option; }
+		public TunerOption Option;
+	}
+
+	public interface ITuner {
+		event EventHandler TuningChanged;
+		event EventHandler<TunerOptionChangedEventArgs> OptionChanged;
+		void Open();
+		void Close();
+		void Poll();
+		TunerCapabilities Capabilities { get; }
+		ulong Frequency { get; set; }
+		byte Mode { get; set; }
+		byte Filter { get; set; }
+		bool SetTuning(ulong frequency, byte mode, byte filter);
+		bool SetOption(TunerOption Option, byte Value);
+		byte GetOption(TunerOption Option);
+	}
+
+	public abstract class Tuner : ITuner {
+		private ulong _frequency;
+		private byte _mode, _filter;
+		private TunerCapabilities _capabilities = new TunerCapabilities();
+		private byte[] _options = new byte[256];
+
+		public event EventHandler TuningChanged;
+		public event EventHandler AvailableModesChanged;
+		public event EventHandler<TunerOptionChangedEventArgs> OptionChanged;
+
+		protected Tuner() {
+			//AcceptOption(ReceiverOptions.IfShift, 127);
+			//AcceptOption(ReceiverOptions.Online, 1);
+		}
+
+		public virtual void Open() { }
+		public virtual void Close() { }
+		public virtual void Poll() { }
+
+		public TunerCapabilities Capabilities { get { return _capabilities; } }
+
+		public ulong Frequency {
+			get { return _frequency; }
+			set {SetTuning(value, 0, 0); }
+		}
+		public byte Mode {
+			get { return _mode; }
+			set { SetTuning(0, value, 0); }
+		}
+		public byte Filter {
+			get { return _mode; }
+			set { SetTuning(0, 0, value); }
+		}
+		public virtual bool SetTuning(ulong frequency, byte mode, byte filter) {
+			return SetTuning(ref frequency, ref mode, ref filter);
+		}
+		public virtual bool SetTuning(ref ulong frequency, ref byte mode, ref byte filter) {
+			bool notexact = false;
+			CheckFrequency(ref frequency, ref notexact);
+			CheckMode(ref mode, ref notexact);
+			CheckFilter(ref filter, ref notexact);
+			AcceptTuning(frequency, mode, filter);
+			return !notexact;
+		}
+
+		public virtual bool SetOption(TunerOption Option, byte Value) {
+			return SetOption(Option, ref Value);
+		}
+		public virtual bool SetOption(TunerOption Option, ref byte Value) {
+			bool notexact = false;
+			CheckOption(Option, ref Value, ref notexact);
+			AcceptOption(Option, Value);
+			return !notexact;
+		}
+		public virtual byte GetOption(TunerOption Option) {
+			return _options[(int)Option];
+		}
+		protected bool CheckOption(TunerOption Option, ref byte Value, ref bool notexact) {
+			switch (Option) {
+				case TunerOption.Filter:
+				case TunerOption.Frequency:
+				case TunerOption.Mode:
+				case TunerOption.Signal:
+					Value = 0;
+					notexact = true;
+					return false;
+				case TunerOption.AGC:
+				case TunerOption.Attenuator:
+				case TunerOption.NoiseBlanker:
+				case TunerOption.StereoMono:
+				case TunerOption.VSC:
+					if (Value > 1) Value = 1;
+					return (Value != _options[(int)Option]);
+				case TunerOption.IfShift:
+				case TunerOption.Squelch:
+				case TunerOption.Volume:
+					return (Value != _options[(int)Option]);
+				case TunerOption.RadioText:
+					Value = 1;
+					return true;
+				default:
+					return true;
+			}
+		}
+		protected void AcceptOption(TunerOption Option, byte Value) {
+			if (_options[(int)Option] != Value) {
+				_options[(int)Option] = Value;
+				if (OptionChanged != null) OptionChanged(this, new TunerOptionChangedEventArgs(Option));
+			}
+		}
+
+		protected bool CheckFrequency(ref ulong frequency, ref bool notexact) {
+			ulong closest = 0;
+			ulong diff = ulong.MaxValue;
+			if (frequency == 0 || frequency == _frequency) { //Frequency was not changed, return current mode
+				frequency = _mode;
+				return false;
+			}
+			foreach (TunerFrequencyRange f in _capabilities.Bands) {
+				if (frequency >= f.Begin && frequency <= f.End) return true;
+				if (frequency < f.Begin && diff > f.Begin - frequency) {
+					closest = f.Begin;
+					diff = closest - frequency;
+				} else if (frequency > f.End && diff > frequency - f.End) {
+					closest = f.End;
+					diff = frequency - closest;
+				}
+			}
+			if (closest != 0 && closest != _frequency) {
+				notexact = true;
+				frequency = closest;
+				return true;
+			} else {
+				return false;
+			}
+		}
+		protected bool CheckMode(ref byte mode, ref bool notexact) {
+			if (mode == 0 || mode == _mode) { //Mode was not changed, return current mode
+				mode = _mode;
+				return false;
+			}
+			foreach (byte b in _capabilities.AvailableModes) { //Mode was changed, accept if allowed
+				if (mode == b) return true;
+			}
+			mode = _mode; //Mode was changed but not allowed, keep current mode
+			return false;
+		}
+		protected bool CheckFilter(ref byte filter, ref bool notexact) {
+			byte closest = 0;
+			int diff = int.MaxValue;
+			//Filter has to be checked against AvailableFilters, in case AvailableFilters was changed
+			/*if (filter == 0 || filter == _filter) { //Filter was not changed, return current filter
+				filter = _filter;
+				return false;
+			}*/
+			foreach (byte b in _capabilities.AvailableFilters) { //Filter was changed, find closest one
+				if (filter == b) return true;
+				if (filter < b && diff > b - filter) {
+					closest = b;
+					diff = closest - filter;
+				} else if (filter > b && diff > filter - b) {
+					closest = b;
+					diff = filter - closest;
+				}
+			}
+			if (closest != 0 && closest != _filter) {
+				notexact = true;
+				filter = closest;
+				return true;
+			} else {
+				return false;
+			}
+		}
+
+		protected void AcceptTuning(ulong frequency, byte mode, byte filter) {
+			bool changed = false;
+			if (frequency != 0 && frequency != _frequency) { changed = true; _frequency = frequency; }
+			if (mode != 0 && mode != _mode) { changed = true; _mode = mode; }
+			if (filter != 0 && filter != _filter) { changed = true; _filter = filter; }
+			if (changed && TuningChanged != null) TuningChanged(this, new EventArgs());
+		}
+
+		protected void AcceptAvailableFilters(byte[] Filters) {
+			AcceptAvailableModes(null, Filters);
+		}
+		protected void AcceptAvailableModes(byte[] Modes, byte[] Filters) {
+			if (Modes != null) _capabilities.AvailableModes = Modes;
+			if (Filters != null) _capabilities.AvailableFilters = Filters;
+			if (AvailableModesChanged != null) AvailableModesChanged(this, new EventArgs());
+		}
+	}
+}