diff
diff --git a/src/com/android/fm/radio/FmSharedPreferences.java b/src/com/android/fm/radio/FmShared index 6843b53..8fb6338 100644 --- a/src/com/android/fm/radio/FmSharedPreferences.java +++ b/src/com/android/fm/radio/FmSharedPreferences.java @@ -12,6 +12,8 @@ import java.util.HashMap; import java.util.List; import java.util.ListIterator; import java.util.Map; +import java.io.IOException; + public class FmSharedPreferences { public static final int REGIONAL_BAND_NORTH_AMERICA = 0; @@ -562,12 +564,20 @@ public class FmSharedPreferences { mFrequencyBand_Stepsize = 50; mFMConfiguration.setLowerLimit(76000); mFMConfiguration.setUpperLimit(108000); + //BCM4325_I2C_FM_RDS_SYSTEM BCM4325_FM_RDS_SYSTEM_FM + try { Runtime.getRuntime().exec("hcitool cmd 0x3f 0x15 0x00 0x00 0x01"); }catch (IOExcepti + //BCM4325_I2C_FM_CTRL BCM4325_I2C_FM_CTRL_BAND_JAPAN BCM4325_I2C_FM_CTRL_STEREO + try { Runtime.getRuntime().exec("hcitool cmd 0x3f 0x15 0x01 0x00 0x05"); }catch (IOExcepti break; } case FmReceiver.FM_JAPAN_STANDARD_BAND: { mFrequencyBand_Stepsize = 100; mFMConfiguration.setLowerLimit(76000); mFMConfiguration.setUpperLimit(90000); + //BCM4325_I2C_FM_RDS_SYSTEM BCM4325_FM_RDS_SYSTEM_FM + try { Runtime.getRuntime().exec("hcitool cmd 0x3f 0x15 0x00 0x00 0x01"); }catch (IOExcepti + //BCM4325_I2C_FM_CTRL BCM4325_I2C_FM_CTRL_BAND_JAPAN BCM4325_I2C_FM_CTRL_STEREO + try { Runtime.getRuntime().exec("hcitool cmd 0x3f 0x15 0x01 0x00 0x05"); }catch (IOExcepti break; } case FmReceiver.FM_USER_DEFINED_BAND: { @@ -579,6 +589,10 @@ public class FmSharedPreferences { band = FmReceiver.FM_US_BAND; mFMConfiguration.setLowerLimit(87500); mFMConfiguration.setUpperLimit(107900); + //BCM4325_I2C_FM_RDS_SYSTEM BCM4325_FM_RDS_SYSTEM_RDS + try { Runtime.getRuntime().exec("hcitool cmd 0x3f 0x15 0x00 0x00 0x02"); }catch (IOExcepti + //BCM4325_I2C_FM_CTRL BCM4325_I2C_FM_CTRL_BAND_US BCM4325_I2C_FM_CTRL_STEREO + try { Runtime.getRuntime().exec("hcitool cmd 0x3f 0x15 0x01 0x00 0x04"); }catch (IOExcepti mFrequencyBand_Stepsize = 200; } } @@ -679,7 +693,8 @@ public class FmSharedPreferences { switch (nCountryCode) { case REGIONAL_BAND_NORTH_AMERICA: { // NORTH_AMERICA 87500 TO 108000 IN 200 KHZ STEPS - mFMConfiguration.setRadioBand(FmReceiver.FM_US_BAND); + //mFMConfiguration.setRadioBand(FmReceiver.FM_US_BAND); + setRadioBand(FmReceiver.FM_US_BAND); mFMConfiguration.setChSpacing(FmReceiver.FM_CHSPACE_200_KHZ); mFMConfiguration.setEmphasis(FmReceiver.FM_DE_EMP75); mFMConfiguration.setRdsStd(FmReceiver.FM_RDS_STD_RBDS); @@ -692,17 +707,18 @@ public class FmSharedPreferences { } case REGIONAL_BAND_EUROPE: { // EUROPE/Default: 87500 TO 10800 IN 100 KHZ STEPS - mFMConfiguration.setRadioBand(FmReceiver.FM_EU_BAND); + //mFMConfiguration.setRadioBand(FmReceiver.FM_EU_BAND); + setRadioBand(FmReceiver.FM_EU_BAND); break; } case REGIONAL_BAND_JAPAN: {// - JAPAN 76000 TO 090000 IN 100 KHZ // STEPS - mFMConfiguration.setChSpacing(FmReceiver.FM_CHSPACE_100_KHZ); mFMConfiguration.setEmphasis(FmReceiver.FM_DE_EMP75); mFMConfiguration.setLowerLimit(76000); mFMConfiguration.setUpperLimit(90000); + setRadioBand(FmReceiver.FM_JAPAN_STANDARD_BAND); break; } case REGIONAL_BAND_JAPAN_WIDE: {// - JAPAN_WB 090000 TO 108000 IN 100 @@ -711,6 +727,7 @@ public class FmSharedPreferences { mFMConfiguration.setEmphasis(FmReceiver.FM_DE_EMP75); mFMConfiguration.setLowerLimit(90000); mFMConfiguration.setUpperLimit(108000); + setRadioBand(FmReceiver.FM_JAPAN_WIDE_BAND); break; }
hcitoolについて
サブコマンドの cmd だけ覚書として載せておく。
hcitoolのコードは、external/bluetooth/bluez/tools/ にある.
FMラジオモジュールへ読書の説明は、探した限りでは
frameworks/base/core/jni/android_hardware_fm.cpp にしかなかった
Usage: cmd[parameters] Example: cmd 0x03 0x0013 0x41 0x42 0x43 0x44
- ogfは、Opcode Group Fieldの略で、コマンドのグループを指す
- ocfは、Opcode Command Filedの略で、コマンドを指す
らしいが、コードを見ても 0x3f 0x15 が何を意味するのかはわからなかった
おそらく、FMモジュールにパラメータを渡す命令ではないだろうか。
HCI Commands(1/15 追記)
上で書いたhcitoolのマジックナンバーをdefine,enumどおりに書くと下記になる
hcitool cmd 0x3f 0x15 BCM4325_I2C_FM_RDS_SYSTEM 0x00 BCM4325_FM_RDS_SYSTEM_FM hcitool cmd 0x3f 0x15 BCM4325_I2C_FM_CTRL 0x00 BCM4325_FM_CTRL_BAND_JAPAN
4番目の引数は、I2Cでおくるコマンド?を指していると思う
やっていることは読み書きなので、チップのレジスタを指しているのかもしれない
5番目が0x00なら書き込み、0x01なら読み込み
6番目が書き込む値で、読み込む場合は0x01で固定のようだ。
int hci_w(int reg, int val) { int returnval = 0; char s1[100] = "hcitool cmd 0x3f 0x15 "; char stemp[10] = ""; char starget[100] = ""; char *pstarget = starget; sprintf(stemp, "0x%x ", reg); pstarget = strcat(s1, stemp); sprintf(stemp, "0x%x ", 0); pstarget = strcat(pstarget, stemp); sprintf(stemp, "0x%x ", val); pstarget = strcat(pstarget, stemp); returnval = system(pstarget); return returnval; } int hci_r(int reg) { int returnval = 0; char s1[100] = "hcitool cmd 0x3f 0x15 "; char stemp[10] = ""; char starget[100] = ""; char *pstarget = starget; sprintf(stemp, "0x%x ", reg); pstarget=strcat(s1, stemp); sprintf(stemp, "0x%x ", 1); pstarget=strcat(pstarget, stemp); sprintf(stemp, "0x%x ", 1); pstarget = strcat(pstarget, stemp); returnval = system(pstarget); returnval /= 0x100; LOGD("hci_r 0x%x \n", returnval); return returnval; }
hcitoolで周波数を変える
android_hardware_fm.cpp:setControlNativeにあるが、
hcitoolで周波数を変えることができる。
80MHz似合わせたいときは、
- 16000(=80000-64000) => 0x3E80
- BCM4325_I2C_FM_FREQ0 に 0x80 を、
- BCM4325_I2C_FM_FREQ1 に 0x3E を、
- BCM4325_I2C_FM_SEARCH_TUNE_MODE に BCM4325_FM_PRE_SET_MODE を書き込む
hcitool cmd 0x3f 0x15 0x0a 0x00 0x80 hcitool cmd 0x3f 0x15 0x0b 0x00 0x3e hcitool cmd 0x3f 0x15 0x09 0x00 0x01
/*native interface */ static jint android_hardware_fmradio_FmReceiverJNI_setFreqNative (JNIEnv * env, jobject thiz, jint fd, jint freq) { /* Adjust frequency to be an offset from 64MHz */ freq -= BCM4325_FREQ_64MHZ; /* Write the FREQ0 register */ hci_w(BCM4325_I2C_FM_FREQ0, freq & 0xFF); /* Write the FREQ1 register */ hci_w(BCM4325_I2C_FM_FREQ1, freq >> 8); /* Write the TUNER_MODE register to PRESET to actually start tuning */ if ( hci_w(BCM4325_I2C_FM_SEARCH_TUNE_MODE, BCM4325_FM_PRE_SET_MODE) < 0){ LOGE("fail \n"); } return 0; }
NexusOneのラジオモジュールについて
CyanogenMod6.1でFMラジオ
6.1がリリースされて一月経ったが、
誰も興味ないのか、FMラジオが聞けないままだ。
コードを見たらアプリ自体作りかけという感じだったが、
いじったら、とりあえず聞けるようになった。
暫定対応的なパッチを添付したかったが、できなかったので diff を1番下に載せた。
ただ、ラジオを聞けるようにするだけならアプリの再インストールの必要はなく、
adb shell で下記のコマンドを打つだけでいいはず。
hcitool cmd 0x3f 0x15 0x00 0x00 0x01 hcitool cmd 0x3f 0x15 0x01 0x00 0x01
HttpEntity中のInputStreamについて
DefaultHttpClient を使ってpostをするとき、
HttpPostでリクエストを作り,HttpPost.setEntityでリクエストパラメータを仕込む
大雑把には下記のようになる
File file = new File(path); HttpPost request = new HttpPost(); request.setEntity(new InputStreamEntity(new FileInputStream(file))); DefaultHttpClient client = new DefaultHttpClient(); HttpResponse response = client.execute(request);
普通に考えると、
この時仕込んだInputStreamを使用後にcloseしなくてはいけないが、
DefaultHttpClientの使用例を調べた際、closeしている記述が見当たらなかった。
ひょっとしてexecute内でcloseしてくれているのかと思ったが,そのような説明もなかったので、
本当に必要か、コードを追って見てみた。
今振り返ると、実際にcloseせずに大量にFileInputStreamを作ってexecuteしてみるのが
手っ取り早いし確実な確認方法だったと思う。
結論を言えばやはりcloseは必要なようだ。
DefaultHttpClient.executeをたどると、
DefaultHttpClient.execute → AbstractHttpClient.execute →
DefaultRequestDirector.execute →
DefaultRequestDirector.tryExecute
HttpRequestExecutor.execute→
HttpRequestExecutor.doSendRequest→
HttpClientConnection.sendRequestEntity;
と、sendRequestEntityに行き着く。DefaultRequestDirector.executeが、
コネクションを開いて,sendし、receiveし、redirect等の処理をしている実態のようだった。
このDefaultRequestDirector.executeや他のメソッドを眺めてみたが、
リクエストのentityについてconsumeしている処理は見当たらなかった。
HttpClientConnectionは、
DefaultHttpClient→
SingleClientConnManager(いくつかあるようだが今回はこれを辿った)→
DefaultClientConnectionOperator→
DefaultClientConnection→
AbstractHttpClientConnection
とたどっていくと、AbstractHttpClientConnectionがその実態であることが分かる
AbstractHttpClientConnection.sendRequestEntityをさらに辿ると、
AbstractHttpClientConnection.sendRequestEntity→
EntitySerializer.serialie→
HttpEntity.writeTo
となって、ようやくInputStream.readをよんでいるメソッドに行き着いた
ここまでで InputStream の close をしているような箇所は出会わず、
HttpEntityの実態であるInputStreamEntityのwriteToではJavaDocにあるようにcloseはしていない。
というわけで、やはりInputStreamのcloseは必要で,上記例では、下記のようなものを書く必要がある
File file = new File(path); HttpPost request = new HttpPost(); request.setEntity(new InputStreamEntity(new FileInputStream(file))); DefaultHttpClient client = new DefaultHttpClient(); HttpResponse response = client.execute(request); request.getEntity().getContent().close();
ちなみに、HttpEntity.consumeContent は depriciated であり,
InputStreamをとりだして、直接 close することが推奨されている
直接が推奨されているが、DefaultRequestDirector.execute をみると、
再利用するresponseをクリアする際には,EntityUtils.consumeを使っていることが分かる。
EntityUtilsには、Entity操作でよく利用する処理が入っているようで、
おそらくこのユーティリティの利用が望ましいのだろう。
と思ったら,HttpCore 4.1 API の JavaDoc には、EntitiyUtils.consume が載っているのだが,
Android Developers の JavaDoc には EntitiyUtils.consume が載っておらず、
Eclipseで確認した限りでは実装もされていないようだった。
結局Androidでは自前で書くことになりそうだ。
これだけではただの覚書になってしまうが、この件についてはここまでにする。