Math world, simple mental calculations or what’s going on with education?

Today, I want to write blog post which is absolutely not related to programming. It related to math and education in general those days. During work interviews, I see a lot of people, who was absolutely unable to calculate mentally. They just can’t understand, that it’s possible to do without calculators. When my kids (2nd, 6th and 7th grade) were small I taught them to play with numbers, and until 4th grade (bigger kids) they were able do it. but then school teachers “killed” this ability. Why people should use calculator for simple math operations, if he can do it mentally? Shame you, the modern educational system. Let’s go back and try to understand how people were able to live without devil devices, such as calculators…

Following the paint of Nikolai Bogdanov-Belsky “Counting in their heads”. This painting is dated 1895.

Богданов Бельский - Устный счёт

As you can see at the painting, peasant kids trying to solve following exercise mentally:

(102 + 112 + 122 + 132 + 142) / 365

This is not very simple exercise, especially when should be solved without your favorite calculator. However, when I was 4th grade I learned to square two-digit numbers mentally (my, and I think, yours too): First, find the nearest multiple of ten, by raising or lowering your number, then add and remove the rest to each of numbers and add the square of oddment. For example

45 * 45 = (45+5) * (45-5) + (5 * 5) = 50 * 40 + 25 = (5 * 4) * 100 + 25 = 20 * 100 + 25 = 2000 + 25 = 2025
14 * 14 = (14+4) * (14-4) + (4 * 4) = 18 * 10 + 16 = 180 + 16 = 196

So, now it can be solved easily:

102 = 100
112= (11+1) * (11-1) + 1 = 12 * 10 + 1 = 121
122= (12+2) * (12-2) + 4 = 14 * 10 + 4 = 144
132= (13+3) * (13-3) + 9 = 16 * 10 + 9 = 169
142= (14+4) * (14-4) + 16 = 18 * 10 + 16 = 196

And so on… but wait, 100+121+144 already equals 365, which is our denominator. Next sequence will bring us 169+196, which is also 365. So the answer to this black board brain teaser is 2.

However, it can be rather complicated to calculate 862 for instance:

862 = (86 + 4) * (86 – 4) + (4 * 4) = 90 * 82 + 16…

Let’s try another way – multiple the difference between the number and 25 by 100, then add the square of the difference or excess of the number and 50. For example

862 = (86 – 25) * 100 + (86 – 50)2 = 61 * 100 +  362 = 6100 + (36 – 25) * 100 + (50 – 36)2 = 6100 + 1100 + 142 = 7200 + 196 = 7396

Isn’t it really simple and fun to calculate squares of numbers?

Bonus: how to calculate multiple of two digit numbers with the sum of its unity digits equals to 10?

  1. Multiply first digit of the first number by 10
  2. Add 1 to first digit of second number and multiply the result by 10
  3. Multiply results of step 1 and step 2
  4. Deduct second number and the result of step 1
  5. Multiply second digit of the first number by the result of step 4
  6. Add results of steps 3 and 5

Looks complicated? Let’s make it easier. Assuming that first number is X = 10x + z and second number is Y = 10y + (10 – z), the formula for quick multiplication calculation is: 100 * x * (y + 1) + z * (Y – 10 * x). For example:

96 * 84 = 100 * 9 * (8+1) + 6 * (84-10 * 9) = 100 * 9 * 9 + 6 * (84 – 90) = 8100 – 6 * 6 = 8100 – 36 = 8064
37 * 93 = 100 * 3 * (9+1) + 7 * (93 – 10 * 3) = 3000 + 7 * 63 = 3000 + (100 * 6 * 1 + 3 * (7 – 60)) = 3000 + 600 – 3 * 53 = 3600 – 159 = 3441

Have a nice day and be good people. Also, throw out all hardware calculators and uninstall all software :)

Bootstrapper for .NET framework version detector

You wrote your .NET program, that can be used as stand alone portable application (such as it should be for Smart Client Apps), however you have to be sure, that necessary prerequisites (such as .NET framework) are installed on client’s machine. What to do? How to detect .NET framework version installed on target machine before running .NET application. The answer is – to use unmanaged C++ bootstrapper, that invoke your application if correct version of framework is installed.

.NET framework vrsion detector

Until now there are 15 possible .NET frameworks can be installed on client’s machine. Here the table of possible and official supported versions, as appears in Q318785

.NET version Actual version
3.5 SP1 3.5.30729.1
3.5 3.5.21022.8
3.0 SP2 3.0.4506.2152
3.0 SP1 3.0.4506.648
3.0 3.0.4506.30
2.0 SP2 2.0.50727.3053
2.0 SP1 2.0.50727.1433
2.0 2.0.50727.42
1.1 SP1 1.1.4322.2032
1.1 SP1 (in 32 bit version of Windows 2003) 1.1.4322.2300
1.1 1.1.4322.573
1.0 SP3 1.0.3705.6018
1.0 SP2 1.0.3705.288
1.0 SP1 1.0.3705.209
1.0 1.0.3705.0

All of those versions are detectible by queering specific registry keys. However, in some cases, you need to load mscoree.dll and call “GETCOREVERSION” API to determine whether specific version of .NET is installed. You can read more about it in MSDN.

So it’s really simple to write small C++ application (or PowerShell applet), that queries registry and invoke your managed application. How to do this? You can either read about it in outstanding blog of Aaron Stebner, who is Project Manager in XNA platform deployment team or attend my session next week to learn do it yourself. We’ll speak about nifty ways to do it also.

Anyway, by now, you can use small stand alone program, I wrote a while ago, that will tell you all versions of .NET frameworks installed in target machine without any prerequisites. It can be run even from shared network location :)

Download whoooot.exe (13K) >>

See you next week.

PS: Do not forget to download and install the new version of Visual Studio Snippet Designer, which is extremely useful tool by MVP Bill McCarthy, you’ll need it later next week…

Have a nice day and be good people.

Line-Of-Business vs. Beautifulness or two dogmas comparison as exemplified by two Twitter applications

Today I want to speak about two dogmas: design and functional driven programming. As the example of those two approaches, I want to introduce two Twitter clients: *Chirp by thirteen23 and TwitterFox by Naan Studio

Chirp and TwitterFox comparision

As you can see, *Chirp is state of art application with outstanding user interface, and well-defined usability studies. While TwitterFox is wacky grey boring kind-of-grid only. However, you cannot judge app by only how it looks like. Let’s try to understand first what’s for you need twitter client?

Defining application goals by user story

I’m using twitter as quick and handy business tool to write my thought, feelings and everyday events. It is not my main (not even secondary) task during the day, so I want to be able to open, write and forget. Thus, I need an application, that can be invoked by one click and dismissed after writing. Also, I do not want background application to gasp valuable space in my screen, when not in use. Thus it should be background process with reduced workset and one textarea, to be focused when the main window become active. Also the application should hide itself when unfocus, yet be able to notify me about events without disturbing.

Let’s see how it done in *Chirp:

  • 140MB workset
  • No ability to hide
  • Bouncing thingy at left upper corner to disturb you – it designed as you main desktop beautifier.
  • No ability to know that new twittes arrived without showing main window
  • Twit process required to click additional button (named “Update” for some reason)
  • If you not finished typing, you can either dismiss all text of post it.
  • Strange 140 characters countdown on background absolutely esthetical, yet very disturbing.
  • You cannot type more, then 140 characters – this restricted by textbox. If pasted bigger text all additional characters truncated.
  • You need mouse to operate an application

Now TwitterFox:

  • 10MB workset
  • You can hide it by hitting escape or clicking X button
  • Small and portable without disturbing elements – it not designed as your main everyday app.
  • New twits counter over small icon in browser tray, all other notifications can be disabled
  • Once focused text are become active, expanded automatically and ready to write
  • If you’re hiding it without clearing area, all un write text remains – you can clear it by one click
  • Small 140 characters countdown which is visible only when typing
  • You can type more, then 140 characters – counter becomes red, and you cannot post, however you’re able to fix, by dismissing unnecessary spaces or characters.
  • Can be operated by only keyboard.

Bottom line: *Chirp designed to show how good it looks, while TwitterFox to twit only. Thus for my specific user story TwitterFox won!

Defining functional specifications

Next task defined for Twitter is read other twits. I used to read all my following and followers when I have free minute. Sometimes I retwit things, rather often reply followers and read replies and rarely send direct messages.

*Chirp provides twit area without scrollbar, yet not restricted to number of twits. Other words, you can scroll with mouse wheel only or by holding somewhere inside and dragging unlimited up and down. When the mouse is over specific twit, it fades and show three buttons: reply, direct and retwit. Also each twit contains the name of the client was used (just like in regular web interface). When clicking user avatar it brings to special internal screen with last twit of the user, information and statistics about him, three functional buttons: UnFollow, Fave and Block and huge button Get User’s Tweets. When clicking the line displays the time of the twit it puts twit url into clipboard.

