net microframework untuk pemula -...

112
.NET Microframework Untuk Pemula Muhammad Ibnu Fadhil Gravicode Multinovative Plexindo 2017

Upload: ngoque

Post on 03-Feb-2018

226 views

Category:

Documents


2 download

TRANSCRIPT

.NET Microframework Untuk Pemula

Muhammad Ibnu Fadhil

Gravicode Multinovative Plexindo

2017

Pengantar Dunia pemrograman embedded electronic masih didominasi oleh bahasa-bahasa tingkat rendah, ini

tentu karena banyak pertimbangan seperti terbatasnya jumlah memory (RAM), kecepatan processor,

dan kapasitas penyimpanan (Flash). Buat rekan-rekan developer .NET yang ingin membangun solusi

untuk perangkat embedded dapat menggunakan .NET Microframework yaitu platform open source

yang dapat digunakan untuk membangun aplikasi embedded dengan bahasa C# dan VB dengan visual

studio.

Jadi beberapa kelebihan menggunakan .NET Microframework antara lain:

1. Menggunakan Visual Studio C# (bisa versi yang community juga alias free)

2. Open Source

3. Source code yang sama dapat berjalan dengan device yang berbeda

4. Debugger (Breakpoint, Stepping in code, Variables, Watcher, dsb..)

5. Sudah banyak digunakan di produk komersil dan industri dengan kualitas yang baik

6. Mendukung aneka jenis Bus Driver (SPI, UART, I2C, dsb)

7. Jika sudah menguasai programming .NET akan cepat sekali menguasai framework ini

8. Mengurangi ketergantungan terhadap datasheet prosesor karena sudah diabstraksi di level

HAL dan PAL

Target dari pembaca adalah developer, hobbyist dan engineer yang tertarik untuk mempelajari .NET

Microframework. Tidak diperlukan pengetahuan .NET yang mendalam sebelumnya karena dijelaskan

sedikit mengenai fundamental bahasa pemrograman yang digunakan.

Tujuan dari buku ini adalah agar pembaca bisa dengan cepat memahami konsep programming

embedded device dengan .NET Microframework dengan contoh source code yang siap untuk di

copy-paste.

Harapan penulis sangat sederhana, yaitu supaya rekan-rekan makers di Indonesia bisa maju dan

berkembang seperti negara-negara maju, dan buku ini bisa menjadi salah satu sumber referensi

untuk mengembangkan produknya yang berbasis .NET Microframework.

Alhamdulilah, penulis bersyukur pada Allah SWT karena diberikan kekuatan untuk menyelesaikan

buku ini, dan penulis berterimakasih pada orang-orang spesial yang selalu memberikan dukungan

dan kasih sayangnya yang tak berujung yaitu Babeh ZAM, Mum Imar, My lovely wifey Amanda dan

Bosku Hanna yang tersayang. Tak lupa sohib-sohib yang selalu ada dikala susah dan senang, Kang

Ousny, Mbae Atul, temen-temen di Gravicode, para makers keren Agus Kurniawan, Andri Yadi,

temen-temen di Buitenzorg Makers Club, Dirakit dan IoT4Bdg.

Penulis

Bogor, 04 Januari 2017

Daftar Isi Pengantar.......................................................................................................................................... 2

Daftar Isi............................................................................................................................................ 3

Persiapan dan Instalasi ...................................................................................................................... 6

Memilih Hardware (Development Board) ...................................................................................... 6

NETDUINO ................................................................................................................................. 6

Mikrobus.NET ............................................................................................................................ 6

GHI’s FEZ (Duino Style Dev Board) .............................................................................................. 7

Gadgeteer.................................................................................................................................. 8

Persiapan dan Instalasi Software (SDK, IDE, Drivers) ...................................................................... 9

Project Pertama Saya ...................................................................................................................... 10

Menulis Kode .............................................................................................................................. 10

Melakukan Debugging ................................................................................................................. 11

Menjalankan Aplikasi Pada Development Board .......................................................................... 12

.NET Microframework dan Dasar Pemrograman C# ......................................................................... 14

Apa itu .NET dan .NET Microframework ? .................................................................................... 14

Apa itu C# ? ................................................................................................................................. 14

Basic C# ....................................................................................................................................... 15

Semua Mulai dari Main Method............................................................................................... 15

Comment................................................................................................................................. 15

Looping.................................................................................................................................... 15

Variabel ................................................................................................................................... 16

Array dan Array List ................................................................................................................. 17

Ekspresi Logika......................................................................................................................... 18

Method dan Argument ............................................................................................................ 19

Class ........................................................................................................................................ 20

Public vs Private ....................................................................................................................... 22

Static vs Non Static .................................................................................................................. 23

Konstanta ................................................................................................................................ 24

Enumerasi................................................................................................................................ 24

Assembly ................................................................................................................................. 25

Menambahkan Assembly NETMF ............................................................................................. 25

Threading ................................................................................................................................ 26

Contoh Code (Snippets) ................................................................................................................... 27

Digital IO ..................................................................................................................................... 27

Digital Output .......................................................................................................................... 27

Digital Input ............................................................................................................................. 28

Interrupt Port .......................................................................................................................... 29

Tristate Port ............................................................................................................................. 30

PWM ....................................................................................................................................... 31

Analog Input ............................................................................................................................ 35

Analog Output ......................................................................................................................... 36

Bus Driver .................................................................................................................................... 37

UART (Serial)............................................................................................................................ 37

I2C ........................................................................................................................................... 39

SPI ........................................................................................................................................... 41

Folder dan File ............................................................................................................................. 43

Akses ke File dan Folder ........................................................................................................... 43

Large Memory Object dan Bitmap............................................................................................ 51

Membaca Resources ................................................................................................................ 52

Networking (Wifi & Ethernet) ...................................................................................................... 53

Lora ............................................................................................................................................. 59

Display dan Grafis ........................................................................................................................ 72

NETMF Native Graphic ............................................................................................................. 72

GHI Glide ................................................................................................................................. 74

Low Power................................................................................................................................... 76

3rd Party Tools dan Contoh Driver ................................................................................................ 78

Distance Sensor ....................................................................................................................... 78

Gas .......................................................................................................................................... 82

PIR Sensor................................................................................................................................ 83

NETMF Toolbox ....................................................................................................................... 83

Serialization ................................................................................................................................. 86

Json ......................................................................................................................................... 86

Class to Byte ............................................................................................................................ 87

RTC .............................................................................................................................................. 88

Membaca dan Menulis XML ........................................................................................................ 90

Register Access ............................................................................................................................ 93

Memory Management ................................................................................................................. 94

Timers ......................................................................................................................................... 95

Touch .......................................................................................................................................... 96

WAV Audio Playback ................................................................................................................. 100

Protokol Komunikasi IoT dan Embedded Device ........................................................................ 104

MQTT .................................................................................................................................... 104

AMQP .................................................................................................................................... 106

Azure IoT ............................................................................................................................... 108

ModBus ................................................................................................................................. 110

Fitur Spesial dari GHI ................................................................................................................. 111

CAN ....................................................................................................................................... 111

In-Field Update (IFU) .............................................................................................................. 111

SQLite .................................................................................................................................... 111

RLP ........................................................................................................................................ 111

USB Client .............................................................................................................................. 111

USB Host ................................................................................................................................ 112

Signal Generator .................................................................................................................... 112

Signal Capture........................................................................................................................ 112

Watchdog .............................................................................................................................. 112

Encryption (XTEA) .................................................................................................................. 112

Pulse Feedback ...................................................................................................................... 112

Pengetahuan Umum...................................................................................................................... 113

Update Firmware....................................................................................................................... 113

Menampilkan Boot Up Message ............................................................................................ 113

Garbage Collector ...................................................................................................................... 114

Hilangnya Referensi ............................................................................................................... 116

Dispose .................................................................................................................................. 118

Menampilkan Informasi GC .................................................................................................... 118

Referensi dan Sumber ................................................................................................................... 119

E-book ....................................................................................................................................... 119

Komunitas & Website ................................................................................................................ 119

Persiapan dan Instalasi

Memilih Hardware (Development Board) Pembaca bisa memilih beberapa hardware yang dapat digunakan untuk membangun aplikasi .NET

Microframework, beberapa pilihannya adalah sebagai berikut:

NETDUINO

Netduino memiliki form factor dan header seperti Arduino UNO, dan juga kompatibel dengan

beberapa shield Arduino. Beberapa variannya adalah Netduino 3, Netduino 3 ethernet, Netduino 3

Wifi. Perbedaannya terletak pada built-in network supportnya. Ada yang support wifi, Ethernet RJ45

Connector atau tanpa dukungan network.

Pelajari lebih lanjut di http://www.netduino.com/hardware/

Mikrobus.NET

Mikrobus.NET ini digarap oleh developer dan maker dari perancis, mereka melakukan porting

NETMF agar bisa running di Mikroelektronika Development Board yang berbasis STM32, yang special

dari board ini adalah Mikrobus Socket yang mendukung module Click Boards seperti dibawah ini.

Click board adalah nama dagang modul sensor / actuator yang diproduksi oleh Mikroelektronika

yang kompatibel dengan Mikrobus socket. Mikrobus.NET sudah berhasil memporting hampir seluruh

driver-driver click board ke NETMF. Beberapa board yang sudah tersedia dipasaran diantaranya

adalah Quail, Dalmatian dan Tuatara. Perbedaannya hanya sebatas jumlah socket Mikrobus dan

ukuran form factornya.

Pelajari lebih lanjut dari https://mikrobusnet.org/

GHI’s FEZ (Duino Style Dev Board)

GHI adalah manufaktur elektronik yang berbasis di Michigan, Amerika Serikat. Perusahaan ini

memproduksi beberapa development board yang support .NET Microframework antara lain Fez

Lemur, Fez Panda III, Fez Cobra III. Perbedaan yang mencolok diantara produk-produk tersebut

adalah fitur (Dukungan software dan jumlah bus interface dan GPIO) dan performanya (kecepatan

CPU, Jumlah Memory, Besar Flash), yang menarik dari produk-produk GHI adalah tambahan

ekstension software dan driver yang diberikan GHI seperti dukungan graphic, RLP (runtime loadable

procedures) memungkinkan kita mengeksekusi native code dari managed code (.NET) sehingga

performanya lebih cepat, SQLite, In-Field Update (untuk mengupdate firmware dari kode langsung),

RTC, USB Client/Host untuk mengakses input dan output melalui konektor USB, Watchdog, PPP,

Startup Logo, dsb. Board ini juga compatible dengan Arduino header.

Gadgeteer

Gadgeteer adalah konsep hardware modular yang dibuat oleh Microsoft Research UK. Intinya kita

dapat membangun solusi embedded kita dengan cara plug-n-play antara board dengan modulenya

melalui socket 10-pin. Berikut adalah penampakannya:

Beberapa manufaktur board Gadgeteer antara lain: GHI Electronics, Love Electronics, Micromint,

Mountaineer Group, Seeed Studio, Sytech design. Beberapa diantaranya sudah tidak lagi

memproduksi board tersebut. Konsep Gadgeteer sangat menarik karena sangat terintegrasi dengan

visual studio yang memiliki visual composer yaitu visualisasi desain hardware yang kita buat. Konsep

10 pin socket Gadgeteer juga tidak memungkinkan kita mencolok socket secara terbalik, dan

menyebabkan kerusakan pada board. Ketika modul-modul disambungkan dalam visual composer

otomatis driver-driver dari modul tersebut ditambahkan ke reference project kita secara otomatis,

dan kita bisa focus pada logic program kita. Gadgeteer sangat cocok buat developer yang ingin

memulai belajar pembuatan aplikasi embeddded.

Pelajari lebih lanjut di http://www.netmf.com/gadgeteer/

Setiap device biasanya disertakan tambahan driver dan aplikasi khusus dari manufakturnya, jadi

pastikan mengikuti guideline dari mereka untuk memastikan device yang kita gunakan sudah

menggunakan driver dan firmware/bootloader versi terakhir.

Persiapan dan Instalasi Software (SDK, IDE, Drivers)

Setelah membeli development board yang kita butuhkan, langkah selanjutnya adalah

mempersiapkan SDK, Tools dan IDE yang diperlukan untuk pengembangan aplikasi. Berikut adalah

langkah-langkahnya:

1. Download dan install Visual Studio 2013 Community dari

http://go.microsoft.com/fwlink/?LinkId=517284, Visual Studio 2015 belum disupport karena

masih ada problem dengan Roslyn, tapi kalau mau tetap memaksa mencoba dengan VS 2015

coba ikuti langkah di https://www.ghielectronics.com/docs/346/using-visual-studio-2015

2. Download SDK dan library NETMF dari http://netmf.codeplex.com/downloads/get/1423115,

unzip dan install file MicroFrameworkSDK.MSI baru selanjutnya file netmfvs2013.vsix

3. Opsional, kalau menggunakan device Gadgeteer silakan download dan install

http://gadgeteer.codeplex.com/downloads/get/1519812 dan

https://www.ghielectronics.com/support/netmf/sdk/41/ghi-electronics-netmf-sdk-2016-r1

4. Opsional, kalau menggunakan device Netduino download dan install

http://static.netduino.com/downloads/netduinosdk/netduinosdk.exe

Selesai deh, kalau mau verifikasi, silakan buka Visual Studio 2013 lalu buka menu, File > New >

Project. Di sebelah kiri cari “Micro Framework”, nanti penampakannya seperti gambar dibawah.

Project Pertama Saya

Menulis Kode Disini kita akan memulai membuat aplikasi NETMF (.NET Microframework) pertama kita. Ikuti

langkah berikut:

1. Buka Visual Studio 2013

2. Buat project baru : File > New > Project. Pilih “Micro Framework”, lalu pilih “Console

Application” Silakan isi name dengan “MyFirstApp”

3. Klik dua kali pada program.cs di sebelah kanan layar

4. Lalu ketik ubah source code program.cs menjadi seperti ini :

5.

6. Kemudian tekan tombol Start, untuk menjalankan aplikasi.

7. Otomatis emulator akan jalan dan lihat di jendela output dibagian bawah layar, akan muncul

tulisan seperti di kode di atas.

Melakukan Debugging

Untuk mendebug aplikasi silakan ubah kode aplikasi diatas menjadi seperti ini:

using System; using Microsoft.SPOT; namespace MyFirstApp { public class Program { public static void Main() { Debug.Print("Ini aplikasi pertama saya, hello cantik.."); } } }

Lalu masukan breakpoint (tanda bulat warna merah) di kode tersebut, dengan mengklik kiri dengan

mouse pada posisi breakpoint tersebut. Kemudian jalankan aplikasi dengan menekan tombol F5.

Program akan berhenti pada baris kode tersebut dan kita dapat mengekspeksinya dengan meng-

hover mouse ke variabel ‘i’. Coba tekan F5 kembali, maka variabel ‘i’ akan bertambah terus. Fitur ini

akan sangat bermanfaat ketika kita mencoba mengevaluasi code kita saat aplikasi dijalankan.

Gunakan “F10” untuk stepping code line by line, dan “F11” untuk stepping-in code, biasanya untuk

masuk ke dalam method.

Menjalankan Aplikasi Pada Development Board

Setelah kita melakukan instalasi SDK dan library NETMF, disitu disertakan tool untuk membantu kita

dalam mengecek, mengupdate device kita yaitu .NET Microframework Deployment Tool

(MFDEPLOY). Dengan tool ini kita bisa mengecek versi firmware, me-reboot CLR, melakukan flashing

firmware, melakukan konfigurasi network, SSL, dsb.

Silakan sambungkan development board dengan PC development menggunakan USB cable. Lalu

buka aplikasi MFDeploy, bisa dengan menekan tombol Start, ketik “MFDEPLOY” atau membuka

folder instalasi langsung dan mencari aplikasi tersebut. Lokasi defaultnya biasanya ada di

C:\ProgramData\Microsoft\Windows\Start Menu\Programs\Microsoft .NET Micro Framework 4.4,

silakan sesuaikan versinya.

Ikuti langkah berikut:

1. Pada combobox Device pilih USB

2. Otomatis device name kita akan muncul pada textbox disebelah kanan

3. Lalu klik menu: Plug-in > Debug > Show Device Info. Maka akan muncul informasi tentang

device tersebut.

4. Lalu kembali ke visual studio, kemudian ke menu : Project > MyFirstApp Properties.

5. 6. Kemudian disebelah kiri pilih .NET Microframework, pilih transport : USB, pilih device: sesuai

nama device yang muncul pada MFDeploy sebelumnya.

7. Kemudian jalankan aplikasi dengan menekan “F5”

8. Yihaa… sekarang aplikasi pertama sudah berhasil jalan di device kita, mudah khan ?

.NET Microframework dan Dasar Pemrograman C#

Apa itu .NET dan .NET Microframework ?

.NET adalah framework aplikasi yang dibuat oleh Microsoft, awalnya .NET dikembangkan khusus

untuk berjalan di lingkungan windows (.NET Framework) tapi saat ini sudah bisa berjalan di platform

lain seperti Linux dan MacOS dengan .NET Core atau Mono. .NET memiliki library yang sangat banyak

dan lengkap, sehingga ukurannya pun sangat besar. Saat ini developer dapat melakukan koding

sekali untuk menjalankannya di berbagai platform. Untuk menjalankan .NET di device yang lebih

kecil seperti PDA, Fingerprint Scanner, EDC, dsb microsoft membuat versi yang lebih compact yaitu

.NET Compact Framework, dan untuk mikrokontroller yang memiliki keterbatasan dalam processing

power dan jumlah ram dan flash maka dibuatlah .NET Microframework dan dapat berjalan tanpa OS.

Microsoft juga membuat OS khusus IoT yaitu Win 10 IoT Core.

Apa itu C# ?

C# adalah Bahasa pemrograman object oriented yang dikembangkan Microsoft untuk mendukung

pengembangan aplikasi berbasis .NET. Bahasa ini banyak mengadopsi syntax dan fitur dari C, C++.

Beberapa fiturnya antara lain garbage collector, run-time validation, type safe, interoperability,

scalable and updatable.

Basic C#

Semua Mulai dari Main Method

Aplikasi NETMF saat dijalankan akan mengeksekusi method main. Semua code didalam tanda kurung

“{ [code] }” tersebut akan dijalankan.

Comment

Komentar digunakan untuk memberi keterangan pada kode, seperti ini contohnya:

Komen diawali dengan tanda “//” atau diapit dengan tanda /* komentar anda */

Looping

Looping atau perulangan dapat dilakukan dengan 3 cara yaitu:

1. While loop: kondisi perulangan dicek di awal

2. Do-While loop: kondisi dicek di akhir

3. For loop: dapat mengulang kode blok dengan sebanyak repetisi tertentu

Berikut adalah contohnya:

