Sunday, July 8, 2012


Sending IR Signals to Control my TV

Quick follow-up to my prior post. Tried generating some IR codes to control my TV. Used a Radio Shack High-Output Infrared LED. Decided to tap the PWM sub-system of the PIC. Slightly complicated setup, but pretty straightforward. Set PWM on RB3/PA1 (pin 18, again) at 38.5KHz. Wrote a series of routines for sending a packet; bytes; and bits. Tried sending VOL+/VOL- pairs, but no joy. Tried receiving the IR output with the IR receiver, nada. Found some silly errors in my PWM handling (needed to arm the timer to drive PWM generation). After this, I was able to detect my generated signal :) Forward progress...

But still no joy on controlling the TV. The online information I found about NEC encoding suggests the first two bytes are a device code/complemented device code. This doesn't match my 0x7B/0x1F pair, but for some reason I was suspicious of that anyway. So I modified my code to cycle through all device IDs, hoping if I hit the right one, I'd see the button effect on-screen. But still nothing. However, while running this code, the regular remote stopped working: I was seemingly overwhelming the TV receiver with my own transmission. This meant I was definitely generating the right frequency, and was transmitting signals that the TV receiver couldn't ignore (and maybe I'd reinvented the "Stop That!" remote jammer from years ago).

Looking at the online doc further, I noticed the 3rd byte is supposed to be the command code, and the 4th the complement of it. My fourth byte is listed in the table above, and feels right: button 1 is 0x01, 2 is 0x02, etc. Buy if those are the complimented codes...maybe I messed up in my interpretation of the remote's transmissions?

I found a pair of valid codes that were compliments of each other: MUTE (0x64) and INFO (0x9B). If I attempted to send either, and my bits were reversed, I'd still be sending a valid code.


Still no response from the TV. So I switched back to my original device ID (7B1F); still nothing. Finally, I complemented the codes I was sending, and...


SUCCESS!


Mute-Unmute-Mute-Unmute!
Mute command received, TV muted

Mute command received again, TV un-muted




So looks like my previous analysis was complemented?

I double-checked my earlier code, and sure-enough, I used a skip-if-less-than when I should have used a skip-if-greater-than: my codes were in fact complimented!

Or, rather, my device id was complemented, and my interpretation of byte order for bytes 3 and 4 were reversed. So the correct sequence is:

0x84/ 0xE0 / Command Code/ ~Command Code

So the above table is still correct. But send the true code as the third byte, and the complemented one as the fourth.

EPILOGUE

It's a bit glitchy. Interestingly, codes that end in a 1 work better than those that end in a 0. There's a big clue somewhere in there: almost certainly my timing is a bit off, and I'm crossing bit boundaries. Too tired to think deeply on this. But the basic setup seems to work. I'm using a granularity of 100 uS, I might do better with a smaller interval. Even better would be to use timer functions to reduce the variability due to code-path timing differences.


DOUBLE EPILOGUE

Just on a hunch, I tweaked my basic bit timing for a "1" bit, from an off time of 2.4 mS to 2.2 mS. Voila, much happiness! Even codes now work lol. Still some oddness, especially with sending different codes in rapid succession. More evidence of timing skew. Okay really strange observation: I put a (clear) glass in front of the LED to stop it from transmitting, but instead it seemed to make the system work even better! Something optical or multi-path going on? I can alternate channel and volume commands and it seems to do what it's supposed to. Much weirdness! OKAY FINAL TWEAK: scaled back my 0.6 mS intervals to 0.5 mS. Yay! Seems to work darn near perfectly now. Good enough for me, good proof of concept :)


IR TRANSMISSION CODE


;
; Try sending IR codes to TV
;
; N. Macias  July 2012
;
    #include    "P18F1320.INC"
    list    p=18F1320
    config  wdt=off, lvp=off
    radix   dec
    EXTERN  delay


    udata
bitCount    res 1
ourByte     res 1
workingByte res 1
iterCount   res 1   ; for delay100 code


    code
    org     0


Start:
    call    IRInit
mainLoop:
    ;movlw   0x9e    ; freeze code
    ;call    IRSend
    ;call    delay5Sec
    ;goto    mainLoop


    movlw   0x51    ; Channel down
    call    IRSend
    movlw   0x60
    call    IRSend
    movlw   0x60    ; vol+
    call    IRSend
    movlw   0x61    ; vol-
    call    IRSend
    movlw   0x40    ; Source
    call    IRSend
    movlw   0x40    ; Source
    call    IRSend
    goto    mainLoop




