<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7165003663082593115</id><updated>2024-09-25T22:56:18.589+01:00</updated><title type='text'>I Can&#39;t Hold It All In My Brain!</title><subtitle type='html'>A place to keep all those things I figure out, and then promptly forget! Hope you find something that helps you.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://icantholditallinmybrain.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7165003663082593115/posts/default?redirect=false'/><link rel='alternate' type='text/html' href='http://icantholditallinmybrain.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/02396299665268094026</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>1</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7165003663082593115.post-2311725371280139616</id><published>2010-08-02T11:41:00.124+01:00</published><updated>2010-08-03T23:16:07.973+01:00</updated><title type='text'>Controlling V4L2 radio with Perl on Linux.</title><content type='html'>Everyone buys their Hauppauge cards to use the TV aspect of the cards, but when my stereo gave up the ghost, I decided to look at using the computer in the kitchen as a replacement radio. This is&amp;nbsp;my journey!&lt;br /&gt;
&lt;br /&gt;
I first had a look at the apps bundled with Gnome and KDE that claimed to control the radio, but very few of them could control a V4L2 device, they were all aimed at V4L devices. I have a PVR350 in the box (from when it was a MythTV PVR back in the day), which is a V4L2 device. I wondered could I integrate the radio as a streaming source for my Logitech/SlimDevices Squeezeserver, and then get radio on any of the Squeezeboxes in the house, as well as anything else that could play a stream. I could have done this in C, but I like a challenge, and wanted to learn about device control! So I went with Perl.&lt;br /&gt;
&lt;br /&gt;
The ivtv driver that controls the PVR350 comes with a sample radio command line program - &lt;span style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;ivtv-radio&lt;/span&gt;. It was an easy introduction to device control using ioctl, which I had no experience of before, but basically is a way of controlling I/O devices by sending a command and a variable. The command is sent as certain number, depending on the command you want, and the variable is a struct - a specific combination of ints, doubles etc to hold various information. The command is either a &quot;set&quot; or &quot;get&quot; - so either writing to the device using data in the struct, or reading from the device into the struct.&lt;br /&gt;
&lt;br /&gt;
First, the commands. In C, there are header files (.h) that hold the correct commands and appropriate numbers, but not for Perl. There&#39;s a command line tool - &lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;h2ph&lt;/span&gt; - which converts C header files into Perl Header files. For V4L2 ioctl, the header file is &lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;&amp;lt;linux/videodev2.h&amp;gt;&lt;/span&gt;. So:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: shell&quot;&gt;cd /usr/include
h2ph -d /example/perlradio/inc -a linux/videodev2.h
&lt;/pre&gt;&lt;br /&gt;
creates the perl version of this file and all necessary other .ph files in the &lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;/example/perlradio/inc&lt;/span&gt; directory.&lt;br /&gt;
&lt;br /&gt;
It doesn&#39;t do the whole job unfortunately, and there&#39;s very little feedback when things go wrong. So it helps to redefine a function:&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: perl&quot; style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;# redefine unhelpful _IOC_TYPECHECK macro
sub _IOC_TYPECHECK {
  $sizeof{$_[0]} or do {
  # complain that we don&#39;t know the size of this struct
  # (we can&#39;t die because we&#39;re being eval-ed by _IOR or _IOW)
  print STDERR &quot;invalid size argument for IOC: &quot;.
    &quot;\%sizeof array contains no &#39;$_[0]&#39; key\n&quot;;
  exit 1;
  }
}
&lt;/pre&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;and we have to tell it how big each struct is using a hash array called &lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;%sizeof&lt;/span&gt; - C can figure this out by itself. So:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: perl&quot; style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;# define a sizeof hash
%sizeof = (
        &#39;struct v4l2_tuner&#39; =&amp;gt; 84,
        &#39;struct v4l2_frequency&#39; =&amp;gt; 44,
        &#39;struct v4l2_control&#39; =&amp;gt; 8,
);
&lt;/pre&gt;&lt;br /&gt;
Those structs came from the videodev2.h file and the V4L2 documentation - the best of which I found here: &lt;a href=&quot;http://v4l2spec.bytesex.org/spec/r7624.htm&quot;&gt;http://v4l2spec.bytesex.org/spec/r7624.htm&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
As an example, the first thing we do is query the tuner to get some information. This means sending a&amp;nbsp;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;VIDIOC_G_TUNER&lt;/span&gt; command, with a &lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;v4l2_tuner&lt;/span&gt; struct to hold the response. The radio is &lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;/dev/radio0&lt;/span&gt;, so we open that and call &lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;ioctl&lt;/span&gt; on it. &lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: perl&quot; style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;require &quot;sys/ioctl.ph&quot;;
require &quot;linux/videodev2.ph&quot;;

