2014年4月2日水曜日

iOSテストフレームワークKIFで大ハマリ

カード決済会社Squareが開発・提供しているオープンソースのiOS用テストフレームワーク、KIFについて。

■これは良い物だ■

わりと余裕のある開発案件を担当中なので今度こそTDD…とは言わないまでもユニットテストばりばりに活用してテスト負担を下げてやろうじゃん、と思いまして。

ググったところ、60分で始めるiOSアプリのUI自動テストという記事がトップに出てきました。既存のテストフレームワークやInstrumentsのUI Automationよりもかなり直感的かつラクにテストが出来そうです。

というわけで、さっそく試してみたのですが…。

先に結論を書くと、GUI要素を拾うのにAccessibility Labelを使っているのでNavigation Bar / Tab Barなどに対応するのが面倒くさい(座標でタップ位置を指定する必要がある)のと、フレームワークが非公開APIを使っているということで断念しました。

本体に非公開API使っていなければrejectされることはないと思いますが、ある日突然テストを使えなくなるのは避けたいし、納品物としては法的リスクには近寄れません。

■でも一応インストール方法など■

GitHubのKIFのページにインストール方法が書いてありますが、残念ながらXcode5とは微妙に違っていてハマりまくりました。ということで、まとめておきます。

まずKIFを動かすのに必要なものは以下の通り:

  • Xcode command line tools(Xcode5は標準で入ってる?)
  • Cocoa Pods

CocoaPodsでなくてもGitHubからFrameworkを手動でインストールできますが、ラクなのでこの機会にインストールした方が良いと思います。ということで、CocoaPodsが入っていることを前提として以下手順です。

  1. 新しくtest targetを追加します。
    XcodeでFile->New...->Target、iOS other、Cocoa Touch Unit Testing Bundleを選び、Next。Product Nameはお好きな名前(Testだとわかるものが良いです)、Typeとして「OCUnit」を選びます。OCUnitはDeprecatedになっているかもしれませんが、問題ないっす。FinishボタンでTest Targetが追加されます。
  2. Terminal.appを起動します。
    もしエンコードがUTF-8以外だったら、UTF-8に変更して新しいウィンドウを開きます。これハマりネタです。podを実行した時にワーニングが出るのですが「どうせ使ってないから関係ないだろ」と無視していたら、これが原因でターゲットが認識されずに30分ほど悩みました。
  3. プロジェクトのルートディレクトリにPodfileというファイル名で下記の様なテキストを作ります。ここでTargetには上で作ったProduct Nameを指定します。もちろんお好みのエディタを使って結構ですが、エンコーディングがUTF-8になっていることをくれぐれもご確認ください。

    #Podfile
    target 'ターゲット名', :exclusive => true do
        pod 'KIF', '~> 2.0'
    end

  4. ターミナルでプロジェクトディレクトリへ移動し、pod installを実行します。正常終了のメッセージが出れば、プロジェクトが出来上がりました。
  5. 一度Xcodeを終了します。
  6. プロジェクト・ディレクトリの中を見ると、<プロジェクト名>.xcworkspaceができていると思いますので、これをダブルクリックするとXcodeが起動します。
  7. ワークスペースの中のPodsをbuildします。

あとは、前記「60分で始めるiOSアプリのUI自動テスト」の「KIFの使い方」にある通りでばっちりです。

なお、私はLabelとAccessibility Labelを間違えて、「ボタンが認識されないなー」地獄で15分ほど溺れておりました。皆さんがハマらないようお祈りしております。

2014年3月16日日曜日

LPC1114FN28の小さな落とし穴:その2・「Timeは止まってます」


以前ハマったのは落とし穴というかミスですが、参照電圧端子をフリーにしたままで「AnalogInが動かない」と騒いでいた件。

で、今回の落とし穴は…Time。構成上RTCが入っていないということは知っていました。でも大抵の場合、リセット後の経過秒数がカウントされる、という仕様になっているチップが多い…よね(必死に同意を求める)。Arduinoもそうだし。

その前提でタイミングに関わる処理を書いていたのですが…どうにも動かない。まぁそりゃ動きませんよね、いつまでたってもtime = 0なのだから。

幸い、メインループの処理が非常に軽いしwaitも必要なプログラムだったので、メインループの中でcounter++を使って処理しました。いやはや。

--

その他、ADXL345という3軸の加速度をI2Cで読み取れるチップを使おうとして、なかなかうまく動かせませんでした。

