📄 rio500.java
字号:
/*
* Java USB Library
* Copyright (C) 2000 by David Brownell
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package usb.devices;
import java.io.*;
import java.util.Vector;
import usb.core.*;
import usb.util.USBSocket;
/**
* This provides access Rio500 status, and potentially to the
* full range of functionality supported by this device.
* It's been created using the
* <a href=http://rio500.sourceforge.net>Rio500.sourceforge.net</a>
* resources ... many thanks to the folk there!
* At this writing, this class exposes roughly the functionality
* that the rio_stat program provides.
*
* <hr>
*
* <p> Be very sure to invoke {@link #finish} (if you'll be using the
* device again) or {@link #close} (so other drivers can use it), after
* you {@link #start} to use the Rio. If you don't, a power cycle of
* the player may be needed to recover. Use a <code>finally</code> clause
* to make sure you clean up before you switch to another task. Only
* the thread which invokes <code>start</code> may perform subsequent
* operations with this object, until <code>finish</code>.
*
* <p> <em>Do not use your Rio when its battery indicator is so low that
* none of the solid segments are showing. It's been seen to behave quite
* poorly when it's got that little power. You could need to reformat your
* storage media; some users have even had to have their Rio units replaced
* by Diamond. (This is evidently a known Rio firmware bug.) </em>
*
* @version $Id: Rio500.java,v 1.2 2000/11/20 17:09:03 dbrownell Exp $
*/
public final class Rio500
{
private final ControlMessage msg = new ControlMessage ();
private final byte scratch [] = new byte [4096];
private /* final */ USBSocket socket;
private Thread talking;
/**
* Initializes to talk to the specified device.
* Claims ownership of the bulk interface.
*/
public Rio500 (Device dev) throws IOException
{
socket = new USBSocket (dev);
}
/**
* If you didn't finish and close this device, they'll be done here.
* Since finalization won't always be invoked, don't rely on this.
*/
protected void finalize () throws IOException
{
close ();
}
/**
* After you close this object, other drivers can access
* this particular MP3 player. Java code will see it as
* a disconnect followed by a reconnect, with those other
* drivers competing to claim the interface.
*/
public void close () throws IOException
{
finish ();
socket.close ();
}
/**
* You must say you are going to start talking to the player, since it
* can't be used while your thread is doing so. If the player is now
* in use, it typically stops playing.
*/
public void start () throws IOException
{
synchronized (socket) {
if (talking != null)
throw new IllegalStateException ();
get (RIO_COMM_START, 0, 0);
talking = Thread.currentThread ();
}
// why op 42 all the time -- 1ms pause each?
// they don't always seem to be necessary
// on first call only, C code gets result 0x60000100
// Java (and C on other calls) gets result 0xf0000100
get (RIO_UNKNOWN_42, 0, 0);
get (RIO_UNKNOWN_42, 0, 0);
}
/**
* When you finish with this object, it can normally be used to
* play back audio until you start to use it again. Use this in
* a "finally" clause around any block where you start().
*/
public void finish ()
{
boolean noNukes = false;
try {
checkTalking ();
get (RIO_COMM_END, 0, 0);
get (RIO_UNKNOWN_42, 0, 0);
} catch (IOException e) {
// ignored
} catch (IllegalStateException e) {
noNukes = true;
} finally {
if (!noNukes)
talking = null;
}
}
// must have start()ed
private void checkTalking ()
{
if (talking != Thread.currentThread ())
throw new IllegalStateException ();
}
/**
* Returns the number of bytes of free memory in the player's
* internal or external memory.
*/
public int getFreeMemory (boolean external) throws IOException
{
int retval;
checkTalking ();
retval = get (RIO_MEM_QUERY, 0, external ? 1 : 0);
get (RIO_UNKNOWN_42, 0, 0);
get (RIO_UNKNOWN_42, 0, 0);
// rio_add_song retries twice if retval is zero
// on grounds that it sometimes lied ... old bug?
return retval;
}
/**
* Returns the frmware revision of this MP3 player.
*/
public String getFirmwareRevision ()
throws IOException
{
Device dev = socket.getDevice ();
DeviceDescriptor info;
// MORE CORRECTLY, bcd-ize:
// 0x0ffff & get (RIO_FIRMWARE_REV, 0, 0)
if (dev != null) {
info = dev.getDeviceDescriptor ();
return info.getDeviceId ();
} else
return null;
}
/**
* Returns true if a removable SmartMedia memory card is available
* for song storage.
*/
public boolean hasExternalMemory () throws IOException
{
return ((get (RIO_UNKNOWN_42, 0, 0) >> 30) & 0x01) != 0;
}
/**
* Returns information about the internal or external memory.
* @param external when true, the external memory is checked.
*/
public MemoryStatus getMemoryStatus (boolean external) throws IOException
{
checkTalking ();
synchronized (msg) {
// which card provides the status?
get (RIO_UNKNOWN_51, 1, external ? 1 : 0);
return new MemoryStatus (this, rioRead (RIO_MEM_STATUS, 0, 0, 20));
}
}
private int getFolderBlockCount (boolean external)
throws IOException
{
int card = external ? 1 : 0;
return get (RIO_GET_BLOCK_COUNT, ROOT_FOLDER_ADDRESS, card);
}
/**
* Returns an array of the folders in internal or external memory.
*/
public FolderEntry [] getFolders (boolean external) throws IOException
{
int blocks = getFolderBlockCount (external);
byte folders [] = new byte [blocks * BLOCKSIZE];
Data data = new Data (this, folders);
Vector v = new Vector (8);
int offset = 0;
int folderNum = 0;
FolderEntry temp;
FolderEntry retval [];
checkTalking ();
read (external, ROOT_FOLDER_ADDRESS, folders, 0, folders.length);
while (offset < folders.length) {
temp = new FolderEntry (this, external, folderNum++, data, offset);
if (temp.getOffset () == 0xffff)
break;
v.addElement (temp);
offset += 2048;
}
retval = new FolderEntry [v.size ()];
for (int i = 0; i < retval.length; i++)
retval [i] = (FolderEntry) v.elementAt (i);
return retval;
}
/*==================================================================*/
// commands
private static final byte RIO_FIRMWARE_REV = 0x40;
private static final byte RIO_UNKNOWN_42 = 0x42;
private static final byte RIO_OFFSET_QUERY = 0x43;
private static final byte RIO_SET_READ_LEN = 0x45;
private static final byte RIO_WRITE = 0x46;
private static final byte RIO_COMM_START = 0x47;
private static final byte RIO_COMM_END = 0x48;
private static final byte RIO_FORMAT = 0x4D;
private static final byte RIO_UNKNOWN_4C = 0x4C;
private static final byte RIO_SET_READ_PTR = 0x4E;
private static final byte RIO_UNKNOWN_4F = 0x4F;
private static final byte RIO_MEM_QUERY = 0x50;
private static final byte RIO_UNKNOWN_51 = 0x51;
private static final byte RIO_FOLDER_QUERY = 0x56;
private static final byte RIO_MEM_STATUS = 0x57;
private static final byte RIO_FOLDER_END = 0x58;
private static final byte RIO_GET_BLOCK_COUNT = 0x59;
// "big" chunk is 64k; small is a block.
private static final int IO_SIZE_BIG = 0x10000;
// memory is block-addressed
private static final int BLOCKSIZE = 0x4000;
// eight song entries per block
private static final int SONG_ENTRY_SIZE = BLOCKSIZE / 8;
// directory of folders (which are directories of songs)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -