[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 245
  • Last Modified:

Audio::Radio::Sirius Command Line Interface.

Group,

Audio::Radio::Sirius
http://search.cpan.org/~jtatum/Audio-Radio-Sirius-0.03/lib/Audio/Radio/Sirius.pm

I'm trying to create a command line interface for the modole mentioned above.  I want the interface to be able to present title/artist for the channel chosen.  And change channel based on Command Line argument.  I was able to manage the changing channel, with one hookup that may or may not be my ignorence of perl programming.  Here's the perl script I have created the change the channel.

----------SOF
#!/usr/bin/perl
  use Audio::Radio::Sirius;
  use Device::SerialPort;

  my $serial = new Device::SerialPort('/dev/ttyS1');
  my $tuner = new Audio::Radio::Sirius;

  $tuner->connect($serial);
#  $tuner->power(1);
  $tuner->channel(@ARGV[0]);
----------EOF

The commented portion above is the problem I'm having with the channel change script.  If it's uncommented then the radio has a large gap as it powers down, then powers back up, so I'd rather not have it in.  However, if it's left out, running the script once will change the channel correctly, second and subsequent attempts to change to a different channel will gracefully fail (no error messages).  After the line is placed back in, the cycle repeats, it'll change the channel only once.  I'm not sure if this is a problem with the script, or the module.

As for the title/artist information, it appears a "callback" is used?...  Does the script have to conintually run in order for the call back system to work?...  I know nothing of the callback method, and can't seem to find the right things to search for on Google to obtain the information I need.

What would be best would be a script that would return the artist/song name.  Something like,

[user@server]# song_info 21
Matchbook Romance - Monsters
[user@server]#

Is this possible with this module?...

MUCH TIA,
Knightofoldcode.
0
knightofoldcode
Asked:
knightofoldcode
  • 6
  • 5
  • 2
2 Solutions
 
mjcoyneCommented:
Looking briefly at the documentation, there doesn't seem to be a way to check if the power is already on, which is of course what you need -- why turn the power on if it already is?

Maybe you could attempt to do something and assume the power is off if it fails?  For example, what if you attempt to retrieve the current channel, and only if that fails, cycle the power?

The documentation for channel says "Can be used without a parameter to get the current channel number or with a parameter to change channels. When used with a parameter, returns true on success and false on failure. Offset is -1 to select the channel before the specified number, 1 to select the channel above the specified number, or 0 (default) to simply go to the specified channel".

So, it says that it returns true or false when used with a parameter", but it doesn't say what it returns when it attempts to retrieve current channel information from an off device.  If it does return failure, you can use this to decide whether to turn the power on or not:
 
  unless ($tuner->channel) {
    $tuner->power(1);
  }
 
If calling channel without parameters does not return failure, you can still do the same type of thing, you'd just need to provide a channel.  Since your next step is to actually go to your desired channel, maybe this wouldn't be such a big deal?
0
 
Adam314Commented:
I can't test anything here... so everything is untested.

This returns an array, when you probably want a scalar: @ARGV[0]
Try using $ARGV[0] instead

The channel function should return false on failure... does it on the times it doesn't work?
if($tuner->channel($ARGV[0])){
    print "Success\n";
} else {
    print "Failure: $!\n";
}



A callback function is a function that is called by the module.  Try something like this:
#Create a function
sub channel {
    my ($channel, $pid, $artist, $title, $composer) = @_;
    print "Channel Info:  channel=$channel, pid=$pid, artist=$artist, title=$title, composer=$composer\n";
    $wait=5;
}

#Use that function as callback
$tuner->set_callback ('channel_update', \&channel);

#Tell tuner you want info
$tuner->verbosity(1);

#Get some info (it will come in your callback)
$tuner->monitor(1)

#wait for tuner to finish sending data
while($wait>0){
    sleep(1);
}
0
 
Adam314Commented:
That last part should have set $wait first, and decremented it in the loop....


#wait for tuner to finish sending data
$wait=5;
while($wait>0){
    sleep(1);
    $wait--;
}
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
knightofoldcodeAuthor Commented:
Well.....  First on the change_channel script,

if($tuner->channel($ARGV[0])){
    print "Success\n";
} else {
    print "Failure: $!\n";
}

returns success every time.  It never fails, even though the channel never actually changes the second time you run it when the power is commented out.  I'm willing to live with the gap, since there doesn't appear to be a easy fix.

Just for the archives and anyone else who might need help with this, the code posted by Adam has a bug or two that I corrected, when I get this all solved, I'll post the entire scripts in entirety for simplicity.

On the song_info script, it works, but not as I expected....  Everytime the code is ran it displays all the channels have had information change!  Sometimes it could be one or two (if ran recently) other times it'll display every channel's information!  It looks like this is going to be a little more complicated.  There are times that you'll be on say channel 21, and run the song_info script, and it'll display one or two channels, none of which are 21.  I need some way to determine what is on that channel, it looks like this is going to be more in depth, some kind of a daemon system, with updating the information in a db, or flat file?...  I have root access, and can setup a cron tab.

Ultimatly I'm trying to get the information displayed on a PHP system for a whole house audio system, with multiple Sirius recievers.  I know that this sort of thing already exists for XM, but Sirius is lacking in that regard, and I don't like XM,  :(.  I am familiar with PHP and have created enough scripts, and have worked with the command line enough to know how to accomplish the php portion.

I guess if I needed to, the PHP portion could do the processing of the song_info script, but that'd be really messy.

Knight.
0
 
Adam314Commented:
The documentation states that some tuners support more features than the perl module.  So, if you don't mind writing/reading the port, you might be able to do what you want.

As for the monitor and callback: the documentation states the callback will be called whenever there is new information.  So, if it's been a while since last time you ran, all stations should have new info.  If you just ran it, then most channels will not have new info, so info for those won't be sent.  So you will probably want to store the information whenever you get it, then just overwrite whenever you get new info.  I would think a flat file would be just fine for the amount of info you'll have.  Store the data in an array, with the channel as the index.

I'm not sure how your whole-house system will be setup, but if you want to know if a song changed right away, you'll have to keep some script running with your callback function waiting.  The documentation says "Reads happen automatically when commands are executed (for example changing the channel or muting the tuner). Still, monitor generally needs to be called as often as possible to gather the latest data from the Tuner.", so you might want to call monitor inside of the while loop.

Sorry about the bugs... they happen, esp when I can't test the code.  Posting your final solution would be good.
0
 
knightofoldcodeAuthor Commented:
[quote]
As for the monitor and callback: the documentation states the callback will be called whenever there is new information.  So, if it's been a while since last time you ran, all stations should have new info.  If you just ran it, then most channels will not have new info, so info for those won't be sent.  So you will probably want to store the information whenever you get it, then just overwrite whenever you get new info.  I would think a flat file would be just fine for the amount of info you'll have.  Store the data in an array, with the channel as the index.

I'm not sure how your whole-house system will be setup, but if you want to know if a song changed right away, you'll have to keep some script running with your callback function waiting.  The documentation says "Reads happen automatically when commands are executed (for example changing the channel or muting the tuner). Still, monitor generally needs to be called as often as possible to gather the latest data from the Tuner.", so you might want to call monitor inside of the while loop.
[/quote]

Is there anyway I could talk you into setting up a loop?....  Unfortunately my perl is horrible, and I havn't played in perl for a long time.  Also, I tried to get the srcipt running recently, before this post, and realized the reason was because my callback function was at the bottom of hte script, I think this has something to do with it, but I wasn't aware of that limitation.  

I'm also VERY unfamiliar with how to write to a file in perl.  My attempt was
echo "text info...." > channel-1.txt;  
Which obviously won't work.....  I think it requires print, but I'm not familiar.....

If it'd help, I'll close out this post and repost a new question.  Or increase the number of points for this question, if that's possible, it used to be....  Points arn't a issue here.  I'm more than willing to purchase as many are required.

[quote]
Sorry about the bugs... they happen, esp when I can't test the code.  Posting your final solution would be good.
[/quote]

No problem, I understand completly!  I just wanted to let anyone else know.  :D  Besides, it was just a ; ...  those shouldn't be needed anyway, it outta just look for CRLF's.  :D

Knight.
0
 
mjcoyneCommented:
Did checking for success at retrieving the current channel setting relieve your $tuner->power(1); cycling gaps?  If not, you should be able to achieve the same effect by explicitly changing the channel, e.g.:

  unless ($tuner->channel(184)) {
    $tuner->power(1);
  }

The documentation states "when used with a parameter, returns true on success and false on failure", and -- assuming that trying to change the channel on a device that is off would return failure -- we can use this return value to decide whether the device is already on or not.

It is troubling that if($tuner->channel($ARGV[0])){ is always returnig true -- it returns true even if you leave a channel off the command line?

Opening a file in perl is easy:

open (FH, ">myfile.txt") or die "Can't open myfile.txt : $!";
print FH "whatever you want to appear in the file\n";

So basically you associate at file handle (FH) with a file (myfile.txt) opened for writing (>).  Then you print whatever you want to appear in the file to the filehandle.  Note if you want to append to a file rather than clobber it, use >> in place of > when you open it.  Variables will be interpolated, so you can say something like:

print FH "The error was $error\n";

and the scalar $error will be interpolated.
0
 
knightofoldcodeAuthor Commented:
mjcoyne,

I appreciate the help, as for the question, I tried the original commands, and they caused the unit to power cylce each time.  I'm not sure if you understood the original problem.  I want to be able to switch which channel the unit is on, say from 21, to 20.  If I don't put in the "$tuner->power(1);" command, it will change the channel, only once, any subsequent changes to say channel 1, will not work.  The unit should remain on, permanently.  I havn't tried running your code with the radio off, I didn't see any point since 1) it's going to always be on, and 2, I don't want to have to build in the turning on/off in PHP, just let it play forever.  It's all solid state, so it shouldn't matter, plus it'll allow the users to be able to notice that their favorite song is on, so let's turn it on to listen, etc.

I appreciate the information on writing to files.  I may have to see if I can read some older books that I have on perl. (Like, 7-8 years old, but I just need basic structure, if then statements, checking if a file is present, etc.)  On writing to a file, if the commands:

open (FH, ">myfile.txt") or die "Can't open myfile.txt : $!";
print FH "whatever you want to appear in the file\n";

are used, will this 'cause perl to choke if the file isn't present?  Should I touch the file if not present first, etc?

if($tuner->channel($ARGV[0])){
    print "Success\n";
} else {
    print "Failure: $!\n";
}

Will 'cause a failure if no argument is specified.

Knight.
0
 
knightofoldcodeAuthor Commented:
Nevermind.

I have solved this problem.  I havn't assigned points yet, because the script isn't exactly complete.  Should be iwthin 24 hours.  When the script is complete, I'll post for completeness. I just didn't want any of hte experts to be making the loop requested above.



Knight.
0
 
knightofoldcodeAuthor Commented:
File:  change_channel

#!/usr/bin/perl
  use Audio::Radio::Sirius;
  use Device::SerialPort;

  my $serial = new Device::SerialPort('/dev/ttyS1');
  my $tuner = new Audio::Radio::Sirius;
  #Unfortunatly, we can't add in very many error checking fucntions, the module doesn't really support it.
  $tuner->connect($serial);
  $tuner->power(1);

  $tuner->channel($ARGV[0])

------
EOF



File:  song_info

#!/usr/bin/perl
  use Audio::Radio::Sirius;
  use Device::SerialPort;

  my $serial = new Device::SerialPort('/dev/ttyS1');
  my $tuner = new Audio::Radio::Sirius;

  $tuner->connect($serial);

  #Create a function
  sub channel {
      my ($channel, $pid, $artist, $title, $composer) = @_;
      open (FH, ">$channel" ) or die "Can't open myfile.txt : $!";
      print FH "$channel|$artist|$title|$composer\n";
      print "$channel|$artist|$title|$composer\n";
      close FH;
  }

  #Start an endless loop.... Not hte most efficient or..  "normal" way, but it works.
  #We put the verbosity, monitor, and set_callback inside the loop, otherwise
  #when we change the channel with the other script, it breaks the song info
  #script.

  $wait=1;
  while($wait>0){
      sleep(1);
      #$wait--;
      $tuner->set_callback ('channel_update', \&channel);
      $tuner->verbosity(1);
      $tuner->monitor(1);
  }

------
EOF




Much appreciation to all the experts!

Knight.

0
 
Adam314Commented:
Just had an idea about the channel only changing once:
You script does this:
  connect
  turn on
  change channel

There is no disconnect.  I know there isn't a disconnect method in the module, but maybe the tuner requires it (meaning the module isn't doing quite all it needs to).  Do you have the specs for the tuner?
0
 
knightofoldcodeAuthor Commented:
No, I don't, unfortunatly.  The tuner uses a standardized rs-232 communications.  This communcations protocal is VERY secrative.  A guy is trying to give out the information but a commercial company is doing their best to withold the information.  It's a lot of politics, and I'm lcky to have gotten where I am.  

http://www.rush2112.net is where I purchased my tuner modified portion, if anyone else is interested.


Knight.
0
 
Adam314Commented:
Sucks they keep the protocol secret... without knowing the protocol, there is no way to tell if the problem is with the tuner, or with the module not exactly implementing the correct protocol.

If you have any other questions, just post.  Good luck with your system.
0

Featured Post

Hire Technology Freelancers with Gigs

Work with freelancers specializing in everything from database administration to programming, who have proven themselves as experts in their field. Hire the best, collaborate easily, pay securely, and get projects done right.

  • 6
  • 5
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now