; IR initialization code
IRInit:
    movlw   0x70
    movwf   OSCCON  ; 8MHz operation


; start with output pin set to input
    bsf     TRISB,3 ; use pin 18 (RB3) as output to drive the IR transmitter


; we want to use the PWM feature of the PIC (P1A). This requires some setup...
; At a frequency of 38.5 KHz, we need PR2=51. and TMR2 prescale=1 (FOSC=8MHz)
; For 50% duty cycle we need to load 104. into CCPR1L:CCP1CON<5:4>
; 104. is 0001 1010 00 (10-bit binary): so set CCPR1L=0x1a and CCP1CON<5:4>=00


; set PWM period (51.)
    movlw   51
    movwf   PR2 ; set PWM period


; set ECCP control register
    movlw   0x0c ; 00 (P1A modulated) 00 (LSBs of duty cycle) 1100 (active high)
    movwf   CCP1CON


; set rest of PWM duty cycle (104. since not mult by 4)
    movlw   0x1a
    movwf   CCPR1L  ; MSBs of duty cycle (2 LSBs set to 00 above)


    bcf     ECCPAS,7    ; clear any shutdown code


; TMR2 setup
    bcf     PIR1,1  ; clearTMR2 int flag
    bcf     T2CON,0
    bcf     T2CON,1 ; set prescale value=1
    bsf     T2CON,2 ; Turn on the timer!


; To turn on PWM output, we need to:
; - wait until PIR1<1> is set (and then clear it?); and
; - clear bit 3 of TRISB
;
; to turn OFF, just set TRISB<3>


    return


; Send full packet containing code (in W) through IR
; NEC coding:
;   8.55 ON, 4.275 OFF - START
;   0.55 ON, either 2.4 OFF (1) or 0.6 OFF (0) - repeat for each bit
;   0.55 ON, 35 OFF - STOP
IRSend:
    movwf   ourByte ; save this
; send START pulse
    call    IROn    ; begin START pulse
    movlw   86
    call    delay100
    call    IROff
    movlw   43
    call    delay100


; send 4-byte message
    movlw   0x84        ; start of address
    call    sendIRByte
    movlw   0xE0        ; end of address
    call    sendIRByte
    movf    ourByte,w
    call    sendIRByte  ; actual code
    movf    ourByte,w
    comf    WREG        ; toggle bits
    call    sendIRByte  ; and send actual code


; send STOP bit
    call    IROn
    movlw   5
    call    delay100
    call    IROff
    movlw   125
    call    delay100
    movlw   125
    call    delay100
    movlw   107
    call    delay100    ; total 35.7 mSec
    movlw   127
    call    delay100    ; extra just for good measure


    return


; pump out a single byte
sendIRByte:
    movwf   workingByte ; send this byte as 8 pulse patterns
    movlw   8
    movwf   bitCount    ; count down to 0


sibLoop:
    call    IROn        ; turn on the beam
    movlw   5
    call    delay100    ; ON pulse; approx 5.5 mSec


    call    IROff       ; and turn off
    movlw   5
    call    delay100    ; .6 mS off time (this is a 0)
    movlw   16          ; prepare for additional 1.8 mS off-time
    btfsc   workingByte,0   ; skip next if bit=0
    call    delay100    ; else wait additional time


; now move to next byte
    rrncf   workingByte ; move next bit to LSB
    decfsz  bitCount
    goto    sibLoop     ; repeat 8 times


    return              ; all bits sent!


; turn on PWM output
IROn:
    btfss   PIR1,1  ; wait for interrupt request from timer
    goto    IROn
    bcf     PIR1,1  ; clear the bit (do we need to do this?)
    bcf     ECCPAS,7    ; clear any shutdown code
    bcf     TRISB,3 ; set RB3 as an output
    bsf     T2CON,2 ; Turn on the timer!
    return


; and turn off PWM output
IROff:
    bsf     TRISB,3
    return


; delays 100 uS * WREG
; Based on 8MHz FOSC, that's 200 instruction cycles
delay100:
    movwf   iterCount
delay100Loop1:      ; start of single 100 uS delay loop
    movlw   65  ; actual time is (199*w) + 5
delay100Loop2:
    decfsz  WREG
    goto    delay100Loop2   ; inner loop runs 201 cycles
    decfsz  iterCount
    goto    delay100Loop1   ; repeat the whole thing
    return


delay5Sec:
    movlw   50  ; wait 5 seconds
delay5SecLoop:
    call    delay   ; wait 0.1 sec
    decfsz  WREG    ; repeat 50 times
    goto    delay5SecLoop
    return


    end

Saturday, July 7, 2012

IR TV Remote Sensing with a PIC processor


Hacking around with a PIC18F1320 to do some IR sensing and, eventually, generation.

Working with a Sylvania TV remote.
Remote control with appropriate foreshortening for creepy effect

IR Reception

This remote seems to use IR (~900 nm?) with a carrier around 38.5KHz and PWM encoding.

I'm using a basic RadioShack IR receiver:

Pinout from front view:

+-----+
| /-\ |
| \-/ |
+-----+
 | | |
 | | |
 | | |
 | | +-- Vcc
 | +---- Gnd
 +------ Signal


Signal is normally 1; it goes LOW when an IR signal is detected. This is connected to a PIC via pin 18 (RB3).

IR Interpretation and Display

With this setup, I can read RB3 to see if the IR receiver is detecting a pulse. By counting how long pulses are present or absent, I can determine the encoding of each signal. Packets are received, one bit at a time, and stored in a series of four bytes.

After the STOP bit is received, I send the received bit pattern to my laptop via a serial port connection. The PIC's internal UART makes this transmission simple (code included below). I send the UART output through a 1K/2.2K ohm voltage divider to scale high outputs to ~3.3V (probably not necessary). This signal connects to a CP2103 breakout board (http://http://www.sparkfun.com/products/199): an easy way to connect uPs to a host machine via USB :) For this setup I only need to connect to 2 pins on the breakout board:

RXI this is where data is sent; and
GND

Then I can read transmitted bytes using minicom.

Full setup. That's a PICKit2 programmer on the right. IR receiver is next to the red wire on the left.

IR Encoding

The remote seems to use a standard NEC format:
ON for 8.6, OFF for 4.3 - START BIT
On for 0.6, OFF for either 2.4 (1) or 0.6 (0) - REPEAT FOR EACH BIT
ON for 0.6, OFF for >10 - STOP bit

Note that the information is encoded in the duration of the OFF pulses. This may be different from SONY encoding?

NOTE that repeat codes are different...

I then hit different buttons on the remote to see what was being transmitted. Here's the results.

RESULTS

Each packet appears to be 32 bits.
Some of the capture codes. I changed from showing all 4 bytes to just the final byte :)
Written as LSB first, the first byte received is 0x7B, followed by 0x1F These seem to be some sort of device code.
The third byte is the complement of the actual data byte (4th byte).
Thus there seems to be a simple 1-byte encoding per key. The mapping is as follows:

Final Code Table

BUTTON CODE(hex)
-----------------
POWER 20
0     00
1 01
2 02
3 03
4       04
5       05
6       06
7 07
8       08
9       09
Prev Ch 57
. 1B
Source  40
Sleep 22
Freeze  9E
Format 90
Eco 26
Menu 70
UP 73
DOWN 74
RIGHT 75
LEFT 76
OK    77
Back  78
Info  9B
Vol+  60
VOL-  61
SAP 65
Mute    64
CH+ 50
CH- 51

So the VOL+ button, for example, sends 7B 1F 9F 60 (first byte's LSB first).

Next Steps

The next step is to use this information to generate IR pulses to control the TV via the PIC uP. But since I don't actually watch that much TV, it's not clear why I would want to do this! Except I can combine this with the WiFly board I've been playing with and be able to control my TV from down the street :P

IR DETECTION CODE:

Monday, June 11, 2012

GPIO on Raspberry Pi

Finally playing some with Raspberry Pi HW. http://elinux.org/Rpi_Low-level_peripherals describes the 26 pin header available on the board; a number of GPIO pins, plus some serial lines etc. http://www.alliedelec.com/images/Products/mkt/lp/1203/resources/Broadcom_datasheet.pdf details the hardware of the Raspberry Pi unit, including the memory map for the device. Peripherals start at physical address 0x20000000 which maps to peripheral bus address 0x7E000000.

Video of blinking lights :)

Pg 89 begins the discussion of GPIO, which are based at 0x7E200000 (physical address 0x20200000). Setup is similar to e.g. PXA270: set the Function Select register to specify alternate functions (but also to specify straight input or output); bits are SET with the GPSETn registers, and cleared with the GPCLRn registers. There are also rising edge detect enable regs, etc.

Here's some C code, partially copied from the web and modified to make a stand-along function for mapping a block (4096 bytes) of physical addresses to virtual space:


#include <stdio.h>
#include <stdlib.h>
#include<fcntl.h>
#include<sys/mman.h>
#include<sys/types.h>
#include<sys/stat.h>


// map a page (4096 bytes) starting at physical address base
int *phys_to_virt(long base)
{
  int mem_fd;
  char *io_mem;
  char *io_m;
  volatile unsigned *io;

  mem_fd=open("/dev/mem",O_RDWR|O_SYNC);

// create page-aligned pointer to 4096 bytes
  io_mem=(char *) malloc(8192);
  io_mem+=4096;
  io_mem=(char*) (((int) io_mem) & 0xfffff000);

  io_m=(char *) mmap((caddr_t)io_mem,4096,
                     PROT_READ|PROT_WRITE,
                     MAP_SHARED|MAP_FIXED,
                     mem_fd,base);
  //io=(volatile unsigned *)io_m;
  return((int *)io_m);
}

This is called with a base address, such as 0x20200000; it returns a pointer to a block of virtual memory mapped into physical memory starting at that base address. You can compile this with

       gcc -c phys_to_virt.o phys_to_virt.c

No error checking: if something goes wrong you'll probably get a seg fault.

Now you can write standard ARM assembly to interact with the GPIO pins (or the RTC, etc.) You only need to call phys_to_virt() in the beginning, save the return value (from R0), and then use that as a base address into the memory-mapped space.

Here's an ARM assembly program for blinking an LED!


@
@ GPIO demonstration code NJM
@ Just calls phys_to_virt (a C program that calls mmap())
@ to map a given physical page to virtual memory
@ Must be run as root of course :) Use at your own risk!
@
.text
.align 2
.global main
main:
@ Map GPIO page (0x20200000) to our virtual address space
ldr r0, =0x20200000
bl phys_to_virt
mov r7, r0 @ r7 points to that physical page
ldr r6, =myloc
str r7, [r6] @ save this just for fun

@ Need to set the function register at [r7+4] so that bits <26:24>=001
@@@ Ooops forgot to do this! do the usual bit-twiddling lol
@@@ AND with 0xF8FFFFFF
@@@ OR with 0x01000000