Also *Chirp contains five main functional buttons: Faves, Home, Direct, Update and Refresh. When Home tab unfocused (for example you’re on other screen), it also displays a number of new twits.

Error screen of *Chirp is really odd. It contains everything you not really need to know and beautiful whales moving on screen.

WTF?

TwitterFox is much simpler. It contains two buttons on mouse/keyboard over – reply and fave. When clicking on user’s avatar it opens it’s page in Twitter with all necessary information. Main TwitterFox window contains three buttons: Recent, Replies, Messages.

No doubt, that *Chirp provides much richer functional spec, but wait, am I really need all this? I told earlier, that I used to read twits and replies, while *Chirp has no such view at all. You can easy copy twit url into clipboard, but what for? Also, you can read  bio and statistics of people you following whenever you want without opening browser window. But how often you’re doing that?

TwitterFox concentrated on functionality – twit, read, reply, read replies (and direct messages) – base tasks , Twitter designed for. It also marks replies with contrast color in public timeline, while *Chirp has inline reply functionality with threaded discussions support (which is very odd for Twitter)

Bottom line: *Chirp is enriched with not useful features, while TwitterFox contains only things, you’re use. Thus for my specific functional requirements TwitterFox won again!

Developers vs. Designers final round

So, we already understand, that *Chirp is an application, designed to show how skilled thirteen23 designers are. And it achieved this goal. The application is state-of-art, looks and designed very well with taking into account even small details, however it huge, unusable for everyday twittering and extremely slow. This is a general example about Designers’ doctrine.

TwitterFox is very ugly, but concentrated on functionality, tiny and reactive. It includes only features are necessary for twittering and has no other goals. So, this is a general example about Developers’ doctrine.

Is it possible to messmate those doctrines? Probably it is. And it is really simple. Each one of actors should do his own work. Designers should design and Developers – develop. I spoke about it a lot during my lectures, I’ll speak about it also at 11th February in user group meeting. By now, when you know how I see Twitter, you can start following me. Also, I’m interesting to hear your ideas about Designer-Developer intercommunication. It is not just about Microsoft way :)

Designer and Developer - Microsoft way

Have a nice day and be good people.

Making TFS better or what is TITS?

Those days me and my team work very hard toward new version of “The System”. This includes massive refactoring of all solutions, hard work with TFS (which not restricted to only adding files, but also deleting, moving, etc. other words, all stuff, which TFS is not really love). Because of this, we need a bunch of handy tools to make our dreams come true and to decrease unnecessary number of clicks inside Team System Explorer and Visual Studio. You do not really think, that we have no tools to make our everyday job easier. We have. However, we never package and release it. Let me introduce “TITS” – Tools, Invaluable for Team System. This suite I’m planning to release as another open source project within couple of months.

TITS - Tools, Invaluable for Team System

What “TITS” includes? First of all –

“QOF” – Quick Open File

QOF - Quick Open File

This tools is absolutely invaluable if you have big solutions. While all it knows to do is to search. But, wait, what’s wrong with build-in search of Visual Studio? First of all, it does not search Solution items and files, are in solution directory, but not in project. Also it cannot fix your typos and errors. Also it does not know to move you quickly to found solution item in Solution Explorer or in Source Editor.

Basic set of QOF features:

  • No mouse – open any file
  • No mouse – locate any file in solution explorer
  • Highlighting found items
  • Multiple files open
  • Filter by source files only, resources, owner or any other kind of filters
  • Search inside TFS, including history, changesets, shelves (either private and public)
  • …and much much more

Next tool is:

“WIBREW” – Who Is Breaking What

WIBREW - Who is breaking what

Absolutely invaluable tool to know who actually breaking what file inside TFS. For example, I do not want to lock files, while I still want to know who holds what file. TFS provides such feature out-of-the-box, however from command prompt only. You can add it even as macro. Like this:

WIBREW for poor people

However it not user friendly and impossible for use, ‘cos it looks as following:

WIBREW for poor people in action

You do not know what actually developer doing, where and why. With “WIBREW”, you can know:

  • When developer started to break files
  • What exactly he’s doing
  • Is the breaking file locked or now
  • Where the developer breaks it (workspace and computer name of the user)
  • …and much much more

Another tool is:

“WITCH” – What I have To Check-in

If you ever worked with Team Force, you know what this tool is doing. It shows you a preview of all changed files, you’ll check-in. For some reason, TFS has no such feature. Let’s imagine, that your work method is to check out everything, change something and check-in only changed files. Until here TFS does everything, however if you want to preview changeset (for example in order to compare with “WIBREW” output), you can not. Here “WITCH” comes to help.

[Here should be a screenshot of “WITCH”, but it looks exactly the same as “WIBREW” with shameless blurring]

Another invaluable tool is:

“VOCUS” – VOid CUstom Settings for check in

This tool is absolutely UI-less. It allows developers to work with their own custom settings in Visual Studio, while for check-in and check-out it format all documents, according predefined custom settings (for example indentation). How many times, you tried to merge files, when all the difference is indentation it tab size? Well, this tool solves this problem.

VOCUS – VOid CUstom Settings for check in

It stores custom settings for each user (BTW, it also makes able for each developer to restore his settings fluently in any computer) and reformat documents on check-in action toward corporate settings, when on check-out toward custom developer’s setting.

“SHMOC” – SHow MOre Code

This is not actually tool, works with TFS. It rather works with your Visual Studio Development Environment. It’s UI-less as well and makes able to hide and restore all docking windows in VS. It makes you able to write in “Dark Room” mode (which is full screen, distraction free environment) and return to Visual Studio within one button press. It can also change VS color scheme, if required.

“SHMOC” – SHow MOre Code

There are some other tools should be inside this suite, however, I still have no names for them :) Also, if you have something interesting, and you want to contribute it to this suite, you’re highly welcome.

PS: This blog is about code, but this post is 6th in row without even one line of code, so I have to fix it as soon as possible. Thus, I’ll example how WIBREW works under the hood. Other words, small example of how to work with TFS API from Visual Studio plugin.

First of all, as in any VS plugin, you need to acquire DTE2 application object:

_applicationObject = (DTE2)application;
_addInInstance = (AddIn)addInInst;

When you have it, you need to detect what TFS server you’re working with and what are user credentials for this session. The common problem of WIBREW for poor men, was how to work with this tool over VPN (when your connected session is only inside VS). So each time, you tried to run it, you had to enter your domain credentials – very inconvenience way of work.

In order to prevent it, let’s ask your environment about Team Foundation information:

private TeamFoundationServerExt _tfsExt;

_tfsExt = (TeamFoundationServerExt)_applicationObject.GetObject("Microsoft.VisualStudio.TeamFoundation.TeamFoundationServerExt");

Also, you can be notified when your work project context was changed. To do this, just subscribe to ProjectContextChanged event and handle it inside:

_tfsExt.ProjectContextChanged += OnProjectContextChanged;