いくつかボケはあったのですが、最終的にはアドレスセレクタのところにハンダ玉が落ちてGNDと短絡しており、プログラムからいくら呼びかけても無駄だった、というのが原因でした。念の為に別アドレスで呼びかけてみたらすんなり動いてしまったので、原因判明。一応、その他のボケも書いておきます。

  • CSをGNDに落としてた(GNDはSPIモード)
  • 正しい値が返っていたのに別のレジスタ見て「返ってこない」と思い込んでた

もうアリガチすぎて参考にもならないですね…。

まぁしかし、加速度計も面白いです。3軸の絶対値にFFTをかけて振動のモードを割り出して、それとは別に過去100ミリ秒の平均値からオフセットを出しておき、加速度の変化量などと組み合わせて動きを解析して…云々 アプリ屋としてはこの辺はそんなに苦労しないで作れたのですが、ともかく第一歩の「データを取り込む」というところでコケていました。

いやはや…。

2014年2月1日土曜日

今日の進捗報告

■iPhone/Force.comアプリ■

Force.com mobile SDK 2.1で作ったプロジェクトにあまり手を加えることなく旧プロジェクトの要素を移植したら、案の定バグが噴出。一番困ったのは、UITableViewControllerの描画が異常に遅い。cellで全部のセルの構成が終わっているのに、その後30秒ぐらい返ってこない。めぼしいところにはNSLogを入れてみたけど、何も出てこない。一体どこで何をして時間をしているのだウガー…というところでおしまい。

昔のWebページみたいにAuto Layoutがお互いに「あっちいけ こっちいけ」とサイズを調整しあっているような気がするんですが、どうやってソレを回避しようか思案中。

■電子工作方面■

LPCxpresso LPC1769で遊ぼうとするが、IDEからボードが認識されない。IDEの再起動、マシンの再起動をしてもダメ。あちこちググったりするが同じ症状が見当たらない。

原因:USBケーブルがちゃんと根本までささっていなかった件

なお、LPC-Link2に乗っているLPC4370は、単体のLPC4370 Evaluation boardとしても使用できることが判明。英語のページを読み進めながら作業していったけど、うまく動かない。よく見たら最初の方にTwo LPC-Link2と書いてあった件(一つをLink、もう一つをboardとして使うわけですね)。


…はい、今日も何も進みませんでした…。

Force.com mobile SDK for iOS 2.1でusernameを取得するには?

長野新幹線の車窓から、浅間山?
Chatterへ「いいね!」を送る場合などにはuser idが必要です。そのために以前のSDKでは、
AppDelegate *app = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSString *userId = [[[app coordinator] credentials] userId];
なんて書いていましたが、今は
#import "SFAccountManager.h"
#import "SFIdentityData.h"
(略) 
NSString *userId = [SFAccountManager sharedInstance].idData.userId;
と書くそうです(Query for username in Salesforce iOS SDK)。

SFAccountManagerなんてSalesforceのClass Referenceに出ていないですが、SFIdentityDataは掲載されています。

ではでは。

2014年1月31日金曜日

Force.com mobile SDK 2.1.0 for iOS(追記)

■まずインストール■

インストールの方法と基本的な操作はここに書いてあります。

forceios
Utilities for creating mobile apps based on the Salesforce Mobile SDK for iOS

2.0まではgitからのcloneでしたが、2.1になってnpmが用意されたようです。自分のアカウント用として作るのであれば、適当なディレクトリに移動してから
    $ sudo npm install forceios
を実行すると直下にnode_modulesディレクトリが出来、その下にインストールされます。

Macの全てのユーザから使えるようにするには
    $ sudo npm install forceios -g
いずれもターミナルから実行します。この場合は/usr/local/lib/node_modules下にパッケージがインストールされます。

以下、-gの付いている方を前提とします…Terminalでパスなど切らなくて良いのでラクですし。インストールが終わったら、
    $ forceios version

    forceios version 2.1.0
と表示されればインストールOKです。

■まずはSamples■

もうSampleは見なくていいよ、という方は次の段落へどうぞ。これもターミナルでの作業です。まず、適当なディレクトリに移動してから
    $ forceios samples -outpoutDir=Samples
とすれば、直下にSamplesというディレクトリが作られ、さらにその下にサンプルプロジェクトが並びます。



あとは各フォルダの中にある .xcodeproj をダブルクリックしてXcodeで開き、どういう作りになっているか覗いてみてください。

■プロジェクトの作り方■

