65,577

Wednesday, May 22, 2013

Meng-Compile Beberapa Fungsi C/MEX dalam Satu File MEX di Matlab

Atau dengan kata lain: Membuat Library MEX

Salah satu kemelahan MEX adalah setiap fungsi C yang akan dicompile, harus di-wrap dalam sebuah fungsi beranama mexFunction, dan nama file yang berisi mexFunction harus sama dengan nama fungsi yang diinginkan. Misalnya, kita ingin membuat fungsi "adder: di MEX berikut:

#include "mex.h"
/* Input Arguments */
#define X1 prhs[0]
#define X2 prhs[1]
/* Output Arguments */
#define Y plhs[0]
void mexFunction( int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[] )
{
printf("adder\n");
/* Check for proper number of arguments */
if (nrhs != 2) {
mexErrMsgTxt("Two input arguments required.");
} else if (nlhs > 1) {
mexErrMsgTxt("Too many output arguments.");
} else {
printf("Adder from MEX function\n");
}
//Allocate ouptut
Y = mxCreateNumericMatrix(1, 1, mxDOUBLE_CLASS, mxREAL);
//Adder function
*mxGetPr(Y) = *mxGetPr(X1) + *mxGetPr(X2);
}
view raw gistfile1.c hosted with ❤ by GitHub

FIle tersebut jika dicompile menggunakan MEX, akan menghasilkan file .mex (atau .mexgw, .mexw64, dsb), dimana namafungsi sama dengan nama file-nya. Agar fungsi hasil compileasi bisa dipanggil di Matlab dengan cara berikut:

>> adder(2,3)
adder
Adder from MEX function

ans =

     5

Maka file tersebut harus disimpan dengan nama file adder.c, sehinggal ketika dicompile menghasilkan file adder.mex (lihat keterangan diatas).

Demikian juga kalau kita punya beberapa fungsi C lainnya yang ingin dicompile ke MEX, maka tiap fungsi harus disimpan dalam nama file yang sesuai dengan nama fungsi yang dimaksud. Ini menjadi drawback ketika kita punya banyak sekali fungsi, sehingga terpaksa dicompile dalam banyak file MEX (misal: adder.mex, mult.mex, div.mex, dsb.). Bisakah kita mengcompile semua fungsi MEX tersebut dalam satu file MEX saja, sebutlah library.mex? Bisa.

Berikut workaround-nya:

1. Buat satu fungsi MEX (library.c) yang berfungsi untuk memparsing nama fungsi.

Masukkan nama-nama fungsi sebagai header, misalnya:

void mexAdder( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] );
void mexMult( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] );

Lihat code library.c berikut:

#include "mex.h"
#include <string.h>
void mexAdder( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] );
void mexMult( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] );
void mexFunction( int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[] )
{
char *functionName;
int functionNameLen;
/* Get the length of the function name string. */
functionNameLen = (mxGetM(prhs[0]) * mxGetN(prhs[0])) + 1;
/* Allocate memory for input strings. */
functionName = (char *) mxCalloc(functionNameLen, sizeof(char));
/* Copy the string to functionName. */
functionName = mxArrayToString(prhs[0]);
if ( !strcmp(functionName,"adder") ) {
mexAdder(nlhs, plhs, nrhs-1, &(prhs[1]));
} else if ( !strcmp(functionName,"mult") ) {
mexMult(nlhs, plhs, nrhs-1, &(prhs[1]));
}
}
view raw gistfile1.c hosted with ❤ by GitHub

2. Sesuaikan nama fungsi pada masing-masing file sesuai nama yang ada di header (poin 1).

Misalnya untuk adder.c jadi begini:

#include "mex.h"
/* Input Arguments */
#define X1 prhs[0]
#define X2 prhs[1]
/* Output Arguments */
#define Y plhs[0]
void mexAdder( int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[] )
{
printf("adder\n");
...
view raw gistfile1.c hosted with ❤ by GitHub

3. Compile library.c bersamaan dengan fungsi-fungsi lainnya.

>> mex library.c adder.c mult.c

4. Selesai! Untuk memanggil fungsi, caranya:

>> library('adder', 2, 3)
adder
Adder from MEX function

ans =

     5

Sekarang kita punya satu file MEX (library.mex) yang berisi semua fungsi C/MEX. Mudah kan!? (ya2n) :D

Referensi:
- http://www.mathworks.com/help/matlab/matlab_external/building-mex-files.html
- http://is.muni.cz/th/256594/fi_m/thesis.pdf

Membuat Aplikasi Smart Poster Writer/Reader Menggunakan Android NFC dan Mifare Classic

Smart Poster merupakan teknologi yang mengubah poster yang tadinya hanya "statis" menjadi "dinamis", yaitu dengan meng-embed sebuah URL pada poster tersebut sehingga alih-alih membaca keterangan yang tertera pada poster, pembaca akan membuka link URL yang tentunya isinya dapat berubah-ubah sesuai kebutuhan.

Teknologi ini diimplementasikan dengan dua cara: QR Code (barcode 2 dimensi), dan NFC. Ada perdebatan mengenai teknologi smart poster ini.

Pertama, secara natural, orang tidak tertarik untuk melihat poster yang sama berulang kali, walaupun sebenarnya isi URL-nya berubah-ubah, lagipula bagaimana kita bisa tahu kalau isi URL-nya telah berubah?

Kedua, masalah security. Orang dapat mengganti gambar QR code, atau menyusupkan kartu NFC tanpa sepengetahuan pemilik poster karena keduanya tidak mencolok (sulit membedakan secara visual). Dengan cara ini, orang dapat memanfaatkan smart poster orang lain untuk meredirect ke URL dia.

Ketiga, masalah harga tag NFC. Perbedaan harga smart poster NFC dengan poster biasa sangat jauh. Apakah memang tambahan harga itu worth it untuk kebutuhan bisnis.

Terlepas dari tiga masalah diatas, smart poster sudah mulai dipakai terutama pada poster informasi publik di bandara, stasiun, terminal, dsb. Juga sudah diimplementasi di restoran-restoren (untuk pesan makanan), dan juga diimplementasikan di etalase virtual (orang melihat etalase produk berupa smart poster, lalu dari URL semart poster, orang tersebut membeli produknya).

Berikut contoh code aplikasi smart poster writer pada Android:

package com.SmartPosterTagWriter;
import java.io.IOException;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.content.DialogInterface;
import android.content.Intent;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.TagLostException;
import android.nfc.tech.MifareClassic;
import android.nfc.tech.Ndef;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
public class WriteToPoster extends Activity implements Runnable {
Tag mTagFromIntent = null;
MifareClassic mClassic = null;
private NfcAdapter mAdapter;
private PendingIntent mPendingIntent;
...
/**
* This method is called when the activity is first created.
**/
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.writer);
View view = this.getWindow().getDecorView();
view.setBackgroundColor(100);
setPoster();
mAdapter = NfcAdapter.getDefaultAdapter(this);
mPendingIntent = PendingIntent.getActivity(this, 0,
new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
createTag(getIntent());
}
...
view raw gistfile1.java hosted with ❤ by GitHub

Pada code diatas, kita mengimport library NFC dan Mifare, lalu membuat variable berupa Tag, NFC, dan MifareClassic. Pada saat onCreate, semua variable ini diinisialisasi, dan fungsi handlernya juga diinisialisasi. Saya membuat dua fungsi handler yang dipanggil berdasarkan intent-nya. Yang akan saya jelaskan adalah createTag(getIntent()). Berikut isi createTag(getIntent()):

private void createTag(final Intent intent) {
final Thread thread = new Thread(this);
mTagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
if (mTagFromIntent != null) {
mClassic = MifareClassic.get(mTagFromIntent);
if (mClassic != null) {
/* Start the thread to read the DESFire */
thread.start();
}
}
}
/** Called on thread.start() */
@Override
public void run() {
writePoster();
/* Open dialog from handleMessage */
handler.sendEmptyMessage(1);
}
view raw gistfile1.java hosted with ❤ by GitHub

Code akan dieksekusi ketika muncul trigger berupa terdeteksinya NFC card/tag ke Android. Lihat line berikut:

mTagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);.

Variable mTagFromIntent di-bind dengan intent, ika intent tidak NULL, maka jalankan thread, dimana thread akan menjalankan fungsi writePoster() di background. Fungsi writePoster() adalah untuk melakukan koneksi dan transaksi data dengan NFC card/tag. Lihat code dibawah ini:

private void writePoster()
{
boolean succes = false;
try {
/* Connect to the Tag */
mClassic.connect();
/* Authenticate the MAD Sector, sector 0, with key A */
succes = mClassic.authenticateSectorWithKeyA(0, MifareClassic.KEY_MIFARE_APPLICATION_DIRECTORY );
if (succes) {
/* Authentication succeeded proceed to write */
} else {
/* Authentication failed */
}
mClassic.close();
}
/* Catch the TagLostException */
catch (final TagLostException tag) {
tag.printStackTrace();
}
/* Catch the IOException */
catch (final IOException e) {
e.printStackTrace();
}
String text = url;
writeRecord(1, text);
}
/**
* This method is used to write "URI record only" to NDEF
*/
private void writeRecord(int recordId, String text) {
NdefRecord uriRecord = NdefRecord.createUri(url);
NdefMessage message = new NdefMessage(uriRecord);
// Get an instance of Ndef for the tag.
Ndef ndef = Ndef.get(mTagFromIntent);
// Enable I/O
try {
ndef.connect();
}
catch (IOException e) {
e.printStackTrace();
}
// Write the message
try {
ndef.writeNdefMessage(message);
}
catch (Exception e) {
e.printStackTrace();
}
// Close the connection
try {
ndef.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
view raw gistfile1.java hosted with ❤ by GitHub

Pada code diatas, kita menulis data (NdefRecord) ke NFC card/tag berupa URI, sehingga ketika card ini dideteksi oleh Android, secara otomatis Android akan membuka web-bowser dan redirect page ke URI yang tertulis pada card/tag tersebut. Lihat line berikut:

NdefRecord uriRecord = NdefRecord.createUri(url);
NdefMessage message = new NdefMessage(uriRecord);

Adapun untuk jenis data yang lain, cara penulisannya berbeda. Jenis-jenis data yang bisa ditulis ke NFC dijelaskan pada spesifikasi NDEF (NFC Data Exchange Format), atau bisa juga dicek di Android SDK API berikut: http://developer.android.com/reference/android/nfc/NdefRecord.html

OK, sampai disini kita bisa melakukan fungsi write ke NFC tag berupa data URL. Selebihnya, code yang ada adalah bagian User Interface. Sebagai bonusnya, saya berikan contoh code sleek User Interface dengan fitur-fitur berikut:

  • Card Sliding Animation - mirip animasi card-nya Google Now
  • Tranparent Image Overlay - bisa dipakai untuk membuat UI tutorial, biasanya ditampilkan ketika user baru pertama buka aplikasi
  • Web View - web browser yang diembed di aplikasi
  • Multiple Page/Actvity with PushButton Intent - ini sih standard, yaitu perpindahan page/activity yang ditrigger PushButton

Code bisa didownload di https://github.com/yansyaf/android-smartposter-writer. Kalau ada pertanyaan, silakan comment dibawah. Enjoy! (ya2n)