public void OnProjectContextChanged(object sender, EventArgs e) {
         if (!string.IsNullOrEmpty(_tfsExt.ActiveProjectContext.ProjectName)) {

Now when we know, that we have out active project context, all we have to do is to ask about changes

private VersionControlExt _vcExt;

_vcExt = (VersionControlExt)_applicationObject.GetObject("Microsoft.VisualStudio.TeamFoundation.VersionControl.VersionControlExt");

Inside VersionControlExt object you have following self-descriptive properties and methods: FindChangeSet, History, PendingChanges, SolutionWorkspace etc. however it works only with TFS solution explorer. To handle pending changes for the project without tickling TFS, we can use it internal methods. All the difference is with references. To work with Visual Studio TFS explorer methods, you should reference:
Microsoft.VisualStudio.TeamFoundation.dll, Microsoft.VisualStudio.TeamFoundation.Client.dll and Microsoft.VisualStudio.TeamFoundation.VersionControl.dll, while working with TFS API directly, use Microsoft.TeamFoundation.dll, Microsoft.TeamFoundation.Client.dll and Microsoft.TeamFoundation.VersionControl.dll from [PROGRAM FILES]\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\. Just like this:

VersionControlServer _vcs…_vcs = (VersionControlServer)_server.GetService(typeof(VersionControlServer));…var _sets = _vcs.QueryPendingSets( new[] { new ItemSpec(serverPath, RecursionType.Full) }, null, null);…foreach (PendingSet set in sets) {…
//Get everything you need here

We done. It’s very easy to work with Team System from inside Visual Studio. Also it’s very easy to build useful tools, not built by Microsoft for some reason :)

Have a nice day, be good people and wait for me to beatify sources before releasing as another Open Source application.

Nifty time savers for WPF development

I just published an article on Code Project, that explains how to use my latest FM USB library for building real world software radio receiver with WPF. There I referenced to some nifty WPF time savers, I’m using for everyday development. So, today I want to share those code pieces with you.

Software radio reciever screenshot

Binding time savers

Want to use following syntax for set binding in code?

Presets.SetBinding(ListBox.ItemsSourceProperty, _device, "Presets");

This piece of code sets binding to Preset DependencyObject, which is Listbox and connects ListBox.ItemsSource dependency property with “Presets” property of CLR object _device. How it done? Simple, as usual

[DebuggerStepThrough]
public static BindingExpressionBase SetBinding(this DependencyObject target, DependencyProperty dp, object source, string path) {
   Binding b = new Binding(path);
   b.Source = source;
   return BindingOperations.SetBinding(target, dp, b);
}

But what to do when we need a converter? Simple:

[DebuggerStepThrough]
public static BindingExpressionBase SetBinding(this DependencyObject target, DependencyProperty dp, object source, string path, IValueConverter converter) {
   Binding b = new Binding(path);
   b.Source = source;
   b.Converter = converter;
   return BindingOperations.SetBinding(target, dp, b);
}

However to use this method, we need to create special object, which implements IValueConverter. Whey not to do it generically? Like this:

SignalTransform.SetBinding(ScaleTransform.ScaleYProperty, _device.RDS,"SignalStrength", new ValueConverter<byte, double>(b => { return 1-(b / 36d); }));

But we need this special handy ValueConverter class. What’s the problem? Here come the king:

public class ValueConverter<TIN, TOUT> : IValueConverter {

   public ValueConverter(Func<TIN, TOUT> forwardConversion) {
      ForwardConversion = forwardConversion;
   }

   public ValueConverter(Func<TIN, TOUT> forwardConversion, Func<TOUT, TIN> reverseConversion) {
      ForwardConversion = forwardConversion;
      ReverseConversion = reverseConversion;
   }

   public Func<TIN, TOUT> ForwardConversion { get; set; }

   public Func<TOUT, TIN> ReverseConversion { get; set; }
   public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
      try {
         var in1 = Object.ReferenceEquals(value, DependencyProperty.UnsetValue) ? default(TIN) : (TIN)value;
         return ForwardConversion(in1);
      } catch {
         return Binding.DoNothing;
      }
   }

   public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
      try {
         var out1 = Object.ReferenceEquals(value, DependencyProperty.UnsetValue) ? default(TOUT) : (TOUT)value;
         return ReverseConversion(out1);
      } catch {
         return Binding.DoNothing;
      }
   }

}

Isn’t it really simple? But what to do with ugly App.Current.Dispatcher.BeginInvoke((SendOrPostCallback)delegate(object o)…? Use dispatcher time savers.

Dispatcher time savers

Don’t you ever want to do this in order to make context switching between UI thread and other application thread in WPF?

this.Dispatch(() => {… DO SOMETHING IN UI THREAD …};

Now you can (with default and preset DispatcherPriority:

public static DispatcherOperation Dispatch(this DispatcherObject sender, Action callback) { return sender.Dispatch(DispatcherPriority.Normal, callback); }

public static DispatcherOperation Dispatch(this DispatcherObject sender,  DispatcherPriority priority, Action callback) {
   if (sender.Dispatcher == null) return null;
   if (sender.Dispatcher.CheckAccess()) {
      callback();
      return null;
   } else {
      return sender.Dispatcher.BeginInvoke(priority, callback);
   }
}

Nice, isn’t it? But what to do if we do not want to set binding, but we do want to be notified about property change of dependency objects?

Bindingless handlers time saver

Let’s assume, that we have “Tune” UIelement, which has Angle property, but not exposes PropertyChanged event (like it done with Rotary custom control by Expression Blend team… Designers, you know… :)

However I want to be able to add handler for Angle dependency property changed event and do something when it changed. Like this:

Tune.AddValueChanged(RotaryControl.RotaryControl.AngleProperty, (s, ex) => {
   _device.Tune(Tune.Angle > _prevTune);
   _prevTune = Tune.Angle;
});

Here comes our time saver for this purpose:

public static void AddValueChanged(this DependencyObject sender, DependencyProperty property, EventHandler handler) {
   DependencyPropertyDescriptor.FromProperty(property, sender.GetType()).AddValueChanged(sender, handler);
}

But if we add handler we should be able to remove it too.

public static void RemoveValueChanged(this DependencyObject sender, DependencyProperty property, EventHandler handler) {
   DependencyPropertyDescriptor.FromProperty(property, sender.GetType()).RemoveValueChanged(sender, handler);
}

Now we done with some of my nifty helpers. And last, but not the least:

All times question: how to scale ranges

Here is how :)

public static double ToRange(this double value, double minSource, double maxSource, double minTarget, double maxTarget) {
   var sr = maxSource – minSource;
   var tr = maxTarget – minTarget;
   var ratio = sr / tr;
   return minTarget+(value / ratio);
}

Now we can connect them and get something like this:

Volume.AddValueChanged(RotaryControl.RotaryControl.AngleProperty, (s, ex) => {
   DirectSoundMethods.Volume = (int)Volume.Angle.ToRange(Volume.CounterClockwiseMostAngle, Volume.ClockwiseMostAngle, -4000, 0);
});

Isn’t it brilliant?

Have a good day and be sure to read and rate my last article on Code Project :) Be good people.

Audio CD operation including CD-Text reading in pure C#

Recently we spoke about reading radio data in C#, however as in any vehicle we have also CD players. So what can be better, than to have an ability to play CDs while being notified about track name, gathered from CD-Text?

image

So, let’s start. First of all, I want to express my pain with MSDN documentation about CD-ROM structure. Documentation team, please, please, please update it. First of all it is no accurate, then there are a ton of things missing. However, “À la guerre comme à la guerre”, thus I invested three days in deep DDK research.

Before we can do anything with CD-ROM, we have to find it. I took the same approach as I used for HID devices. Let’s create a device

[SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode = true)]
[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
public class CDDADevice : SafeHandleZeroOrMinusOneIsInvalid, IDisposable, INotifyPropertyChanged {

Internal constructor for security reasons

[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
internal CDDADevice(char drive) : base(true) {
   findDevice(drive);
}

And a find method itself

[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
private void findDevice(char drive) {
   if (Drive == drive) return;
   if (Native.GetDriveType(string.Concat(drive, ":\")) == Native.DRIVE.CDROM) {
      this.handle = Native.CreateFile(string.Concat("\\.\", drive, ‘:’), Native.GENERIC_READ, Native.FILE_SHARE_READ, IntPtr.Zero, Native.OPEN_EXISTING, Native.FILE_ATTRIBUTE_READONLY | Native.FILE_FLAG_SEQUENTIAL_SCAN, IntPtr.Zero);
      if (this.handle.ToInt32() != -1 && this.handle.ToInt32() != 0) this.Drive = drive;
   }
}

Where GetDriveType and CreateFile are win32 methods with following signatures

[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
internal static extern DRIVE GetDriveType(string drive);
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
internal static extern IntPtr CreateFile(
      string lpFileName,
      uint dwDesiredAccess,
      uint dwShareMode,
      IntPtr SecurityAttributes,
      uint dwCreationDisposition,
      uint dwFlagsAndAttributes,
      IntPtr hTemplateFile);
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
[DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
internal static extern bool CloseHandle(IntPtr hHandle);

Also, we need some constants

internal enum DRIVE : byte {
   UNKNOWN = 0,
   NO_ROOT_DIR,
   REMOVABLE,
   FIXED,
   REMOTE,
   CDROM,
   RAMDISK
}

internal const uint GENERIC_READ = 0×80000000;
internal const uint FILE_SHARE_READ = 0×00000001;
internal const uint OPEN_EXISTING = 3;
internal const uint FILE_ATTRIBUTE_READONLY = 0×00000001;
internal const uint FILE_FLAG_SEQUENTIAL_SCAN = 0×08000000;

Now, when we have our cdrom handle in hands, we can read it’s Table Of Content. Now, thing become harder because of the fact, that we have to use very complicated platform method:

[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
[DllImport("kernel32.dll", EntryPoint = "DeviceIoControl", SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DeviceIoControl(
   [In] IntPtr hDevice,
   IOCTL dwIoControl,
   [In] IntPtr lpInBuffer,
   uint nInBufferSize,
   IntPtr lpOutBuffer,
   uint nOutBufferSize,
   out uint lpBytesReturned,
   IntPtr lpOverlapped);

When thing are generic it’s good, however this one is, probably, most generic method in Win32 API. You can do anything with this method and you never know what to expect in lpOutBuffer :)

However, as I told earlier, I invested three days in investigations and researches (tnx to DDK documentation team) and now things become to be clearer. We need to get CDROM_TOC. It done by invoking IOCTL_CDROM_READ_TOC call

uint bytesRead = 0;
TOC = new Native.CDROM_TOC();
TOC.Length = (ushort)Marshal.SizeOf(TOC);
var hTOC = Marshal.AllocHGlobal(TOC.Length);
Marshal.StructureToPtr(TOC, hTOC, true);
if (Native.DeviceIoControl(this.handle, Native.IOCTL.CDROM_READ_TOC, IntPtr.Zero, 0, hTOC, TOC.Length, out bytesRead, IntPtr.Zero)) Marshal.PtrToStructure(hTOC, TOC);
Marshal.FreeHGlobal(hTOC);

But, not too fast. CDROM_TOC contains array of TRACK_DATA with unknown size.

typedef struct _CDROM_TOC {  UCHAR  Length[2];  UCHAR  FirstTrack;  UCHAR  LastTrack;  TRACK_DATA  TrackData[MAXIMUM_NUMBER_TRACKS];} CDROM_TOC, *PCDROM_TOC;
typedef struct _TRACK_DATA {  UCHAR  Reserved;  UCHAR  Control : 4;  UCHAR  Adr : 4;  UCHAR  TrackNumber;  UCHAR  Reserved1;  UCHAR  Address[4];} TRACK_DATA, *PTRACK_DATA;

P/Invoke it! But how to marshal unknown array? We should create wrapper object. Also there is very fun BitVector, used in this structure! What’s the problem? Pin it with some Math!

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]

public class CDROM_TOC {

   public ushort Length;

   public byte FirstTrack;

   public byte LastTrack;

   public TRACK_DATA_ARRAY TrackData;

}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]

public struct TRACK_DATA {

   public byte Reserved;

   public byte bitVector;

   public byte Control {

      get { return ((byte)((this.bitVector & 15u))); }

      set { this.bitVector = ((byte)((value | this.bitVector))); }

   }

   public byte Adr {

      get { return ((byte)(((this.bitVector & 240u) / 16))); }

      set { this.bitVector = ((byte)(((value * 16) | this.bitVector))); }

   }

   public byte TrackNumber;

   public byte Reserved1;

   public uint Address;

}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]

internal sealed class TRACK_DATA_ARRAY {

   internal TRACK_DATA_ARRAY() { data = new byte[MAXIMUM_NUMBER_TRACKS * Marshal.SizeOf(typeof(TRACK_DATA))]; }

   [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAXIMUM_NUMBER_TRACKS * 8)]

   private byte[] data;

   public TRACK_DATA this[int idx] {

      get {

         if ((idx < 0) | (idx >= MAXIMUM_NUMBER_TRACKS)) throw new IndexOutOfRangeException();

         TRACK_DATA res;

         var hData = GCHandle.Alloc(data, GCHandleType.Pinned);

         try {

            var buffer = hData.AddrOfPinnedObject();

            buffer = (IntPtr)(buffer.ToInt32() + (idx * Marshal.SizeOf(typeof(TRACK_DATA))));

            res = (TRACK_DATA)Marshal.PtrToStructure(buffer, typeof(TRACK_DATA));

         } finally {

            hData.Free();

         }

         return res;

      }

   }

}

Fuf, done. The code is rather self explaining, we just “tell” marshaler, that we have byte array, while calculating pointers to pinned object to get actual value and marshal it back. So, now we have TOC. So, we know how many tracks we have and addresses to data chunks inside the CD.

But it now enough to understand where our tracks. CD-ROM structure is very tricky. There we have blocks or sectors (which is the smallest chunks of data), so we have to convert bytes into sector addresses. Each block is 2352 bytes in RAW mode, while address value inside TRACK_DATA points us to layout address with is sync, sector id, error detection etc… So, in order to convert TRACK object into actual track number on disk, we have to stick to following method

public static int SectorAddress(this TRACK_DATA data) {

   var addr = BitConverter.GetBytes(data.Address);

   return (addr[1] * 60 * 75 + addr[2] * 75 + addr[3]) – 150;

}

Now, when we know numbers of tracks, we also know start and end sector, disk type and other useful information we are ready to twist it a bit and read CD-Text (if there are and your CD reader supports it).

So, coming back to our favorite method DeviceIoControl, but this time with IOCTL_CDROM_READ_TOC_EX control.

bytesRead = 0;           
TOCex = new Native.CDROM_READ_TOC_EX {

   Format = Native.CDROM_READ_TOC_EX_FORMAT.CDTEXT

};

var sTOCex = Marshal.SizeOf(TOCex);

var hTOCex = Marshal.AllocHGlobal(sTOCex);

Marshal.StructureToPtr(TOCex, hTOCex, true);

var Data = new Native.CDROM_TOC_CD_TEXT_DATA();

Data.Length = (ushort)Marshal.SizeOf(Data);

var hData = Marshal.AllocHGlobal(Data.Length);

Marshal.StructureToPtr(Data, hData, true);

if (Native.DeviceIoControl(this.handle, Native.IOCTL.CDROM_READ_TOC_EX, hTOCex, (ushort)sTOCex, hData, Data.Length, out bytesRead, IntPtr.Zero)) Marshal.PtrToStructure(hData, Data);

Marshal.FreeHGlobal(hData);

Marshal.FreeHGlobal(hTOCex);

Looks too simple? Let’s see inside CDROM_READ_TOC_EX structure. It is very similar to _CDROM_TOC.

typedef struct _CDROM_READ_TOC_EX {  UCHAR Format : 4;  UCHAR Reserved1 : 3;   UCHAR Msf : 1;  UCHAR SessionTrack;  UCHAR Reserved2;  UCHAR Reserved3;} CDROM_READ_TOC_EX, *PCDROM_READ_TOC_EX;

Simple. Isn’t it?

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]

public struct CDROM_READ_TOC_EX {

   public uint bitVector;

   public CDROM_READ_TOC_EX_FORMAT Format {

      get { return ((CDROM_READ_TOC_EX_FORMAT)((this.bitVector & 15u))); }

      set { this.bitVector = (uint)((byte)value | this.bitVector); }

   }

   public uint Reserved1 {

      get { return ((uint)(((this.bitVector & 112u) / 16))); }

      set { this.bitVector = ((uint)(((value * 16) | this.bitVector))); }

   }

   public uint Msf {

      get { return ((uint)(((this.bitVector & 128u) / 128))); }

      set { this.bitVector = ((uint)(((value * 128) | this.bitVector))); }

   }

   public byte SessionTrack;

   public byte Reserved2;

   public byte Reserved3;

}

But what will come inside lpOutBuffer? Fellow structure, named CDROM_TOC_CD_TEXT_DATA with unknown size array of CDROM_TOC_CD_TEXT_DATA_BLOCK

typedef struct _CDROM_TOC_CD_TEXT_DATA {  UCHAR  Length[2];  UCHAR  Reserved1;  UCHAR  Reserved2;  CDROM_TOC_CD_TEXT_DATA_BLOCK  Descriptors[0];} CDROM_TOC_CD_TEXT_DATA, *PCDROM_TOC_CD_TEXT_DATA;
typedef struct _CDROM_TOC_CD_TEXT_DATA_BLOCK {  UCHAR  PackType;  UCHAR  TrackNumber:7;  UCHAR  ExtensionFlag:1;  UCHAR  SequenceNumber;  UCHAR  CharacterPosition:4;  UCHAR  BlockNumber:3;  UCHAR  Unicode:1;  union {    UCHAR  Text[12];    WCHAR  WText[6];  };  UCHAR  CRC[2];} CDROM_TOC_CD_TEXT_DATA_BLOCK, *PCDROM_TOC_CD_TEXT_DATA_BLOCK;

Too bad to be true. Isn’t it? Let’s try to marshal it my hands (with the trick used for TRACK_DATA

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]

public class CDROM_TOC_CD_TEXT_DATA {

   public ushort Length;

   public byte Reserved1;

   public byte Reserved2;

   public CDROM_TOC_CD_TEXT_DATA_BLOCK_ARRAY Descriptors;

}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]

internal sealed class CDROM_TOC_CD_TEXT_DATA_BLOCK_ARRAY {

   internal CDROM_TOC_CD_TEXT_DATA_BLOCK_ARRAY() { data = new byte[MINIMUM_CDROM_READ_TOC_EX_SIZE * MAXIMUM_NUMBER_TRACKS * Marshal.SizeOf(typeof(CDROM_TOC_CD_TEXT_DATA_BLOCK))]; }

   [MarshalAs(UnmanagedType.ByValArray, SizeConst = MINIMUM_CDROM_READ_TOC_EX_SIZE * MAXIMUM_NUMBER_TRACKS * 18)]

   private byte[] data;

   public CDROM_TOC_CD_TEXT_DATA_BLOCK this[int idx] {

      get {

         if ((idx < 0) | (idx >= MINIMUM_CDROM_READ_TOC_EX_SIZE * MAXIMUM_NUMBER_TRACKS)) throw new IndexOutOfRangeException();

         CDROM_TOC_CD_TEXT_DATA_BLOCK res;

         var hData = GCHandle.Alloc(data, GCHandleType.Pinned);

         try {

            var buffer = hData.AddrOfPinnedObject();

            buffer = (IntPtr)(buffer.ToInt32() + (idx * Marshal.SizeOf(typeof(CDROM_TOC_CD_TEXT_DATA_BLOCK))));

            res = (CDROM_TOC_CD_TEXT_DATA_BLOCK)Marshal.PtrToStructure(buffer, typeof(CDROM_TOC_CD_TEXT_DATA_BLOCK));

         } finally {

            hData.Free();

         }

         return res;

      }

   }

}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]

public struct CDROM_TOC_CD_TEXT_DATA_BLOCK {

   public CDROM_CD_TEXT_PACK PackType;

   public byte bitVector1;

   public byte TrackNumber {

      get { return ((byte)((this.bitVector1 & 127u))); }

      set { this.bitVector1 = ((byte)((value | this.bitVector1))); }

   }

   public byte ExtensionFlag {

      get { return ((byte)(((this.bitVector1 & 128u) / 128))); }

      set { this.bitVector1 = ((byte)(((value * 128) | this.bitVector1))); }

   }

   public byte SequenceNumber;

   public byte bitVector2;        

   public byte CharacterPosition {

      get { return ((byte)((this.bitVector2 & 15u))); }

      set { this.bitVector2 = ((byte)((value | this.bitVector2))); }

   }

   public byte BlockNumber {

      get { return ((byte)(((this.bitVector2 & 112u) / 16))); }

      set { this.bitVector2 = ((byte)(((value * 16) | this.bitVector2))); }

   }

   public byte Unicode {

      get { return ((byte)(((this.bitVector2 & 128u) / 128))); }

      set { this.bitVector2 = ((byte)(((value * 128) | this.bitVector2))); }

   }

   [MarshalAs(UnmanagedType.ByValArray, SizeConst = 12, ArraySubType = UnmanagedType.I1)]

   public byte[] TextBuffer;

   public string Text {

      get { return (Unicode == 1) ? ASCIIEncoding.ASCII.GetString(TextBuffer) : UTF32Encoding.UTF8.GetString(TextBuffer); }

   }

   public ushort CRC;

}

Can’t you see a small problem here? Yes, we do not know the actual/maximum size of CDROM_TOC_CD_TEXT_DATA_BLOCK array. Until, I’ll find a nice way to marshal smart pointers, we’ll stick to MAX_TRACKS (100) * MIN_DATA_BLOCK (2).

We almost finished and the worst things are behind us. Now you should enumerate thru CDROM_TOC_CD_TEXT_DATA_BLOCK and look for Text, TrackNumber and SequenceNumber (which is continuation of text reported). For example, slot for ALBUM_NAME “Satisfaction” will looks as following

BlockNumber 0×00
CharacterPosition 0×00
CRC 0x3EAB
SequenceNumber 0×00
Text SATISFACTIO
BlockNumber 0×00
CharacterPosition 0x0B
CRC 0×0564
SequenceNumber 0×01
Text N

 

And so on… What to do with all other data and how to use it to enhance listening (ripping/crunching/seeking) experience we’ll speak next time. Have a good day and be good people.

Read and use FM radio (or any other USB HID device) from C#

Last time we spoke about reading and decoding RDS information from FM receivers. Also we already know how to stream sound from DirectSound compatible devices. However, before we can do it, we should be able to “speak” with such devices. So, today we’ll spoke about detection and reading information from Radio USB adapters (actually from any Human Input Devices). Let’s start.

USB FM HID

First, if you want to do it, go and buy such device. The are not a lot of alternatives, but if you’ll seek, you’ll find it very quickly.

So, let’s start. First of all, we’ll use platform invoke to get and set the information. Also, we have to preserve handle of the device from being collected by GC. After we’ll finish using the device, we’ll have to dispose it. Thus it makes sense to inherit from SafeHandle and IDisposable.

[SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode = true)]
[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
public class USBDevice : SafeHandleZeroOrMinusOneIsInvalid, IDisposable {

Next, we’ll set a number of arguments, that will be in use during the device lifetime.

public uint ProductID { get; private set; }
public uint VendorID { get; private set; }
public uint VersionNumber { get; private set; }
public string Name { get; private set; }
public string SerialNumber { get; private set; }
public override bool IsInvalid { get { return !isValid; } }

internal ushort FeatureReportLength { get; private set; }
internal ushort[] Registers { get; set; }

Now, we have to find it. The best way of detection human input devices is by product and vendor IDs. Those values are always unique for certain device type.

[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
internal USBDevice(uint pid, uint vid) : base(true) { findDevice(pid, vid); }

Next step is to find a device. To do this, we have to provide extern interfaces to methods of hid.dll and setupapi.dll. Here all methods we will use in our class

[SuppressUnmanagedCodeSecurity()]
internal static class Native {
   #region methods
   [DllImport("hid.dll", SetLastError = true)]
   internal static extern void HidD_GetHidGuid(
      ref Guid lpHidGuid);

   [DllImport("hid.dll", SetLastError = true)]
   internal static extern bool HidD_GetAttributes(
      IntPtr hDevice,
      out HIDD_ATTRIBUTES Attributes);

   [DllImport("hid.dll", SetLastError = true)]
   internal static extern bool HidD_GetPreparsedData(
      IntPtr hDevice,
      out IntPtr hData);

   [DllImport("hid.dll", SetLastError = true)]
   internal static extern bool HidD_FreePreparsedData(
      IntPtr hData);

   [DllImport("hid.dll", SetLastError = true)]
   internal static extern bool HidP_GetCaps(
      IntPtr hData,
      out HIDP_CAPS capabilities);

   [DllImport("hid.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
   internal static extern bool HidD_GetFeature(
      IntPtr hDevice,
      IntPtr hReportBuffer,
      uint ReportBufferLength);

   [DllImport("hid.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
   internal static extern bool HidD_SetFeature(
      IntPtr hDevice,
      IntPtr ReportBuffer,
      uint ReportBufferLength);

   [DllImport("hid.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
   internal static extern bool HidD_GetProductString(
      IntPtr hDevice,
      IntPtr Buffer,
      uint BufferLength);

   [DllImport("hid.dll", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
   internal static extern bool HidD_GetSerialNumberString(
      IntPtr hDevice,
      IntPtr Buffer,
      uint BufferLength);

   [DllImport("setupapi.dll", SetLastError = true)]
   internal static extern IntPtr SetupDiGetClassDevs(
      ref Guid ClassGuid,
      [MarshalAs(UnmanagedType.LPTStr)] string Enumerator,
      IntPtr hwndParent,
      UInt32 Flags);

   [DllImport("setupapi.dll", SetLastError = true)]
   internal static extern bool SetupDiEnumDeviceInterfaces(
      IntPtr DeviceInfoSet,
      int DeviceInfoData,
      ref  Guid lpHidGuid,
      uint MemberIndex,
      ref  SP_DEVICE_INTERFACE_DATA lpDeviceInterfaceData);

   [DllImport("setupapi.dll", SetLastError = true)]
   internal static extern bool SetupDiGetDeviceInterfaceDetail(
      IntPtr DeviceInfoSet,
      ref SP_DEVICE_INTERFACE_DATA lpDeviceInterfaceData,
      IntPtr hDeviceInterfaceDetailData,
      uint detailSize,
      out uint requiredSize,
      IntPtr hDeviceInfoData);

   [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
   [DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
   internal static extern IntPtr CreateFile(
         string lpFileName,
         uint dwDesiredAccess,
         uint dwShareMode,
         IntPtr SecurityAttributes,
         uint dwCreationDisposition,
         uint dwFlagsAndAttributes,
         IntPtr hTemplateFile);

   [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
   [DllImport("kernel32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall, SetLastError = true)]
   internal static extern bool CloseHandle(IntPtr hHandle);

Also, we will need a number of structures, such as device attributes and capabilities.

[StructLayout(LayoutKind.Sequential)]
internal struct SP_DEVICE_INTERFACE_DATA {
   public int cbSize;
   public Guid InterfaceClassGuid;
   public int Flags;
   public int Reserved;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
internal class PSP_DEVICE_INTERFACE_DETAIL_DATA {
   public int cbSize;
   [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
   public string DevicePath;
}

[StructLayout(LayoutKind.Sequential)]
internal struct HIDD_ATTRIBUTES {
   public int Size; // = sizeof (struct _HIDD_ATTRIBUTES) = 10
   public UInt16 VendorID;
   public UInt16 ProductID;
   public UInt16 VersionNumber;
}
[StructLayout(LayoutKind.Sequential)]
internal struct HIDP_CAPS {
   public UInt16 Usage;
   public UInt16 UsagePage;
   public UInt16 InputReportByteLength;
   public UInt16 OutputReportByteLength;
   public UInt16 FeatureReportByteLength;
   [MarshalAs(UnmanagedType.ByValArray, SizeConst = 17)]
   public UInt16[] Reserved;
   public UInt16 NumberLinkCollectionNodes;
   public UInt16 NumberInputButtonCaps;
   public UInt16 NumberInputValueCaps;
   public UInt16 NumberInputDataIndices;
   public UInt16 NumberOutputButtonCaps;
   public UInt16 NumberOutputValueCaps;
   public UInt16 NumberOutputDataIndices;
   public UInt16 NumberFeatureButtonCaps;
   public UInt16 NumberFeatureValueCaps;
   public UInt16 NumberFeatureDataIndices;
}

And a number of system constants

internal const uint DIGCF_PRESENT = 0×00000002;
internal const uint DIGCF_DEVICEINTERFACE = 0×00000010;
internal const uint GENERIC_READ = 0×80000000;
internal const uint GENERIC_WRITE = 0×40000000;
internal const uint FILE_SHARE_READ = 0×00000001;
internal const uint FILE_SHARE_WRITE = 0×00000002;
internal const int OPEN_EXISTING = 3;
internal const int FILE_FLAG_OVERLAPPED = 0×40000000;
internal const uint MAX_USB_DEVICES = 16;

Now, we are ready to start. So let’s find all devices and get its information

Native.HidD_GetHidGuid(ref _hidGuid);
hHidDeviceInfo = Native.SetupDiGetClassDevs(ref _hidGuid, null, IntPtr.Zero, Native.DIGCF_PRESENT | Native.DIGCF_DEVICEINTERFACE);

Now, if a handle we get is valid, we should search our specific device. For this purpose, we have to read device interface information and then get details info about this device.

if (hHidDeviceInfo.ToInt32() > -1) {
   uint i = 0;
   while (!isValid && i < Native.MAX_USB_DEVICES) {
      var hidDeviceInterfaceData = new Native.SP_DEVICE_INTERFACE_DATA();
      hidDeviceInterfaceData.cbSize = Marshal.SizeOf(hidDeviceInterfaceData);
      if (Native.SetupDiEnumDeviceInterfaces(hHidDeviceInfo, 0, ref _hidGuid, i, ref hidDeviceInterfaceData)) {

Once we have all this and information is valid, let’s detect its capabilities

bool detailResult;
uint length, required;
Native.SetupDiGetDeviceInterfaceDetail(hHidDeviceInfo, ref hidDeviceInterfaceData, IntPtr.Zero, 0, out length, IntPtr.Zero);
var hidDeviceInterfaceDetailData = new Native.PSP_DEVICE_INTERFACE_DETAIL_DATA();
hidDeviceInterfaceDetailData.cbSize = 5; //DWORD cbSize (size 4) + Char[0] (size 1) for 32bit only!
var hDeviceInterfaceDetailData = Marshal.AllocHGlobal(Marshal.SizeOf(hidDeviceInterfaceDetailData));
Marshal.StructureToPtr(hidDeviceInterfaceDetailData, hDeviceInterfaceDetailData, true);
detailResult = Native.SetupDiGetDeviceInterfaceDetail(hHidDeviceInfo, ref hidDeviceInterfaceData, hDeviceInterfaceDetailData, length, out required, IntPtr.Zero);
Marshal.PtrToStructure(hDeviceInterfaceDetailData, hidDeviceInterfaceDetailData);
if (detailResult) {

To do this, we have to create memory file first and then share device attributes by using this file.

base.handle = Native.CreateFile(hidDeviceInterfaceDetailData.DevicePath,
                        Native.GENERIC_READ |
                        Native.GENERIC_WRITE,
                        Native.FILE_SHARE_READ |
                        Native.FILE_SHARE_WRITE,
                        IntPtr.Zero,
                        Native.OPEN_EXISTING,
                        Native.FILE_FLAG_OVERLAPPED,
                        IntPtr.Zero);
                     if (base.handle.ToInt32() > -1) {
                        Native.HIDD_ATTRIBUTES hidDeviceAttributes;
                        if (Native.HidD_GetAttributes(base.handle, out hidDeviceAttributes)) {

All the rest is straight forward. Just compare info retrieved with one we already have. And, of cause, release all resources were used (remember, we’re in win32 api world!)

if ((hidDeviceAttributes.VendorID == vid) && (hidDeviceAttributes.ProductID == pid)) {
                              isValid = true;
                              ProductID = pid;
                              VendorID = vid;
                              VersionNumber = hidDeviceAttributes.VersionNumber;
                              IntPtr buffer = Marshal.AllocHGlobal(126);//max alloc for string;
                              if (Native.HidD_GetProductString(this.handle, buffer, 126)) Name = Marshal.PtrToStringAuto(buffer);
                              if (Native.HidD_GetSerialNumberString(this.handle, buffer, 126)) SerialNumber = Marshal.PtrToStringAuto(buffer);
                              Marshal.FreeHGlobal(buffer);
                              var capabilities = new Native.HIDP_CAPS();
                              IntPtr hPreparsedData;
                              if (Native.HidD_GetPreparsedData(this.handle, out hPreparsedData)) {
                                 if (Native.HidP_GetCaps(hPreparsedData, out capabilities)) FeatureReportLength = capabilities.FeatureReportByteLength;
                                 Native.HidD_FreePreparsedData(hPreparsedData);
                              }
                              break;
                           }
                        } else {
                           Native.CloseHandle(base.handle);
                        }
                     }
                  }
                  Marshal.FreeHGlobal(hDeviceInterfaceDetailData);
               }
               i++;

            }

Now we have a handle to our device and can manipulate it. Like this:

using (var device = USBRadioDevice.FindDevice(0×0000, 0×1111)) {

}

But we still have to provide methods for such usage. Here there are no very complicated code.

public static USBDevice FindDevice(uint pid, uint vid) {
   var device = new USBDevice(pid,vid);
   var fillRegisters = device.InitRegisters();
   if (!device.IsInvalid && fillRegisters) return device;
   else throw new ArgumentOutOfRangeException(string.Format("Human input device {0} was not found.", pid));
}

public override string ToString() {
   return string.Format("{0} (Product:{1:x}, Vendor:{2:x}, Version:{3:x}, S/N:{4})", Name, ProductID, VendorID, VersionNumber, SerialNumber);
}

[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
protected override bool ReleaseHandle() {
   return Native.CloseHandle(base.handle);
}

#region IDisposable Members
public void Dispose() {
   Dispose(true);
   GC.SuppressFinalize(this);

}
[SecurityPermission(SecurityAction.Demand, UnmanagedCode = true)]
void IDisposable.Dispose() {
   if (base.handle != null && !base.IsInvalid) {
      // Free the handle
      base.Dispose();
   }
}

#endregion

We done. Have a nice day and be good people.

Capturing and streaming sound by using DirectSound with C#

I already wrote a little about managed way to use DirectX DirectSound. Today we’ll speak about how to get sound from your microphone or any other DirectSound capturing device (such as FM receiver) and stream it out to your PC speakers and any other DirectSound Output device. So, let’s start creating our first echo service by using managed DirectX.

image

First of all we should decide what Wave format we want to use for capturing and recording. So, let’s choose anything reasonable :)

var format = new WaveFormat {
            SamplesPerSecond = 96000,
            BitsPerSample = 16,
            Channels = 2,
            FormatTag = WaveFormatTag.Pcm
         };

Now, we should calculate block align and average byte per second value for this format. I’m wondering why it cannot be done automatically…

format.BlockAlign = (short)(format.Channels * (format.BitsPerSample / 8));
format.AverageBytesPerSecond = format.SamplesPerSecond * format.BlockAlign;

Next step is to set the size of two buffers – one for input and other for output. Generally those buffers are circular, and capturing one should be twice bigger, then output. Why? Because we choose two channels to use. Also, we should decide about chunk size of the buffer, we want to signal when filled.

_dwNotifySize = Math.Max(4096, format.AverageBytesPerSecond / 8);
_dwNotifySize -= _dwNotifySize % format.BlockAlign;
_dwCaptureBufferSize = NUM_BUFFERS * _dwNotifySize;
_dwOutputBufferSize = NUM_BUFFERS * _dwNotifySize / 2;

Next step is to create CaptureBufferDescriptor and actual capturing buffer. We’ll enumerate all devices and choose one, satisfies given string (captureDescriptor) – for example “Mic” :)

var cap = default(Capture);
var cdc = new CaptureDevicesCollection();
for (int i = 0; i < cdc.Count; i++) {
   if (cdc[i].Description.ToLower().Contains(captureDescriptor.ToLower())) {
      cap = new Capture(cdc[i].DriverGuid);
      break;
   }
}
var capDesc = new CaptureBufferDescription {
   Format = format,
   BufferBytes = _dwCaptureBufferSize
};
_dwCapBuffer = new CaptureBuffer(capDesc, cap);

Then we’ll create output device and buffer. To simplify program, we will use default speakers to output, however, you can choose output device the same way we did for capturing. Also, because DirectSound uses any window as it’s message pump, we have to use SetCooperativeLevel method. In my case (windowless application), I’ll use desktop window as message broker. This why you will have to add Windows.Forms as reference for your project, even if it console application. Also, do not forget to set GlobalFocus value to True, if you want to play echo, even if desktop window is not focused.

var dev = new Device();
dev.SetCooperativeLevel(Native.GetDesktopWindow(), CooperativeLevel.Priority);

var devDesc = new BufferDescription {
   BufferBytes = _dwOutputBufferSize,
   Format = format,
   DeferLocation = true,
   GlobalFocus = true
};
_dwDevBuffer = new SecondaryBuffer(devDesc, dev);

Now, we will subscribe to buffer notifications and set autoResetEvent to be fired when it filled up.

var _resetEvent = new AutoResetEvent(false);
var _notify = new Notify(_dwCapBuffer);
//half&half
var bpn1 = new BufferPositionNotify();
bpn1.Offset = _dwCapBuffer.Caps.BufferBytes / 2 – 1;
bpn1.EventNotifyHandle = _resetEvent.SafeWaitHandle.DangerousGetHandle();
var bpn2 = new BufferPositionNotify();
bpn2.Offset = _dwCapBuffer.Caps.BufferBytes – 1;
bpn2.EventNotifyHandle = _resetEvent.SafeWaitHandle.DangerousGetHandle();

_notify.SetNotificationPositions(new BufferPositionNotify[] { bpn1, bpn2 });

Almost done, the only thing we should do is to fire worker thread to take care on messages

int offset = 0;
_dwCaptureThread = new Thread((ThreadStart)delegate {
   _dwCapBuffer.Start(true);

   while (IsReady) {
      _resetEvent.WaitOne();
      var read = _dwCapBuffer.Read(offset, typeof(byte), LockFlag.None, _dwOutputBufferSize);
      _dwDevBuffer.Write(0, read, LockFlag.EntireBuffer);
      offset = (offset + _dwOutputBufferSize) % _dwCaptureBufferSize;
      _dwDevBuffer.SetCurrentPosition(0);
      _dwDevBuffer.Play(0, BufferPlayFlags.Default);
   }
   _dwCapBuffer.Stop();
});
_dwCaptureThread.Start();

That’s it. Compile and run. Now if you’ll speak, you can hear your echo from PC speakers.

Merry Christmas for whom concerns and be good people – do not scare your co-workers with strange sounds – be polite and make the volume lower :)

Quick Silverlight (and WPF) tip: How to write program without XAML

From the moment, 10K MIX09 contest was launched, I got more, then 20 people, asking the same question: Is it possible to have Silverlight program up and running without XAML at all?

image

The answer is “YES, IT IS”. Here is how:

All you need for run WPF or Silverlight application is

  1. Class inherited from System.Windows.Application
  2. Class inherited from System.Windows.Controls.UserControl

So, Let’s create new WPF or Silverlight application and delete all files from the project directory. Then add one file, named App.cs (or Foo.cs or Whatever.cs – the length of the file name is not included :) ) and write there :

using System.Windows.Controls;
using System.Windows;

public class App : Application {public App() {this.Startup += (s, e) => { this.RootVisual = Foo.M; };}} 
class Foo: UserControl {static Foo _b = new Foo();public static Board M { get { return _b; } }

We done. F5, be happy. You just wrote first officially smallest Silverlight functional application. Good luck with Mix09 contest.

Reading and decoding RDS (Radio Data System) in C#

RDS or Radio Data System is very common in US and many European countries. It is communication protocol used to send small amount of digital information using regular FM radio broadcast. This protocol is used to “tell” your receiver about alternative frequencies, time, program notifications, program types, traffic information and regular text (such as singer name or genre). Unfortunately in Israel RDS is not very common and there is very limited number of radio stations broadcasts RDS information.

image

How RDS works?

As mentioned earlier, it uses FM subcarrier to broadcast digital information. It was designed to support 10 and 18 characters numeric and 80 characters alphanumeric displays. RDS operates at 1187.5 bps and based on 26-bit word consisting of 16 data and 10 error detection bits. Due to the fact, that FM carrier is not very reliable, error code allows correct information to be received even if an error of 3-5 bits exists within 26 bit block. Each four data blocks interpreted as 104-bit signal and named “group”. Depending of the type of information, contained within the group, as different group type code is defined and transmitted within the group as upper five bits code. Even if more, then 104 bits required to completely send the information, there is no requirement that the next segment of the transmission be sent in the next group. There are 32 known groups types, defined by RFC:

private enum groupType : byte {
   RDS_TYPE_0A = (0 * 2 + 0),
   RDS_TYPE_0B = (0 * 2 + 1),
   RDS_TYPE_1A = (1 * 2 + 0),
   RDS_TYPE_1B = (1 * 2 + 1),
   RDS_TYPE_2A = (2 * 2 + 0),
   RDS_TYPE_2B = (2 * 2 + 1),
   RDS_TYPE_3A = (3 * 2 + 0),
   RDS_TYPE_3B = (3 * 2 + 1),
   RDS_TYPE_4A = (4 * 2 + 0),
   RDS_TYPE_4B = (4 * 2 + 1),
   RDS_TYPE_5A = (5 * 2 + 0),
   RDS_TYPE_5B = (5 * 2 + 1),
   RDS_TYPE_6A = (6 * 2 + 0),
   RDS_TYPE_6B = (6 * 2 + 1),
   RDS_TYPE_7A = (7 * 2 + 0),
   RDS_TYPE_7B = (7 * 2 + 1),
   RDS_TYPE_8A = (8 * 2 + 0),
   RDS_TYPE_8B = (8 * 2 + 1),
   RDS_TYPE_9A = (9 * 2 + 0),
   RDS_TYPE_9B = (9 * 2 + 1),
   RDS_TYPE_10A = (10 * 2 + 0),
   RDS_TYPE_10B = (10 * 2 + 1),
   RDS_TYPE_11A = (11 * 2 + 0),
   RDS_TYPE_11B = (11 * 2 + 1),
   RDS_TYPE_12A = (12 * 2 + 0),
   RDS_TYPE_12B = (12 * 2 + 1),
   RDS_TYPE_13A = (13 * 2 + 0),
   RDS_TYPE_13B = (13 * 2 + 1),
   RDS_TYPE_14A = (14 * 2 + 0),
   RDS_TYPE_14B = (14 * 2 + 1),
   RDS_TYPE_15A = (15 * 2 + 0),
   RDS_TYPE_15B = (15 * 2 + 1)
}

Not all groups are in use all the time. However, there are some commitments, defined by the protocol. For example, 1A have to be transmitted at least once a second. This group contains special information, required for receivers to be synchronized and locked into the transmitting channel.

Within the error correction information we also receive the direction to treat them.

private enum correctedType : byte {
   NONE = 0,
   ONE_TO_TWO = 1,
   THREE_TO_FIVE = 2,
   UNCORRECTABLE = 3
}

Also, each message type has it own limits. For example RT (Radio Text – 64 character text to display on your receiver) and PS (Programme Service – eight character station identification) message are limited to 2 groups, when PI (Programme Identification – unique code of the station) and PTY (Programme Type – one of 31 predefined program types – e.g. News, Drama, Music) are limited to 4.

In addition to those constraints, block types are also different. But in this case, there are only 4 kinds

private enum blockType : byte {
   A = 6,
   B = 4,
   C = 2,
   D = 0
}

So, what we’re waiting for? Let’s start working.

Handling errors

First of all we should take care on errors and fix them if possible. For this purpose, we should first count them and detect the way of fixing

var errorCount = (byte)((registers[0xa] & 0x0E00) >> 9);
var errorFlags = (byte)(registers[0x6] & 0xFF);
if (errorCount < 4) {
   _blocksValid += (byte)(4 – errorCount);
} else { /*drop data on more errors*/ return; }

Once it done, we can try to fix them

//Also drop the data if more than two errors were corrected
if (_getErrorsCorrected(errorFlags, blockType.B) > correctedType.ONE_TO_TWO) return;

private correctedType _getErrorsCorrected(byte data, blockType block) { return (correctedType)((data >> (byte)block) & 0×30); }

Now, our registers should be fine and we can start the detection of group type

Group Type Detection

This is very simple task, all we have to do is to get five upper bites to get a type and version.

var group_type = (groupType)(registers[0xD] >> 11);

Then we can handle PI and PTY, which we always have in RDS.

PI and PTY treatment

Now, let’s update pi code, due to the fact, that B format always have PI in words A and C

_updatePI(registers[0xC]);

if (((byte)group_type & 0×01) != 0) {
_updatePI(registers[0xE]);
}

To update PI, we should check whether the new value is different from the previous and update it only in case it changed.

private void _updatePI(byte pi) {
   uint rds_pi_validate_count = 0;
   uint rds_pi_nonvalidated = 0;

   // if the pi value is the same for a certain number of times, update a validated pi variable
   if (rds_pi_nonvalidated != pi) {
      rds_pi_nonvalidated = pi;
      rds_pi_validate_count = 1;
   } else {
      rds_pi_validate_count++;
   }

   if (rds_pi_validate_count > PI_VALIDATE_LIMIT) {
      _piDisplay = rds_pi_nonvalidated;
   }
}

Then we will update PTY

_updatePTY((byte)((registers[0xd] >> 5) & 0x1f));

PTY treatment is very similar to PI, however it can be multiplied. 

private void _updatePTY(byte pty) {
   uint rds_pty_validate_count = 0;
   uint rds_pty_nonvalidated = 0;

   // if the pty value is the same for a certain number of times, update a validated pty variable
   if (rds_pty_nonvalidated != pty) {
      rds_pty_nonvalidated = pty;
      rds_pty_validate_count = 1;
   } else {
      rds_pty_validate_count++;
   }

   if (rds_pty_validate_count > PTY_VALIDATE_LIMIT) {
      _ptyDisplay = rds_pty_nonvalidated;
   }
}

When we done with those two groups, we can start handling another. Today, we’ll handle only 0B, 2A and 2B types (I have a good reason for it, due to the fact, that only those are supported in Israel by now :) ) So,

Handling PS and different RTs

Simple switch on those groups

switch (group_type) {
   case groupType.RDS_TYPE_0B:
      addr = (byte)((registers[0xd] & 0×3) * 2);
      _updatePS((byte)(addr + 0), (byte)(registers[0xf] >> 8));
      _updatePS((byte)(addr + 1), (byte)(registers[0xf] & 0xff));
      break;
   case groupType.RDS_TYPE_2A:
      addr = (byte)((registers[0xd] & 0xf) * 4);
      abflag = (byte)((registers[0xb] & 0×0010) >> 4);
      _updateRT(abflag, 4, addr, (byte[])registers.Skip(0xe), errorFlags);
      break;
   case groupType.RDS_TYPE_2B:
      addr = (byte)((registers[0xd] & 0xf) * 2);
      abflag = (byte)((registers[0xb] & 0×0010) >> 4);
      // The last 32 bytes are unused in this format
      _rtTmp0[32] = 0x0d;
      _rtTmp1[32] = 0x0d;
      _rtCnt[32] = RT_VALIDATE_LIMIT;
      _updateRT(abflag, 2, addr, (byte[])registers.Skip(0xe), errorFlags);
      break;
}

and let’s dig into PS.

In PS, we have high and low probability bits. So, if new bit in sequence matches the high probability bite and we have recieved enough bytes to max out the counter, we’ll push it into the low probability array.

if (_psTmp0[idx] == default(byte)) {
           if (_psCnt[idx] < PS_VALIDATE_LIMIT) {
               _psCnt[idx]++;
            } else {
               _psCnt[idx] = PS_VALIDATE_LIMIT;
               _psTmp1[idx] = default(byte);
            }
         }

Else, if new byte matches with the low probability byte, we should swap them and then reset the counter, by flagging the text as in transition.

else if (_psTmp1[idx] == default(byte)) {
            if (_psCnt[idx] >= PS_VALIDATE_LIMIT) {
               isTextChange = true;
            }
            _psCnt[idx] = PS_VALIDATE_LIMIT + 1;
            _psTmp1[idx] = _psTmp0[idx];
            _psTmp0[idx] = default(byte);
         }

When we have an empty byte in high probability array or new bytes does not match anything we know, we should put it into low probability array.

else if (_psCnt[idx] == null) {
            _psTmp0[idx] = default(byte);
            _psCnt[idx] = 1;
         } else {
            _psTmp1[idx] = default(byte);
         }

Now, if we marked our text as changed, we should decrement the count for all characters to prevent displaying of partical message, which in still in transition.

         if (isTextChange) {
            for (byte i = 0; i < _psCnt.Length; i++) {
               if (_psCnt[i] > 1) {
                  _psCnt[i]–;
               }
            }
         }

Then by checking PS text for incompetence, when there are characters in high probability array has been seen fewer times, that was limited by validation.

         for (byte i = 0; i < _psCnt.Length; i++) {
            if (_psCnt[i] < PS_VALIDATE_LIMIT) {
               isComplete = false;
               break;
            }
         }

Only if PS text in the high probability array is complete, we’ll copy it into display.

         if (isComplete) {
            for (byte i = 0; i < _psDisplay.Length; i++) {
               _psDisplay[i] = _psTmp0[i];
            }
         }

It is not very hard to treat PS. Isn’t it? Let’s see what’s going on with RT.

If A and B message flag changes, we’ll try to force a display by increasing the validation count for each byte. Then, we’ll wipe any cached text.

   if (abFlag != _rtFlag && _rtFlagValid) {
      // If the A/B message flag changes, try to force a display
      // by increasing the validation count of each byte
      for (i = 0; i < _rtCnt.Length; i++) _rtCnt[addr + i]++;
      _updateRTValue();

      // Wipe out the cached text
      for (i = 0; i < _rtCnt.Length; i++) {
         _rtCnt[i] = 0;
         _rtTmp0[i] = 0;
         _rtTmp1[i] = 0;
      }
   }

Now A and B flags are safe, sp we can start with message processing. First of all, NULL in RDS means space :)

   _rtFlag = abFlag;   
   _rtFlagValid = true;   

   for (i = 0; i < count; i++) {
      if (p[i] == null) p[i] = (byte)’ ‘;

The new byte matches the high probability byte also in this case. We habe to recieve this bite enough to max out counters. Then we can push it into the low probability as well.

      if (_rtTmp0[addr + i] == p[i]) {
         if (_rtCnt[addr + i] < RT_VALIDATE_LIMIT) _rtCnt[addr + i]++;
         else {
            _rtCnt[addr + i] = RT_VALIDATE_LIMIT;
            _rtTmp1[addr + i] = p[i];
         }
      }

When the new byte matches with low probability byte, we’ll swap them as well and reset counters to update text in transition flag. However in this case, our counter will go higher, then the validation limit. So we’ll have to remove it down later.

else if (_rtTmp1[addr + i] == p[i]) {

         if (_rtCnt[addr + i] >= PS_VALIDATE_LIMIT) isChange = true;

         _rtCnt[addr + i] = RT_VALIDATE_LIMIT + 1;
         _rtTmp1[addr + i] = _rtTmp0[addr + i];
         _rtTmp0[addr + i] = p[i];
      }

Now, the new byte is replaced an empty byte in the high probability array. Also, if this byte does not match anything, we should move it into low probability.

else if (_rtCnt[addr + i] == null) {
         _rtTmp0[addr + i] = p[i];
         _rtCnt[addr + i] = 1;
      } else _rtTmp1[addr + i] = p[i];

   }

Now when the text is changing, we’ll decrement the counter for all characters exactly as we did for PS.

      for (i = 0; i < _rtCnt.Length; i++) {
         if (_rtCnt[i] > 1) _rtCnt[i]–;
      }
   }

However, right after, we’ll update display. 

   _updateRTValue();
}

Displaying RT

But how to convert all those byte arrays into readable message? Simple :)

First of all if text is incomplete, we should keep loading it. Also it makes sense to check whether the target array is shorter then maximum allowed to prevent junk from being displayed.

for (i = 0; i < _rtTmp0.Length; i++) {
   if (_rtCnt[i] < RT_VALIDATE_LIMIT) {
      isComplete = false;
      break;
   }
   if (_rtTmp0[i] == 0x0d) {
      break;
   }
}

Now, when our Radio Text is in the high probability and it complete, we should copy buffers.

if (isComplete) {
   _Text = string.Empty;

   for (i = 0; i < _rtDisplay.Length; i += 2) {
      if ((_rtDisplay[i] != 0x0d) && (_rtDisplay[i + 1] != 0x0d)) {
         _rtDisplay[i] = _rtTmp0[i + 1];
         _rtDisplay[i + 1] = _rtTmp0[i];
      } else {
         _rtDisplay[i] = _rtTmp0[i];
         _rtDisplay[i + 1] = _rtTmp0[i + 1];
      }

      if (_rtDisplay[i] != 0x0d)
         _Text += _rtDisplay[i];

      if (_rtDisplay[i + 1] != 0x0d)
         _Text += _rtDisplay[i + 1];

      if ((_rtDisplay[i] == 0x0d) || (_rtDisplay[i + 1] == 0x0d))
         i = (byte)_rtDisplay.Length;
   }

And not forget to wipe out everything after the end of the message :)

   for (i++; i < _rtDisplay.Length; i++) {
      _rtDisplay[i] = 0;
      _rtCnt[i] = 0;
      _rtTmp0[i] = 0;
      _rtTmp1[i] = 0;
   }
}

And finally update the text

Text = _Text;

We done. Now we can handle RDS digital messages, but what to do with analog data we get? Don’t you already know? I blogged about it here.

Have a nice day and be good people, because you know how to write client, knows to get and parse radio data in managed code.

image

Recommended

 


Sponsor


Partners

WPF Disciples
Dreamhost
Code Project
Switched to Better Place

Together