Loop:
mov r2, #0x40000 @ mask with a 1 in bit 18
str r2, [r7,#0x1c] @ set bit in GPSET0

bl wait @ wait a bit

mov r2, #0x40000
str r2, [r7,#0x28] @ set bit in GPCLR0

bl wait
b Loop @ and do this forever :)

@ brief pause routine
wait:
mov r0, #0x4000000 @ big number
sleepLoop:
subs r0,#1
bne sleepLoop @ loop delay
mov pc,lr

.data
.align 2
myloc: .word 0

.end

R7 contains the base address of the GPIO registers. Blinking an LED on GPIO18 is a simple matter of:

  1. setting the function register to turn port 18 into an output;
  2. writing a 1 to bit 18 of the GPSET0 register and pausing; and
  3. writing a 0 to bit 18 of the GPCLR0 register and pausing.
Steps 2 and 3 are then repeated indefinitely.

For the board setup, I put a socket ont he header and pulled 5V from pin 2; ground form pin 6; and GPIO18 from pin 12. I put this into a simple transistor amplifier to drive an LED with very little current draw.

Note that the documentation warns that some of these header pins are directly connected to the main CPU chip, with no buffering etc. So proceed with caution!

Assemble with

    as -o gpio.o gpio.s -g

(-g if you want debug symbols)
 then link with gcc (to include the libraries needed for phys_to_virt):

   gcc -o gpio gpio.o phys_to_virt.o

Then run as

    sudo ./gpio

You can run this from gdb, but within gdb you can't directly read protected memory locations, even if you run gdb with sudo. But you can step through code that accesses protected memory and that works fine.

For a simpler demo, map phys address 0x20003000 into your virtual address space, then read the word (32 bits) at address offset 0x4. That's the lower word of a free-running system timer counter: it contains the number of microseconds since some basetime. Divide by 1,000,000 and you get seconds yay! So you can write code that just reads that location to keep track of time etc.





Wednesday, January 11, 2012

Upcoming talk: Android App Development with Eclipse and the SDK

I went to the ENGRCS club meeting yesterday at Clark, and Izad asked if I could do a brief talk on Android development. I'm going to do that in 2 weeks, following the 24 Jan meeting. I'm planning to talk about the following:

  • creating a new project;
  • basic GUI layout/properties/etc.
  • where you write your code (onCreate()...);
  • how to find your objects (findViewById);
  • coding for events; and
  • compiling/debugging/executing.
I hope to go through some simple demos, including a basic Hello World app, some interactions with pushbuttons, and an example of reading sensors.

Things I may also get to include:
  • virtual devices (AVD) - so you can develop without an actual Android device;
  • adb (Android Debugging Bridge) - really useful and fun if you do have an Android device;
  • intents (e.g. receiving SMS messages);
  • application lifecycle;
  • string externalization; and
  • database interaction (e.g. reading your contacts).
If you're interested in working along during this discussion, you'll probably want to have pre-installed Eclipse, the Android ADT plugin, and the Android SDK. This can take a long time, and I'm not really planning to discuss the details of it; excellent instructions are available at http://developer.android.com/sdk/index.html   I followed the instructions blindly, with very little understanding of what I was doing, and it worked out fine :)

DISCLAIMER: I've got a lot of programming experience in general (more than I care to admit), but I am not an expert Android developer, nor am I the least bit proficient at using Eclipse. I've learned enough to develop some simple apps of my own, but I still take some things on faith; I'm still working somewhat at the cut-and-paste level for certain things; and I don't know anything about "best practices" and so on. But I have figured out enough to get started and to navigate the SDK documentation, and given enough time and good fast techno music, I can generally get things working, eventually. My goal is just to help others get to that point.

Monday, January 9, 2012

Android BASIC

This is cool - playing on a friend's Kindle last week, I found an app called "BASIC!" It's good old BASIC as we all know and love it, but with hooks for most of the good Android hardware like GPS, WiFi, camera, etc. It's pretty darn cool; doesn't teach you anything about Android per se, but if you want a simple/fast way to start interacting with Android hardware, it's about the quickest route I can imagine. For example:

gps.open
gps.latitude i

will load your current latitude into i.

tts.init
tts.speak "Hello there"

will invoke the speech synthesis subsystem and speak your text. Seems like a quick way to try out some HW-related ideas and see if they're worth pursuing; or to simply entice people that Android is cool :)

Android

I've been programming for a long time - in C, assembly, Java, and a variety of other languages, under Unix/linux, VMS, RSTS, CMS, and of course Windows; but I'm very new to Android programming, and the experience has been different from what I expected. I'm far from an expert, so some of my perceptions may still be off the mark; this is just my current understanding of things...

As I've discussed elsewhere, I had never been fond of IDEs. But looking at documentation for the Android SDK was compelling enough to get me to stick with Eclipse, long enough to get over the first big bumps in the learning curve. I've since grown sort of fond of the whole integrated-environment approach :)

My first attempts at Android were based on a Hello World tutorial. It was fairly painless, the end-result worked as expected, and I could make minor changes to the code; but it wasn't very satisfying.

A while later, I tried Google App Inventor. I had read about this and downloaded the software, but not actually fired it up. Around the time I started playing with Lego Mindstorm, I finally tried App Inventor. It was fun! Pretty limited compared to the entire SDK (or so it seemed to me), but really fun nonetheless.

After clearing the Eclipse mental-hurdle (separate post), I was finally able to start using the SDK. Some things, like displaying text on the screen or responding to button presses, were straightforward to implement. Others required a but of a paradigm shift. For example, sending text messages. While I could create an object and invoke methods to send a message, I also needed to register to receive information about the success/failure of that operation. The keyword here is "intents." As far as I can tell, by registering an intent, you put yourself in line to receive (effectively) callbacks following certain actions. That's a mangled explanation I'm sure, but good enough for working purposes for now.