open(RADIO_DEV, &quot;+&amp;lt;&quot;, &quot;/dev/radio0&quot;);
my $v4l2_tuner = pack(&quot;c84&quot;, 0);
my $retval = ioctl(RADIO_DEV, VIDIOC_G_TUNER(), $v4l2_tuner) || -1;
my @struct = unpack(&quot;LZ32iLLLLLLlLLLL&quot;, $v4l2_tuner);
&lt;/pre&gt;&lt;br /&gt;
&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;@struct&lt;/span&gt; now contains the information. We need to create a place to hold the data, so we pack 84 null chars into &lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;$v4l2_tuner&lt;/span&gt;. Afterwards, this variable holds a packed set of variables, which we can extract using &lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;unpack&lt;/span&gt;. The &quot;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;LZ32iLLLLLLlLLLL&lt;/span&gt;&quot; comes from the documentation - &lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;__u32&lt;/span&gt;, &lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;__u8[32]&lt;/span&gt; (string), &amp;nbsp;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;__s32&lt;/span&gt; etc. See &lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;pack&lt;/span&gt; from the perl documentation for more on this.&lt;br /&gt;
&lt;br /&gt;
To set the frequency, we&#39;ll use the&amp;nbsp;&lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;VIDIOC_S_FREQUENCY&lt;/span&gt; command, with a struct holding the frequency we want. Some tuner cards need the frequency in MHz (e.g 90.7) and some want it in KHz (e.g. 90700). To find out what we have, we can use the &lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;capability&lt;/span&gt; field in the struct we just retrieved. This is in &lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;@struct[3]&lt;/span&gt;. We logical-AND it with &lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;V4L2_TUNER_CAP_LOW&lt;/span&gt; - 1 means KHz, 0 means MHz. &amp;nbsp;There&#39;s also a constant mutiplier - 16.&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: perl&quot; style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;my $freqMultiplier = $struct[3] &amp;amp; V4L2_TUNER_CAP_LOW() ? 1000 : 1;
my $frequency = sprintf(&quot;%u&quot;, 90.7 * $freqMultiplier * 16);
my $tuner = 0;
my $tuner_type = V4L2_TUNER_RADIO();
&lt;/pre&gt;&lt;br /&gt;
We pack up the &lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;v4l2_frequency&lt;/span&gt; struct, and provide it to &lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;ioctl&lt;/span&gt;:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: perl&quot;&gt;$v4l2_frequency = pack(&quot;LiLLLLLLLLLL&quot;, 
    $tuner, $tuner_type, $frequency, 0,0,0,0,0,0,0,0);
$retval = ioctl(RADIO_DEV, VIDIOC_S_FREQUENCY(), $v4l2_frequency) || -1;
&lt;/pre&gt;&lt;br /&gt;
The radio is now set to 90.7MHz, all we need to do is play the audio, which comes through &lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;/dev/video24&lt;/span&gt;. A quick way to do this is to use &lt;span class=&quot;Apple-style-span&quot; style=&quot;font-family: &#39;Courier New&#39;, Courier, monospace;&quot;&gt;aplay&lt;/span&gt;:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class=&quot;brush: perl&quot; style=&quot;margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;&quot;&gt;system(&quot;aplay -f dat &amp;lt; /dev/video24 &amp;amp;&quot;);&lt;/pre&gt;</content><link rel='replies' type='application/atom+xml' href='http://icantholditallinmybrain.blogspot.com/feeds/2311725371280139616/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://icantholditallinmybrain.blogspot.com/2010/08/controlling-v4l2-radio-with-perl-on.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7165003663082593115/posts/default/2311725371280139616'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7165003663082593115/posts/default/2311725371280139616'/><link rel='alternate' type='text/html' href='http://icantholditallinmybrain.blogspot.com/2010/08/controlling-v4l2-radio-with-perl-on.html' title='Controlling V4L2 radio with Perl on Linux.'/><author><name>Anonymous</name><uri>http://www.blogger.com/profile/02396299665268094026</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry></feed>