/* ini adalah method yang pertama dijalankan */ public static void Main() { for (int i = 0; i < 10; i++) { //print tulisan ke luar Debug.Print("Ini aplikasi pertama saya, iterasi ke - "+ i); } }

Variabel

Variabel di C# di deklarasi dengan jenis type data lalu diikuti nama variabelnya.

Beberapa tipe data yang sering digunakan:

Tipe Data Keterangan int Angka bulat

double, float, single Angka desimal

char Karakter ASCII string Array dari karakter

byte Angka bulat (0-255)

bool Ya atau Tidak (true/false)

Contoh penggunaan seperti berikut ini:

using System; using Microsoft.SPOT; namespace MyFirstApp { public class Program { /* ini adalah method yang pertama dijalankan */ public static void Main() { //ini adalah contoh while-loop var counter = 0; while (counter < 10) { Debug.Print("Itung maju - " + counter); counter++; } //ini adalah contoh do-while do { Debug.Print("Itung mundur - " + counter); counter--; } while (counter > 0); //ini adalah contoh for-loop for (int x = 0; x < 100; x++) { Debug.Print(x + " x " + x + " = " + x * x); } } } }

Array dan Array List

Untuk menampung beberapa variabel dengan tipe sama kita gunakan array, untuk menampung

beberapa variabel dengan tipe yang sama atau berbeda kita dapat gunakan arraylist. Array memiliki

fixed size sedangkan arraylist memiliki dynamic size.

Berikut adalah contohnya:

using System; using Microsoft.SPOT; namespace MyFirstApp { public class Program { /* ini adalah method yang pertama dijalankan */ public static void Main() { //byte variabel byte a = 10; //array of byte byte[] b = new byte { 1, 2, 3 }; //char variabel char satu = '1'; char enter = (char)13; char[] test = "Hello".ToCharArray(); //variabel double double uang = 10.5; double hasil = uang * 100; //variabel int int angkabulat = int.Parse("11"); //string var SayHello = "Hallo say.."; string Nama = "Jojon Pelor"; //boolean bool Tidak = false; bool ApakahJonny = Nama == "Jonny" ? true : false; } } }

Ekspresi Logika

Digunakan untuk mengatur alur logika aplikasi. Beberapa syntaxnya antara lain :

1. If-then-else: digunakan untuk mengecek kondisi tertentu dengan statement ‘if’ jika tidak

sesuai maka akan ke blok ‘else’

2. Switch: digunakan untuk melakukan pencocokan variable dengan beberapa alternative nilai

tertentu.

Berikut adalah contoh penggunaannya:

using System; using Microsoft.SPOT; using System.Collections; namespace MyFirstApp { public class Program { public static void Main() { var DynamicData = new ArrayList { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; DynamicData.Add(9); Array data = DynamicData.ToArray(typeof(int)); var data2 = new int[10]; Array.Copy(data, data2, 10); } } }

Method dan Argument

Method adalah blok kode yang menjalankan fungsi tertentu atau aksi yang dilakukan oleh sebuah

object, method ini dapat mengembalikan nilai (function) atau tidak (void). Argument adalah

parameter yang kita kirimkan ke Method yang kita panggil, parameter bisa sebagai input atau

output. Berikut adalah contohnya:

using System; using Microsoft.SPOT; namespace MyFirstApp { public class Program { enum KondisiRobot { Mati, Standby, Maju, Mundur }; /* ini adalah method yang pertama dijalankan */ public static void Main() { Random x = new Random(); var AngkaAcak = x.Next(100); //contoh if statement if (AngkaAcak % 2 == 0) { Debug.Print(x + " adalah genap."); } else { Debug.Print(x + " adalah ganjil."); } //contoh switch statement KondisiRobot Status = KondisiRobot.Maju; switch (Status) { case KondisiRobot.Maju: case KondisiRobot.Mundur: Debug.Print("Bergerak"); break; case KondisiRobot.Mati: Debug.Print("Mati"); break; //jika kondisi selain diatas default: Debug.Print("Standby"); break; } } } }

Class

Di c# semua adalah object, dan object adalah representasi dari class. Class biasanya berisi property

dan method dengan level enkapsulasi tertentu yang membatasi akses terhadap isi class tersebut.

Class dapat diturunkan (inheritance). Analogi sederhana, class Manusia memiliki property Usia,

Gender, Tinggi, Berat dan memiliki Method Berjalan, Lari, Tidur, Makan, dsb. Berikut adalah

contohnya:

using System; using Microsoft.SPOT; namespace MyFirstApp { public class Program { /* ini adalah method yang pertama dijalankan */ public static void Main() { var hasil = Matematik.Tambah(10, 5); Debug.Print("hasil 10 + 5 = " + hasil); Matematik.Kali(10, 15, out hasil); Debug.Print("hasil 10 x 15 = " + hasil); var summary = Matematik.Sum(1,2,3,4,5,6,7,8); Debug.Print("hasil penjumlah 1-8 = " + summary); } } public class Matematik { //method dengan input parameter dan return value public static int Tambah(int a, int b) { return a + b; } //method dengan input dan output parameter public static void Kali(int a, int b, out int hasil) { hasil = a * b; } //method dengan parameter params public static int Sum(params int[] angka) { int hasil = 0; foreach (var x in angka) { hasil += x; } return hasil; } } }

using System; using Microsoft.SPOT; namespace MyFirstApp { public class Program { /* ini adalah method yang pertama dijalankan */ public static void Main() { //create object manusia Manusia otong = new Manusia(DateTime.Now, "Jonggol", Manusia.JenisKelamin.Cowok); //panggil method dari object manusia otong.Ultah(); otong.Jalan(); otong.Mati(); } //class manusia inherit dari makhluk public class Manusia : Makhluk { //property dari class public enum JenisKelamin { Cowok, Cewek, BanciKaleng }; public JenisKelamin Kelamin { set; get; } public string TempatLahir { set; get; } public bool IsHidup { set; get; } public DateTime TanggalLahir { set; get; } //constructor, saat instance dibuat dipanggil method ini public Manusia(DateTime Lahir, string TempatLahir, JenisKelamin Kelamin) { this.TempatLahir = TempatLahir; this.TanggalLahir = TanggalLahir; this.Kelamin = this.Kelamin; this.IsHidup = true; this.Jenis = JenisMakhluk.Nyata; this.Usia = 0; } //method jalan public void Jalan() { Debug.Print("Manusia berjalan."); } //method ultah public void Ultah() { Usia++; Debug.Print("Manusia usia jadi "+Usia); } //method mati public void Mati() { IsHidup = false; Debug.Print("Manusia mati"); } } //root class dari manusia public class Makhluk { public enum JenisMakhluk {Nyata, Ghaib}; public int Usia { set; get; } public JenisMakhluk Jenis { set; get; } } } }

Public vs Private

Method atau property dapat diatur aksesnya melalui syntax public, private dan protected.

Public : Ketika property/method ingin dapat diakses dari luar object

Private : ketika property/method hanya dapat diakses oleh class tersebut

Protected : ketika property/method hanya dapat diakses oleh class tersebut dan turunannya

Contoh:

Static vs Non Static

Tidak semua object dapat dicreate lebih dari 1 instance, sebagai contoh object debug dan method

print. Debug.Print(“Hello…”); karena aplikasi hanya jalan 1 buah dalam sekali eksekusi, sehingga

Debug dijadikan static method. Contoh lain adalah fungsi-fungsi matematik yang independent

karena semua parameter di input melalui method parameter. Math.Round, Math.Abs, dsb.

Static method hanya di create 1 kali dalam sekali eksekusi sehingga sangat hemat memory dan

sangat cepat eksekusinya, pertimbangkan untuk menggunakan static method dan variabel.

using System; using Microsoft.SPOT; namespace MyFirstApp { public class Program { /* ini adalah method yang pertama dijalankan */ public static void Main() { Robot bot = new Robot(); bot.IsiBaterai(100); bot.TambahSpeed(); Debug.Print("Kecepatan robot = "+bot.Speed); } public class Robot(){ private int Fuel{ private set;get; } public int Speed{ private set;get; } public void Jalan(){ Fuel--; } public void TambahSpeed(){ Speed++; } public void IsiBaterai(int InputPower){ Fuel+=InputPower; } } } }

Konstanta

Digunakan untuk variabel yang tidak pernah berubah nilainya. Contoh:

Enumerasi

Enum memudahkan kita dalam memberi nama suatu variabel yang tetap nilainya (constant).

Contoh:

Dapat diubah jadi:

using System; using Microsoft.SPOT; using Microsoft.SPOT.Hardware; namespace MyFirstApp { public class Program { static LaserSensor laser; /* ini adalah method yang pertama dijalankan */ public static void Main() { var jarak = laser.MeasureDistance(); } public class LaserSensor { AnalogInput sensor = new AnalogInput((Cpu.AnalogChannel)Cpu.AnalogChannel.ANALOG_7); public double MeasureDistance() { return sensor.Read(); } } } }

const double pi = 3.141592653589793238462643383279502884197169399375105820974944592307816406286;

const int MOVE = 1; const int STOP = 2; const int RIGHT = 3; const int LEFT = 4; SendCommand(MOVE); SendCommand(STOP);

enum Command { MOVE = 1, STOP = 2, RIGHT = 3, LEFT = 4, } SendCommand(Command.LEFT); SendCommand(Command.STOP);

Assembly

Assembly adalah file yang sudah decompile yang dapat dimasukan sebagai reference ke project kita.

Assembly biasanya dibuat dengan class library project di visual studio. Dengan assembly ini kita

dapat menyembunyikan source code karena sudah tercompile, walaupun dengan reflector kita

masih tetap bisa melakukan reverse engineering. ;)

Kalau kita lihat di source code bagian atas, terdapat reference name seperti using Microsoft.SPOT;

nah itu adalah contoh dari namespace assembly yang di reference ke project kita, sehingga kita

dapat menggunakan fungsi-fungsi yang ada di dalamnya. Namespace memudahkan kita dalam

mengorganisasi file-file project kita berdasarkan fungsi dan strukturnya.

Mungkin ada yang bertanya-tanya “SPOT” itu apa ? itu adalah awal mula namaproject .NET

Microframework yang dikembangkan oleh Microsoft, SPOT = .NET Microframework.

Menambahkan Assembly NETMF

Untuk menggunakan fungsi-fungsi yang ada di dalam assembly maka kita perlu menambahkannya ke

dalam project kita. Bagaimana caranya ? Ikuti langkah dibawah ini.

1. Di dalam project yang sudah terbuka, klik kanan pada nama project kita, lalu pilih Add

Reference.

2. Lalu masukan beberapa assembly dibawah ini

3. Kemudian tinggal masukan reference-nya dalam project kita seperti berikut:

4. Selesai… ;)

Threading

Prosesor / program hanya menjalankan 1 instruksi dalam satu waktu. Seperti saat kita melakukan

debugging program, baris demi baris. Tapi kok sepertinya bisa menjalankan semuanya bersamaan ?

yang dilakukan computer adalah task switching, yaitu mengerjakan satu pekerjaan dalam waktu

yang singkat, stop, lalu pindah ke pekerjaan lain, stop, dan ke pekerjaan-pekerjaan lainnya.

Untuk menggunakan threading dalam NETMF maka kita perlu menambahkan namespace

System.Threading. Sebagai contoh kita mau membuat aplikasi dengan 2 thread terpisah yang

pertama mengedipkan LED dan satu lagi melakukan iterasi penjumlahan.

Berikut adalah contoh penggunaan multi-threading di NETMF.

Contoh Code (Snippets)

Digital IO Pada prosesor terdapat digital pin yang dapat bernilai 1 atau 0. NETMF mendukung digital input dan

output, masukan reference ke “Microsoft.SPOT.Hardware” ke project untuk menggunakan fitur ini.

NOTE: Jika Anda memegang prosesor/board disarankan menggunakan sandal karet atau gelang anti

statis, agar tidak ada static discharge yang bisa merusak sirkuit elektronik.

Digital Output

Digital pin yang di set dengan nilai 1 berarti pin tersebut dialiri tegangan mendekati 3.3V, sedangkan

0 berarti pin tersebut memiliki tegangan mendekati 0V.

using System; using Microsoft.SPOT; using Microsoft.SPOT.Hardware; using System.Threading; namespace MyFirstApp { public class Program { static OutputPort LED = new OutputPort(Cpu.Pin.GPIO_Pin0, true); public static void Main() { //bikin thread 1 untuk jalankan method blinking led Thread th1 = new Thread(BlinkingLED); //start thread th1.Start(); //thread utama menjalankan counter var counter = 0; while (true) { counter++; Debug.Print("Itung " + counter); //delay 1 detik Thread.Sleep(1000); } } static void BlinkingLED() { while (true) { //nyala LED.Write(true); //delay 1 detik Thread.Sleep(1000); //mati LED.Write(false); Thread.Sleep(1000); } } } }

Biasanya digital output digunakan untuk menyalakan LED atau mendrive output pin lainnya seperti

modul relay. Berikut adalah contoh membuat blinking LED dengan output port:

Note: Jangan menempelkan dua output pin bersama, bisa merusak prosesor.

Digital Input

Digital input membaca tegangan yang masuk ke pin, maksimum tegangan yang masuk ke input pin

tidak boleh lebih besar dari tegangan yang digunakan untuk memberi power pada prosesor, kecuali

prosesor tersebut toleran terhadap tegangan yang lebih tinggi, Contoh: board EMX menggunakan

power sebesar 3.3V tapi 5V tolerant, itu berarti kita masih dapat membaca input pin dengan

tegangan maksimum 5V. Minimum tegangan juga 0V, jika dialiri tegangan negatif dapat merusak pin

/ prosesor.

Dengan NETMF kita dapat menggunakan class InputPort untuk membaca digital input. Jika input pin

tidak tersambung, maka akan terjadi floating, asumsi kita input pin yang tidak terkoneksi adalah low,

ini asumsi yang salah, karena noise yang terjadi pada input pin bisa mempengaruhi nilainya.

Solusinya adalah menggunakan pull-up dan pull-down resistor, untuk memberi nilai awal input pin.

Contoh dari input pin on-board button yang biasa terkoneksi pada loader pin, defaultnya adalah pull-

up, nilainya high. Tapi ketika button ditekan, nilainya low karena loader pin disambungkan ke

ground. Saat board di reset dan tombol ditekan, maka otomatis board masuk ke mode boot loader,

yang biasa digunakan untuk melakukan flashing.

Berikut adalah contoh penggunaan InputPort:

using System; using Microsoft.SPOT; using System.Collections; using Microsoft.SPOT.Hardware; using System.Threading; namespace MyFirstApp { public class Program { public static void Main() { OutputPort LED = new OutputPort(Cpu.Pin.GPIO_Pin0, true); while (true) { //on or off LED LED.Write(!LED.Read()); //delay 1 detik Thread.Sleep(1000); } } } }

Interrupt Port

Kadang kita perlu mengecek nilai suatu pin setiap saat, seperti ketika button di tekan, maka lampu

menyala. Jika menggunakan looping, maka banyak memakan waktu prosesor hanya untuk melihat

nilai suatu pin. Dengan Interrupt port kita dapat memanggil method ketika terjadi perubahan

tegangan dari tinggi ke rendah (low edge), atau rendah ke tinggi (high edge). Berikut adalah cara

penggunaannya:

using System; using Microsoft.SPOT; using System.Collections; using Microsoft.SPOT.Hardware; using System.Threading; namespace MyFirstApp { public class Program { public static void Main() { //init output port OutputPort LED = new OutputPort(Cpu.Pin.GPIO_Pin0, true); //init input port dengan default value high InputPort Button = new InputPort(Cpu.Pin.GPIO_Pin1, false, Port.ResistorMode.PullUp); while (true) { //nyalakan LED ketika button ditekan (nilai = true) dan sebaliknya LED.Write(Button.Read()); Thread.Sleep(10); } } } }

Note: Tidak semua pin di CPU mendukung interrupt

Tristate Port

Jika kita menginginkan sebuah pin secara simultan berfungsi sebagai digital input dan juga digital

output, maka kita dapat menggunakan dua metode, yang pertama dengan meng-assign pin sebagai

input/output lalu mendispose objeknya, kemudian meng-assignnya kembali dengan sebagai

input/output. Cara kedua adalah menggunakan tristate port yang berarti pin dapat memiliki state

sebagai input port, output high dan output low.

Note: Tristate hanya dapat digunakan pada pin yang mendukung interrupt

Ada permasalah jika pada awalnya kita mengeset sebuah pin sebagai output port, dan selanjutnya

mengesetnya kembali sebagai output port, hal ini akan menimbulkan error. Cara pencegahannya

dengan mengecek property “Active” jika nilainya true maka pin sedang dalam state sebagai Output,

jika false maka pin dalam state sebagai Input.

Berikut adalah contoh penggunaannya:

using System; using Microsoft.SPOT; using System.Collections; using Microsoft.SPOT.Hardware; using System.Threading; namespace MyFirstApp { public class Program { static OutputPort LED; public static void Main() { LED = new OutputPort(Cpu.Pin.GPIO_Pin0, true); var Tombol = new InterruptPort(Cpu.Pin.GPIO_Pin1, true, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeBoth); //berikan handler ketika terjadi signal edge Tombol.OnInterrupt += new NativeEventHandler(Tombol_OnInterrupt); Thread.Sleep(Timeout.Infinite); } static void Tombol_OnInterrupt(uint port, uint state, DateTime time) { //set LED sesuai statenya LED.Write(state == 0); } } }

PWM

PWM biasa kita gunakan untuk mengatur ratio pin antara state high dan low atau disebut “duty

cycle”. PWM bisa dilakukan melalui software atau hardware, dengan software kita gunakan class

SignalGenerator, sedangkan hardware kita gunakan built-in PWM pin yang ada di prosesor. PWM pin

lebih baik dari software karena pengaturannya independent, tidak menggunakan prosesor.

Objek dari PWM terdiri dari period dan duration dari pulse. Duration adalah lamanya pin dalam

posisi high (active), sedangkan period adalah waktu antara satu durasi dan durasi selanjutnya. Duty

cycle adalah rasio dari durasi dan period. Scale bisa di set di property PWM.

Cth: pin PWM yang memiliki duty cycle 0.5 berarti setengah waktu dalam posisi high dan

setengah waktu dalam posisi low.

Beberapa pemanfaatan PWM:

Mengatur brightness LED

Mengatur posisi servo Mengatur kecepatan motor Menghasilkan suara dan nada

Berikut adalah contoh codenya:

using System; using Microsoft.SPOT; using System.Collections; using Microsoft.SPOT.Hardware; using System.Threading; namespace MyFirstApp { public class Program { static void MakePinOutput(TristatePort port) { if (port.Active == false) port.Active = true; } static void MakePinInput(TristatePort port) { if (port.Active == true) port.Active = false; } public static void Main() { //init tristate pin TristatePort TriPin = new TristatePort(Cpu.Pin.GPIO_Pin0, false, false, Port.ResistorMode.PullUp); MakePinOutput(TriPin);// set pin sebagai output TriPin.Write(true); MakePinInput(TriPin);// set pin sebagai input Debug.Print(TriPin.Read().ToString()); } } }

LED Brightness

Menghasilkan Musical Tone

using System.Threading; using Microsoft.SPOT.Hardware; public class Program { static PWM MyFader = new PWM(Cpu.PWMChannel.PWM_0, 10000, 0.1, false); public static void Main() { double i = 0.0; while (true) { MyFader.DutyCycle = i; /* Panggil method start untuk me-refresh dutycycle */ MyFader.Start(); if ((i += 0.1) >= 1.0) { i = 0.0; } Thread.Sleep(10); } } }

Menggerakan Servo

using System.Threading; using Microsoft.SPOT.Hardware; public class Program { //masing2 note punya frequensi tertentu const int NOTE_C = 261; const int NOTE_D = 294; const int NOTE_E = 330; const int NOTE_F = 349; const int NOTE_G = 392; const int WHOLE_DURATION = 1000; const int EIGHTH = WHOLE_DURATION / 8; const int QUARTER = WHOLE_DURATION / 4; const int QUARTERDOT = WHOLE_DURATION / 3; const int HALF = WHOLE_DURATION / 2; const int WHOLE = WHOLE_DURATION; //dua array dibawah memiliki size yang sama, artinya array satu berisi note-nya dan array kedua berisi durasinya static int[] note = { NOTE_E, NOTE_E, NOTE_F, NOTE_G, NOTE_G, NOTE_F, NOTE_E, NOTE_D, NOTE_C, NOTE_C, NOTE_D, NOTE_E, NOTE_E, NOTE_D, NOTE_D, NOTE_E, NOTE_E, NOTE_F, NOTE_G, NOTE_G, NOTE_F, NOTE_E, NOTE_D, NOTE_C, NOTE_C, NOTE_D, NOTE_E, NOTE_D, NOTE_C, NOTE_C}; static int[] duration = { QUARTER, QUARTER, QUARTER, QUARTER, QUARTER, QUARTER, QUARTER, QUARTER, QUARTER, QUARTER, QUARTER, QUARTER, QUARTERDOT, EIGHTH, HALF, QUARTER, QUARTER, QUARTER, QUARTER, QUARTER, QUARTER, QUARTER, QUARTER, QUARTER, QUARTER, QUARTER, QUARTER, QUARTERDOT, EIGHTH, WHOLE}; public static void Main() { PWM MyPWM = new PWM(Cpu.PWMChannel.PWM_3, 261, 0.50, false); while (true) { for (int i = 0; i < note.Length; i++) { MyPWM.Stop(); MyPWM.Frequency = note[i]; MyPWM.Start(); Thread.Sleep(duration[i]); } Thread.Sleep(100); } } }

using System.Threading; using Microsoft.SPOT; using Microsoft.SPOT.Hardware; using System; public class Program { public static void Main() { Servo tt = new Servo(Cpu.PWMChannel.PWM_5); //set derajat tt.Degree = 30; tt.setRange(1000, 2000); tt.Dispose(); } public class Servo : IDisposable { private PWM servo; private int[] range = new int[2]; public bool inverted = false; public Servo(Cpu.PWMChannel channelPin) { servo = new PWM((Cpu.PWMChannel)channelPin, 20000, 1500, PWM.ScaleFactor.Microseconds, false); servo.Period = 20000; range[0] = 1000; range[1] = 2000; } public void Dispose() { disengage(); servo.Dispose(); } public void setRange(int fullLeft, int fullRight) { range[1] = fullLeft; range[0] = fullRight; } public void disengage() { servo.DutyCycle = 0; //SetDutyCycle(0); } public double Degree { set { if (value > 180) value = 180; if (value < 0) value = 0; if (inverted) value = 180 - value; servo.Duration = (uint)map((long)value, 0, 180, range[0], range[1]); servo.Start(); } } private long map(long x, long in_min, long in_max, long out_min, long out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; } } }

Analog Input

Analog input pin digunakan untuk membaca level tegangan, rangenya adalah dari low hingga ke

high. Untuk mikrokontroller yang menggunakan 3.3V, maka yang bisa dibaca dari 0 – 3.3V,

maksimum tegangan adalah sampai 3.3V, kalau inputnya lebih dari itu bisa menggunakan voltage

divider atau op-amp circuit.

Berikut contoh penggunaannya:

Analog Output

Analogi output mengeluarkan tegangan dari 0 hingga max. tegangan mikrokontroller, biasa di 3.3V.

Yang dihasilkan pin hanya signal, untuk menguatkan dibutuhkan operational amplifier circuit atau

semacamnya (cth: output ke speaker).

Presisi dari pin analog out ada di datasheet prosesor, sehingga nilai analog output yang actual adalah

perkiraan sesuai presisinya. Contoh, mikrokontroller dengan 8-bit (256 step) analog, memiliki presisi

sekitar 3.3V/256.

Pada NETMF, tegangan output berupa prosentase atau disebut “level”. Jadi untuk prosesor dengan

maksimum output sebesar 3.3V dan level 50% (0.5), perkiraan tegangan outputnya adalah 3.3V x 0.5

= 1.65V.

Dua property yang ada di class AnalogOutput:

1. Scale

2. OffSet

Dengan menggunakan property diatas maka perhitungan tegangan output:

Tegangan output = Maksimum Output * ( (Level * Scale) + Offset))

final voltages akan disesuaikan ke dalam rentang 0V sampai tegangan maksimum.

Berikut adalah contoh penggunaannya:

using System.Threading; using Microsoft.SPOT; using Microsoft.SPOT.Hardware; using System; public class Program { public static void Main() { AnalogInput lightSensor = new AnalogInput((Cpu.AnalogChannel)Cpu.AnalogChannel.ANALOG_7); double lightSensorReading = 0; while (true) { //baca data dari LDR (sensor cahaya) lightSensorReading = lightSensor.Read(); Debug.Print(lightSensorReading.ToString()); Thread.Sleep(500); } } }

Bus Driver

UART (Serial)

UART mengirim data dengan dua pin, pin TXD untuk mengirim dan RXD untuk menerima. Biasanya

untuk komunikasi antara dua device seperti mikrokontroller ke module atau mikrokontroller ke PC,

data dikirimkan dengan kecepatan yang ditentukan, secara sekuensial. Jadi biasanya pin TX dari

device A ke pin RX device B, dan pin RX device A dihubungkan ke pin TX device B.

Baud Rate adalah jumlah bit yang dikirim per detik. Standarnya biasanya di 9600, 119200, 115200,

dsb. Koneksi langsung antara pin TXD dan RXD menggunakan tegangan high/low untuk

merepresentasikan bit (TTL level, 0V – 3.3V).

NETMF mendukung komunikasi serial (UART) sama seperti .NET Framework. Port serial dinamakan

“COM ports”. Nama port dimulai dari COM1, dst. (tidak ada COM0). Sedangkan di prosesor biasa

tertulis UART0, jadi COM1 = UART0, COM2 = UART1, dst.

Penggunaan RS232 tidak bisa langsung disambungkan ke UART di mikrokontroller, karena low state

di RS232 adalah 12V, sedangkan di mikrokontroller 0V. Jadi untuk bisa menghubungkan RS232 ke

mikrokontroller kita butuh RS232 level to TTL seperti chip MAX232 atau level converter lainnya.

Berikut adalah contoh pengiriman data melalui UART:

using System.Threading; using Microsoft.SPOT; using Microsoft.SPOT.Hardware; using System; public class Program { public static void Main() { AnalogOutput output = new AnalogOutput(Cpu.AnalogOutputChannel.ANALOG_OUTPUT_0); output.Scale = 0.2; output.Write(0.5); //Output = (Level x Scale) x Max Volt. => 0.5 x 0.2 x 3.3v = 0.33V } }

Berikut adalah contoh penerimaan data melalui UART:

using System.IO.Ports; using System.Text; using System.Threading; public class Program { public static void Main() { //init UART0 atau COM1 dengan baudrate 115200 SerialPort UART = new SerialPort("COM1", 115200); int counter = 0; UART.Open(); while (true) { // bikin sampel teks string counter_string = "Count: " + counter.ToString() + "\r\n"; // ubah string ke array byte byte[] buffer = Encoding.UTF8.GetBytes(counter_string); // kirim data byte ke serial port UART.Write(buffer, 0, buffer.Length); // tambah counter counter++; // delay Thread.Sleep(100); } } }

using System.Threading; using System.IO.Ports; using System.Text; public class Program { public static void Main() { SerialPort UART = new SerialPort("COM1", 115200); int read_count = 0; byte[] rx_byte = new byte[1]; UART.Open(); while (true) { //baca 1 byte read_count = UART.Read(rx_byte, 0, 1); if (read_count > 0)// cek apakah ada data masuk { // tampilkan data yang diterima string counter_string = "Data diterima: " + rx_byte[0].ToString() + "\r\n"; // ubah lagi string ke byte byte[] buffer = Encoding.UTF8.GetBytes(counter_string); // kirim melalui serial port UART.Write(buffer, 0, buffer.Length); // delay Thread.Sleep(10); } } } }

I2C

I2C (baca: eye-squared-sea / eye-two-sea), dibuat oleh Phillips untuk membuat beberapa chipset

bisa berkomunikasi melalui 2-wire bus di perangkat elektronik rumah. Satu sebagai master dan

lainnya sebagai slave, slave device ini melakukan sharing data di bus yang sama. Setiap slave device

memiliki address masing-masing. Agar master bisa berkomunikasi dengan device slave tertentu ada

mekanisme addressing, dimana master mengirimkan address (7 bit data) slave yang dituju dan juga

mengirim 1 bit yang berisikan perintah untuk membaca atau menulis, device slave akan

menerimanya dan mengirimkan ack sebagai indikasi perintah diterima, kemudian master bisa

mengirim atau menerima data. Master akan mulai mengirim data dengan kondisi “start” sebelum

mengirim data atau address, dan selesai dengan kondisi “stop”.

I2C menggunakan 2 pin untuk komunikasi antara perangkat master dan slave. 2 pin tersebut

dinamakan SDA dan SCL, SDA berarti Serial Data dan SCL adalah Serial Clock.

Driver I2C NETMF berbasiskan transaksi, jika kita ingin membaca dari register di sebuah sensor,

pertama kita perlu mengirim no. register sensor yang ingin dibaca, lalu baru baca registernya. Kedua

hal tersebut terdiri dari 2 transaksi, menulis register dan dilanjutkan membaca register.

Hal yang perlu diketahui tentang I2C adalah perangkat I2C slave memiliki 7-bit address, tapi

sebenarnya yang dikirim master adalah 8-bit, ditambah 1 bit “control byte”, yang berisi informasi

apakah operasi yang dilakukan adalah baca (1) atau tulis (0).

Berikut adalah contoh komunikasi I2C dengan 1 device slave:

Dan berikut adalah contoh komunikasi dengan 2 device slave:

Perlu diketahui class I2C itu representasi dari BUS bukan devicenya, jadi untuk menghubungkan 1

master dengan beberapa device slave, cukup 1 object I2C tapi setiap mau melakukan transaksi

dikonfigurasi dulu I2C objeknya ke device slave yang akan dituju.

using Microsoft.SPOT; using Microsoft.SPOT.Hardware; public class Program { public static void Main() { //init I2C: masukan address device dan clock rate I2CDevice.Configuration con = new I2CDevice.Configuration(0x38, 400); I2CDevice MyI2C = new I2CDevice(con); // Buat transaksi, yang pertama adalah write dan kedua adalah read I2CDevice.I2CTransaction[] xActions = new I2CDevice.I2CTransaction[2]; // bikin write buffer, dengan 1 bit byte[] RegisterNum = new byte[1] { 2 }; xActions[0] = I2CDevice.CreateWriteTransaction(RegisterNum); // siap read buffer untuk baca data byte[] RegisterValue = new byte[1]; xActions[1] = I2CDevice.CreateReadTransaction(RegisterValue); // sekarang eksekusi transaksi dengan time out 1 detik // jika hasil eksekusi = 0 maka transaksi gagal // pastikan tidak ada masalah di wiring dan device slavenya if (MyI2C.Execute(xActions, 1000) == 0) { Debug.Print("Failed to perform I2C transaction"); } else { //data yang dibaca dari I2C slave Debug.Print("Register value: " + RegisterValue[0].ToString()); } } }

SPI

SPI menggunakan 3 atau 4 pin untuk mengirim data. Bus SPI bisa terdiri dari 1 master dan beberapa

perangkat slave. Pertama-tama, master akan mengirimkan clock ke slave bersama dengan data, dan

akan membaca data dengan clock yang sama. Clock digunakan untuk mengatur seberapa cepat data

bergerak (shift register).

Jadi master akan mengirim Clock melalui pin SCK (serial clock), dan secara bersamaan

mengirim data di pin MOSI (master out slave in). Slave akan membaca clock di pin SCK, dan secara bersamaan membaca data dari MOSI pin. Ini baru 1 arah komunikasi. Ketika data dikirim

using Microsoft.SPOT; using Microsoft.SPOT.Hardware; public class Program { public static void Main() { //siapkan konfigurasi untuk 2 device slave, sesuaikan aja ada berapa device I2CDevice.Configuration conDeviceA =new I2CDevice.Configuration(0x38, 400); I2CDevice.Configuration conDeviceB = new I2CDevice.Configuration(0x48, 400); //bikin I2C objek dengan konfigurasi device A I2CDevice MyI2C = new I2CDevice(conDeviceA); //siapkan transaksi I2CDevice.I2CTransaction[] xActions = new I2CDevice.I2CTransaction[2]; // siapkan write buffer 1 bit byte[] RegisterNum = new byte[1] { 2 }; xActions[0] = I2CDevice.CreateWriteTransaction(RegisterNum); // siapkan read buffer byte[] RegisterValue = new byte[1]; xActions[1] = I2CDevice.CreateReadTransaction(RegisterValue); //set config ke device A, untuk memilih device slave mana yang ingin dituju MyI2C.Config = conDeviceA; if (MyI2C.Execute(xActions, 1000) == 0) { Debug.Print("Failed to perform I2C transaction"); } else { //baca data dari device A Debug.Print("Register value: " + RegisterValue[0].ToString()); } // sekarang komunikasi dengan device B MyI2C.Config = conDeviceB; if (MyI2C.Execute(xActions, 1000) == 0) { Debug.Print("Failed to perform I2C transaction"); } else { //baca data dari device B Debug.Print("Register value: " + RegisterValue[0].ToString()); } } }

dari master ke slave melalui pin MOSI, 1 set data lainnya dikirimkan slave ke master melalui pin

MISO (master in slave out). NETMF mendukung 8-bit (byte) dan 16-bit (short) data transfer; Jika master terhubung dengan beberapa slave device, maka master akan memilih slave yang ingin dituju melalui pin (CS, chip select). Secara teori 1 master bisa memiliki banyak slave (tidak terbatas), tapi hanya bisa berkomunikasi dengan 1 slave dalam 1 waktu. Master ke slave butuh 3

kabel untuk konek ke semua slave (SCK, MOSI, MISO) dan beberapa kabel (sejumlah slave) untuk kabel CS untuk ke setiap slave.

Beberapa device SPI (slave) bisa memilihi lebih dari 1 pin CS. Contohnya VS1053 MP3 dekoder chip. 1 pin cs untuk menerima data, 1 lagi untuk mengirim command. Tapi dua-duanya share 3 pin yang sama (SCK, MISO, MOSI).

SPI memang menggunakan lebih banyak pin, tapi memiliki kecepatan transfer data yang cepat. 50 Mhz clock memungkinkan diterapkan di SPI, yang berarti 50 juta bit dalam 1 detik. Perangkat NETMF selalu sebagai master di SPI.

Sebelum membuat objek SPI, kita membutuhkan konfigurasi. Konfigurasi digunakan untuk mengatur state dari pin SPI dan parameter timing. Di beberapa kasus, kita cukup mengatur active state = false, clock idle = false dan clock edge = true, 0 untuk setup time dan hold time, dan yang perlu diatur hanya frekuensi clock, beberapa device bisa menerima frekuensi tinggi, lainnya tidak. Set frekuensi clock di 1000Khz (1 Mhz), cukup oke untuk memulai.

Contoh komunikasi SPI 1 master ke 1 slave:

Contoh SPI 1 master ke 2 slave:

using System.Threading; using Microsoft.SPOT.Hardware; public class Program { public static void Main() { //set freq SPI di 1 Mhz SPI.Configuration MyConfig = new SPI.Configuration(Cpu.Pin.GPIO_Pin1, false, 0, 0, false, true, 1000, SPI.SPI_module.SPI1); SPI MySPI = new SPI(MyConfig); //siapkan buffer untuk write dan read byte[] tx_data = new byte[10]; byte[] rx_data = new byte[10]; //lakukan transaksi MySPI.WriteRead(tx_data, rx_data); //delay Thread.Sleep(100); } }

Folder dan File

Akses ke File dan Folder

Akses file sytem di NETMF mirip dengan .NET Framework, tidak ada limit dengan ukuran file dan

jumlahnya. Terbatas sesuai spesifikasi FAT file system saja. NETMF support 2 jenis file system yaitu

FAT 16 dan FAT 32. Perbedaan NETMF dan .NET Framework terdapat pada kebutuhan melakukan

mounting pada media terlebih dahulu, dan perbedaan pada nama media.

Note: internal buffer digunakan untuk menulis data ke media penyimpanan, ini digunakan untuk

mempercepat akses dan memperpanjang usia media flash. Untuk memastikan data dari buffer

semua tersimpan dengan baik di media, kita butuh melakukan flush data. Untuk melakukannya

panggil code VolumeInfo.GetVolumes()[0].FlushAll() atau new

Microsoft.SPOT.IO.VolumeInfo("\SD").FlushAll().

Berikut adalah beberapa contoh cara mengakses file dan folder di SD/MMC dan USB Disk.

Note: contoh dibawah menggunakan assembly GHI.Hardware.dll

Melihat root folder dari SDCard:

using Microsoft.SPOT; using Microsoft.SPOT.Hardware; public class Program { public static void Main() { SPI.Configuration ConfigDeviceA = new SPI.Configuration(Cpu.Pin.GPIO_Pin1, false, 0, 0, false, true, 1000, SPI.SPI_module.SPI1); SPI.Configuration ConfigDeviceB = new SPI.Configuration(Cpu.Pin.GPIO_Pin4, false, 0, 0, false, true, 1000, SPI.SPI_module.SPI1); SPI MySPI = new SPI(ConfigDeviceA); byte[] tx_data = new byte[10]; byte[] rx_data = new byte[10]; // akses device A MySPI.Config = ConfigDeviceA; MySPI.WriteRead(tx_data, rx_data); Debug.Print("Read value:"+rx_data.ToString()); // akses device B MySPI.Config = ConfigDeviceB; MySPI.WriteRead(tx_data, rx_data); Debug.Print("Read value:" + rx_data.ToString()); } }

Menulis file ke SDCard:

using System.IO; using Microsoft.SPOT; using Microsoft.SPOT.Hardware; using Microsoft.SPOT.IO; using GHI.IO; using GHI.IO.Storage; class Program { public static void Main() { // Masukan SDCard dulu, NETMF cuma bisa baca 1 SDCard dalam 1 waktu SDCard sd_card = new SDCard(); // handler RemovableMedia.Insert akan dipanggil setelah mount selesai sd_card.Mount(); // jika handler insert dijalankan, status fs_ready jadi true bool fs_ready = false; RemovableMedia.Insert += (a, b) => { fs_ready = true; }; //tunggu sampai sd ready di akses while (!fs_ready) { System.Threading.Thread.Sleep(50); } // tampilkan file dan folder Debug.Print("Getting files and folders:"); if (VolumeInfo.GetVolumes()[0].IsFormatted) { string rootDirectory = VolumeInfo.GetVolumes()[0].RootDirectory; string[] files = Directory.GetFiles(rootDirectory); string[] folders = Directory.GetDirectories(rootDirectory); Debug.Print("Files available on " + rootDirectory + ":"); for (int i = 0; i < files.Length; i++) Debug.Print(files[i]); Debug.Print("Folders available on " + rootDirectory + ":"); for (int i = 0; i < folders.Length; i++) Debug.Print(folders[i]); } else { Debug.Print("Storage is not formatted. " + "Format on PC with FAT32/FAT16 first!"); } // Unmount jika sudah tidak digunakan sd_card.Unmount(); } }

Deteksi jika SDCard dipasang / lepas:

using System.Threading; using System.Text; using Microsoft.SPOT; using System.IO; using Microsoft.SPOT.IO; using GHI.IO.Storage; public class Program { static void Main() { SDCard sd_card = new SDCard(); sd_card.Mount(); bool fs_ready = false; RemovableMedia.Insert += (a, b) => { fs_ready = true; }; while (!fs_ready) { System.Threading.Thread.Sleep(1); } //tulis file teks dengan nama hello.txt di root string rootDirectory = VolumeInfo.GetVolumes()[0].RootDirectory; FileStream FileHandle = new FileStream(rootDirectory + @"\hello.txt", FileMode.Create); byte[] data = Encoding.UTF8.GetBytes("This string will go in the file!"); FileHandle.Write(data, 0, data.Length); FileHandle.Close(); sd_card.Unmount(); } }

using System; using System.IO; using System.Threading; using Microsoft.SPOT; using Microsoft.SPOT.IO; using GHI.IO.Storage; using Microsoft.SPOT.Hardware; public class Program { // evt digunakan tuk mastiin akses ke sdcard tidak dilakukan sebelum mount selesai dilakukan private static AutoResetEvent evt = new AutoResetEvent(false); //sambungkan ke pin SDcard detect private static InputPort sdCardDetect = new InputPort(Cpu.Pin.GPIO_NONE, false, Port.ResistorMode.Disabled); public static void Main() { RemovableMedia.Insert += new InsertEventHandler(RemovableMedia_Insert); RemovableMedia.Eject += new EjectEventHandler(RemovableMedia_Eject); // jalankan thread untuk mendeteksi jika ada sdcard yang dimasukan new Thread(SDMountThread).Start(); evt.WaitOne(); //tunggu sampai ada sdcard yang dimasukan dan berhasil di mount // program Anda } // method dijalankan ketika method unmount dipanggil, bukan pas sdcard di eject static void RemovableMedia_Eject(object sender, MediaEventArgs e) { Debug.Print("SD card unmounted, eject event fired"); } //dijalankan ketika proses mount selesai static void RemovableMedia_Insert(object sender, MediaEventArgs e) { Debug.Print("Insert event fired; SD card mount is finished."); //jika sdcard sudah di format, baca folder dan file di root if (e.Volume.IsFormatted) { Debug.Print("Available folders:"); string[] strs = Directory.GetDirectories(e.Volume.RootDirectory); for (int i = 0; i < strs.Length; i++) Debug.Print(strs[i]); Debug.Print("Available files:"); strs = Directory.GetFiles(e.Volume.RootDirectory); for (int i = 0; i < strs.Length; i++) Debug.Print(strs[i]); } else { Debug.Print("SD card is not formatted. Formatting..."); // format sdcard dengan file system FAT VolumeInfo.GetVolumes()[0].Format("FAT", 0); } evt.Set(); // lanjutkan proses di main thread }

Mengakses data di USB Disk:

Note: masukan reference ke assembly GHI.Usb.dll

public static void SDMountThread() { SDCard SD = null; const int POLL_TIME = 500; // cek setiap 0.5 detik bool sdExists; while (true) { try // ketika sdcard di eject saat di mount maka akan terjadi error exception { sdExists = sdCardDetect.Read(); // pastikan sdcard terpasang dengan baik if (sdExists) { Thread.Sleep(50); sdExists = sdCardDetect.Read(); } if (sdExists && SD == null) { SD = new SDCard(); SD.Mount(); } else if (!sdExists && SD != null) { SD.Unmount(); SD.Dispose(); SD = null; } } catch { if (SD != null) { SD.Dispose(); SD = null; } } Thread.Sleep(POLL_TIME); } } }

using System; using System.Threading; using System.IO; using Microsoft.SPOT; using System.Text; using Microsoft.SPOT.IO; using GHI.Usb; using GHI.Usb.Host; using GHI.IO.Storage; public class Program { // evt memastikan akses ke sdcard tidak dilakukan sebelum mounting selesai private static AutoResetEvent evt = new AutoResetEvent(false); private static MassStorage usb_storage; private static string rootDirectory; public static void Main() { RemovableMedia.Insert += new InsertEventHandler(RemovableMedia_Insert); RemovableMedia.Eject += new EjectEventHandler(RemovableMedia_Eject); // tidak seperti deteksi SDCard, usb host controller memanggil handler ketika ada usb device yang dicolok Controller.MassStorageConnected += (sender, massStorage) => { usb_storage = massStorage; usb_storage.Mount(); // panggil event insert begitu selesai }; Controller.Start(); evt.WaitOne(); // tunggu proses mounting beres byte[] data; // write data ke usb disk using (var FileHandle = new FileStream(rootDirectory + @"\hello.txt", FileMode.Create)) { data = Encoding.UTF8.GetBytes("This string will go in the file!"); FileHandle.Write(data, 0, data.Length); } // read data dari usb disk int read_count; using (var FileHandle = new FileStream(rootDirectory + @"\hello.txt", FileMode.Open, FileAccess.Read)) { data = new byte[100]; read_count = FileHandle.Read(data, 0, data.Length); } Debug.Print("The size of data we read is: " + read_count.ToString()); Debug.Print("Data from file:"); Debug.Print(new string(Encoding.UTF8.GetChars(data), 0, read_count)); usb_storage.Unmount(); } // handler ni dijalankan ketika method unmount dipanggil static void RemovableMedia_Eject(object sender, MediaEventArgs e) { Debug.Print("USB unmounted, eject event fired"); }

Large Memory Object dan Bitmap

Managed system NETMF membutuhkan Manajemen memory yang rumit, untuk membatasi agar

tidak terjadi overhead, NETMF hanya mendukung alokasi object sebesar 700KB saja. Untuk yang

lebih besar kita dapat menggunakan buffer yang lebih besar dengan custom heap. Dengan custom

heap kita dapat membuat buffer dan bitmap dengan ukuran yang besar. Secara internal, heap ini

tidak disimpan di heap standar melainkan di custom heap, di region memory yang terpisah.

Beberapa hal yang perlu diketahui agar custom heap dapat dibersihkan dari memory:

1. Referensi ke object harus di hapus

2. GC harus jalan

3. System harus dalam keadaan idle untuk menjalankan dispose object.

Custom heap tidak mudah dibersihkan dari memory, jadi kita perlu memanggil dispose begitu object

tersebut selesai digunakan.

Berikut adalah contoh penggunaan large buffer:

Note: code dibawah butuh referensi ke assembly Microsoft.SPOT.Hardware

static void RemovableMedia_Insert(object sender, MediaEventArgs e) { Debug.Print("Insert event fired; USB Storage mount is finished."); if (e.Volume.IsFormatted) { rootDirectory = e.Volume.RootDirectory; Debug.Print("Available folders:"); string[] strs = Directory.GetDirectories(e.Volume.RootDirectory); for (int i = 0; i < strs.Length; i++) Debug.Print(strs[i]); Debug.Print("Available files:"); strs = Directory.GetFiles(e.Volume.RootDirectory); for (int i = 0; i < strs.Length; i++) Debug.Print(strs[i]); } else { Debug.Print("Media is not formatted. Formatting..."); e.Volume.Format("FAT", 0); rootDirectory = e.Volume.RootDirectory; } evt.Set(); // lanjutkan proses thread main } }

Penggunaan Large Bitmap:

Note: bitmap yang lebih besar dari 192.000 pixel akan otomatis menggunakan custom heap. Cth:

800x600 bitmap butuh sekitar 800x600x4 bytes = 1.5 Mb. Jadi otomatis pake custom heap, jangan

lupa untuk men-dispose object.

Membaca Resources

Resources biasanya digunakan untuk menyimpan asset yang kita perlukan dalam aplikasi, bisa

berupa string, file, gambar, icon, sound, dsb. Resources akan dideploy bersama dengan aplikasi, jika

ukuran aplikasi dan resources lebih besar dari kapasitas yang tersedia di flash, maka akan error saat

melakukan deploy.

Resources dapat di akses dari solution explorer, lalu klik dua kali pada resources.resx. Lalu

tambahkan jenis resources yang diinginkan.

using System; using Microsoft.SPOT.Hardware; class Program { public static void Main() { // alokasi 1 mb buffer using (LargeBuffer lb = new LargeBuffer(1024 * 1024)) { // gunakan buffer lb.Bytes[5] = 123; } // begitu keluar dari branch using, dispose akan dipanggil } }

using System; using Microsoft.SPOT; using Microsoft.SPOT.Presentation.Media; class Program { public static void Main() { using (Bitmap largeBitmap = new Bitmap(800, 480)) { // bikin lingkaran largeBitmap.DrawEllipse(Color.White, 100, 100, 10, 10); largeBitmap.Flush();//tampilkan pada display } //otomatis object largebitmap di dispose } }

Berikut adalah cara mengakses resources dari aplikasi kita:

String Resources:

File teks:

Binary file:

Networking (Wifi & Ethernet)

Saat ini networking menjadi hal yang essensial dalam kehidupan, di rumah, kantor, sekolah, dan

lainnya. Network punya standard yaitu TCP/IP, ada beberapa protocol yang bisa kita gunakan

dengan fungsi yang berbeda-beda: DNS, DHCP, IP, ICMP, TCP, UDP, PPP, dan lainnya.

Saat menulis code, kita menggunakan class socket, socket memungkinkan komunikasi antara 1

perangkat dengan beberapa perangkat lainnya. Socket bisa menggunakan TCP, UDP dan lainnya.

Socket di NETMF mirip dengan di .NET Framework.

Berikut adalah contoh penggunaan network di NETMF:

Wifi

Note: contoh dibawah menggunakan modul wifi RS9110 GHI, dan referensi ke GHI.Networking.dll,

untuk module lain biasanya menggunakan driver yang berbeda

Debug.Print(Resources.GetString(Resources.StringResources.String1));

var str = Resources.GetString(Resources.StringResources.SomeFile);

byte[] file_data = Resources.GetBytes(Resources.BinaryResources.labamba);

Ethernet dengan ENC28 dengan contoh web request:

using GHI.Networking; using Microsoft.SPOT; using Microsoft.SPOT.Hardware; using Microsoft.SPOT.Net.NetworkInformation; using System; using System.Net; using System.Threading; public class Program { private static WiFiRS9110 netif; public static void Main() { NetworkChange.NetworkAvailabilityChanged += NetworkChange_NetworkAvailabilityChanged; NetworkChange.NetworkAddressChanged += NetworkChange_NetworkAddressChanged; //menggunakan modul wifirs9110 dari GHI netif = new WiFiRS9110(SPI.SPI_module.SPI1, Cpu.Pin.GPIO_Pin1, Cpu.Pin.GPIO_Pin2, Cpu.Pin.GPIO_Pin3); netif.Open(); netif.EnableDhcp(); netif.EnableDynamicDns(); netif.Join("SSID", "Password"); while (netif.IPAddress == "0.0.0.0") { Debug.Print("Waiting for DHCP"); Thread.Sleep(250); } //network sudah tersambung, siap digunakan } private static void NetworkChange_NetworkAddressChanged(object sender, Microsoft.SPOT.EventArgs e) { Debug.Print("Network address changed"); } private static void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e) { Debug.Print("Network availability: " + e.IsAvailable.ToString()); } }

using GHI.Networking; using Microsoft.SPOT; using Microsoft.SPOT.Hardware; using Microsoft.SPOT.Net.NetworkInformation; using System; using System.Net; using System.Threading; public class Program { private static EthernetENC28J60 netif; public static void Main() { NetworkChange.NetworkAvailabilityChanged += NetworkChange_NetworkAvailabilityChanged; NetworkChange.NetworkAddressChanged += NetworkChange_NetworkAddressChanged; netif = new EthernetENC28J60(SPI.SPI_module.SPI1, Cpu.Pin.GPIO_Pin1, Cpu.Pin.GPIO_Pin2, Cpu.Pin.GPIO_Pin3); netif.Open(); netif.EnableDhcp(); netif.EnableDynamicDns(); while (netif.IPAddress == "0.0.0.0") { Debug.Print("Waiting for DHCP"); Thread.Sleep(250); } //network ready byte[] result = new byte[65536]; int read = 0; using (var req = HttpWebRequest.Create("http://gravicode.com") as HttpWebRequest) { using (var res = req.GetResponse() as HttpWebResponse) { using (var stream = res.GetResponseStream()) { do { read = stream.Read(result, 0, result.Length); //cetak response Debug.Print(new string(System.Text.Encoding.UTF8.GetChars(result))); Thread.Sleep(20); } while (read != 0); } } } } private static void NetworkChange_NetworkAddressChanged(object sender, Microsoft.SPOT.EventArgs e) { Debug.Print("Network address changed"); } private static void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e) { Debug.Print("Network availability: " + e.IsAvailable.ToString()); } }

PPP, menggunakan GSM modem yang menggunakan komunikasi via UART:

using GHI.Networking; using Microsoft.SPOT.Net.NetworkInformation; using System.IO.Ports; using System.Text; using System.Threading; public class Program { private static AutoResetEvent evt; private static void Main() { evt = new AutoResetEvent(false); NetworkChange.NetworkAvailabilityChanged += NetworkChange_NetworkAvailabilityChanged; //set serial port using (var port = new SerialPort("YOUR COM PORT", 115200, Parity.None, 8, StopBits.One)) { port.Open(); port.DiscardInBuffer(); port.DiscardOutBuffer(); SendATCommand(port, "AT+CGDCONT=2,\"IP\",\"YOUR APN\""); SendATCommand(port, "ATDT*99***2#"); using (var netif = new PPPSerialModem(port)) { netif.Open();

netif.Connect(PPPSerialModem.AuthenticationType.Pap, "", ""); evt.WaitOne();

//network ready } } } private static void NetworkChange_NetworkAvailabilityChanged(object sender, NetworkAvailabilityEventArgs e) { if (e.IsAvailable) evt.Set(); } private static void SendATCommand(SerialPort port, string command) { var sendBuffer = Encoding.UTF8.GetBytes(command + "\r"); var readBuffer = new byte[256]; var read = 0; port.Write(sendBuffer, 0, sendBuffer.Length); while (true) { read += port.Read(readBuffer, read, readBuffer.Length - read); var response = new string(Encoding.UTF8.GetChars(readBuffer, 0, read)); if (response.IndexOf("OK") != -1 || response.IndexOf("CONNECT") != -1) break; } } }

SSL, untuk komunikasi yang aman gunakan SSL, saat ini hanya SSL2, SSL3, dan TLS1.0 yang didukung

NETMF. Tidak seperti PC, perangkat NETMF tidak memiliki database root certificate yang

digunakan untuk memverifikasi remote server. Sehingga kita perlu secara manual memasukan

root certificate untuk site tertentu. Caranya sbb:

1. Buka site di browser

2. Klik tanda gembok deket address bar

3. View certificate, dan buka tab Certification Path

4. Klik (the root) certificate entry paling atas, lihat, dibagian Details, kopi ke file, pastikan

menggunakan base 64 encoding, tambahkan file ini sebagai resources di project.

Cara ini belum tentu bisa digunakan, kadang-kadang beberapa site menggunakan certificate

yang berbeda berdasarkan siapa yang mengakses. Gunakan pencarian online atau tool

wireshark untuk mengetahui dengan benar certificate apa yang sebenarnya digunakan di site

tersebut.

Contoh penggunaan SSL:

Untuk akses network yang lebih komplit bisa gunakan library MIP, http://mip.codeplex.com/

Lora

Lora adalah teknologi wireless yang biasa digunakan untuk komunikasi M2M dan IoT. Lora

menggunakan modulasi tertentu dan frekuensi FM. Lora sangat hemat energy dan memiliki rentang

pengiriman yang jauh (sampai 20km di daerah terbuka, line of sight). Tapi ukuran data yang

dikirimkan sangat kecil. Berikut ini adalah contoh penggunaan Lora dengan modul RN2483 dari

Microchip menggunakan NETMF.

Mengirim data dengan Lora (point to point):

static void DownloadOverSsl(string url, byte[] certificate) { using (var request = HttpWebRequest.Create(url) as HttpWebRequest) { request.HttpsAuthentCerts = new X509Certificate[] { new X509Certificate(certificate) }; request.KeepAlive = false; using (var response = request.GetResponse()) { using (var stream = response.GetResponseStream()) { var result = string.Empty; var buffer = new byte[4096]; var read = 0; stream.ReadTimeout = 5000; for (var left = response.ContentLength; left > 0; ) { Thread.Sleep(1000); try { read = stream.Read(buffer, 0, buffer.Length); } catch { continue; } left -= read; result += new string(Encoding.UTF8.GetChars(buffer, 0, read)); } Debug.Print(result); } } } }

using GHI.Networking; using Microsoft.SPOT; using Microsoft.SPOT.Hardware; using Microsoft.SPOT.Net.NetworkInformation; using MyFirstApp; using System; using System.Collections; using System.Net; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading; namespace MyFirstApp { public class Program { static int Counter = 0; //LORA setting.. private static SimpleSerial _loraSerial; private static string[] _dataInLora; //sesuaikan reset pin di RN2483 static OutputPort _restPort = new OutputPort(Cpu.Pin.GPIO_Pin1, true); static string rx; public static void Main() { Debug.Print("INIT LORA RADIO"); //LORA init _loraSerial = new SimpleSerial("COM1", 57600); _loraSerial.Open(); _loraSerial.DataReceived += _loraSerial_DataReceived; //reset lora _restPort.Write(false); Thread.Sleep(1000); _restPort.Write(true); Thread.Sleep(1000); //setup lora for point to point //get lora version _loraSerial.WriteLine("sys get ver"); Thread.Sleep(1000); //pause join _loraSerial.WriteLine("mac pause"); Thread.Sleep(1000); //set antena power _loraSerial.WriteLine("radio set pwr 14"); Thread.Sleep(1000); new Thread(SendData).Start(); } static void SendData() { //loop forever for (; ; ) { string data = "Data ke " + Counter; byte[] b = Encoding.UTF8.GetBytes(data); string hex = "radio tx " + ToHexString(b, 0, b.Length); // TX payload needs to be HEX //send data via lora _loraSerial.WriteLine(hex); Debug.Print("TRANSMIT DATA " + (Counter++)); //delay 5 sec Thread.Sleep(5000); } }

//convert byte to hex public static string ToHexString(byte[] value, int index, int length) { char[] c = new char[length * 3]; byte b; for (int y = 0, x = 0; y < length; ++y, ++x) { b = (byte)(value[index + y] >> 4); c[x] = (char)(b > 9 ? b + 0x37 : b + 0x30); b = (byte)(value[index + y] & 0xF); c[++x] = (char)(b > 9 ? b + 0x37 : b + 0x30); } return new string(c, 0, c.Length - 1); } //lora data received static void _loraSerial_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) { //do nothing } } public static class ByteExt { private static char[] _hexCharacterTable = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; public static string ToHexString(this byte[] array, string delimiter = "-") { if (array.Length > 0) { // it's faster to concatenate inside a char array than to // use string concatenation char[] delimeterArray = delimiter.ToCharArray(); char[] chars = new char[array.Length * 2 + delimeterArray.Length * (array.Length - 1)]; int j = 0; for (int i = 0; i < array.Length; i++) { chars[j++] = (char)_hexCharacterTable[(array[i] & 0xF0) >> 4]; chars[j++] = (char)_hexCharacterTable[array[i] & 0x0F]; if (i != array.Length - 1) { foreach (char c in delimeterArray) { chars[j++] = c; } } } return new string(chars); } else { return string.Empty; } } } }

Menerima data dengan Lora (point to point):

using GHI.Networking; using Microsoft.SPOT; using Microsoft.SPOT.Hardware; using Microsoft.SPOT.Net.NetworkInformation; using MyFirstApp; using System; using System.Collections; using System.Net; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Threading; namespace MyFirstApp { public class Program { //lora init private static SimpleSerial _loraSerial; private static string[] _dataInLora; //lora reset pin, sesuaikan sesuai data sheet static OutputPort _restPort = new OutputPort(Cpu.Pin.GPIO_Pin1, true); private static string rx; public static void Main() { //reset lora _restPort.Write(false); Thread.Sleep(1000); _restPort.Write(true); Thread.Sleep(1000); _loraSerial = new SimpleSerial("COM1", 57600); _loraSerial.Open(); _loraSerial.DataReceived += _loraSerial_DataReceived; //get version _loraSerial.WriteLine("sys get ver"); Thread.Sleep(1000); //pause join _loraSerial.WriteLine("mac pause"); Thread.Sleep(1500); //antena power _loraSerial.WriteLine("radio set pwr 14"); Thread.Sleep(1500); //set device to receive _loraSerial.WriteLine("radio rx 0"); //set module to RX Debug.Print("LORA-RN2483 setup has been completed..."); } //convert hex to string string HexStringToString(string hexString) { if (hexString == null || (hexString.Length & 1) == 1) { throw new ArgumentException(); } var sb = new StringBuilder(); for (var i = 0; i < hexString.Length; i += 2) { var hexChar = hexString.Substring(i, 2); sb.Append((char)Convert.ToByte(hexChar)); } return sb.ToString(); }

//convert hex to ascii private string HexString2Ascii(string hexString) { StringBuilder sb = new StringBuilder(); for (int i = 0; i <= hexString.Length - 2; i += 2) { int x = Int32.Parse(hexString.Substring(i, 2)); sb.Append(new string(new char[] { (char)x })); } return sb.ToString(); } //lora data received static void _loraSerial_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e) { _dataInLora = _loraSerial.Deserialize(); for (int index = 0; index < _dataInLora.Length; index++) { rx = _dataInLora[index]; //if error if (_dataInLora[index].Length > 7) { if (rx.Substring(0, 9) == "radio_err") { Debug.Print("!!!!!!!!!!!!! Radio Error !!!!!!!!!!!!!!"); Debug.Print("Radio Error"); _restPort.Write(false); Thread.Sleep(1000); _restPort.Write(true); Thread.Sleep(1000); _loraSerial.WriteLine("mac pause"); Thread.Sleep(1000); _loraSerial.WriteLine("radio rx 0"); return; } //if receive data if (rx.Substring(0, 8) == "radio_rx") { string hex = _dataInLora[index].Substring(10); Thread.Sleep(500); Debug.Print(hex); Debug.Print(Unpack(hex)); //tampilkan data yang diterima Debug.Print(Unpack(hex)); Thread.Sleep(100); // set module to RX _loraSerial.WriteLine("radio rx 0"); } } } }

//extract hex to string public static string Unpack(string input) { byte[] b = new byte[input.Length / 2]; for (int i = 0; i < input.Length; i += 2) { b[i / 2] = (byte)((FromHex(input[i]) << 4) | FromHex(input[i + 1])); } return new string(Encoding.UTF8.GetChars(b)); } public static int FromHex(char digit) { if ('0' <= digit && digit <= '9') { return (int)(digit - '0'); } if ('a' <= digit && digit <= 'f') return (int)(digit - 'a' + 10); if ('A' <= digit && digit <= 'F') return (int)(digit - 'A' + 10); throw new ArgumentException("digit"); } }

Class helper untuk komunikasi serial:

public static class ByteExt { private static char[] _hexCharacterTable = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; public static string ToHexString(this byte[] array, string delimiter = "-") { if (array.Length > 0) { // it's faster to concatenate inside a char array than to // use string concatenation char[] delimeterArray = delimiter.ToCharArray(); char[] chars = new char[array.Length * 2 + delimeterArray.Length * (array.Length - 1)]; int j = 0; for (int i = 0; i < array.Length; i++) { chars[j++] = (char)_hexCharacterTable[(array[i] & 0xF0) >> 4]; chars[j++] = (char)_hexCharacterTable[array[i] & 0x0F]; if (i != array.Length - 1) { foreach (char c in delimeterArray) { chars[j++] = c; } } } return new string(chars); } else { return string.Empty; } } } }

using System; using System.Text; namespace MyFirstApp { public class SimpleSerial : System.IO.Ports.SerialPort { // CONSTRUCTORS -- Pass the Buck public SimpleSerial(string portName, int baudRate, System.IO.Ports.Parity parity, int dataBits, System.IO.Ports.StopBits stopBits) : base(portName, baudRate, parity, dataBits, stopBits) { } public SimpleSerial(string portName, int baudRate, System.IO.Ports.Parity parity, int dataBits) : base(portName, baudRate, parity, dataBits) { } public SimpleSerial(string portName, int baudRate, System.IO.Ports.Parity parity) : base(portName, baudRate, parity) { } public SimpleSerial(string portName, int baudRate) : base(portName, baudRate) { } public SimpleSerial(string portName) : base(portName) { } public void Write(string txt) { base.Write(Encoding.UTF8.GetBytes(txt), 0, txt.Length); } public void WriteLine(string txt) { this.Write(txt + "\r\n"); } public byte[] ReadExistingBinary() { int arraySize = this.BytesToRead; byte[] received = new byte[arraySize]; this.Read(received, 0, arraySize); return received; } public string ReadExisting() { try { return new string(Encoding.UTF8.GetChars(this.ReadExistingBinary())); } catch (Exception) { return string.Empty; } } public new void Open() { this._Remainder = string.Empty; // clear the remainder so it doesn't get mixed with data from the new session base.Open(); }

private string _Remainder = string.Empty; public string Remainder { get { return this._Remainder; } } public string[] Deserialize(string delimiter = "\r\n") { string receivedData = string.Concat(this._Remainder, this.ReadExisting()); // attach the previous remainder to the new data return SplitString(receivedData, out this._Remainder, delimiter); // return itemized messages and store remainder for next pass } private static string[] SplitString(string input, out string remainder, string delimiter = "\r\n", bool includeDelimiterInOutput = false) { string[] prelimOutput = input.Split(delimiter.ToCharArray()); if (prelimOutput[prelimOutput.Length - 1] == string.Empty) remainder = string.Empty; // input string terminated in a delimiter, so there is no remainder else { remainder = prelimOutput[prelimOutput.Length - 1]; // store the remainder prelimOutput[prelimOutput.Length - 1] = string.Empty; // remove the remainder string from prelimOutput to avoid redundancy } if (includeDelimiterInOutput == true) return ScrubStringArray(prelimOutput, removeString: string.Empty, delimiter: delimiter); else return ScrubStringArray(prelimOutput, removeString: string.Empty, delimiter: string.Empty); } private static string[] ScrubStringArray(string[] input, string removeString = "", string delimiter = "\r\n") { int numOutputElements = 0; for (int k = 0; k < input.Length; k++) { if (input[k] != removeString) numOutputElements++; } string[] output = new string[numOutputElements]; int m = 0; // output index for (int k = 0; k < input.Length; k++) { if (input[k] != removeString) { output[m] = input[k] + delimiter; m++; } } return output; } } }

Menggunakan LoraWAN (Class A): LoraWAN adalah spesifikasi Low Power Wide Area Network,

protocol komunikasi berbasis Lora. Untuk mengirimkan data ke lora gateway berikut adalah

contohnya:

using System; using System.Collections; using System.Threading; using Microsoft.SPOT; using Microsoft.SPOT.Presentation; using Microsoft.SPOT.Presentation.Media; using Microsoft.SPOT.Touch; using System.IO.Ports; using System.Text; using Microsoft.SPOT.Hardware; namespace MyFirstApp { public partial class Program { SerialPort UART = null; // This method is run when the mainboard is powered up or reset. void ProgramStarted() { // Use Debug.Print to show messages in Visual Studio's "Output" window during debugging. Debug.Print("Program Started"); UART = new SerialPort("COM1", 57600); UART.ReadTimeout = 0; Debug.Print("57600"); Debug.Print("RN2483 Test");

OutputPort reset = new OutputPort(GHI.Pins.FEZSpiderII.Socket8.Pin6, false);

//reset lora reset.Write(true); Thread.Sleep(50); reset.Write(false); Thread.Sleep(50); reset.Write(true); Thread.Sleep(50); waitForResponse(); sendCmd("sys factoryRESET"); sendCmd("sys get hweui"); sendCmd("mac get deveui"); // For TTN sendCmd("mac set devaddr AABBCCDD"); // Set own address sendCmd("mac set appskey 2B7E151628AED2A6ABF7158809CF4F3C"); //apps key sendCmd("mac set nwkskey 2B7E151628AED2A6ABF7158809CF4F3C"); //network key sendCmd("mac set adr off"); sendCmd("mac set rx2 3 869525000"); //freq : 869 Mhz sendCmd("mac join abp"); //method : abp sendCmd("mac get status"); sendCmd("mac get devaddr"); Thread.Sleep(1000); Thread th1 = new Thread(new ThreadStart(Loop)); th1.Start(); }

void Loop() { Debug.Print("Ready"); while (true) { string dataStr = "data kiriman "+DateTime.Now; sendData(dataStr); Thread.Sleep(5000); byte[] rx_data = new byte[20]; if (UART.CanRead) { var count = UART.Read(rx_data, 0, rx_data.Length); if (count > 0) { Debug.Print("count:" + count); var hasil = new string(System.Text.Encoding.UTF8.GetChars(rx_data)); Debug.Print("read:" + hasil); } } Thread.Sleep(5000); } } void sendCmd(string cmd) { byte[] rx_data = new byte[20]; Debug.Print(cmd); Debug.Print("\n"); // flush all data UART.Flush(); // send some data var tx_data = Encoding.UTF8.GetBytes(cmd); UART.Write(tx_data, 0, tx_data.Length); tx_data = Encoding.UTF8.GetBytes("\r\n"); UART.Write(tx_data, 0, tx_data.Length); Thread.Sleep(100); while (!UART.IsOpen) { UART.Open(); Thread.Sleep(100); } if (UART.CanRead) { var count = UART.Read(rx_data, 0, rx_data.Length); if (count > 0) { Debug.Print("count:" + count); var hasil = new string(System.Text.Encoding.UTF8.GetChars(rx_data)); Debug.Print("read:" + hasil); } } }

void waitForResponse() { byte[] rx_data = new byte[20]; while (!UART.IsOpen) { UART.Open(); Thread.Sleep(100); } if (UART.CanRead) { var count = UART.Read(rx_data, 0, rx_data.Length); if (count > 0) { Debug.Print("count:" + count); var hasil = new string(System.Text.Encoding.UTF8.GetChars(rx_data)); Debug.Print("read:" + hasil); } } } char getHexHi(char ch) { int nibbleInt = ch >> 4; char nibble = (char)nibbleInt; int res = (nibble > 9) ? nibble + 'A' - 10 : nibble + '0'; return (char)res; } char getHexLo(char ch) { int nibbleInt = ch & 0x0f; char nibble = (char)nibbleInt; int res = (nibble > 9) ? nibble + 'A' - 10 : nibble + '0'; return (char)res; }

Display dan Grafis

NETMF menyediakan library untuk menampilkan grafis di layar, dan GHI juga membuat satu library

free yang dapat digunakan yaitu Glide. Mari kita simak satu persatu fiturnya.

NETMF Native Graphic

NETMF memiliki dukungan grafis melalui class Bitmap. Dengan class ini kita dapat menggambar

berbagai shape, menulis teks, dan gambar dari tipe BMP, JPG, GIF yang dapat kita ambil dari file

system, network atau resources aplikasi.

Saat menggambar dengan Bitmap, semuanya akan di-render di objek in-memory yang ukurannya

sesuai dengan layar yang digunakan. Untuk mengirim gambar dari memory ke layar, kita dapat

menggunakan method Flush pada objek Bitmap. Method ini hanya akan berfungsi jika ukuran

gambar sesuai dengan ukuran layar, jika tidak maka tidak ada yang akan tampil.

void sendData(string msg) { byte[] rx_data = new byte[20]; char[] data = msg.ToCharArray(); Debug.Print("mac tx uncnf 1 "); var tx_data = Encoding.UTF8.GetBytes("mac tx uncnf 1 "); UART.Write(tx_data, 0, tx_data.Length); // Write data as hex characters foreach (char ptr in data) { tx_data = Encoding.UTF8.GetBytes(new string(new char[] { getHexHi(ptr) })); UART.Write(tx_data, 0, tx_data.Length); tx_data = Encoding.UTF8.GetBytes(new string(new char[] { getHexLo(ptr) })); UART.Write(tx_data, 0, tx_data.Length); Debug.Print(new string(new char[] { getHexHi(ptr) })); Debug.Print(new string(new char[] { getHexLo(ptr) })); } tx_data = Encoding.UTF8.GetBytes("\r\n"); UART.Write(tx_data, 0, tx_data.Length); Debug.Print("\n"); Thread.Sleep(5000); if (UART.CanRead) { var count = UART.Read(rx_data, 0, rx_data.Length); if (count > 0) { Debug.Print("count:" + count); var hasil = new string(System.Text.Encoding.UTF8.GetChars(rx_data)); Debug.Print("read:" + hasil); } } } } }

Beberapa mikrokontroller kecil tidak memiliki LCD controller, biasanya untuk menampilkan gambar

dilayar, device ini menggunakan display dengan SPI. Beberapa Display SPI mendukung method flush,

jika tidak gunakan driver bawaan dari display tersebut.

Berikut adalah contoh menggambar dengan Bitmap:

Note: masukan referensi ke assembly Microsoft.SPOT.TinyCore;

Menulis teks:

Note: contoh font terdapat di folder : C:\Program Files (x86)\Microsoft .NET Micro

Framework\v4.3\Fonts , tambahkan ke dalam resources aplikasi.

Contoh konfigurasi SPI Display:

using Microsoft.SPOT; using Microsoft.SPOT.Presentation; using Microsoft.SPOT.Presentation.Media; namespace MyFirstApp { public class Program { public static void Main() { Bitmap lcd = new Bitmap(SystemMetrics.ScreenWidth, SystemMetrics.ScreenHeight); lcd.DrawLine(Colors.Green, 1, 20, 20, 40, 40); lcd.DrawEllipse(Colors.Blue, 5, 5, 5, 5); lcd.Flush(); } } }

using Microsoft.SPOT; using Microsoft.SPOT.Presentation; using Microsoft.SPOT.Presentation.Media; namespace MyFirstApp { public class Program { public static void Main() { Font font = Resources.GetFont(Resources.FontResources.NinaB); Bitmap lcd = new Bitmap(SystemMetrics.ScreenWidth, SystemMetrics.ScreenHeight); lcd.DrawText("Hello, World!", font, Colors.White, 0, 0); lcd.Flush(); } } }

GHI Glide

Glide adalah library grafik buatan GHI, GHI menyediakan glide designer pada tautan berikut:

https://www.ghielectronics.com/glide/designer. Dengan Glide designer kita bisa mendesain

tampilan aplikasi seperti membuat aplikasi desktop, drag n drop. Setelah itu Glide designer akan

menghasilkan xml dari desain yang kita buat. XML ini kita dapat masukan sebagai file teks di dalam

resources aplikasi kita.

Glide lebih responsif daripada built-in WPF di NETMF. Tersedia beberapa component seperti button,

list, keyboard, message box. Selama display yang kita gunakan mendukung bitmap class maka kita

dapat menggunakan Glide.

Berikut adalah contoh penggunaan Glide:

Kita menghasilkan XML dari glide designer seperti ini:

Lalu kita masukan ke dalam resources sebagai file teks dengan nama window, lalu masukan kode ini:

using GHI.Pins; using GHI.Processor; using GHI.Utilities; using Microsoft.SPOT; using Microsoft.SPOT.Hardware; using Microsoft.SPOT.Presentation.Media; public class Program { public static void Main() { Display.Width = 128; Display.Height = 160; Display.Type = Display.DisplayType.Spi; Display.CurrentRotation = Display.Rotation.Normal; Display.BitmapFormat = Bitmaps.Format.Bpp16BgrLe; Display.SpiConfiguration = new SPI.Configuration(Cpu.Pin.GPIO_Pin6, false, 0, 0, false, true, 1000, SPI.SPI_module.SPI1); Display.ResetPin = FEZCerberus.Socket5.Pin3; Display.BacklightPin = FEZCerberus.Socket5.Pin4; Display.ControlPin = FEZCerberus.Socket5.Pin5; Display.Save(); var bmp = new Bitmap(Display.Width, Display.Height); bmp.DrawEllipse(Colors.Red, 5, 5, 5, 5); bmp.DrawEllipse(Colors.Green, 15, 5, 5, 5); bmp.DrawEllipse(Colors.Blue, 25, 5, 5, 5); } }

<Glide Version="1.0.7"> <Window Name="window" Width="320" Height="240" BackColor="dce3e7"> <Button Name="btnClick" X="100" Y="104" Width="120" Height="32" Alpha="255" Text="Click me" Font="4" FontColor="000000" DisabledFontColor="808080" TintColor="000000" TintAmount="0"/> <TextBox Name="txtNama" X="42.9" Y="37.5" Width="240" Height="32" Alpha="255" Text="" TextAlign="Left" Font="4" FontColor="000000"/> </Window> </Glide>

Berikut adalah contoh kalibrasi layar:

XML Glide:

Programnya:

using GHI.Glide; using GHI.Glide.Display; using GHI.Glide.UI; using Microsoft.SPOT; using System; using System.Threading; namespace MyFirstApp { public class Program { private static Window window; private static TextBlock textBlock; public static void Main() { //load form dari resources window = GlideLoader.LoadWindow(Resources.GetString(Resources.StringResources.window)); //init glide touch GlideTouch.Initialize(); Button btn = (Button)window.GetChildByName("btnClick"); //assign handler click btn.TapEvent += OnClick; textBlock = (TextBlock)window.GetChildByName("txtNama"); //buka on screen keyboard textBlock.TapEvent += new OnTap(Glide.OpenKeyboard); //tampilkan form Glide.MainWindow = window; //infinite delay Thread.Sleep(-1); } private static void OnClick(object sender) { //cetak tanggal textBlock.Text = DateTime.UtcNow.ToString(); window.FillRect(textBlock.Rect); textBlock.Invalidate(); Debug.Print("Button tapped."); } } }

<Glide> <Window Name="window" Width="320" Height="240" BackColor="dce3e7"> <Button Name="btn" X="20" Y="20" Width="80" Height="32" Alpha="255" Text="Calibrate" Font="3" FontColor="000000" DisabledFontColor="808080" TintColor="000000" TintAmount="0"/> </Window> </Glide>

Low Power

Perangkat embedded seringkali harus membatasi penggunaan power sebaik mungkin. Beberapa

yang bisa dilakukan antara lain:

1. Mengurangi clock prosesor

2. Mematikan prosesor ketika system idle (peripheral lain dan interrupt tetap jalan)

3. Mematikan beberapa peripheral yang tidak digunakan

4. Hibernasi

NETMF mendukung beberapa cara diatas, ketika system hibernasi cpu dan peripheral akan mati, jadi

jika ada data masuk melalui UART atau bus tidak akan diterima.

Berikut adalah 2 contoh code yang bisa dilakukan untuk menghemat power ketika device idle.

Note: Ketika device hibernasi, maka USB tidak berfungsi, jadi tidak dapat di debug. Jika system

melakukan hibernasi terus menerus maka harus flash ulang firmware.

Contoh RTC alarm:

using GHI.Glide; using GHI.Glide.Display; using GHI.Glide.UI; using System.Threading; namespace MyFirstApp { public class Program { private static Window mainWindow; private static CalibrationWindow calibrationWindow; public static void Main() { mainWindow = GlideLoader.LoadWindow(Resources.GetString(Resources.StringResources.window)); GlideTouch.Initialize(); var btn = (Button)mainWindow.GetChildByName("btn"); btn.TapEvent += OnTap; //load window kalibrasi calibrationWindow = new CalibrationWindow(false, false); calibrationWindow.CloseEvent += OnClose; Glide.MainWindow = mainWindow; Thread.Sleep(-1); } private static void OnTap(object sender) { //buka kalibrasi window Glide.MainWindow = calibrationWindow; } private static void OnClose(object sender) { Glide.MainWindow = mainWindow; } } }

Note: referensikan assembly GHI.Hardware dan Microsoft.SPOT.Hardware. Gunakan

Microsoft.SPOT.Hardware.HardwareEvent.OEMReserved2 untuk RTC alarm.

Contoh dengan Interrupt:

Kita juga dapat membangunkan device yang hibernasi dengan interrupt. Gunakan

Microsoft.SPOT.Hardware.HardwareEvent.OEMReserved1

Note: Interrupt hanya berfungsi jika glitch filter dalam keadaan aktif, dan di assign ke event handler.

Pastikan pin yang akan digunakan untuk melakukan interrupt.

3rd Party Tools dan Contoh Driver

Dengan NETMF kita dapat membuat sendiri driver module (sensor/actuator) dengan C#. Berikut

adalah contoh bagaimana membuat driver sendiri.

using GHI.Processor; using Microsoft.SPOT; using Microsoft.SPOT.Hardware; using System; public class Program { public static void Main() { //set RTC alarm dalam 30 detik ke depan RealTimeClock.SetAlarm(RealTimeClock.GetDateTime().AddSeconds(30)); //device hibernasi PowerState.WakeupEvents |= HardwareEvent.OEMReserved2; PowerState.Sleep(SleepLevel.DeepSleep, HardwareEvent.OEMReserved2); //Program lanjut disini setelah 30 detik selesai Debug.Print("Program jalan kembali setelah hibernasi"); } }

using Microsoft.SPOT.Hardware; using System; public class Program { public static void Main() { var interrupt = new InterruptPort(Cpu.Pin.GPIO_Pin0, true, Port.ResistorMode.PullUp, Port.InterruptMode.InterruptEdgeHigh); interrupt.OnInterrupt += interrupt_OnInterrupt; //hibernasi PowerState.WakeupEvents |= HardwareEvent.OEMReserved1; PowerState.Sleep(SleepLevel.DeepSleep, HardwareEvent.OEMReserved1); ///Program jalan kembali setelah ada interrupt } private static void interrupt_OnInterrupt(uint data1, uint data2, DateTime time) { //Interrupted } }

Distance Sensor

Berikut adalah contoh driver HC_SR04 (distance sensor) buatan John Wilson.

using System; using Microsoft.SPOT; using Microsoft.SPOT.Hardware; using System.Threading; namespace MyFirstApp { /// Class for controlling the HC-SR04 Ultrasonic Range detector /// Written by John E. Wilson public class HC_SR04 { private OutputPort portOut; private InterruptPort interIn; private long beginTick; private long endTick; private long minTicks; // System latency, subtracted off ticks to find actual sound travel time private double inchConversion; private double version; public HC_SR04(Cpu.Pin pinTrig, Cpu.Pin pinEcho) { portOut = new OutputPort(pinTrig, false); interIn = new InterruptPort(pinEcho, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLow); interIn.OnInterrupt += new NativeEventHandler(interIn_OnInterrupt); minTicks = 6200L; inchConversion = 1440.0; version = 1.1; } public double Version { get{return version;} } /// <returns>Number of ticks it takes to get back sonic pulse</returns> public long Ping() { // Reset Sensor portOut.Write(true); Thread.Sleep(1); // Start Clock endTick = 0L; beginTick = System.DateTime.Now.Ticks; // Trigger Sonic Pulse portOut.Write(false); // Wait 1/20 second (this could be set as a variable instead of constant) Thread.Sleep(50); if (endTick > 0L) { // Calculate Difference long elapsed = endTick - beginTick; // Subtract out fixed overhead (interrupt lag, etc.) elapsed -= minTicks; if (elapsed < 0L) { elapsed = 0L; } // Return elapsed ticks return elapsed; } // Sonic pulse wasn't detected within 1/20 second return -1L; }

Cara penggunaannya:

/// <param name="data1">Not used</param> /// <param name="data2">Not used</param> /// <param name="time">Transfer to endTick to calculated sound pulse travel time</param> void interIn_OnInterrupt(uint data1, uint data2, DateTime time) { // Save the ticks when pulse was received back endTick = time.Ticks; } /// <param name="ticks"></param> public double TicksToInches(long ticks) { return (double)ticks / inchConversion; } /// The ticks to inches conversion factor public double InchCoversionFactor { get{return inchConversion;} set{inchConversion = value;} } /// The system latency (minimum number of ticks) /// This number will be subtracted off to find actual sound travel time public long LatencyTicks { get{ return minTicks;} set{ minTicks = value;} } } }

using Microsoft.SPOT; using Microsoft.SPOT.Hardware; using System; using System.Threading; namespace MyFirstApp { public class Program { public static void Main() { var th2 = new Thread(new ThreadStart(TestDistanceSensor)); th2.Start(); Thread.Sleep(Timeout.Infinite); } static void TestDistanceSensor() { //led red (2) var redled = new OutputPort(Cpu.Pin.GPIO_Pin2, false); //triger (3), echo (4), 5V + G var pin3 = Cpu.Pin.GPIO_Pin3; var pin4 = Cpu.Pin.GPIO_Pin4; HC_SR04 sensor = new HC_SR04(pin3, pin4); while (true) { long ticks = sensor.Ping(); if (ticks > 0L) { double inches = sensor.TicksToInches(ticks); Debug.Print("jarak :" + inches); if (inches < 4) { redled.Write(true); } else { redled.Write(false); } } Thread.Sleep(100); } } } }

Gas

using Microsoft.SPOT; using Microsoft.SPOT.Hardware; using System; using System.Threading; namespace MyFirstApp { public class Program { public static void Main() { var gas = new AnalogInput(Cpu.AnalogChannel.ANALOG_4); while (true) { var intensity = gas.Read(); Debug.Print("Gas :" + intensity); Thread.Sleep(200); } } } }

PIR Sensor

NETMF Toolbox

Ini adalah kumpulan library dan driver yang akan membantu kita untuk mempercepat

pengembangan aplikasi. Berikut adalah isinya:

Hardware Drivers

Berisi beberapa driver-driver modul hardware yang ada di pasaran.

Toolbox.NETMF.Hardware.AdafruitMotorshield

Toolbox.NETMF.Hardware.AutoRepeatInputPort

using Microsoft.SPOT; using Microsoft.SPOT.Hardware; using System; using System.Threading; namespace MyFirstApp { public class Program { public static void Main() { //thread untuk pir sensor dan led var th2 = new Thread(new ThreadStart(TestPIR)); th2.Start(); } static void TestPIR() { //led merah pake pin 5 var ledRed = new OutputPort(Cpu.Pin.GPIO_Pin5, false); //led ijo pake pin 6 var greenLed = new OutputPort(Cpu.Pin.GPIO_Pin6,false); //pir pake pin 3 + 5v var pir = new InputPort(Cpu.Pin.GPIO_Pin3, false,Port.ResistorMode.Disabled); while (true) { var detect = pir.Read(); if (detect) { ledRed.Write(true); greenLed.Write(false); Debug.Print("ada gerakan"); } else { greenLed.Write(true); ledRed.Write(false); Debug.Print("tidak ada gerakan"); } Thread.Sleep(200); } } } }

Toolbox.NETMF.Hardware.BitBangBuzzer

Toolbox.NETMF.Hardware.BlinkM

Toolbox.NETMF.Hardware.DS1307

Toolbox.NETMF.Hardware.Fez.ADC (until .NETMF 4.1)

Toolbox.NETMF.Hardware.Fez.PWM (until .NETMF 4.1)

Toolbox.NETMF.Hardware.HBridge

Toolbox.NETMF.Hardware.Hd44780Lcd

Toolbox.NETMF.Hardware.Ic74hc165

Toolbox.NETMF.Hardware.Ic74hc595

Toolbox.NETMF.Hardware.LolShield

Toolbox.NETMF.Hardware.MatrixKeyPad

Toolbox.NETMF.Hardware.Mcp23017

Toolbox.NETMF.Hardware.MicroSerialServoController

Toolbox.NETMF.Hardware.NESControllerAdapter

Toolbox.NETMF.Hardware.Netduino.ADC

Toolbox.NETMF.Hardware.Netduino.PWM

Toolbox.NETMF.Hardware.NmeaGps

Toolbox.NETMF.Hardware.Rdm630

Toolbox.NETMF.Hardware.RgbLed

Toolbox.NETMF.Hardware.RgbLedStrip

Toolbox.NETMF.Hardware.RotaryDIPSwitch

Toolbox.NETMF.Hardware.RotaryEncoder

Toolbox.NETMF.Hardware.SevenSegment

Toolbox.NETMF.Hardware.SharpGP2Y0A02YK

Toolbox.NETMF.Hardware.Somo

Toolbox.NETMF.Hardware.Speaker

Toolbox.NETMF.Hardware.ThermalPrinter

Toolbox.NETMF.Hardware.ThumbJoystick

Toolbox.NETMF.Hardware.Tmp36

Toolbox.NETMF.Hardware.WearableKeypad

Toolbox.NETMF.Hardware.WiFlyGSX

Toolbox.NETMF.Hardware.WiiNunchuk

Networking Classes

Berisi fungsi-fungsi untuk networking.

Toolbox.NETMF.NET.HTTP_Client

Toolbox.NETMF.NET.IntegratedSocket

Toolbox.NETMF.NET.IRC_Client

Toolbox.NETMF.NET.POP3_Client

Toolbox.NETMF.NET.SMTP_Client

Toolbox.NETMF.NET.SNTP_Client

Toolbox.NETMF.NET.TelnetServer

Toolbox.NETMF.NET.WiFlySocket (part of the WiFlyGSX hardware driver)

Core classes

Class-class Utama dari library.

Core library

Helper function, seperti konversi, round, zero filling.

Toolbox.NETMF.Tools

Hardware Core

Interface ke hardware

Toolbox.NETMF.Hardware.IADCPort (Interface)

Toolbox.NETMF.Hardware.IGPIPort (Interface)

Toolbox.NETMF.Hardware.IGPOPort (Interface)

Toolbox.NETMF.Hardware.IIRQPort (Interface)

Toolbox.NETMF.Hardware.IParallelOut (Interface)

Toolbox.NETMF.Hardware.IPWMPort (Interface)

Toolbox.NETMF.Hardware.IntegratedGPI

Toolbox.NETMF.Hardware.IntegratedGPO

Toolbox.NETMF.Hardware.IntegratedIRQ

Toolbox.NETMF.Hardware.IntegratedADC (since .NETMF 4.2)

Toolbox.NETMF.Hardware.IntegratedPWM (since .NETMF 4.2)

Toolbox.NETMF.Hardware.MultiI2C

Toolbox.NETMF.Hardware.MultiSPI

Toolbox.NETMF.Hardware.ProviderCollection

Networking Core

Toolbox.NETMF.NET.SimpleSocket (Interface)

Silakan unduh pada tautan berikut https://netmftoolbox.codeplex.com

Serialization

Serialization sangat dibutuhkan ketika kita ingin mengirimkan data, biasanya data yang berbentuk

objek dari class kita konversikan terlebih dahulu ke format yang standard dan compact agar cepat

dikirimkan (serialization) dan mudah dikonversikan kembali oleh device lain (deserialization).

Json

Kita dapat gunakan library Json Netmf, caranya:

1. Buka package console manager, Tools > Nugget Package Manager > Package Manager

Console.

2. Lalu ketik "Install-Package Json.NetMF" dan enter

3. Kembali ke listing program

Berikut adalah cara penggunaannya:

Class to Byte

Untuk melakukan serialization dari objek (class/struct) ke array byte, maka kita dapat menggunakan

built-in method di NETMF. Biasanya jika kita ingin mengirimkan data antar device, atau dari device

ke PC, kita bisa memanfaatkan method ini.

Contoh penggunaan:

using Microsoft.SPOT; using Microsoft.SPOT.Hardware; using System; using System.Threading; using Json.NETMF; using System.Collections; namespace MyFirstApp { public class Program { public static void Main() { //bikin objek var device = new DeviceData() { DeviceSN = "XX01", Data = new DataSensor() { Gas=10, Humid=12, Light=100, Temp=31 } }; //serialize objek ke string json string JSON = JsonSerializer.SerializeObject(device); //deserialize json ke hashtable var obj = JsonSerializer.DeserializeString(JSON) as Hashtable; var detail = obj["Data"] as Hashtable; //ambil nilainya dari hashtable var DeviceSN = obj["DeviceSN"].ToString(); var Gas = Convert.ToDouble(detail["Gas"].ToString()); } } public class DeviceData { public string DeviceSN { set; get; } public DataSensor Data { set; get; } } public class DataSensor { public double Gas { set; get; } public double Temp { set; get; } public double Humid { set; get; } public double Light { set; get; } } }

RTC

RTC (Real Time Clock) adalah komponen yang menggunakan baterai backup dan crystal yang

terpisah untuk memastikan waktu tetap jalan walaupun system tidak dinyalakan. Crystal yang

digunakan biasanya bernilai 32.768 Khz. Pastikan mikrokontroller yang kita gunakan memiliki RTC

jika ingin mencoba kode berikut.

Note: NETMF memiliki fungsi DateTime.Now untuk mengambil nilai waktu saat ini, tapi jika device di

reset atau mati maka waktu akan ter-reset kembali. Jadi pastikan untuk mengambil waktu dari

RTC, atau bisa melakukan sync waktu pertama kali ke internet (time server).

Contoh pemanfaatan RTC:

using System; using Microsoft.SPOT; public class Program { [Serializable] public class MyClass { public int ax; public float ay; } public static void Main() { MyClass before = new MyClass(); before.ax = 1; before.ay = 1; //serialize objek ke byte array byte[] SerializedData = Reflection.Serialize(before, typeof(MyClass)); // kirim data dalam byte array //deserialize byte array ke object MyClass after = (MyClass)Reflection.Deserialize(SerializedData, typeof(MyClass)); // seharusnya objek before dan aftar memiliki nilai dan struktur yang sama } }

using System; using GHI.Processor; using Microsoft.SPOT; using Microsoft.SPOT.Time; using System.Net; using GHI.Networking; using System.Threading; using Microsoft.SPOT.Hardware; public class Program { private static EthernetENC28J60 netif; public static void Main() { netif = new EthernetENC28J60(SPI.SPI_module.SPI1, Cpu.Pin.GPIO_Pin1, Cpu.Pin.GPIO_Pin2, Cpu.Pin.GPIO_Pin3); netif.Open(); netif.EnableDhcp(); netif.EnableDynamicDns(); while (netif.IPAddress == "0.0.0.0") { Debug.Print("Waiting for DHCP"); Thread.Sleep(250); } DateTime DT; try { DT = RealTimeClock.GetDateTime(); Debug.Print("Current Real-time Clock " + DT.ToString()); } catch // jika power bermasalah sehingga RTC error maka kita perlu melakukan setup ulang waktu RTC { UpdateTimeFromInternet(); DT = DateTime.Now; } if (DT.Year < 2011) { Debug.Print("Time is not resonable"); } Debug.Print("Current Real-time Clock " + RealTimeClock.GetDateTime().ToString()); DT = new DateTime(2014, 9, 15, 7, 30, 0); // set new clock RealTimeClock.SetDateTime(DT); //set real-time clock Debug.Print("New Real-time Clock " + RealTimeClock.GetDateTime().ToString()); } static void UpdateTimeFromInternet() { // Konfigurasi timer service TimeServiceSettings settings = new TimeServiceSettings(); settings.ForceSyncAtWakeUp = true; settings.RefreshTime = 1800; // dalam detik IPAddress[] address = Dns.GetHostEntry("time-a.nist.gov").AddressList; if (address != null && address.Length > 0) settings.PrimaryServer = address[0].GetAddressBytes(); address = Dns.GetHostEntry("pool.ntp.org").AddressList; if (address != null && address.Length > 0) settings.AlternateServer = address[0].GetAddressBytes(); TimeService.Settings = settings; //Indonesia, GMT + 7 TimeService.SetTimeZoneOffset(60 * 7); RealTimeClock.SetDateTime(DateTime.Now); } }

Membaca dan Menulis XML

Extensible Markup Language atau disingkat XML adalah standar format data yang biasa digunakan

untuk pertukaran data antar computer atau perangkat. XML sangat mudah dibaca baik oleh

computer maupun Manusia, sehingga banyak digunakan.

Di NETMF sudah disediakan fungsi untuk membaca dan menulis XML dengan mudah, perhatikan

contoh berikut:

Note: tambah referensi ke System.Xml dan MFDwpsExtensions

Contoh XML:

Contoh kode untuk menulis XML diatas:

<?xml version="1.0" encoding="utf-8"?> <!--This is just a comment--> <NETMF_DataLogger> <FileName>Data</FileName> <FileExt>txt</FileExt> <SampleFreq>10</SampleFreq> </NETMF_DataLogger>

Contoh untuk melakukan parsing XML:

using System.IO; using System.Xml; using System.Ext.Xml; using Microsoft.SPOT; public class Program { public static void Main() { MemoryStream ms = new MemoryStream(); XmlWriter xmlwrite = XmlWriter.Create(ms); xmlwrite.WriteProcessingInstruction("xml", "version=\"1.0\" encoding=\"utf-8\""); xmlwrite.WriteComment("This is just a comment"); xmlwrite.WriteRaw("\r\n"); xmlwrite.WriteStartElement("NETMF_DataLogger");//root element xmlwrite.WriteString("\r\n\t"); xmlwrite.WriteStartElement("FileName");//child element xmlwrite.WriteString("Data"); xmlwrite.WriteEndElement(); xmlwrite.WriteRaw("\r\n\t"); xmlwrite.WriteStartElement("FileExt"); xmlwrite.WriteString("txt"); xmlwrite.WriteEndElement(); xmlwrite.WriteRaw("\r\n\t"); xmlwrite.WriteStartElement("SampleFeq"); xmlwrite.WriteString("10"); xmlwrite.WriteEndElement(); xmlwrite.WriteRaw("\r\n"); xmlwrite.WriteEndElement();//end the root element xmlwrite.Flush(); xmlwrite.Close(); //////// tampilkan xml /////////// byte[] byteArray = ms.ToArray(); char[] cc = System.Text.UTF8Encoding.UTF8.GetChars(byteArray); string str = new string(cc); Debug.Print(str); } }

using System.IO; using System.Xml; using System.Ext.Xml; using Microsoft.SPOT; public class Program { public static void Main() { MemoryStream ms = new MemoryStream(); XmlWriter xmlwrite = XmlWriter.Create(ms); xmlwrite.WriteProcessingInstruction("xml", "version=\"1.0\" encoding=\"utf-8\""); xmlwrite.WriteComment("This is just a comment"); xmlwrite.WriteRaw("\r\n"); xmlwrite.WriteStartElement("NETMF_DataLogger");//root element xmlwrite.WriteString("\r\n\t"); xmlwrite.WriteStartElement("FileName");//child element xmlwrite.WriteString("Data"); xmlwrite.WriteEndElement(); xmlwrite.WriteRaw("\r\n\t"); xmlwrite.WriteStartElement("FileExt"); xmlwrite.WriteString("txt"); xmlwrite.WriteEndElement(); xmlwrite.WriteRaw("\r\n\t"); xmlwrite.WriteStartElement("SampleFeq"); xmlwrite.WriteString("10"); xmlwrite.WriteEndElement(); xmlwrite.WriteRaw("\r\n"); xmlwrite.WriteEndElement();//akhir dari root element xmlwrite.Flush(); xmlwrite.Close(); //////// tampilkan xml /////////// byte[] byteArray = ms.ToArray(); char[] cc = System.Text.UTF8Encoding.UTF8.GetChars(byteArray); string str = new string(cc); Debug.Print(str); ///////////baca xml MemoryStream rms = new MemoryStream(byteArray); XmlReaderSettings ss = new XmlReaderSettings(); ss.IgnoreWhitespace = true; ss.IgnoreComments = false;

Register Access

Developer dapat mengakses register prosesor secara langsung dengan class ini, ini adalah library

extension dari GHI.

Berikut ini adalah contoh kode untuk mengeset timer 3 dan P0.4 di prosesor LPC2478 NXP untuk

menghitung pulse. Kode ini hanya jalan di prosesor tersebut. Prosesor lain memiliki fitur dan register

yang berbeda. Datasheet: http://www.nxp.com/documents/data_sheet/LPC2478.pdf

Manual: http://www.keil.com/dd/docs/datashts/philips/lpc23xx_um.pdf

//XmlException.XmlExceptionErrorCode. XmlReader xmlr = XmlReader.Create(rms, ss); while (!xmlr.EOF) { xmlr.Read(); switch (xmlr.NodeType) { case XmlNodeType.Element: Debug.Print("element: " + xmlr.Name); break; case XmlNodeType.Text: Debug.Print("text: " + xmlr.Value); break; case XmlNodeType.XmlDeclaration: Debug.Print("decl: " + xmlr.Name + ", " + xmlr.Value); break; case XmlNodeType.Comment: Debug.Print("comment " + xmlr.Value); break; case XmlNodeType.EndElement: Debug.Print("end element"); break; case XmlNodeType.Whitespace: Debug.Print("white space"); break; case XmlNodeType.None: Debug.Print("none"); break; default: Debug.Print(xmlr.NodeType.ToString()); break; } } } }

Memory Management

Kode aplikasi yang lancer berjalan di PC terkadang tidak pas jika dijalankan di embedded device,

biasanya terkait keterbatasan memory dan prosesor. Sehingga perlu hati-hati dalam membuat kode

yang efisien, saat membuat objek, sebisanya menggunakan objek yang sama berkali-kali. Gunakan

memory seperlunya. Contoh: Saat membaca data dari serial UART disiapkan 100 byte buffer,

ternyata saat pembacaan data Cuma perlu 50 byte, jadi tidak perlu alokasi sebesar itu cukup 50-60

byte saja. Untuk beberapa driver seperti file system, USB, UART, ini semua menggunakan internal

buffer pada native code untuk memastikan data siap untuk diakses dari managed code oleh

developer. Contoh: untuk membaca 6 Mb file Mp3 kita tidak perlu buffer besar, cukup 100 byte

buffer, kemudian kita baca potongan data secara sekuensial dari file, dan kirimkan data tersebut ke

Mp3 decoder.

using System; using System.Threading; using Microsoft.SPOT; using GHI.Processor; namespace MFConsoleApplication1 { public class Program { public static void Main() { Register PCONP = new Register(0xE01FC0C4); PCONP.SetBits(1 << 22);//enable timer2 // Select IO0 on EMX CAP2.0 Register PINSEL0 = new Register(0xE002C000); PINSEL0.SetBits((3 << 8));//set bits 8 and 9 // To enable timer/counter Register T2TCR = new Register(0xE0070004); T2TCR.Value = 1; // set prescale to 0 Register T2PR = new Register(0xE007000C); T2PR.Value = 0; Register T2CTCR = new Register(0xE0070070); T2CTCR.Value = (2 << 0 | 0 << 2);//count on falling edge and use CAPn.0 // should be 0 for a counter Register T2CCR = new Register(0xE0070028); T2CCR.ClearBits(0x07); // Don't do anything on match Register T2MCR = new Register(0xE0070014); T2MCR.Value = 0; // To reset the counter T2TCR.SetBits((1 << 1)); T2TCR.ClearBits((1 << 1)); // To read Register T2TC = new Register(0xE0070008); while (true) { uint count = T2TC.Value; Debug.Print("Total count: " + count); Thread.Sleep(1000); } } } }

Hindari membuat objek dan dispose berkali-kali di dalam loop, atau method yang sering dipanggil,

karena itu akan memakan waktu prosesor secara intensif dan membuat fragmentasi memory yang

menyebabkan GC sering berjalan, membuat aplikasi jadi lambat.

Berikut adalah contoh bagaimana kita menggunakan objek berulang untuk membaca data dari SPI:

Timers

Timer di NETMF ada 2 class yaitu : Tiemr dan ExtendedTimer. Timer class sama seperti yang terdapat

di .NETFramework, sedangkan ExtendedTimer spesifik untuk NETMF dengan beberapa fungsi ekstra.

Berikut adalah contoh penggunaan timer:

using Microsoft.SPOT.Hardware; public class Program { //cukup dibuat 1 kali saat aplikasi dijalankan private static SPI spi = new SPI(new SPI.Configuration(Cpu.Pin.GPIO_NONE, false, 0, 0, false, true, 1000, SPI.SPI_module.SPI1)); private static byte[] buffer = new byte[2]; private static void WriteRegister(byte address, byte value) { //gunakan objek sama berkali-kali buffer[0] = address; buffer[1] = value; //begitu juga dengan objek SPI spi.Write(buffer); } public static void Main() { for (byte i = 0; i < 255; i++) for (byte j = 0; j < 255; j++) WriteRegister(i, j); } }

Touch

NETMF punya kemampuan untuk menerima input dari perangkat sentuh seperti LCD Touch Screen.

Berikut adalah contoh kodenya:

Note: tambahkan referensi ke assembly Microsoft.SPOT.Graphic, Microsoft.SPOT.TinyCore, dan

Microsoft.SPOT.Touch.

using System.Threading; using Microsoft.SPOT; public class Program { class OurClass { public int x; } static void RunMe(object o) { OurClass cls = (OurClass)o; Debug.Print("From timer!"); Debug.Print("Value: " + cls.x.ToString()); } public static void Main() { OurClass cls = new OurClass(); cls.x = 5; Timer MyTimer = new Timer(new TimerCallback(RunMe), cls, 5000, 1000); Debug.Print("Timer ini akan jalan dalam 5 detik, dan selanjutnya jalan setiap 1 detik"); Thread.Sleep(Timeout.Infinite); } }

Untuk melakukan kalibrasi layar sentuh, bisa gunakan kode berikut:

using Microsoft.SPOT; using Microsoft.SPOT.Input; using Microsoft.SPOT.Presentation; using Microsoft.SPOT.Presentation.Media; using Microsoft.SPOT.Touch; public class Program : Application { private Bitmap lcd; public static void Main() { Program app = new Program(); app.Run(); } public Program() { this.lcd = new Bitmap(SystemMetrics.ScreenWidth, SystemMetrics.ScreenHeight); Touch.Initialize(this); this.MainWindow = new Window(); this.MainWindow.TouchDown += MainWindow_TouchDown; this.MainWindow.TouchUp += MainWindow_TouchUp; this.MainWindow.TouchMove += MainWindow_TouchMove; } private void MainWindow_TouchMove(object sender, TouchEventArgs e) { Debug.Print("Touch move at (" + e.Touches[0].X.ToString() + ", " + e.Touches[0].Y.ToString() + ")"); this.lcd.DrawEllipse(Colors.Blue, e.Touches[0].X, e.Touches[0].Y, 5, 5); this.lcd.Flush(); } private void MainWindow_TouchUp(object sender, TouchEventArgs e) { Debug.Print("Touch up at (" + e.Touches[0].X.ToString() + ", " + e.Touches[0].Y.ToString() + ")"); } private void MainWindow_TouchDown(object sender, TouchEventArgs e) { Debug.Print("Touch down at (" + e.Touches[0].X.ToString() + ", " + e.Touches[0].Y.ToString() + ")"); } }

using Microsoft.SPOT; using Microsoft.SPOT.Input; using Microsoft.SPOT.Presentation; using Microsoft.SPOT.Presentation.Media; using Microsoft.SPOT.Touch; using MyFirstApp; public class Program : Application { private Bitmap lcd; private bool started; private bool finished; private int currentCalibrationPoint; private int calibrationPoints; private short[] screenX; private short[] screenY; private short[] uncalibratedX; private short[] uncalibratedY; public static void Main() { new Program().Run(); } public Program() { this.lcd = new Bitmap(SystemMetrics.ScreenWidth, SystemMetrics.ScreenHeight); Touch.Initialize(this); this.MainWindow = new Window(); this.MainWindow.TouchUp += this.OnTouchUp; this.currentCalibrationPoint = 0; this.calibrationPoints = 0; this.started = false; this.finished = false; Touch.ActiveTouchPanel.GetCalibrationPointCount(ref this.calibrationPoints); this.screenX = new short[this.calibrationPoints]; this.screenY = new short[this.calibrationPoints]; this.uncalibratedX = new short[this.calibrationPoints]; this.uncalibratedY = new short[this.calibrationPoints]; for (int i = 0, x = 0, y = 0; i < this.calibrationPoints; i++) { Touch.ActiveTouchPanel.GetCalibrationPoint(i, ref x, ref y); this.screenX[i] = (short)x; this.screenY[i] = (short)y; } //memulai kalibrasi Touch.ActiveTouchPanel.StartCalibration(); //simpan nilai variabel : screenX, screenY, uncalibratedX, uncalibratedY //jika variabel diatas sudah disimpan, untuk eksekusi kedua bisa langsung meload data kalibrasi dengan method ini Touch.ActiveTouchPanel.SetCalibration(calibrationPoints, screenX, screenY, uncalibratedX, uncalibratedY); }

private void OnTouchUp(object sender, TouchEventArgs e) { if (this.started && !this.finished) { this.uncalibratedX[this.currentCalibrationPoint] = (short)e.Touches[0].X; this.uncalibratedY[this.currentCalibrationPoint] = (short)e.Touches[0].Y; if (++this.currentCalibrationPoint == this.calibrationPoints) { Touch.ActiveTouchPanel.SetCalibration(this.calibrationPoints, this.screenX, this.screenY, this.uncalibratedX, this.uncalibratedY); this.lcd.Clear(); var str = "Screen X: ["; for (int i = 0; i < this.calibrationPoints; i++) str += this.screenX[i].ToString() + (i + 1 != this.calibrationPoints ? ", " : string.Empty); str += "]"; this.lcd.DrawText(str, Resources.GetFont(Resources.FontResources.NinaB), Colors.White, 0, 0); str = "Screen Y: ["; for (int i = 0; i < this.calibrationPoints; i++) str += this.screenY[i].ToString() + (i + 1 != this.calibrationPoints ? ", " : string.Empty); str += "]"; this.lcd.DrawText(str, Resources.GetFont(Resources.FontResources.NinaB), Colors.White, 0, 15); str = "Uncalibrated X: ["; for (int i = 0; i < this.calibrationPoints; i++) str += this.uncalibratedX[i].ToString() + (i + 1 != this.calibrationPoints ? ", " : string.Empty); str += "]"; this.lcd.DrawText(str, Resources.GetFont(Resources.FontResources.NinaB), Colors.White, 0, 30); str = "Uncalibrated Y: ["; for (int i = 0; i < this.calibrationPoints; i++) str += this.uncalibratedY[i].ToString() + (i + 1 != this.calibrationPoints ? ", " : string.Empty); str += "]"; this.lcd.DrawText(str, Resources.GetFont(Resources.FontResources.NinaB), Colors.White, 0, 45); this.lcd.Flush(); this.finished = true; } else { this.DrawPoint(this.screenX[this.currentCalibrationPoint], this.screenY[this.currentCalibrationPoint]); } } else if (!this.started) { this.started = true; this.DrawPoint(this.screenX[0], this.screenY[0]); } else if (this.finished) { this.DrawPoint(e.Touches[0].X, e.Touches[0].Y); } }

WAV Audio Playback

Wave adalah format suara yang biasa dijalankan di computer, kita dapat menjalankannya juga

dengan NETMF. Berikut adalah contoh kodenya:

Buat class baru dengan nama WAVE.cs

private void DrawPoint(int x, int y) { this.lcd.Clear(); this.lcd.DrawEllipse(Colors.Red, x, y, 6, 6); this.lcd.Flush(); } }

using System; using Microsoft.SPOT; using Microsoft.SPOT.Hardware; namespace MyFirstApp { public class WAVE { int index; int dataSize; int sampleRate; /// Loads a WAV file. ONLY PCM 8-bit Mono. public WAVE(byte[] wav) { index = 0; if (wav[index + 0] != 'R' || wav[index + 1] != 'I' || wav[index + 2] != 'F' || wav[index + 3] != 'F') { throw new Exception("File is not RIFF"); } index += 4; // ChunkSize uint ChunkSize = Utility.ExtractValueFromArray(wav, index, 4); index += 4; //format if (wav[index + 0] != 'W' || wav[index + 1] != 'A' || wav[index + 2] != 'V' || wav[index + 3] != 'E') { throw new Exception("File is not WAVE format"); } index += 4; // fmt sub chunk ////////////////////// //subchunk ID if (wav[index + 0] != 'f' || wav[index + 1] != 'm' || wav[index + 2] != 't' || wav[index + 3] != ' ') { throw new Exception("Unexpected fmt subchunk!"); } index += 4; bool BitVarSampleRate16; uint Subchunk1Size = Utility.ExtractValueFromArray(wav, index, 4); index += 4; if (Subchunk1Size == 16) { BitVarSampleRate16 = true; } else if (Subchunk1Size == 18) { BitVarSampleRate16 = false; } else { throw new Exception("Invalid Subchunk1Size."); } ushort AudioFormat = (ushort)Utility.ExtractValueFromArray(wav, index, 2); index += 2; if (AudioFormat != 1) { throw new Exception("AudioFormat invalid."); }

ushort NumChannels = (ushort)Utility.ExtractValueFromArray(wav, index, 2); index += 2; if (NumChannels != 1) { throw new Exception("Must be mono."); } sampleRate = (int)Utility.ExtractValueFromArray(wav, index, 4); index += 4; if (sampleRate != 8000) { throw new Exception("Sample rate must be 8000KHz."); } ushort ByteRate = (ushort)Utility.ExtractValueFromArray(wav, index, 4); index += 4; ushort BlockAlign = (ushort)Utility.ExtractValueFromArray(wav, index, 2); index += 2; if (BitVarSampleRate16) { ushort BitsPerSample = (ushort)Utility.ExtractValueFromArray(wav, index, 2); index += 2; if (BitsPerSample != 8) { throw new Exception("Must be 8 bit."); } } else { uint BitsPerSample = Utility.ExtractValueFromArray(wav, index, 4); index += 4; if (BitsPerSample != 8) { throw new Exception("Must be 8 bit."); } } //// data sub-chunk /////////////////////////////////////// if (wav[index + 0] != 'd' || wav[index + 1] != 'a' || wav[index + 2] != 't' || wav[index + 3] != 'a') { throw new Exception("Unexpected data subchunk!"); } index += 4; uint Subchunk2Size = (ushort)Utility.ExtractValueFromArray(wav, index, 4); index += 4; dataSize = (int)Subchunk2Size; } public int GetDataIndex() { return index; } public int GetDataSize() { return dataSize; } public int GetSampleRate() { return sampleRate; } } }

Lalu programnya sebagai berikut:

Note: tambahkan assembly GHI.Hardware dan GHI.Pins (opsional)

Jika ingin memutar MP3, kita dapat membaca potongan file secara sekuensial lalu mengirimnya ke

chip MP3 dekoder.

Protokol Komunikasi IoT dan Embedded Device

Internet of Things akan menjadi trend saat ini, semua device akan terhubung melalui internet.

Sebagai developer embedded device kita dapat menggunakan beberapa protocol yang khusus

digunakan untuk komunikasi antar microdevice, yang sangat ringan dan cepat. Beberapa

diantaranya adalah MQTT dan AMQP. Simak cara penggunaannya dengan NETMF dibawah ini.

MQTT

MQTT atau MQ-telemetry transport dibuat oleh IBM, lalu dijadikan project open source. Protokol ini

menggunakan mekanisme publish dan subscribe pada topik tertentu. Di desain sedemikian rupa

sangat kecil ukurannya dan ringan. Agar MQTT dapat digunakan kita memerlukan broker, beberapa

broker yang cukup banyak digunakan adalah Mosquito, HiveMQ, RabbitMQ, dsb.

Di NETMF kita memiliki library “M2Mqtt” yaitu client library untuk mengirim dan menerima data

dengan protocol MQTT. Berikut adalah cara penggunaannya:

Di project buka package manager console, Tools > Nugget Package Manager > Package Manager

Console.

Lalu ketik "Install-Package M2Mqtt", dan enter

using Microsoft.SPOT; using Microsoft.SPOT.Input; using Microsoft.SPOT.Presentation; using Microsoft.SPOT.Presentation.Media; using System.Threading; namespace MyFirstApp { public class Program { public static void Main() { byte[] rawData = Resources.GetBytes(Resources.BinaryResources.scream); WAVE wav = new WAVE(rawData); while (true) { GHI.IO.Audio.PlayPcm(GHI.Pins.G80.AnalogOutput.PA4, rawData, wav.GetDataIndex(), wav.GetDataSize(), wav.GetSampleRate()); Thread.Sleep(1000);// Scream once a second! } } } }

Ketik juga "Install-Package Json.NetMF", dan enter

Setelah selesai ketik kode berikut:

using Microsoft.SPOT; using System; using System.Net; using System.Text; using System.Threading; using uPLibrary.Networking.M2Mqtt; using uPLibrary.Networking.M2Mqtt.Messages; namespace MyFirstApp { public class Program { public static MqttClient client { set; get; } public static void Main() { if (client == null) { // create client instance client = new MqttClient(IPAddress.Parse(MQTT_BROKER_ADDRESS)); string clientId = Guid.NewGuid().ToString(); client.Connect(clientId, "guest", "guest"); SubscribeMessage(); } int counter = 0; for (; ; ) { string Pesan = "Kirim data ke-"+counter++; client.Publish("data/test", Encoding.UTF8.GetBytes(Pesan), MqttMsgBase.QOS_LEVEL_AT_MOST_ONCE, false); //delay 2 detik Thread.Sleep(2000); } } public static string MQTT_BROKER_ADDRESS { //hive mq get { return "35.156.71.85"; } } static void SubscribeMessage() { // register to message received client.MqttMsgPublishReceived += client_MqttMsgPublishReceived; client.Subscribe(new string[] { "data/test" }, new byte[] { MqttMsgBase.QOS_LEVEL_AT_MOST_ONCE }); } static void client_MqttMsgPublishReceived(object sender, MqttMsgPublishEventArgs e) { string Pesan = new string(Encoding.UTF8.GetChars(e.Message)); switch (e.Topic) { case "data/test": Debug.Print(Pesan); break; } } } }

AMQP

AMQP adalah open standard protocol untuk messaging. Fitur AMQP antara lain queue, routing,

point-to-point, publish-subscribe, reliability dan security.

Berikut adalah contoh penggunaan AMQP dengan NETMF:

using Amqp; using Amqp.Framing; using Amqp.Types; using Microsoft.SPOT; using System; using System.Globalization; using System.Text; using System.Threading; namespace MyFirstApp { public class Program { public static void Main() { var host = "amqps://RootManageSharedAccessKey:[password]@[yournanmespace].servicebus.windows.net"; var hubname = "amqp-test"; //kirim pesan SendToPartition(host, hubname); //terima pesan ReceiveFromPartition(host, hubname, "0"); } static void ReceiveFromPartition(string eventhubHost, string eventhubname, string partitionName) { // create address var address = new Address(eventhubHost); // create connection var connection = new Connection(address); // create session var session = new Session(connection); // create a receiver from the default consumer group of the partition var receiveLink = new ReceiverLink( session,"receive-link:" + eventhubname, eventhubname + "/ConsumerGroups/$default/Partitions/" + partitionName); var message = receiveLink.Receive(); var offset = message.MessageAnnotations[new Symbol("x-opt-offset")]; var seqNumber = message.MessageAnnotations[new Symbol("x-opt-sequence-number")]; var enqueuedTime = message.MessageAnnotations[new Symbol("x-opt-enqueued-time")]; receiveLink.Accept(message); System.Text.UTF8Encoding enc = new UTF8Encoding(); var data = (Data)message.BodySection; string str = new string(enc.GetChars(data.Binary)); Debug.Print("receive:" + str); connection.Close(); }

Azure IoT

Azure adalah cloud service dari microsoft, Azure IoT Hub adalah IoT gateway yang berfungsi untuk

menghubungkan device embedded dengan cloud. Microsoft sudah menyediakan Client SDK yang

bisa digunakan langsung di perangkat NETMF. Berikut adalah contoh penggunaannya:

Pertama, download dulu client sdk nya dari link berikut https://github.com/Azure/azure-iot-sdk-

csharp terdapat pada folder device/Microsoft.Azure.Devices.Client.NetMF kemudian pilih sesuai

versi NETMF yang digunakan. Download dan masukan project tersebut ke solusi kita. Lalu di project

kita, add reference ke project.

Lalu di program Utama ketik:

static void SendToPartition(string eventhubHost, string eventhubname) { // create address var address = new Address(eventhubHost); Connection connection = new Connection(address); // create session var session = new Session(connection); // partitions here can be update to any partition id in eventhub. var sendLink = new SenderLink(session, "send-link:" + eventhubname, eventhubname+"/Partitions/0"); // construct message var messageValue = Encoding.UTF8.GetBytes("i am a message."); // here, AMQP supports 3 types of body, here we use Data. for (int i = 0; i < 10; i++) { var message = new Message() { BodySection = new Data() { Binary = messageValue } }; sendLink.Send(message); } connection.Close(); } } }

Note: untuk membuat deviceconnectionstring bisa menggunakan device explorer dari tautan berikut

https://github.com/Azure/azure-iot-sdk-csharp/tree/master/tools/DeviceExplorer

using Microsoft.Azure.Devices.Client; using Microsoft.SPOT; using System; using System.Text; using System.Threading; namespace MyFirstApp { public class Program { // contoh : "HostName=<iothub_host_name>;DeviceId=<device_id>;SharedAccessKey=<device_key>" private const string DeviceConnectionString = "<replace>"; private static int MESSAGE_COUNT = 5; public static void Main() { try { DeviceClient deviceClient = DeviceClient.CreateFromConnectionString(DeviceConnectionString, TransportType.Http1); SendEvent(deviceClient); ReceiveCommands(deviceClient); Debug.Print("Done!\n"); } catch { }; } static void SendEvent(DeviceClient deviceClient) { string dataBuffer; Debug.Print("Device sending " + MESSAGE_COUNT + " messages to IoTHub..."); for (int count = 0; count < MESSAGE_COUNT; count++) { dataBuffer = Guid.NewGuid().ToString(); Message eventMessage = new Message(Encoding.UTF8.GetBytes(dataBuffer)); Debug.Print(DateTime.Now.ToLocalTime() + "> Sending message: " + count + ", Data: [" + dataBuffer + "]"); deviceClient.SendEvent(eventMessage); } }

Kita juga bisa memanfaatkan library MQTT native untuk mengirim data ke azure, silakan lihat tautan

berikut https://docs.microsoft.com/en-us/azure/iot-hub/iot-hub-mqtt-support

ModBus

Modbus adalah protocol komunikasi serial yang sering digunakan untuk menghubungkan perangkat

elektronik di industry. Protokol ini dibuat oleh Modicon (Schneider Electric). Simpel dan cepat, itulah

karakteristiknya. Modbus dapat menghubungkan beberapa perangkat sekaligus dalam satu jaringan,

contoh nyata pemanfaatannya adalah sebagai penghubung computer dengan remote terminal unit

(RTU) untuk aplikasi SCADA (supervisory control and data acquisition).

Beberapa varian ModBus antara lain:

1. Modbus RTU

2. Modbus ASCII

3. Modbus TCP/IP

4. Modbus RTU/IP

Varian-varian diatas tidak interopable satu sama lain, karena memiliki frame format (struktur data)

yang berbeda. Frameformat terdiri dari Application Data Unit dan Protocol Data Unit.

Contoh penggunaan Modbus dengan NETMF:

https://highfieldtales.wordpress.com/2012/03/31/modbus-tcp-library-for-netduino/

Driver Modbus : https://www.ghielectronics.com/community/codeshare/entry/880 ,

http://cetdevelop.codeplex.com/

static void ReceiveCommands(DeviceClient deviceClient) { Debug.Print("Device waiting for commands from IoTHub..."); Message receivedMessage; string messageData; while (true) { receivedMessage = deviceClient.Receive(); if (receivedMessage != null) { StringBuilder sb = new StringBuilder(); foreach (byte b in receivedMessage.GetBytes()) { sb.Append((char)b); } messageData = sb.ToString(); sb = null; Debug.Print(DateTime.Now.ToLocalTime() + "> Received message: " + messageData); deviceClient.Complete(receivedMessage); } Thread.Sleep(10000); } } } }

Fitur Spesial dari GHI

Ini adalah ringkasan beberapa extension dari GHI untuk memperkaya library NETMF, disini tidak

akan dijabarkan satu per-satu contoh source codenya, tetapi akan disertakan link referensi berisi

sample codenya.

CAN

Control Area Network adalah salah satu interface komunikasi yang banyak digunakan di industry dan

piranti otomotif. CAN sangat cepat dan baik bekerja di kondisi yang penuh noise. Pengecekan error

dan recovery dilakukan di layer hardware. Cukup 2 pin untuk menggunakan CAN ini yaitu TD

(transmit data) dan RD (receive data). Tidak ada relasi master-slave, semua node yang terhubung

sama posisinya, dapat mengirim dan menerima data. Minimal ada perangkat yang terhubung agar

CAN ini dapat berfungsi.

Ref: https://www.ghielectronics.com/docs/110/can

In-Field Update (IFU)

Class ini digunakan untuk melakukan update device, yang dapat diupdate antara lain : firmware,

aplikasi, konfigurasi dan tinybooter. Biasanya digunakan jika kita ingin mengupdate device secara

remote (lan/internet) atau melalui SDCard / USB Disk.

File update akan disimpan IFU ke dalam memory, lalu dengan satu method, IFU akan menghapus

flash dan mereplace dengan file yang disimpan di memory, ke region tertentu sesuai jenisnya.

Ref: https://www.ghielectronics.com/docs/147/in-field-update

SQLite

GHI memporting SQLite agar dapat dijalankan diatas perangkat NETMF, sehingga kita memiliki

database kecil untuk menyimpan data pada SDCard / USBDisk. Cocok untuk membuat data logger,

atau penyimpanan konfigurasi. Query SQL biasa dapat digunakan disini.

Ref: https://www.ghielectronics.com/docs/135/sqlite-database

RLP

Runtime Loadable Procedure adalah extension yang paling keren menurut penulis karena kita dapat

mengeksekusi native code (compiled code) yang dibuat dengan bahasa C. Ini sangat bermanfaat

ketika kita butuh processing yang cepat, seperti melakukan enkripsi, CRC, mendrive ribuan LED.

Method yang berada dalam native code dapat kita panggil melalui interop di NETMF.

Dalam prakteknya, file yang sudah compile (elf file) dimasukan ke dalam resources aplikasi atau

diload dari SDCard / USB Drive.Lalu dipanggil dengan class RLP.

Ref: https://www.ghielectronics.com/docs/50/rlp

USB Client

USB biasa digunakan untuk debugging dan deploy aplikasi ke perangkat NETMF, tapi dengan library

ini kita juga bisa memanfaatkan USB untuk mengakses perangkat lain seperti input keyboard,

mouse, virtual serial port, mass storage dan custom device.

Ref: https://www.ghielectronics.com/docs/20/usb-client

USB Host

Perbedaan USB Host dan USB Client adalah USB Host adalah system yang dapat terhubung dengan

berbagai USB Client. Contoh PC, PC dapat terkoneksi ke usb drive, mouse, keyboard, web cam secara

bersamaan. Dengan USB Hub kita dapat menghubungkannya langsung dengan USB client device

atau ke USB Hub dimana berbagai device bisa masuk ke 1 USB Hub sekaligus. Implementasi USB Host

lebih kompleks dari pada USB Client. Event handler akan degenerate ketika ada USB device client

yang terkoneksi atau lepas. Hampir semua USB device client bisa diakses dengan USB Host.

Ref: https://www.ghielectronics.com/docs/36/usb-host

Signal Generator

Ini adalah library yang dapat menghasilkan gelombang sinyal digital, dan dapat juga menghasilkan

sinyal PWM melalui pin output. Ada 2 mode yang bisa dilakukan yaitu:

1. Non-blocking, generator berjalan di background menggunakan system interrupt

2. Blocking, ketika generator jalan tidak menyediakan waktu untuk code lain untuk jalan. Tapi

mode ini yang paling akurat.

Ref : https://www.ghielectronics.com/docs/24/signal-generator

Signal Capture

Library ini digunakan untuk menyimpan perubahan signal yang diterima pada pin tertentu (bisa dari

high-low atau low-high), data ini akan disimpan ke dalam variabel array. Isi dari array adalah jumlah

microsecond diantara perubahan sinyal.

Ref: https://www.ghielectronics.com/docs/106/signal-capture

Watchdog

Aplikasi embedded seringkali berjalan terus menerus tanpa ada interaksi user, jika terjadi kesalahan

maka sangat penting agar bisa melakukan reset otomatis, watchdog adalah reset button otomatis

tersebut. Contoh kasus: ketika kita membuat kios tiket, ketika aplikasi mengakses server melalui

internet terjadi kesalahan dan membuat aplikasi hang karena belum dihandle dengan baik, maka

watchdog akan mereset secara otomatis.

Ketika watchdog diaktifkan, kita atur timeout yang berguna jika timeout berlalu tanpa ada fungsi

yang me-reset timeout maka watchdog akan mereset program.

Note: Begitu watchdog diaktifkan, tidak ada cara untuk mematikannya. Ini dilakukan untuk

memastikan tidak ada system yang korup yang mematikan watchdog secara insidentil.

Ref: https://www.ghielectronics.com/docs/31/watchdog

Encryption (XTEA)

XTEA adalah algoritma untuk enkripsi, tidak se-powerful RSA tapi sudah menggunakan 128 bit key

dan menggunakan power yang rendah.

Ref: https://www.ghielectronics.com/docs/49/xtea

Pulse Feedback

Class ini memiliki beberapa mode untuk melakukan pengukuran antara lain:

1. Echo Duration, mode ini mengirimkan pulse dengan panjang dan state tertentu ke sebuah

pin, kemudian menunggu echo dari pin lainnya dan mengukur berapa lama echo dari pulse

tersebut dalam microsecond. Pin echo dan pin pulse bisa sama jika diperlukan.

2. Duration Until Echo, mode ini mirip dengan Echo Duration, perbedaannya ini mengukur

berapa lama waktu tunggu hingga echo diterima.

3. Drain Duration, mode ini banyak digunakan untuk capacitive touch. Jika resistor, kapasitor

dan capacitive touch pad dihubungkan, kemudian disentuh, pin akan grounding setelah

periode singkat tergantung dengan kapasitan pada pin. Durasi itu dapat diukur. Note: ini

hanya bisa dilakukan dengan 1 pin.

Ref: https://www.ghielectronics.com/docs/326/pulse-feedback

Pengetahuan Umum

Update Firmware

Biasanya manufaktur menyediakan tool dan extension untuk melakukan update firmware, hal ini

sangat penting karena jika versi assembly dan aplikasi yang kita buat tidak cocok dengan firmware

yang terpasang di board maka aplikasi akan gagal dijalankan.

Beberapa cara melakukan update firmware dari beberapa manufaktur:

NETDUINO : http://forums.netduino.com/index.php?/topic/10479-netduino-plus-2-

firmware-v431/

GHI FEZ : https://www.ghielectronics.com/docs/127/firmware-update

Mikrobus.NET : https://mikrobusnet.org/firmwareupdate

Menampilkan Boot Up Message

Biasanya di aplikasi NETMF kita sering menulis informasi ke output window, dengan tool MFDeploy

kita bisa menampilkan informasi apa saja yang ditulis oleh aplikasi. Caranya sbb:

1. Buka MFDeploy, Start, ketik MFDeploy

2. Lalu sambungkan device ke pc

3. Pilih Device : USB, otomatis nama device muncul di textbox kanan

4. Klik menu Target > connect

5. Kemudian klik tombol “Ping”

Garbage Collector

Pada C/C++ setiap objek yang dibuat harus direlease secara manual dari memory, jika lupa atau tidak

melakukan penghapusan dari memory maka memory akan habis dan terjadi memory leaks. Ini bisa

mengakibatkan crash. Dengan .NET Microframework, proses release objek dari memory dilakukan

otomatis, ketika memory resources sangat rendah, GC (garbage collector) akan dijalankan, dan akan

memeriksa setiap object yang ada di memory, jika tidak ada referensi yang merujuk pada object

tersebut maka objek akan di release dari memory.

Memory akan direserver ketika kita memanggil syntax “new” saat membuat objek. Satu objek bisa

memiliki multiple reference selama masih ada reference ke object tersebut maka GC tidak akan

menghapus objek tersebut dari memory.

Sebagai contoh perhatikan kode berikut:

Proses penghapusan objek dari memory oleh GC tidak dilakukan langsung setelah referensi hilang

dari sebuah object, tapi GC akan jalan saat dibutuhkan, dan butuh beberapa mili detik untuk

melakukan pencarian objek-objek dalam memory oleh GC. Jika dibutuhkan kita bisa memanggil GC

langsung tanpa harus menunggu. Seperti ini:

using System; using Microsoft.SPOT; using System.Collections; using Microsoft.SPOT.Hardware; using System.Threading; namespace MyFirstApp { public class Program { public static void Main() { //membuat objek baru di memory OutputPort Ref1 = new OutputPort(GHI.Pins.FEZCobraIII.Gpio.D0, true); //Membuat referensi kedua ke objek tersebut OutputPort Ref2 = Ref1; //menghapus referensi pertama Ref1 = null; // Objek tidak dihapus oleh GC karena masih di reference oleh Ref2 // Hapus referensi objek kedua Ref2 = null; // GC akan menghapus objek karena tidak ada lagi referensi } } }

Hilangnya Referensi

GC memang memudahkan kita dalam melakukan pembebasan objek dalam memory, tapi juga bisa

memunculkan masalah baru, seperti contoh berikut:

using System; using Microsoft.SPOT; using System.Collections; using Microsoft.SPOT.Hardware; using System.Threading; namespace MyFirstApp { public class Program { public static void Main() { //membuat objek baru di memory OutputPort Ref1 = new OutputPort(GHI.Pins.FEZCobraIII.Gpio.D0, true); //Membuat referensi kedua ke objek tersebut OutputPort Ref2 = Ref1; //menghapus referensi pertama Ref1 = null; // Objek tidak dihapus oleh GC karena masih di reference oleh Ref2 // Hapus referensi objek kedua Ref2 = null; // GC akan menghapus objek karena tidak ada lagi referensi //jalankan garbage collector Debug.GC(true); } } }

Untuk mencegah hal tersebut maka kita perlu membuat variable global yang tetap menjaga

referensi ke objek LED diatas. Ini kodenya:

using System; using Microsoft.SPOT; using System.Collections; using Microsoft.SPOT.Hardware; using System.Threading; namespace MyFirstApp { public class Program { static void TurnLEDOn() { //nyalakan LED OutputPort LED = new OutputPort((Cpu.Pin)GHI.Pins.FEZCobraIII.Gpio.D1, true); } public static void Main() { TurnLEDOn(); //Setelah menjalankan method diatas objek LED kehilangan referensi //Jalankan GC Debug.GC(true); //objek LED dihapus oleh GC yang menyebabkan Outputport LED berubah jadi Inputport dan lampu mati } } }

using System; using Microsoft.SPOT; using System.Collections; using Microsoft.SPOT.Hardware; using System.Threading; namespace MyFirstApp { public class Program { static OutputPort LED; static void TurnLEDOn() { //nyalakan LED LED = new OutputPort((Cpu.Pin)GHI.Pins.FEZCobraIII.Gpio.D1, true); } public static void Main() { TurnLEDOn(); //Setelah menjalankan method diatas objek LED tetap memiliki referensi //Jalankan GC Debug.GC(true); //objek LED tidak dihapus oleh GC, lED tetap nyala } } }

Dispose

Hampir setiap object memiliki method Dispose, method ini berguna untuk menghapus objek dari

memory. Ini sangat penting digunakan sebagai contoh ketika kita menggunakan Pin yang sama untuk

membaca input digital dan sekaligus menggunakannya sebagai output digital. Bagaimana caranya,

simak kode berikut:

Menampilkan Informasi GC

Ketika GC dijalankan, maka banyak informasi penting yang ditampilkan di output window. Info ini

sangat berguna untuk melihat apa saja yang menggunakan resources di system. Jika ingin

menghilangkan info tersebut dari output window silakan masukan kode berikut:

Referensi dan Sumber

E-book

Internet of Things,

http://www.ghielectronics.com/downloads/FEZ/Beginners%20Guide%20to%20Porting%20NETMF.pdf

NETMF Porting Guide,

http://www.ghielectronics.com/downloads/FEZ/Beginners%20Guide%20to%20Porting%20NETMF.pdf

Komunitas & Website

Forum Netduino, http://forums.netduino.com/

using System; using Microsoft.SPOT; using System.Collections; using Microsoft.SPOT.Hardware; using System.Threading; namespace MyFirstApp { public class Program { public static void Main() { //Reserve pin 0 sebagai input digital var Button = new InputPort(Cpu.Pin.GPIO_Pin0,true,Port.ResistorMode.PullUp); var x = Button.Read(); //hapus referensi ke pin 0 Button.Dispose(); //assign pin 0 jadi output digital var LED = new OutputPort(Cpu.Pin.GPIO_Pin0, false); LED.Write(true); } } }

Debug.EnableGCMessages(false);

Forum Gadgeteer & NETMF GHI, https://www.ghielectronics.com/community/forum

Forum Mikrobus.NET, https://mikrobusnet.org/bb/

Code Share, https://www.ghielectronics.com/community/codeshare

Komunitas Maker Bogor (Buitenzorg Makers Club),

https://web.facebook.com/buitenzorgmakersclub/?ref=bookmarks

Komunitas IoT Bandung (IoT4Bdg),

https://web.facebook.com/groups/iotforbandung/?ref=ts&fref=ts

Komunitas Makers.ID Indonesia, http://makers.id/

GHI Website, https://www.ghielectronics.com