Intents are also used to receive incoming messages: you register a receiving intent, and when a message arrives, your code will be executed.

The debugging environment is pretty sweet: you can create virtual Android devices, and interact with them the way you would with an Android phone. This is where I began to notice that my Asus netbook is a bit slow for this kind of processing. It worked fine for writing a dissertation (and for doing the actual work on which that dissertation was based), but trying to start 2 virtual devices could take an hour or more. Starting the device from scratch, with no SAVE option, and very little else running seemed to help.

My first surprise came when I started downloading apps to my actual Android phone. Things worked great while the app was running, but after I exited, incoming texts would generate error messages. Moreover, if I rebooted, and never ran the application even once, incoming txxts would still generate error messages. This was a bit confusing to me at first, until I read up on the Android App Lifecycle.

On most operating systems I've worked with, installing a program basically meant copying an executable file into a path where it could later be invoked; but if you didn't invoke it, it was simply a file on disk. In Android, things seem quite different. When you install an app, it seems like it actually becomes part of the OS. In particular, in my case, its intents were registered as soon as the phone booted, and when a text message arrived, the OS tried to instantiate a method on a non-existent object, which generated the errors I was seeing. The key to working with this is to understand that Apps are, in some sense, always "running" (not really); you specify in different pieces of code what to do when the app is visible, when it's backgrounded, when it becomes invisible, and so on. Working with all this helped explain a few mysteries to me, such as why some apps don't seem to have an Exit option.

There's obviously a lot more to Android than I've explored so far. One of the really cool features is that you can invoke parts of other apps inside your own app, so, for example, if you want to let someone browse and select a contact from your address book, you don't need to write your own code for this; you can use intents to leverage pre-existing code to do this.

"adb" is a great tool for debugging when you're working with actual hardware. You can say "adb -d shell" to start an interactive shell running on the (USB-connected) device; "adb logcat" will do something like a "tail -f " on the device's logfile, which gives you a handy way to monitor device activity from the host computer; or to grep for specific tags to pick out your own debug/status messages as your app executes.

Still a lot to learn; next task is to play with some Bluetooth behavior.

IDEs