これもターミナル上での作業です。プロジェクトを置くディレクトリに移動します。少し長いですが、forceiosのcreateコマンドを使います(実際は1行です…nativeの場合apptypeは省略可能です)。
    $ forceios create --apptype=native --appname=TestForce210
    --companyid=com.your.domain --organization=あなたの会社名 

リターンキーを押すと、プロジェクトを作るディレクトリ、App ID、App Callback URI()を聞いてきます。全部リターンキーでOKです。
    Enter the output directory for your app (defaults to the current directory): 
    Enter your Connected App ID (defaults to the sample app's ID): 
    Enter your Connected App Callback URI (defaults to the sample app's URI): 
数秒間メッセージが流れて、最後にこれが出ればOKです。
    Congratulations!  You have successfully created your app.
できました。では、TestForce210/TestForce210.xcodeprojをダブルクリックします。さっきリターンキーで飛ばしたApp IDはProject情報で設定し直すことができます。また、Callback URIとRemoteAccessConsumerKeyも今までと同様、Classesフォルダ下のAppDelegate.mで正しい値に設定することができます。cmd+Rでビルド&実行してみます。スプラッシュの後、認証画面が出て、さらにその数秒後にさっき認証した組織のユーザ名一覧が表示されれば完了です。

さっくり見てみましたが、ARCは前回対応されたものの、Storyboardはやっぱりまだですね…。Storyboardを使うには、AppDelegateの - (void)setupRootViewControllerを変更します。以前書いた方法と少し違いますが、基本的なやり方は同じです。

追記2014/01/31:Storyboard上ではUITableViewControllerにnavigation controllerをEmbed InしてAppDelegate.mの -(void)setupRootViewControllerで以下のようにrootViewControllerにセットするとStatusBar / TopBarが正しく動作します。

- (void)setupRootViewController
{
    UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"Storyboard"
                                                         bundle:[NSBundle mainBundle]];
 
    UINavigationController *navi = [storyboard instantiateViewControllerWithIdentifier:@"naviView"];
    self.window.rootViewController = navi;
}

さて、世界がぶっとぶようなアプリでも作るかねw

2014年1月26日日曜日

LPC1114FN28のアナログ入力で躓く



タイトルの通り「可変抵抗で入力電圧を変えるとその通りにPWMでLEDが明暗する」というのを作ろうとして、見事にハマりました。

結論からいうと、LPC1114FN28のAD変換器(AnalogIn)は、基準電圧0vと3.3vをつながないと正常に動かないよ、ということです。AnalogInが0-3.3vに変化するならば、pin8をGND、pin7を3.3vにつなぐ必要があります。

まぁ、分かってしまえばバカバカしいことなのですが…AnalogInのリファレンスを見ても、基準電圧を設定するためのAPIが見当たらなかったので、0-3.3vになっている、と思い込んでいました。PwmOutも正常に動いているし、AnalogInへの電圧も0-3.3vで変化しているし…あとはAnalogInしかありません。でもググってもそれらしい記事は見当たらない。これはもう、何か根本的なミスだろうと、何度目かの配線チェックをしていて「AVIN」「AGND」に気づいた、という展開でした。

あと、副産物ですが、PwmOut led(dp18);と定義して led = 0.0f; を出力してもLEDは消えません。うっすらと点灯しています。でも、led = 0; と整数をセットすると消えます。

また余談ですが、基板の上で光っているLEDは秋月で10個250円で買って来た「超高輝度赤色LED」です。20mAぐらいでもかなり明るいのですが、連続最大定格の60mAを流すと直視できません。安くなったもんだなぁ…。

2014年1月22日水曜日

Macで初mbed

秋月で買ってきてそのまま引き出しで眠っていたLPC1114FN28、今日ようやく陽の目を見ました。

ジャンパが足りなかったりブレッドボードが小さかったりでムダに苦労しましたが、一昨日FT232の基板にフラックスを塗っておき(秋月の半完成基板は昔からハンダの乗りが悪いような気がします)、昨日FT232を組み立てて、今日会社から戻ってからブレッドボードに組み立て、mbedにサインアップ、lpc21ispのビルド、lpc21ispでのインストール…で、LEDチカチカまでたどり着きましたw

マイコン界のHello,World、Lチカw

なお、秋月のUSBシリアル変換キットFT232RLを買ったのですが、J1のジャンパの説明が今ひとつピンと来なかったので、回路図をにらめっこしJ1のジャンパはGND表記の側、J2ジャンパを差して、最終的にはUSBをつないだ状態でテスターで電圧を測り「3V3」と「VIO」が3.3V前後になっていることを確認しました。最近のLSIは昔より大分丈夫になりましたが、電源間違えると死ぬ確率は飛躍的に高くなります。しっかり確認しましょう。

回路図で電池ってどうやって書いたっけ?w

なお、今回の試作にあたっては、こちらのサイトが大変参考になりました。ありがとうございます。

  [lang:ja] mbed LPC1114での遊び方

なお、補足ですが、Macでの lpc21isp のビルドは

  • LPC21ISPをダウンロード&解凍
  • ターミナルを起動し、解凍してできたLPC21ISPのディレクトリに移動
  • make -f Makefile clean all
  • chmod +x lpc21sp
  • sudo mv lpc21isp /usr/sbin 

これで lpc21ispが使えるようになります。

次にいよいよLPC1114FN28への書き込みですが、その前にシリアルポートの名称を調べる必要がありますが、それにはターミナルで ls /dev/cu.* と入力するとusbserialとか何とかと出てきます。あるいは /dev/cu. まで入力してTabキーを押すと残りが出てくるはずです。では書き込みましょう。

  • USBを接続する
  • リセットボタンとISPボタンを同時に押す。
  • リセットを先に離し、ISPボタンも離す。
  • mbedサイトから落としたバイナリのあるディレクトリへ移動
  • ターミナルで
  • lpc21isp -bin HelloLED_LPC1114.bin /dev/cu.usbserial-AH01KSGF 115200 48000
  • 転送中の表示の後、自動的に実行開始。

28pin、秋月…というとワンチップデジタル時計のMN5311を思い出してしまうんですが、今はこんな高機能なチップが100円かそこらで買えるなんて凄いですね。

2014年1月19日日曜日

反応の鈍くなったリモコンを直す

後記のように鉛筆の芯で姑息的修復をしていましたが、やっぱり所詮粉は粉、次第に反応が鈍くなってきました。ので、アマゾンから届いた「ナノカーボンペン」を使ってみたのですが、まったく使い物になりませんでした。用途が違うんでしょうね。

というわけで、アルミ箔を貼ろうということになったのですが…家にある両面テープは分厚すぎて押さなくてもショートしてしまいます。箸にアルミ箔を巻いて接点に触ってみたら一応機能するのですが、さすがにそれは問題があります(以下の写真)。

導電ゴム板を外した図。穴をアルミ箔巻いた箸でつつけばとりあえず機能します…

あまり粘着力が強すぎるともし失敗した時に貼り直せないし、弱すぎると後でご動作するリスクが高くなる。程々の粘着力でできるだけ薄い物、ということで思いついたのが「テープのり」です。封筒なんかを貼るのに使うアレです。試してみたら実にいい感じでした。なお、テープのりはトンボ鉛筆以外からもでていますが、ドットタイプのものはスイッチの凸部分とドットの位置が合わないと剥がれやすくなるかもしれません。

原価としては1円も掛かっていないと思いますw

アルミ箔、ピンセット、はさみ、テープのり

テフロン加工のハサミだと作業しやすいです。

作業方法は以下の通り:

  1. リモコンを分解する。
  2. 導電ゴムをアルコールなどでよく掃除する。
  3. アルミ箔の裏側(光沢のない面)にテープのりを貼る。
  4. 幅を整えてハサミで手頃な大きさ(3x3mm〜5x5mm)に切る。
  5. ピンセットで導電ゴムに貼り付けて余分な部分を取り除く。
  6. リモコンを組み立て直す
とりあえず、最初は1〜数個だけアルミ箔を貼ってリモコンを仮組みして様子を見た方がいいかもしれません。作業の方向性としては、アルミ箔がしっかり密着することが最優先です。アルミ箔が浮いてしまうと押さなくても押されたようになってしまいますので、リモコンとして機能しません。

これで我が家のリモコンは見事復活しました。


剥がれると押さなくても接触してしまうのでとにかくしっかり密着させることが大事
以下は失敗記録です。

エアコンのリモコン、別に醤油をかけたわけでもないのに反応が鈍くなってきまして。一番劣化著しいのは電源ボタン。最初は少し長い時間押していれば反応してくれたのですが、最近では渾身の力を込めないと反応してくれません。でがけにエアコンの電源が切れないのはイラつきますし、そのうちリモコンが折れそうで怖い。

というわけで、修理します。

最近のリモコンは導電ゴムをプリント基板に押し付けるタイプのスイッチが使われています。ボタンがフニフニと柔らかいやつです。これは大変よく使われているのですが、導電ゴムが劣化して電気を通さなくなってしまうとスイッチとして働かなくなってしまいます。

用意するのは、導電塗料。カーボン粉末などが入っていて、抵抗は大きいものの一応電気が流れます。我が家にあるのはナノカーボンペンです。しかし、どこにしまいこんだか忘れてしまったw

というわけで、代替品として鉛筆の芯を使います。方法は何でも良いのですが、鉛筆の芯の粉末をスイッチシートの導電ゴムの部分、基板の接点と向かい合った真っ黒いところに振りかけます。私は導電ゴムの上にカッターナイフを少し浮かせておき、そこでシャープペンシルを削るようにして粉を落としました。ある程度粉がたまったら、芯の尖ったところではなく「面」を使って粉をなすりつけます。6Bくらいの鉛筆があれば、そのまま導電ゴムの上に書いても良いと思います。いずれにせよ、塗りたくると金属光沢が出てきますが、ボタン面積の70-80%ぐらいが金属光沢になっていればOKです。余分なところについた粉はこすらないように、綿棒などで抑えるようにして取り除きます。

塗りつぶしながら思い出したのは共通一次試験(年がバレるな)。あのマークシート塗りは地獄だったなぁ(当時はマークシートを鉛筆で塗りつぶしたところ=電気が通る、で読み取っていた)。

なお、導電塗料を使う場合には、無水アルコールなどで軽く掃除してから基板と正対する黒いゴムに塗料を薄く薄く塗って乾かすだけです。

リモコンを仮組みしてボタンが反応するか確認してみてください。私は、「リモコンのフタが開いているモードか否か」を切り替えるためのスイッチのことを忘れていて、「あれー、こんだけ塗りつけてもどうしてここのボタンは反応してくれないのだ?」と頭を抱えていましたが、そういう落とし穴にも要注意です。

鉛筆の粉を使うのはあくまでも避難措置というか、導電塗料は1000円ぐらいしますので、原因が導電ゴムなのかそれ以外なのかを鉛筆で安上がりに検証する、という程度のものだと思ってください。導電塗料が手に入ったら、ゴム接点を一度中性洗剤でよくあらい、基板もティッシュで鉛筆の粉をきれいに取り除いてから、塗料を使ってください。

2014年1月16日木曜日

こういうのを作りたかった…。


7500円かー。何かと不便な家電を便利に使えるようにしていきたい、といろいろ実験していて、コアになるアイディアはとっくにできていたものの…WiFi高いし、今どき家庭内にEtherはどうよ?だし、XBeeは商用ライセンスが高いし、赤外線がやっぱり現実解なのかなー、でもセキュリティが…とウダウダ。

いいんだ、私には私の最適解がある←負け惜しみw

2014年1月15日水曜日

Arduinoのバックライトを周辺光で制御

明度センサー(CDS)をアナログ入力ポートにつないで、PWM出力を液晶のバックライト(+)につないだだけですが、それだけではソフト屋として芸がないので「フワッ」と明るくなったり暗くなるように作ってみました。

なお、CDSは、+5V電源〜CDS〜アナログ入力へ〜抵抗〜GNDという配線です。手持ちのCDSの資料がなかったので、抵抗はまずボリュウムをつないでみて、どのぐらいで適当なアナログ入力が得られるかを測定しました。1200Ωと出たのですが、手持ちの関係で1KΩを使いました。

以下、関連するソースです。
// 宣言部
int   backLight = 9;     // pwm出力ポート
float cdsTarget  = 0.0;  // 最後のcds読み込み値
int   lastMillis = 0;    // 最後にバックライトを更新したミリ秒     
// loopに以下の処理を追加:50ミリ秒ごとにバックライト更新
  if ( millis() - lastMillis > 50) {
    lastMillis = millis();
    cdsToBacklight();
  }  
// 関数 : CDSの値でバックライトを制御
void cdsToBacklight() { 
  int current = analogRead(cds);              // 明るさを読み込む
  float diff  = (current - cdsTarget) / 20.0; // 差分の1/20を変化値とする

  cdsTarget += diff;         // 差分を目標値に加算
  int intTarget = cdsTarget;

  int brt = intTarget >> 3; // 目標値の1/8をpwm値とする

  // バックライトへの出力値を制限し、pwm出力
  if (brt < 5) brt = 5;
  if (brt > 128) brt = 128;
  analogWrite(backLight, brt);
}