view Radio/Tuner.cs @ 9:9533a87363f3

Fixed deadlock in QueuedPacketStream
author Ivo Smits <Ivo@UCIS.nl>
date Fri, 18 Jan 2013 16:29:50 +0100
parents 3ab940a0c7a0
children
line wrap: on
line source

???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());
		}
	}
}