vi and cc - for a long time, those were the two tools I used for most of my programming. Maybe a linker once in a while, though I usually just let “cc” invoke it. I debugged by embedding printf() statements, and the closest I got to using a Makefile would be a script (usually named “doit” or “go”) that listed a cc command for each program to be compiled, and a final one to link together the .o files. IDES? Pffft! or so I once thought…
I did use Visual Basic back in the early 90s. That was fun! It was so different from the programming I usually did, that it didn’t feel like I was using something different from what I would normally use. It just felt like VB meant a big graphical environment where you drag and drop objects, click on them to get to their action code, and so on. I was using an IDE, but it didn’t feel wrong.
Then I pushed my luck: I decided to learn MFC, using Visual C++. The experience was horrifying! I wanted to write a simple “Hello World” program. I followed the first few steps of the tutorial, and then BAM! I had what felt like dozens of pieces of code, each requiring me to fill in certain sections, none of it having any meaning to me, and apparently having nothing directly to do with writing “Hello World” to the screen. I followed the steps in the tutorial, feeling a bit like a circus animal. In the end, the program did what it was supposed to, but I had no idea why it worked, or what I had just done. I returned a few times to repeat this exercise, but always felt like instead of programming, I was being enslaved by the IDE: tasked to do its bidding.
That was my last experience with an IDE for something like 17 years.
Last year (2011) I took one shot at developing for Android - again with a Hello World tutorial. Not as bad as my Visual C++ experience, but it didn’t leave me feeling warm and fuzzy.
I bought a TI EZ430-Chronos watch a few years ago, and around the same time I tried developing some code for that. Again, following a tutorial, not sure why I was doing all the things I was doing.
In Fall 2011, I bought some Arduino microprocessor boards. These boards required me to use an IDE, but it was completely painless: really just an editor window, a Compile button, and a Download button. It had some annoying auto-indent, but I mostly just ignored that. Somehow, that seemed to get me over a mental hurdle as far as IDEs.
A bit later, I was looking at the Android SDK, realizing that if I knew how to call these different methods, I could do some really cool programming. I think that planted the seed for really wanting to learn how to program on an Android OS.
While playing with the Arduinos, I developed an application that required a GUI on the connected PC. Here again, I had always done GUI development with pretty low-level tools. For Java, this meant using AWT. “It works, that’s good enough.” But now, the thought of creating my own widgets, writing all that even-handling code for routine events, and so on, felt overwhelming. I started looking for a better way.
I Googled, and found someone who had effectively ported Visual Basic’s look and feel to Linux. I downloaded that (feeling slightly embarrassed), and tried to install it, but it needed a lot of additional software to be installed as well. Combined with my embarrassment, I gave up quickly and kept Googling.
The 3rd or 4th time Netbeans came up, I decided to look at it more closely. I had heard the term over the years, but never knew what it meant. I assumed it was some sort of package/set of libraries/some annoying add-on. But I dug into it, and…wow! Suddenly I understood :)
Netbeans changed my life over a span of 12 hours. Suddenly, I could develop Java GUIs as easily as I had one used Visual Basic. As advertised, it let me concentrate on writing the code itself, without worrying about the display and management of the widgets. Suddenly, creating GUIs was fun again. If I wanted a text box and some push buttons to go with my code, it was easy to add them.
More significantly for me, Netbeans got me over my phobia of IDEs. Maybe it was just my mood, or maybe the time was just right, but for whatever reason, I embraced what the IDE offered, and found it not bad at all. After a few days, I began to actually enjoy certain parts of the experience.
From there, I went to Eclipse, and finally found peace working with the Android SDK. My Hello World was an application to allow me to type SMS messages on my laptop and have them sent by the phone. I didn’t feel like messing with sockets just then, so I used tag-files on the SD card to pass requests and status between the phone and host PC. Old-school, but it worked. From there, I added the ability to monitor incoming text messages and pass those to the PC for display. This was a nice mix of Eclipse for Android development and Netbeans for the PC GUI. Doing this was a blast!
THINGS I LOVE ABOUT IDES
  • automatic syntax/semantic checking, as soon as you make a typo etc.;
  • automatic dropdown boxes showing available methods for a just-typed object;
  • suggestions on how to correct mistakes, often with the option to auto-correct (add an “import” statement, etc.);
  • ability to re-format all code with a single command;
  • externalization of strings. Seemed goofy to me at first, but it really makes a lot of sense, and I can see taking advantage of this a number of ways;
  • “refactoring” - for example, changing the name of a variable or object and having the IDE change all references accordingly.
THINGS I’M STILL WORKING TO LOVE (OR TOLERATE) ABOUT IDES
  • automatic syntax/semantic checking, as soon as you make a typo etc. Because while I’m typing “longvariablename” it’s flashing red and underlining and warning me that “longv” is not a defined name…”longva” is not a defined name…”longvar” is not a defined name…you get the idea. How about waiting till I stop typing, or hit a delimiter like a space or “.”
  • auto-fill-in of text. I think I’ve got this disabled, and things work great, but once in a while, I find a generated closing parenthesis at the end of a line while I’m still typing. Usually it disappears once I type my own “)” but once in a while it stays there. Similarly, sometimes the method that appears after an object is nothing like what I typed, but was a automatically filled-in suggestion that took precedence over what I typed. Sometimes these take a while to find, because I’ve learned to ignore most of the reported errors and warnings, because
  • there are a lot of reported errors and warnings. If I have a debug var I’m not using, it generates a warning. If I am using an object I haven’t yet defined, I get a bunch of warnings. It’s disconcerting. I want to know about these when I compile, not while I’m typing. The worst of all may be when you begin a definition with a “{” and the entire rest of your program is underlined/red/flagged as an error because there’s a brace mismatch now. And if you correct an error, it won’t necessarily correct errors in other files until you save your changes. Makes sense, but kind of changes programming from a nice relaxed encounter to a tense ERROR! ERROR! one.
  • automatic indenting/formatting. It’s useful after the fact, but not so much while typing. I’ve tried the options for tailoring this, but the space between too-much and too-little seems pretty wide. And in fact I enjoy indenting, I like balancing braces. It helps me keep things organized in my mind, helps me know where I am in the code and what I’m doing. When that’s removed, I tend to more-quickly lose track of where I am.
Just my initial experiences :)