Quantcast
Channel: MD's Technical Sharing
Viewing all 63 articles
Browse latest View live

Interfacing Nokia 3510i and 5110 LCD with PIC Microcontroller

$
0
0
Recently I started to regain some interest in embedded systems, and start to experiment with PIC micro-controllers. After some successful attempts with standard character LCDs using using the HD44780 controllers, I decided to get some Nokia LCD modules from eBay to explore.

The 2 LCD modules I purchased are for the 3510i and 5110 models. Both have built-in controllers which use Serial Peripheral Interface (SPI). The following are the pinout for my modules, notice that pin assignments may vary slightly.

LCD pinout

Nokia 5110:



Nokia 3510i:

The only different here is pin #5 which is used as data/command selection for the 5110, and unused for the 3510i.

Voltage difference: 5.5v vs3V

Both LCDs are designed to work with 3.3V, but due to an internal voltage clamp 5V can be used for SCLK, SDATA, REST, D/C and CS as long as a current limiting resistor (around 10k) is connected in series for each line. 3.3V should still be applied to VCC and the LED supply. I have tried using voltage dividers, which did not work, perhaps due to the LCD varying internal resistance and current consumption.

With the above connections we can only write to the LCD but can't read back the LCD response because 3.3v is not high enough to register as logic '1' in the PIC. Luckily reading from the LCD is not required for basic operations; all that is needed is sufficient delay after each operation to make sure the LCD is ready for next command.

I have chosen the PIC16f88 simply because it's available in my junk box. However, as the 16f88 does not have dedicated hardware SPI required by the LCD modules, bit-banging has to be used to simulate SPI. Although this usually means complicated code and lower throughput, it does not matter as all I wanted is to get the LCD to display something useful ;)

LCD Memory Map

The 5110 LCD is monochrome, uses the PCD8544 controller and has a resolution of 48 rows × 84 columns. Each 8 pixels on a single column consumes a single byte on the LCD memory map. It takes 504 bytes to fill the entire LCD.

The 3510i LCD has 97x66 resolution and can operate in either 256 or 4096 colors. Since there seems to be little difference between 256 and 4096 colors due to the small resolution, I have chosen 256 colors for simplicity. Each pixel on the LCD is represented by a single byte and filling the entire LCD takes 6402 bytes in 256-color (8-bit) mode.

Sample code: displaying test patterns

The following code shows how to display all black pixels on the Nokia 5110 LCD. Notice that LCD initialization code is not shown.

void lcd_5110_clear()
{
for(int i=0; i<84;i++)
{
unsignedchar row;
for(row=0;row<6;row++)
{
//all black pixels
char data =0xFF;

lcd_5110_send(0x40+ row,0);//Y address
lcd_5110_send(0x80+ i,0);//X address

//write to display memory
lcd_5110_send(data,1);
}
}
} 

The following code shows how to display a selected color on the 3510i LCD:

void addset(unsignedchar x1,unsignedchar y1,unsignedchar x2,unsignedchar y2)
{
send(0x2a,0);//column address set
send(x1, 1);
send(x2, 1);
send(0x2B, 0);//page address set
send(y1, 1);
send(y2, 1);
send(0x2C,0 );//memory write
}
void LCD_Clear(unsignedint value,unsignedchar Color)
{
unsignedchar x, y;
addset(0,0,97,66);
for(y =0; y <67; y ++)
{
for(x =0; x <98; x ++)
{
send(Color, 1);
}
}
} 

Displaying text and graphics

Up until now you can only display test patterns on the LCDs. The use of a bitmap font (and extra code) is required if you want to display any useful text. I have chosen a 8x12 font for the 3510i LCD, and a 5x8 font for the 5110 LCD. The font, together with any graphics to be displayed, will be stored in a 24C64 (8Kbytes) I2C EEPROM. To program the EEPROM, I use the I2C version of the PonnyProg programmer. Notice that this may not work on newer PCs where the available current from the serial port is limited and will never work with a USB-to-serial converter. In my experiment, I made a stupid mistake of adding a LED via a 470 ohm resistor to show activity during programming. This result in data corruption and verification errors after programming due to excessive current consumption. Changing the resistor to 2k worked fine, although the LED is much dimmer.

With the EEPROM to store font and graphics, the 5110 LCD could now display text and some monochrome bitmap:


The 3510i LCD could do a much better job ;)


Notice that the serial port connector is for debugging purposes only.

The entire source code is attached here. The contents of the EEPROM is included with the source code and named eeprom.bin.

Another customer service tale: "Your system connects me to the wrong number, please refund!"

$
0
0
An early Monday morning at my company, which offers budget international calls via callback, I received a call from a user complaining he was connected to the wrong number and demanded a refund. Below is the conversation. The story is true with some details removed and/or altered to protect privacy.

....
User: Please help me, your system connects me to the wrong number.
Me: Can you describe what exactly happened?
User: I called your callback hotline at 6XXX XXXX, the system called me back, I answered the call and keyed in the number to call. The destination rang but the person picking up the call told me I had called the wrong number. Please refund the credit.
Me: Can I have your username and the number you wished to call?
User: My username is ..... and the number is +84XXXXX
Me: (after checking his account activity) According to our record, you have called +7484XXXXX, did you happen to key in the wrong number?
User: No, I entered it correctly.
Me: Can you tell me what you did exactly when the system prompted you to enter the destination number?
User: I entered +74 first, then realized it should have been +84, so I pressed Clear Display on my phone and re-entered the correct number.
Me: (almost started to laugh) I am sorry sir, the Clear Display only clears the display screen on you phone for your convenience and does not reset what you have entered into the system. Therefore you ended up calling the wrong number.
User: But I am the user and I don't care how your systems works. Please refund my credit!
...

This conversation should be normal and acceptable for a first time callback service user. However, I later found it to be disturbing once I knew that he is a frequent callback user with a PhD degree in computing. All Interactive Voice Response (IVR) system works based on DTMF which does not support a DELETE key or similar. All digits entered locally will be registered with the server, which is why sometimes you are asked to confirm sensitive information (via 'Press 1 to confirm or Press 2 to change') before any action is made. In any case, I believe it doesn't take a genius to know what he did (pressing the 'Clear Display' button) would not have worked. I have always thought that PhDs are supposed to be critical thinkers with good reasoning and whatnot, together with their professional skills. Oh well ...

See also
  1. MobileOne not M1 
  2. Some Technical Tales
  3. Just because a method is called Refresh doesn't mean that it refreshes what you want

Windows Phone 7 and Singapore IDD prefix 0XX

$
0
0
When using my Windows Phone 7 today to make an international call using Singtel IDD 019, I realized that the call could not get through and the operator would always report "The number you have called is incorrect". Checking the call history showed that the prefix 019 has been replaced with "+9" by the Windows phone for unknown reasons.

After much googling, I found a way to disable this. This is part of a feature called International Assist by whoever designs the phone. To disable it, open Settings, click on Applications on the top bar, select Phone and turn off International Assist.

I am not sure which standard defines that "01" is the same as "+" as an IDD prefix or why this feature should be on by default. In any case, it's just another hassle when using Windows Phone 7!

See also:
25 Windows Phone 7 tips and tricks

Samsung P2370 and ATI Moblity Graphics Card

$
0
0
I recently bought a Samsung P2370 LCD monitor in order to watch 1080p HD movies on my HP G42 laptop, which is using an ATI Mobility Radeon HD5470 graphics card. Much to my surprise, this combination did not work at all and was a total waste of time. Here is why.

The monitor screen size is 23-inch, supporting full HD resolution at 1920x1080 and has only one DVI input. Interestingly, the on-screen display shows that the monitor searches for signal on both analog (likely referring to VGA) and digital (DVI) inputs. This is perhaps because the same firmware code base is shared with another similar model, the Samsung P2370HD that supports VGA input, among many other things including a TV tuner.

I first tried to connect the monitor to a DVD player with DVI output and everything worked well, so I proceeded to connect it to my HP G42 laptop HDMI port via a cheap DVI-to-HDMI converter purchased from eBay. Although the PC booted normally, with the monitor showing BIOS POST messages and Windows logo, the display is not detected once Windows finished booting. Screen Resolution settings in Windows 7 reported Another display not detected:

I tried to disconnect, reconnect, reboot Windows, reinstall driver to no avail. I also tried to install the Samsung driver for the LCD. The notebook graphics card has 3 outputs: LCD panel, VGA and HDMI. However, the monitor driver install utility only offers to install driver onto the LCD and VGA output, but not the HDMI output.

It then came to my attention that the P2370 was never detected - Windows played the "device connected" sound when I connected other monitors via HDMI, but not the P2370. The monitor worked well with other graphics cards, and the notebook graphics card HDMI output worked well with other monitors! So there must be something wrong with my special hardware combination. To my knowledge, unlike VGA where handshaking is optional and you can always force the graphics card to output to VGA port even when no monitor is connected, HDMI  has some compulsory handshaking involved and the monitor has to be detected before the graphics card can output anything.

I then tried MonInfo and surprisingly the P2370 could be detected properly, with all the parameters correct. I tried to create a custom monitor driver to use with PowerStrip, which did not help either because the graphics card did not 'see' the monitor! Not giving up yet, I tried Windows XP which does not have automatic monitor detection. This time round, the Samsung driver installation utility could install the driver to the HDMI output, but the HDMI port was still not visible in Display Properties. I then tried to launch Windows in Safe Mode where only the VGA driver is loaded, and the P2370 always displayed a clone of the laptop LCD, much like what happened during boot time. The Fn key combination to switch between clone/extended desktop did not work.

All this observations suggested that the hardware was fine and the problem was with the ATI driver for Windows which could not see the P2370 via HDMI for some reasons. My final attempt was to try various Linux variants, hoping that some Linux drivers may fix the problems. However, the same problem persisted:
  1. On Linux builds where the graphics card was detected properly, no output on HDMI.
  2. On Linux builds with no driver for the graphics card, the P2370 displayed a clone of the laptop LCD
This is a dead end. In the end, I decided to sell the Samsung P2370 LCD and get a Dell S2409W instead, which has served me well so far. During the troubleshooting, my research revealed that this is a common problem (it's even in Google Autocomplete suggestion list, try to search for 'samsung p2370 ati problem') with no official answers from either Samsung or ATI, and no solutions available.

This problem may apply for other ATI card as well. The bottom line is not to buy Samsung P2370 and similar models if you're using an ATI graphics card!

The old new thing: mathematics of paper folding

$
0
0
A few weeks ago I received the following quiz as one of the questions for an exam. The question is about paper folding, something that we all know from an early age, and seems simple but it seems that no-one could answer it. I presented it in this article with my proposed solution in an attempt to show how a frustrating mathematics problem could be set from something so simple in our everyday life.

The Problem

Fold a sheet of A0 paper (841mm x 1189mm) in such a way that the longer side (1189mm) is divided into half its length, you will get a sheet of A1 paper (594mm x 841mm). Do the same for the resulting piece of paper and you'll get a sheet of A2 paper (420mm x 594mm). Repeat the same twice and you will get the commonly used paper size, A4 (210mm x 297mm). This process could repeat over and over again to get a paper size of An after n times, as demonstrated in the following diagram:

Now let us define an "inner fold" as the line created on the original paper when you fold it into half, unfold it and look at it from the front:


On the contrary, if you look at the resulting paper from the back, you will see an "outer fold".

After n steps, unfold the original piece of paper and place it in front of you. Now calculate the number of "inner" and "outer" folds created on the paper (You position the paper and look at it the same way as how you did when you started folding it for the first time).

An example for up to n=3 is demonstrated in the following diagram. A normal dashed line indicates an inner fold while a bold dashed line indicates an outer fold.
 
The number of inner and outer folds for up to n=6 is shown in the following table. Notice that if a fold is intersected by another fold, it is counted as 2 folds.

n
Inner Folds
Outer Folds
Total
0
0
0
0
1
1
0
1
2
3
1
4
3
6
4
10
4
14
10
24
5
28
24
52
6
60
52
112

The first task is to find a general formula or algorithm to calculate the number of inner and outer folds after n times.

My Proposed Solution

As simple as it seems, there is no quick solution the problem. Since most people don't have an A0 sheet of paper at home to try to fold so many times, they can only attempt with the common A4 paper and get frustrated after a short while when the paper becomes too thick to fold or the number of folds too big to count.

I proposed a simple solution below. My research also shows that there are several other approaches which may yield seemingly different formulas. Do not read it until you have attempted the question.:)

First let us simplify the problem by calculating the total number of folds first. It is simply the total number of grid segments on the original piece of paper after n steps.

We first observe the total number of horizontal (from left edge to right edge) lines and vertical (from top edge to bottom edge) lines after every fold:

n
Horizontal
Vertical
1
1
0
2
1
1
3
3
1
4
3
3
5
7
3
6
7
7

This can be generalized into:

Now look at each horizontal and vertical line and calculate the number of segments on each line:

n
Segments
/hori. line
Segments
/vert. line
1
1
0
2
2
2
3
2
4
4
4
4
5
4
8
6
8
8

This can be generalized into (for n=2 and above)
 The total number of folds after n steps is simply:

No. of horizontal lines x No. of segments on each + No. of vertical lines x No. of segments on each

With some efforts we are able to derive the formula for the total number of folds:
Now that we have found out the total number of folds, let's calculate the difference between the number of inner folds and outer folds after each step:

n
Inner Folds
Outer Folds
Diff.
1
1
0
1
2
3
1
2
3
6
4
2
4
14
10
4
5
28
24
4
6
64
56
8

Surprisingly enough, the difference is simply:
I leave this as an exercise for the reader to prove why. With the sum and the difference known, we can now calculate the number of inner and outer folds easily:
The first part of the problem is now solved. You can compare the results from our formulas with the example to make sure that the formulas are correct. Interestingly, the total number of folds after each step is equal to the number of outer folds in the next step.

Bonus Question

This is the next part of the problem: 

"So far you have always been folding by the longer side of the resulting paper after every step (so that you could get an A1 paper from A0, A2 from A1, A3 from A2 and so on). Now you are told that this restriction is no longer necessary and you could fold the paper by either the shorter or the longer side. For example, fold an A0 paper (841mm x 1189mm) by the shorter side and you will get a piece of paper of size 420mm x 1189 mm. 

How would the final formula for the number of inner and outer folds change? Derive a method to calculate the total number of inner and outer folds after a given set of fold steps, where one can fold either way in each step."

Although I managed to write a program to solve this, I believe there is no need to describe it here as most readers by now would have understood the concept and would know how to approach this extension of the original problem.

Afterthoughts

The concept which the problem is based on is very simple and does not require any fancy maths knowledge - anyone with perhaps a secondary school education can understand the problem. However, among many whom I have asked, almost all would immediately attempt the question but most would just become frustrated and give up without ever finding the solution, or even the correct approach. I believe it requires a high level of concentration and logical thinking as the number of folds grows exponentially. Setting this as an exam question where students work under stress and time constraints would therefore be unreasonable.

Still alive after all these years: NEC D3835 45MB SCSI hard disk

$
0
0
Recently I got around 20 old IDE/SCSI hard disks for free from a member of a Singapore technical forum and decided to try out all of them, one by one, with the help of an Adaptec AHA-2940UW, since my motherboard does not have SCSI ports. Utilizing the maximum available space in the chassis, I install 7 of them to my computer:

The 2 identical Seagate ST31276A drives are installed on the primary IDE channel while the IBM DARA-206000 6GB 2.5in drive is installed on secondary master with the help of a cheap 2.5" to 3.5" IDE converter purchased from eBay.

The 4 SCSI hard drives are detected separately by the SCSI BIOS. The last hard disk in the list, also the most notable, is the NEC D3835:

It's a 45MB 3500rpm SCSI hard disk drive, even older than the hard disk of my first computer (an old 80386 with a 106MB IDE hard disk). The rated speed is at 1.5MB/sec, way below the tens or hundreds megabytes per second which modern hard disks are capable of.

It is so old that HDTune refuses to test it:


The error message said "Read Error! Test Aborted" and popped up immediately after I clicked on the button to begin the test. But do not think that the hard disk is faulty - the error shows simply because the hard disk capacity is too small for HDTune to read/write data buffers onto it for testing. Perhaps the author did not expect such an old drive to be still alive today.

All the installed hard disks can be seen from Disk Management in Control Panel, with the NEC in the last position, certified as 'healthy' by Windows:


Unfortunately Windows is just plain wrong and the hard disk is actually on its last legs:



The label says the manufacture date is December 1990, which means the drive is getting 21 this year. That's equivalent to 100+ years for a human being. You will get nowhere near that for a modern hard drive, flash drive, or even solid state drive (SSD). Commercial pressure has forced manufacturers to use cheaper components, resulting in shorter life expectancy of their products, and you must be very lucky to see any modern storage device lasting more than the warranty period without issues.

HTC HD2 Android: Working with ext2 images under Windows

$
0
0
My HTC HD2 running on Android from SD card had been working well for some time until it could not boot to Android one day (booting to Windows Mobile was still fine). Obviously I could redownload the same Android build, but this would mean loss of text messages, applications, call history and any other data not backed up or synchronized with Google server. In an attempt to salvage these data, I looked at the Android folder on the SD card and notice the following files:

data.img: contains user data such as text messages, applications, etc.
system.ext2 and rootfs.img: Android system files

Although most guides suggest using a Linux live CD such as Ubuntu and use the mount command to mount them as drives, which actually works, I wanted to do the same in Windows. My first try is to use Daemon Tools. This obviously has no chance of success, as the tool is meant to mount CD/DVD images, and not disk images, not to mention the Ext2 filesystem used by Android. I then tried various Windows tools to open/mount Linux images, and summarized the results in the following table. Take note that the image may be easily damaged if mounted by a tool not supporting it, or if not unmounted properly. If you want to try this, remember to back up first!



data.img
rootfs.img
system.ext2
R
R
R
X
R
R
X
RW
RW
X
RW
RW
R
X
X
X
R
R

Legend
X=failed
R=read-only access
RW=read/write access

You may need the Ext2 driver for Windows for some of the tools to work. Also read this tutorial on using IMDisk.

Looking at the table, Ext2Explore does the best by supporting all 3 images, albeit with read-only access. GizMo and ImDisk support  read/write access for rootfs.img and system.ext2 (with IMDisk being more stable), but not for data.img, where most of the user data stays. DiskInternal Linux Reader supports data.img in read-only mode, but not the other two images.

So what is so special about data.img? Some websites say it is using YAFFS2 filesystem, which only applies for phones with Android on ROM. Since my Android is on SD card, I believe data.img still uses ext2, perhaps with some special format causing most Windows tools to fail mounting it.

Extending system.ext2

My next challenge is to use Windows to extend my system.ext2 as I want to add some fonts and background images and my system.ext2 does not have enough space. This time, despite finding no Windows tools that provide read/write access to data.img, I find a set of tools from xda-developers that does the job. The author compiled the source code of dd, dumpe2fs, e2fsck, mke2fs and resize2fs to run under Windows and built a user interface for it using Tclkit:

However, the TopoResize app is poorly written and crashes all the time. I resorted to resizing the image using the command line tools mentioned above:

dd if=/dev/zero bs=1M count=XXX >> system.ext2
XXX = Amount of space in MB to be added to the image

resize2fs -f system.ext2
Resize the filesystem in the image

e2fsck -f system.ext2
Perform a check on the new filesystem. Without this, Android may hang while booting up.

The set of command line tools I used can be downloaded here. Next thing on my wishlist is to open data.img read/write on Windows; if anyone knows of a way, do leave a comment here. :)

Xcode 4 bug: Crash when using Core Data Model from Xcode 3

$
0
0
I recently upgraded my Xcode from version 3 to 4.0.2 (build 4A2002a) and notice that Xcode keeps on crashing whenever I right click on a core data model used in an iOS application:


The error message reads:

Xcode encountered an internal logic error. Choose "Continue" to continue running Xcode in an inconsistent state.  Choose "Crash" to halt Xcode and file a bug with Crash Reporter. Choosing "Crash" will result in the loss of all unsaved data.

ASSERTION FAILURE in /SourceCache/IDEKit/IDEKit-303/Framework/Classes/StructureEditingAdditions/IDEStructureEditing+Additions.m:587
Details:  Assertion failed: [indexes lastIndex] <= [_targetGroup.subitems count]
Object:  
Method:   -structureEditingCanGroupSubitemsAtIndexes:
Thread:   {name = (null), num = 1}
Hints:   None
Backtrace:
  0  0x0000000100949773 -[IDEAssertionHandler handleFailureInMethod:object:fileName:lineNumber:messageFormat:arguments:] (in IDEKit)
  1  0x000000010006d394 _DVTAssertionFailureHandler (in DVTFoundation)
  2  0x00000001009a683e -[IDEContainerItemStructureEditingTarget structureEditingCanGroupSubitemsAtIndexes:] (in IDEKit)
  3  0x000000011e9e5661 -[IDEStructureNavigator _testOrGroupSelected:useContextualMenuSelection:] (in IDEStructureNavigator)
  4  0x000000011e9e2617 -[IDEStructureNavigator validateUserInterfaceItem:] (in IDEStructureNavigator)
  5  0x00007fff834a538b -[NSMenu _enableItem:] (in AppKit)
  6  0x00007fff834a50e8 -[NSCarbonMenuImpl _carbonUpdateStatusEvent:handlerCallRef:] (in AppKit)
  7  0x00007fff8348899c NSSLMMenuEventHandler (in AppKit)
  8  0x00007fff884357f7 DispatchEventToHandlers(EventTargetRec*, OpaqueEventRef*, HandlerCallRec*) (in HIToolbox)
  9  0x00007fff88434d46 SendEventToEventTargetInternal(OpaqueEventRef*, OpaqueEventTargetRef*, HandlerCallRec*) (in HIToolbox)
 10  0x00007fff88452a81 SendEventToEventTarget (in HIToolbox)
 11  0x00007fff88481c35 SendHICommandEvent(unsigned int, HICommand const*, unsigned int, unsigned int, unsigned char, void const*, OpaqueEventTargetRef*, OpaqueEventTargetRef*, OpaqueEventRef**) (in HIToolbox)
 12  0x00007fff8849510f UpdateHICommandStatusWithCachedEvent (in HIToolbox)
 13  0x00007fff88431725 HIApplication::EventHandler(OpaqueEventHandlerCallRef*, OpaqueEventRef*, void*) (in HIToolbox)
 14  0x00007fff884357f7 DispatchEventToHandlers(EventTargetRec*, OpaqueEventRef*, HandlerCallRec*) (in HIToolbox)
 15  0x00007fff88434d46 SendEventToEventTargetInternal(OpaqueEventRef*, OpaqueEventTargetRef*, HandlerCallRec*) (in HIToolbox)
 16  0x00007fff88452a81 SendEventToEventTarget (in HIToolbox)
 17  0x00007fff8849476f SendMenuOpening(MenuSelectData*, MenuData*, double, unsigned int, __CFDictionary*, unsigned char, unsigned char*) (in HIToolbox)
 18  0x00007fff885b77ae PopUpMenuSelectCore(MenuData*, Point, double, Point, unsigned short, unsigned int, Rect const*, unsigned short, unsigned int, Rect const*, Rect const*, __CFString const*, OpaqueMenuRef**, unsigned short*) (in HIToolbox)
 19  0x00007fff885b7dc2 _HandlePopUpMenuSelection7 (in HIToolbox)
 20  0x00007fff835da99b _NSSLMPopUpCarbonMenu3 (in AppKit)
 21  0x00007fff835dad4b -[NSCarbonMenuImpl _popUpContextMenu:withEvent:forView:withFont:] (in AppKit)
 22  0x00007fff8372bb37 -[NSMenu _popUpContextMenu:withEvent:forView:withFont:] (in AppKit)
 23  0x00007fff836304c0 -[NSControl _rightMouseUpOrDown:] (in AppKit)
 24  0x00007fff834270c7 -[NSWindow sendEvent:] (in AppKit)
 25  0x00007fff8335bafa -[NSApplication sendEvent:] (in AppKit)
 26  0x000000010085b36e -[IDEApplication sendEvent:] (in IDEKit)
 27  0x00007fff832f26de -[NSApplication run] (in AppKit)
 28  0x00007fff832eb3b0 NSApplicationMain (in AppKit)
 29  0x0000000100000eec

I may click 'Continue' on the dialog box to ignore the error, but subsequently Xcode would just crash randomly and too unstable to be used. For example, clicking on the Help menu would crash Xcode, but not any other menu.

The root cause, after much investigation, was the hierarchy of the .h and .m files for the core data class objects. In my original project from Xcode 3, the .h and .m files stayed under the .xcdatamodeld file in the project tree:

This was the default behavior on Xcode 3. However, Xcode 4 does not allow you to place these files under the .xcdatamodeld file, which is perhaps why it crashed since the case was never handled. I removed all the .h and .m files, regenerated them and put them under the CoreData group, and Xcode stopped crashing (for now):

I thought that was it, but unfortunately the problem did not stop there. Xcode again crashed when I attempted to commit the project to SVN:

The reason for the crash was 'editorDocument should be an instance inheriting from IDE-QuickLookdocument, but...' Perhaps only Apple knows what this really means... Nothing really helped, including restarting Xcode, closing all open source code files or cleaning/rebuilding the project. In the end, I committed to SVN from command line, checked out a fresh copy of the project and Xcode no longer crashed when committing!

Finally, I am somewhat disappointed at Xcode 4.0.2. The UI changed significantly and some of the important behavior also changed, perhaps without any documentation at all! For example, for each core data relationship, the Edit>Create NSManagedObject subclass... creates the methods to add/delete objects to the relationship in the .m file, but forgets to to put them in the header file. This results in plenty of compilation warnings if your code is from Xcode 3 and the core data class files are regenerated using Xcode 4. I have to resort to manually modifying the header files to add the correct method signatures...

I hope these issues will soon be fixed in the next release of Xcode.

Blogspot bug: Google+ Share button and Google Friend Connect widget

$
0
0
Recently I observed that the Google Friend Connect widget that shows my site's followers on the left panel sometimes cannot be displayed. Refreshing the page did not help; clearing cookies and browser cache could only make it appear momentarily - the widget would disappear again eventually.

Firefox's error console (accessible via Tools>Error Console or Ctrl-Shift-J) and this post provide some hint:

The error messages are:

Error: window.googleapisv0 is undefined
Source File: https://apis.google.com/js/plusone.js
Line: 12

Error: google.friendconnect.container is undefined

The .js file used for Google "+1" button displayed at the end of every post is possibly conflicting with the js file for the Followers widget. As the both script files are obfuscated, it is not worthwhile for me to spend time investigating where the problem is. I ended up disabling the Share bar after every post by opening the Design tab of my blog settings, clicking Edit button at the bottom of the Blog Posts element, and unchecking Show Share Buttons


This would disable the entire set of share buttons even though I know I only need to disable the Google+ button. As there seems to be no way to show/hide each button individually, the only way to show only specific Share buttons (for example, share via Facebook) is to modify the page template and manually add in the code for the button.

Once you have manually modified the page template, always use the Edit HTML tab, and not the Page Elements tab to change the blog layout. Otherwise your changes may be lost and there may also be other unexpected results.

This is too much trouble, so the set of Share buttons at the end of every post in my blog will be disabled until this bug is fixed...

Compaq Contura 3/25C 80386 Laptop

$
0
0
I recently picked up a free Compaq Contura 3/25c, a very old IBM-compatible laptop computer from the early 1990s, with a 25MHz 80386 processor, 4MB onboard memory and 3.5in 1.44MB floppy drive. The original 120MB hard drive has been removed by the previous owner. The laptop is also in very bad shape, with dust all over the place and the LCD panel removed:


The laptop must have looked like this when new with the 8.4inch black and white LCD:


I was trying to make it boot up by connecting an external monitor to the VGA port when I noticed that the VGA port is actually keyed via pin #9. No modern VGA cable would fit into this port until you break pin #9 on the cable or punch a hole on pin #9 of the port. Since there is actually no need to key a VGA DB9 connector because the shape of the port would prevent you from inserting it upside down anyway, later VGA ports used pin #9 as an optional +5V DC source.

The unit boots up with a "RTC Lost Power" error message (see this for a full list of Compaq POST error messages). This is quite common with old laptop when the CMOS battery finally dies after a few years. So I opened it up in order to replace the battery:


The laptop is using a CR2430 lithium coin battery placed in a socket to facilitate replacement. There is even a warning, in various languages, telling you about danger of explosion if the battery is incorrectly replaced. This surprised me, since modern laptops would probably just have the battery soldered onboard. Some may feature a motherboard socket for the battery connector, but the actual connections to the battery are permanently soldered, which means some wire-cutting and soldering needs to be done if the battery ever needs to be replaced. This is a CMOS battery from a newer laptop:

I quickly ordered a pack of 5 CR2430 cells for a dirt cheap price from eBay. Notice the funny English on the packaging. Whoever typed this probably had no ideas what it means:

With the CMOS battery replaced and a PS2 keyboard connected, I started the machine. Although many old laptops and PCs do not have an onboard BIOS and require the use of startup disks containing the BIOS utilities to change system settings, this machine has one, available in several languages, accessible via F10 at startup:

There are 2 startup disks for this laptop, formerly downloadable from Compaq website:
  • Disk 1: BIOS setup utility
  • Disk 2: Diagnostic utility
However, these downloads were removed when Compaq was merged with HP in 2003 and a lot of legacy support was gone. Although I eventually managed to find the disks with the help of archive.org, disk 1 comes with no COMMAND.COM and boots up to a DOS error "Bad or Missing Command Interpreter" error message. I fixed the error by putting MS-DOS 6.22 on it. The images for both disks as well as the original tool to create the disks (SP2054.exe) can be downloaded here. You will need WinImage to write the images to floppy disks.

Unlike the motherboard SETUP, the SETUP utility on the disks uses graphic mode and takes a long time to start up:

Since the original hard disk has been removed, my next task is to install a 2.5inch IDE hard drive before the notebook can be used for anything useful. Keeping in mind that laptops of this generation only use CHS addressing and does not support hard drive more than 512MB due to the 1,024 cylinders limitation, I have chosen a 270MB IBM DHAA-2270 hard drive:

Still, installing the hard drive turns out to be no easy tasks as the BIOS only supports a limited number of hard drives types (which does not include my drive). There is also no support for auto detection or user-defined types:

Interestingly, types 65 and 66 are empty, indicating that they are custom types and can be configured by either re-programming the BIOS as suggested in this forum discussion, or by writing a tool that modifies the BIOS hard disk type table stored in memory and hope that the BIOS will recognize the changes. Either way, it's a shoot in the dark as I could find no instructions on flashing this laptop's BIOS, and there is also no documented address where I can hope to find the type table.

However, there is an easier way by using a drive overlay such as ANYDRIVE or EZ-Drive. The trick is to specify a hard disk type in BIOS where the number of cylinders, heads and sectors is smaller than the actual value so that the BIOS will not report an error on POST and accept the hard disk. Once then, boot from a floppy disks with ANYDRIVE to set up the disk overlay, which will overwrite BIOS Int 13h (which is used by DOS to query hard drive info) and respond with the correct disk geometry values. Run FDISK to setup the hard disk and you will be able to use the full capacity.

This will work with DOS and Windows 3.1 or older which relies on Int 13h to access the hard disk. Operating systems such as Linux and some disk utilities may query the hard disk directly, resulting in possible data loss with the overlay installed. In Windows 3.1, 32-bit disk access must be turned off, otherwise Windows may also query the hard disk directly, resulting in similar problems.

With the overlay installed, all existing data on the disk is lost and some PCs may also fail to recognize the drive. Since I do not want to copy data and programs to the laptop using floppy disks, the only other way is to use a serial or parallel cable, with the help of Norton Commander 5.0 Link utility.


Note that you cannot simply use a male-to-male serial or parallel cable, but rather a null modem or a null printer (Laplink) cable respectively. Since these cables are extremely over priced, I decided to go for soldering a null modem cable myself using the connectors available in my junkbox, and the pinout from here. With my other PCs running Norton Commander (NC) from within Windows 98 acting as Master, I am able to copy the data to this laptop (acting as Slave). At a maximum theoretical speed of 115200bps, made slower by the noise-sensitive cable disrupting the copy process resulting in several misleading errors "There is not enough room to copy..." from NC, it took half a day to copy DOS programs, games and Windows 3.1 to the laptop.

However, before I could think of some useful purposes for this laptop, it dies and fails to POST with no beeps and no display output. On every boot, the system simply hung after attempting to seek the floppy drive. There were perhaps several symptoms that the laptop was dying, for example the fact that I needed to press the POWER button multiple times (although the button itself is fine, as checked by a multimeter) to turn the laptop on and the wrong memory count of 21885KBytes extended memory in BIOS:


Since all basic troubleshooting does not seem to help and there are no user replaceable parts inside the motherboard, I eventually removed the hard disk and ran FDISK /MBR to remove the overlay, and toss the machine. Everything has its time, I guess.

Reference:
Contura 3/25 Serie 2820A

Rebuilding the Olevia LT19W 19" LCD TV Remote Control Unit

$
0
0
I have here in my room an Olevia LT19W 19" LCD television that has no remote control unit. The buttons for this TV are located on the top panel so it would be a hassle to change volume or channel while watching. I decided to buy the RM-68 universal remote control from eBay hoping that I will be able to configure it to be used for my TV.

Unfortunately, I was wrong. None of the suggested codes I found online could make the remote control work with my TV. I also spent half a day trying most of the codes listed in the instruction manual, but none works. My last try is to use the auto-search mode, which automatically tries all supported codes to see which one works:
Finally after 20 minutes of pressing the VOLUME+ key, I got my TV not to show the volume control as expected, but to display "Normal" at the bottom of the screen. What should be the volume control key turned out to be the key to change the "Picture Mode" of the TV. The TV also recognized some other keys on the RM68 but the mapping was wrong. For example, pressing channel 2 on the RM68 would turn off the television! In other words, although the TV responds to some keys on the RM68, it can't be used.

I then had an idea. Since I had quite a few keys on the RM68 working, I may be able decode the remote control protocol for this TV. build a PIC-based remote control to simulate other keys and map them to a learning remote controller, which will be used in the long run.

Decoding the protocol

My initial research shows that most TV remote control use consumer IR which transmits using an infrared wavelength of 930 nm, 870 nm or 950 nm at carrier frequency between 33 to 40 kHz or 50 to 60 kHz, with 38kHz being the most common. To decode the protocol, I picked up a TFMS 5400 IR receiver from my junkbox, which is optimal for 950nm infrared @ 40kHz carrier frequency. Although the RM68 transmits at 38kHz, the "Relative Frequency" graph on page 3 of the datasheet shows that the TFMS 5400 would still detect 38kHz signal, just at 95% of the sensitivity. Following the datasheet, I built the receiver and fed the output to channel 1 of my Rigol DS1052E oscilloscope:

 
By pointing the remote controller at the receiver and pressing a few keys while observing the oscilloscope display, the protocol soon became clear. Each key will transmit a data stream, consisting of an ID byte identifying the TV and a data byte identifying the key, in the following format:

[header] [ID byte] [~ID byte] [data byte] [~data byte]
where ~ represents bit-wise NOT operation

The output of the receiver is active low and will remain high if there's no signal received. Each data stream starts with a header consisting of a low pulse for 9ms followed by high pulse for around 4.3ms. The ID byte (which is 8 for the Olevia TV) and its complement (e.g. bit-wise not) is sent following the header. After the ID byte is the byte for the key pressed, and also its complement. Binary 0 is represented by a pulse for 0.5ms and binary 1 by a pulse for 1.6ms. There is a delay of 0.6ms between every bit. Bytes are sent in little-endian format, with the least significant bit being sent first. Depending on the key pressed, the data stream may last anywhere between 50 and 90ms.

For example, the following data stream represents the POWER key, whose data byte is 0b00000010 (2 in decimal)

[9ms low] [4.3ms high] 00010000 11101111   01000000 10111111

The following screenshot from the Rigol oscilloscope shows the header and the ID byte:


Building the transmitter

To be able to simulate the rest of the keys, I used a PIC16F628 and a TSAL 7400 IR LED, with the information available here to build the transmitter circuit:

For the receiver to be able to pick up the transmitter signal, the transmitter needs to modulate the signal at around 38-40kHz. Since the receiver receives in active low, this means pulsing the output at 38-40kHz for around 0.5ms for a binary 0, and staying low for 1.6ms for binary 1.

But how do I actually pulse the output at the required frequency? Luckily the receiver is quite tolerant and any transmitted frequency within the the expected range will work. I used the assembly source code from here and modified it to suit my needs. NOP instructions are used to generate the required pulse frequency, as seen in the following code snippet:

IR_pulse                
        MOVWF    count        ;  Pulses the IR led at 38KHz
irloop        BSF    IR_PORT,    IR_Out
        NOP           
        NOP           
        NOP           
        NOP            
        NOP           
        NOP           
        NOP           
        BCF    IR_PORT,    IR_Out
        NOP           
        NOP           
        NOP           
        NOP           
        NOP           
        NOP               
        NOP           
        NOP               
        NOP           
        NOP           
        NOP
        NOP
        NOP           
        NOP           
        DECFSZ    count,F
        GOTO     irloop   
        RETLW    0

If you're not an assembly guru who knows exactly how many CPU cycles each instruction will take and is able to calculate the output frequency easily, you'll need an oscilloscope and lots of trial and error to get the desired output. This is when the Rigol DS1052E limited memory becomes a hassle. You will need to set the the TIME/DIV setting to a reasonable value that allows you to view the entire transmitted stream, but not at the expenses of losing too many sample points. Even at 1 mega samples of memory in long memory mode, signal aliasing may occur if the TIME/DIV is set so high that the oscilloscope can't capture enough samples. For example, the following puzzled me for a few minutes when I attempted to transmit 1 bit of data:

 

The code pulses the output at 38kHz, but from the oscilloscope screen, it seems much less. However there was nothing wrong with the code, all that was needed is to lower the TIME/DIV settings and capture the output again:


This is the transmitted signal:


Applying "invert" on the input channel on the Rigol oscilloscope, I got the transmitted signal to resemble the received signal:


The PIC-based transmitter now works properly and the TV responds to it as how it did for the universal remote controller.

Simulating other keys

By varying the data byte, I am able to simulate many other keys. The full list of keys and their data bytes can be found in the following table:

Key
Byte
1   
10
2   
9
3   
8
4   
18
5   
17
6   
16
7   
14
8   
13
9   
12
0   
22
Previous Channel   
19
-/--   
21
POWER   
2
MUTE   
4
MENU   
3
Current Channel Display   
24
Sound Mode
25   
Picture Mode
26   
Next Channel
29   
Enter   
28

With this, I am able to get my learning remote controller to learn the above keys and use it as the main remote controller for my TV.

The assembly source code can be downloaded here. It will repeatedly transmit the data stream for the "Channel 1" button. Unfortunately I could not find the data bytes for many other important keys, such as the volume control and TV/Video switch button. Perhaps these keys have data bytes outside the range I tried, or require a different protocol. I hope somebody with more time and expertise at PIC assembly programming can use my code and find out how to simulate these keys...

Reference:
1. Infrared TV Remote Decoder
2. PIC Tutorial Five - Infrared Communication

Dreambook W7: Cheap and apparently features-packed but unusable Chinese-made Android tablet

$
0
0
Well, if you're intending to buy this tablet, the title says it all. This article serves as a reminder to watch out for things that are too good to be true. Save your money and buy a proper tablet!

It all looks promising at first - the Dreambook W7 is an Android 2.2 tablet (upgradeable to 2.3) running on a 1GHz Freescale IMX515 processor, 512MB RAM and 8GB internal storage. The device also has GPS, Bluetooth, SIM card slot (supports 3G, call and SMS), SD card slot supporting up to 16GB, mini-HDMI output and USB host capabilities, all for 350 SGD.

Upon first look, with the HOME button, the device looks like a giant iPhone with a lot of extra connection ports. It is also thicker and heavier than other tablets. No problem yet considering the price, I guess.

However, after some initial testing, problems soon emerged. The following list summarizes my findings:
  1. The touchscreenis very sensitive, to the point that makes the device unusable. Scrolling through a list or a web page would just randomly clicks on items or links on the screen. I install this app, which reduces the sensitivity and seems to help a little, but it's still not good enough for web browsing.
  2. Sometimes it is very hard to get passed the Android lock screen - the green button cannot move long enough to unlock the phone. I disable the lock by using the NoLock app.
  3. In landscape mode, text box occupies entire screen area once the keypad is shown. This is a classic Android bug, reported here.
  4. Even in landscape mode, the launcher home screen or program list still shows in portrait. But other screens appear correctly in landscape. Using a custom launcher such as ADW Launcher correctly changes the orientation, but the icon spacing is wrong.
  5. No matter which firmware I tried, the FM radio doesn't work and just produces white noise, even when the headset is connected. (The headset is known to be used as an antenna in many phone radios)
  6. GPS works intermittently, depending on which firmware I am using. On some firmwares, GPS seems to be working but reports fake location of 0N 0W. Where GPS is working, it reports 2X the speed so it can't be used when driving. Location determination using cell ID and wifi network doesn't work. Neither does the compass work.
  7. Despite numerous sites saying that this device has USB host, I could not get it to work. Basically, it doesn't even supply power to the connected USB device such as a mouse or a thumb drive
  8. Even with the SD card unmounted, hot-swapping the SD card may hang the device. Changing the SIM card while the device is on will definitely lock it. To reset the device, press and hold the reset button, which is also the power indicator light, on the bottom left side.
  9. The device does not seem to support "reboot". The default "reboot" option in Android and all other tools will simply turn the device off.
  10. Many firmwares will have problem receiving incoming SMS (the message is not shown and discarded) while sending outgoing messages is fine.
  11. Finally, things got worse with the Android 2.3 Beta firmware. Wifi will not work until wifi sleep policy is turned off, and 3G works intermittently.
With the long list of problems, all with common use cases, I guess Synrgic, the manufacturer, does not have any kind of quality control over their products. There is also no good official tutorial to flash firmware for this device and all firmwares I could find are uploaded using various file sharing websites, not on the company official site like other devices.

Flashing the firmware

Flashing firmware is a pain on this device. First, you will need to find the correct ROM for your hardware version (either HD104 or HD105). Then, get the device into recovery mode: press and hold the HOME and BACK key and press the POWER key for a few seconds. Copying the bootimg.tgz and update.zip to /sdcard and use the recovery menu to start updating. Notice that on some firmwares, the internal memory is mounted as /sdcard and  the SD card itself is mounted as /sdcard/extsd so you may need to copy the images to the device main memory.

Sometimes it just seems impossible to start in recovery mode despite pressing the correct key combination - the device will just perform a normal boot. You can get over this by using an app to reboot into recovery mode (the device needs to be rooted via z4root). The Dreambook will then turn off, and when started again, it will show the recovery loader.

Another way to flash is via MFGTool, a utility by Freescale, manufacturer of the device's processor. This should be used only at a last resort since incorrect usage may brick the device and turn it into a paperweight. The steps are as follows:
  1. Used Windows XP. Windows 7 may require applications to have admin privilege and different drivers which will just interfere with the flashing process.
  2. Download the MFG ROM package of the device. Some ROMs can be found here.
  3. Start the device in recovery loader, then choose "Wipe for MFG". Connect it to the USB port of your computer, then press and hold the RESET button for a moment.
  4. The PC will then find a new FreeScale BulkIO device which require driver. Install the device using the driver supplied in the MFG ROM package. If the device is identified as Mass Storage, disconnect everything, reboot the device and try again.
  5. Run MFGTool.exe. Click “Options” menu at upper-right corner, and further click configuration item, you can find below pop-up window. Click “USB Ports” tab, you can view all the USB port. Choose the one to which your device is connected and click “OK” to close the window. 
       6. Click the green Start button and the flashing process should start. At the end of the process, the tool may say "Connect device" or report an "Updater Error". This is normal and the device should boot up to Android.
      The latest firmware available is V25 (27 May 2011). Unfortunately it seems that Synrgic has stopped supporting the Dreambook W7 and decided to move on with their other products and no future firmwares will be available.

      My conclusion is that the Dreambook W7, with a lot of out-of-the-box issues, can never be used as a productivity device, only perhaps as an expensive tool for advanced users to learn more about Android by trying different firmwares and applications in an attempt to solve these issues.

      HMC-35HD Media Player with NAS Server Review

      $
      0
      0
      A few days ago I upgraded my home media player from the HMC-35HD made by Mele, a Chinese company, to the ASUS O!Play Air HDP-R3 to enjoy the many video formats supported by the HDP-R3. Before I resell the unit and earn back some cash, I am writing this short review which will hopefully help others who intend to purchase this player.

      Overall the unit is very light, with a dimension of 220x196x73mm and weight of 1096g (without HDD) (see full specs here). It seemingly offers a wide range of features, including playing of music and videos (AVI, WMV, FLV, etc), accessing shared folder via Samba and uPnP using Ethernet or Wifi, Internet radio and an NAS server.


      Storage devices can be connected via USB, or by inserting into the SD card slot. There are also 2 internal slots for 3.5" SATA or IDE hard disk. When connected, the device can be used as an NAS server. Judging based on the physical design, it seems that only one hard disk, either SATA or IDE, can be connected at any time.

      This is the home screen of the player:


      The five icons from the left to right are:
      • USB Devices: open media files on devices connected via USB and on storage card inserted into the card reader. Enabled only if external storage devices are detected.
      • Hard Disk: open media files from the internal HDD. Enabled only if a SATA/IDE HDD is connected.
      • Settings: configure system settings such as video output or wireless access point
      • Ethernet: access Samba/uPnP shared folder on LAN. Enabled only if the device is connected via Ethernet and assigned an IP address.
      • Wireless: access Samba/uPnP shared folder on wireless network. Enabled only if the device is connected to a wireless network and assigned an IP address.
      • Internet Radio. Enabled only if the device has an IP address on the network. I could never get this to work. Upon selection, it will attempt to load for a while and will just say "unable to connect".
      The file explorer interface is fast and intuitive. However, if your storage device has a lot of files/folders, after selecting the icon, it may take up to a minute for the file list to show - I assume the player tries to index all files and folders on the drive as soon as the icon is selected. Sometimes if it takes too long, the operation will time out, resulting in an empty list and the device will erroneously report a huge drive:


        The device supports many video output modes such as component, composite, VGA and HDMI as well as 16:9 and 4:3 aspect ratio on both PAL/NTSC systems. This can be configured in Settings:

        • Video Output: you can set to Composite, VGA or Component. HDMI output is automatic and will be enabled only when the unit detects an HDMI monitor connected. To change the video output without opening Settings, press the TV-OUT button on the player or on the remote control a few times.
          • Component: I could not get it to work with my TV. The TV will just flash the display from black to blue a few times and auto turn off. The setting is also grayed out unless a component cable is connected and video output is set to Component, making it difficult to change the settings to fit your TV if the TV does not like the default values.
          • Composite: this works without much hassle. Just set the correct aspect ratio for your TV and you're good to go. However, the maximum resolution is 480i, defeating the purposes of a high-definition media player.
        • TV Standard: support either PAL or NTSC. Affect only composite output. PAL has slighter higher resolution than NTSC. Modern TVs will handle both PAL/NTSC automatically so there is no need to change this setting.
        • TV Type: Support either 4:3 or 16:9 aspect ratio. However, the settings screen will be wrongly scaled while videos still playback with correct aspect ratio, leaving black gap on the left/right as in the above picture, if 16:9 aspect ratio is selected when it has been selected previously. 16:10 is not supported. 
        • HDMI Mode: Set the HDMI resolution. Auto Detect is recommended. Notice that there may be HDMI handshaking failure, resulting in no output, if you're using a HDMI-to-DVI converter to connect to a monitor with DVI only. See also my previous post.
        • VGA Mode: Although VGA mode apparently only lists 640x480, 800x600, 1024x768 and 1280x1024, the resolution will be automatically adjusted to fit a 16:9 wide-screen monitor if the TV type is set to 16:9. VGA EDID is not used to identify the optimal resolution. Some TV may not show anything if the VGA resolution does not match its preferred resolution. To work around this, connect another LCD monitor and change the resolution.
        At the back of the player, there are two identical rows of composite video and RCA audio output. Perhaps the designer wants you to be able to play on 2 different TVs at the same time, or perhaps for the sake of redundancy...


        The player will always output audio via the RCA ports regardless of which video output mode is selected. This may be useful if you want to use a headphone. A RCA to 3.5mm cable is needed, obviously.

        You can connect the player to your home wireless networks. WEP/WPA/WPA2 encryption modes are supported. However, it is time consuming to enter the wireless key using the remote control:


        There is also a bug here. If the wireless network is using 26 hexadecimal characters as the WEP key, the last hex character must be a digit (0-9) and cannot be between A-F or you won't be able to enter it. I wish future firmwares will address this issue, but given how these Chinese companies work, I doubt there will ever be an update.

        The device has basic support for subtitles (.SRT and .SUB files). Subtitle will be automatically displayed if it has the same file name and is in the same folder as the movie; otherwise it can be selected manually. While English subtitle displays well, Unicode is not supported and font size can't be changed. Word wrapping for subtitle is also not supported.


        I also tried accessing Samba and uPnP shared folders, which works. Take note that your shared folder must not be protected with a password. In Windows 7, Simple File Sharing has to be turned on, otherwise Windows will require the system password to access the shared folder. Unfortunately, NAS did not work in all my attempts. After installing the hard drive and pressing the NAS button on the remote control, the media player appeared to be in NAS mode but the shared folder is not accessible. Until this day, I do not know what the problem was.

        The Verdict

        Despite some problems setting up and the fact that NAS does not work, I would still say that the HMC-35HD is worth considering, especially if you can get it second-hand. To be honest, I never expected a Chinese-made device to deliver all its promised features and therefore mainly use it as a media player. The only two things that irritated me were that most MKV files are not supported and that sometimes playback would stop half way and go back to the file list while showing "UNSUPPORT" on the screen. For this reason, I upgraded and the Asus HDP-R3 has served me well so far.

        The user guide for the player (in Chinese only) can be downloaded here.

        Converting between NSString and C strings in an iOS project

        $
        0
        0
        I recently had to use a C library in an iPhone project, which is mostly in Objective-C. Things were going on smoothly until I had some C functions that return C strings (wchar_t*, char*) and require conversions in order to work with Objective-C NSString* types.

        There are 3 ways to declare a string in an iOS project in xCode:

        NSString* str = @"hello world"; // declare an Objective-C string
        wchar_t* str = L"hello world"; // declare a wide-character (Unicode) string
        char* str = "hello world"; // declare an ANSI string

        If you declare a Unicode string via the L"" syntax, the compiler defaults it to UTF32. The function wcslen() to get the length (e.g. number of characters) of a string may not work properly if the input string is not UTF8 encoded. For example, try the following code:

        wchar_t* str1 = L"Giới thiệu về Google"; // "About Google" in Vietnamese
        wchar_t* str2 = L"Gioi thieu ve Google"; // simplified with ANSI characters only
        printf("str1 length: %d", wcslen(str1));
        printf("str2 length: %d", wcslen(str2));

        The code will output wrong length for str1 and correct length for str2, even though they have the same number of characters. I think wcslen is confused by the UTF32 characters in str1 and counts some characters more than once. However, if I try the folowing code:

        char* str3 = "Giới thiệu về Google";
        setlocale(LC_ALL, "en_US.UTF-8");
        int buflen = strlen(str3)+1;
        wchar_t* buffer = malloc(buflen * sizeof(wchar_t));
        mbstowcs(buffer, str3, buflen);
        printf("str3 length: %d", wcslen(str3));
        free(buffer);

        to declare an ANSI string and convert it to UTF8 wide string by using setlocale to ensure the correct Unicode encoding, wcslen will return the correct string length. Not knowing what the problem is, I have to make sure that all C strings in my project are UTF8 encoded.

        Conversion from NSString* to an ANSI string (char*) is easy using the built in NSUTF8StringEncoding method. The returned value is valid as long as the original value is valid, so there is no need to release or free it. The following method (taken from my custom NSString category) shows how to achieve this:

        - (const char*)getMultiByteString
        {
        return [self cStringUsingEncoding:NSUTF8StringEncoding];
        }

        It is a bit more complicated with C function mbstowcs to convert from NSString* to a wide string (wchar_t*):

        - (wchar_t*)getWideString
        {
        const char* temp = [self cStringUsingEncoding:NSUTF8StringEncoding];
        int buflen = strlen(temp)+1; //including NULL terminating char
        wchar_t* buffer = malloc(buflen * sizeof(wchar_t));
        mbstowcs(buffer, temp, buflen);
        return buffer;
        }

        It is the responsibility of the caller to free the returned buffer. To improve, one can free the return value in the dealloc() method of NSString. The return type should then be changed to const wchar_t* to indicate that the returned value is read-only.

        Take note that wchar_t is 2 bytes on Windows but 4 bytes on Unix/Linux (including iOS) is 4 bytes. The above function uses sizeof to determine the size of wchar_t for the sake of generality.

        Using stringWithUTF8String and wcstombs we can do the reverse and convert a C string into NSString:

        + (NSString*)stringWithWideString:(const wchar_t*)ws
        {
        // Destination char array must allocate more than just wcslen(ws)
        // since unicode chars may consume more than 1 byte
        // we do not yet know how many bytes the created array may consume, so assume the max.
        int bufflen = 8*wcslen(ws)+1;
        char* temp = malloc(bufflen);
        wcstombs(temp, ws, bufflen);
        NSString* retVal = [self stringWithUTF8String:temp];
        free(temp);
        return retVal;
        }

        I hope this will help other with similar problems.

        The good old days: cracking 16-bit DOS games

        $
        0
        0
        I recently wanted to play one of my favorite old games again, Zentris for DOS by Zensoft and realized how much things have changed. First, my 64-bit version of Windows 7 doesn't like 16-bit DOS apps and refuse to run the game:


        Attempting to run on another computer with 32-bit Windows 7 fails because Windows Vista and above no longer supports 16-bit apps in full screen mode required by the game. Although there are various hacks to remove the restriction - some of which may prevent Windows Aero from working, the proper solution is to use DOSBox, which helps me get the game running:

        However, because the version I have is a demo version, I was soon irritated by the numerous registration prompts:




        Since the full version is no longer available for purchase/download either from the official website or from various abandonware sites, with some time at hand, I decided to disassemble the source code in order to remove the registration prompts.

        My first attempt was to use the Interactive Disassembler to analyze ZENTRIS.EXE. However, this failed with error "sp-analysis failed" and showed an incomplete disassembly:

        sp is short for stack pointer. In other words, IDA was unable to identify where the sub-functions start or end, presumably due to unexpected changes in the value of the sp pointer, and stopped analyzing the EXE file. I found this post which suggests manually identifying the sub functions. Not an easy task!

        The proper solution is to be aware of the fact that the executable has been packed to save disk space, preventing IDA from disassembling it. Using my favorite DOS packer analyzer, unp411, I was soon able to detect that ZENTRIS.EXE has been compressed using PKLITE and unpack it:

        IDA now disassembled the file properly:


        However, now the unpacked game didn't even seem to run but instead complained "File ZENTRIS.EXE has been illegally modified". The author has implemented integrity check of the executable file to prevent exactly what I am attempting! What a hassle, but in the end I successfully used Turbo Debugger (IDA does not support debugging 16-bit apps) to locate the various checks, and use HIEW to replace these instructions with 90 NOP, allowing the unpacked game to run.

        It's only now that the real fun began - removing the various registration prompts. Using the same technique as above, I was able to remove the text-mode prompts before and after the game, and the modified game runs flawlessly till the end, when an error message "Divide Error" is shown upon exit:

        I am unable to identify where exactly this error is coming from. From Turbo Debugger disassembly it seems that the error occurs after a RET instruction - most likely due to some previous instructions overflowing some segment registers. Ignoring the error since it does not seem to affect the game functionality, I decided to proceed to try to remove the graphical registration notice.

        For a moment I was not able to find any references to the main game logic in ZENTRIS.EXE. It was only then that the structure of the game is clear to me. ZENTRIS.EXE is only used as a loader that loads ZENTRIS.OVL as an overlay. ZENTRIS.OVL is then responsible for the main game logic.

        ZENTRIS.OVL is also packed, surprisingly twice, using two different packers, PKLITE and LINK:


        Luckily there are no other integrity checks on ZENTRIS.OVL and the game still runs perfectly with the unpacked version of ZENTRIS.OVL.

        However, I never found a way to make Turbo Debugger step into the unpacked ZENTRIS.OVL in order to locate the call to display the registration prompt. In fact, under Turbo Debugger, the main game wouldn't even start, complaining "out of memory" when trying to load the overlay. It is unclear to me why the game has to be designed this way, perhaps to limit the main executable size to less than 64K (the unpacked ZENTRIS.EXE is already 60K), or more likely, to make disassembling the game a hassle.

        The only approach was to use IDA to make an educated guess on which instruction is responsible for the prompt, and then use HIEW to replace them with NOP. Inside ZENTRIS.OVL, I was able to identify a few calls to DOS INT 16h, responsible for keyboard monitoring. Replacing them with NOP and the game was indeed affected, either stopped responding at the menu, or showed the registration prompt and stopped responding without accepting keyboard input. This proved that I was on the right track.

        Unfortunately, the actual counter to how long the prompt should be displayed or the correct way to remove the prompt was never found. In fact, some functions around the "suspected" area are not disassembled properly by IDA, with some instructions still showing as data bytes. It seems as if the author has obfuscated the source code to prevent disassembling. Unless I find a way to step into ZENTRIS.OVL at runtime, at this point it is not worth the time and efforts for me to proceed further.

        The modified ZENTRIS.EXE with the text mode registration prompts removed, which is good enough for me :), can be downloaded here. The original game can be downloaded here. I hope someone with the right expertise can give me some hints on how to step into ZENTRIS.OVL and complete the hacking job :)

        Raw access to SMS/MMS database on Android phones

        $
        0
        0
        My HTC HD2 running on Android from SD card has stopped working recently - the phone simply refused to power up while the battery was still fine. There was nothing I could do except to migrate to a new phone and re-sync everything from my Google account. Restoring the SMS, however, was not an easy task as my latest backup using Sms Backup and Restore is more than 3 months old.

        Fortunately my Android was running from SD card, which was still working fine, so I could still access the entire Android folder on the card. Using various Windows tools (see my previous article) such as Ext2Explore, I was able to read the contents of data.img and found the location of the database storing all text messages, among other things, at /data/data/com.android.providers.telephony/databases/mmssms.db. The database is apparently in SQLite format.

        Nextcomesthe challenge of reading the database. For this I use SQLite Database Browser, and all the tables are listed nicely:


        Opening the SMS table and I can see all messages:

        (phone numbers and message bodies have been removed by me when taking the screenshot)

        The address column stores the sender/recipient of the message. Column body storesthe message body (for MMS/SMS) while subject is for MMS only. The type column specifies the message type (sent, received) and can be 1 or 2. Interestingly, the service centre that sent the message, or SMSC, is also stored but not visible from the stock Messaging application. The time of the message is stored as a Unix timestamp format. To convert it to a readable date in Microsoft Excel, use the following formula, adapted from this blog, and format the cell as Date:

        =(((TIMESTAMP/1000/60)/60)/24)+DATE(1970,1,1)

        If you want to migrate the SMS to a new Android device, you may be able to do it by simply copying the mmssms.db database to the other device. If not, you can export the messages to a CSV file using File->Export Table as CSV File and import them to Android, Blackberry (see my CSV2IPD tool) or other platforms.

        Mac OS X on VmWare - Upgrading from 10.6.4 to 10.6.8

        $
        0
        0
        In my previous articles (this and this) I have shown you how to setup a working Mac OS X 10.6.4 system running on your PC using VmWare Workstation. For some time, the setup has been working perfectly fine for me, mostly for iOS development, since I don't own a Mac.

        However, recently I needed to upgrade my xCode to version 4.2 in order to support the latest iOS SDK, and to my surprise, Xcode 4.2 requires at least 10.6.7 for installation.

        Well, if you don't want to read the rest of this post, there is an easier way. It should be noted that most of xCode and iOS SDK will work just fine without the extra features in 10.6.7 - the minimum version requirement is just Apple's lazy way to reduce development and support efforts by forcing users to upgrade to their latest release.  Following this trick, I opened my SystemVersion.plist located at System/Library/CoreServices, and changed the version number to 10.6.7 or higher:


        After a reboot, the new version was shown in About This Mac and xCode installed and worked just fine! Notice that this would fail (xCode installs but behaves erratically) if your current system is too old, e.g. 10.5.x. You'll need at least 10.6.4 for the trick to work.

        However, with some free time at hand, I still decided to go ahead and properly update my system to 10.6.8 using the built-in Software Update. The updated system rebooted just fine, showing 10.6.8 correctly in About This Mac. For complete functionality, I installed the following 2 patches and rebooted the system again:

        1. IOUSBFamily-378.pkg: allow the virtual OS to recognize USB devices. You would first need to disconnect it from the host and connect to the Mac via VMWare's Removable Devices menu.
        2. EnsoniqAudioPCI_v1.0.3_Common_Installer.pkg: allow audio to work. 

        In my case, I also needed to disable the screensaver and various power management settings. For some reasons, it causes random kernel panic.

        Next, I realized that there was not enough disk space to install the latest iOS SDK. Expanding the hard disk is not an easy task, as common methods fail with a "MediaKit reports partition map too small" error message. In my previous tutorial, I have shown a workaround which took a long time and did not always work. The proper method is to manually modify the partition table to reflect the new hard disk size. Run gpt tool from terminal as described in this post (see also this), destroy the existing partition table and recreate a new one with the correct partition size.

        Take note that for gpt to work, you need to have the disk unmounted which is not easy as it's a system disk. You would need to boot from the install DVD and use Terminal from there. If a boot disk is not available, make a copy of the working virtual machine, insert the original hard disk as another drive, boot from the copied virtual machine and use it to work with the original hard disk. If you choose the second method, take note that the copied hard disk and the original hard disk will have the same UUID, which will cause problems with Disk Utility and VmWare will also warn you upon startup. The correct way to fix this is to use a hex editor that can accept large file such as Hex Editor Neo to edit the VMDK file and change the UUID. Look for ddb.uuid:


        With the expanded hard disk, I installed the latest xCode, iOS SDK and various other apps just fine. Since the default Preview app does not work properly for graphics file due to the lack of QE/CI support, I replaced it with JustLooking, a freeware mac preview app that does not require QE/CI. Taking screenshots is done via VmWare's Capture Screen menu, or via Ctrl-Alt-PrintScreen.

        However, everything was working great and I was developing my iOS app on the simulator when I encountered a kernel panic on the virtual Mac, causing VmWare to shut it down:


        It took a while for me to realize that it wasn't the Mac that crashed first - it was the iOS app crashing on the simulator and taking the entire system down with it. Yes, any kind of crash, even one as simple as calling an unrecognized selector on an object:

        -(BOOL)application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {   
        [self dummyMethod];

           
        return YES;
        }

        If you are unlucky enough and the system is writing to the disk when the crash happens, the disk image will be corrupted and the Mac won't reboot to the desktop successfully. It will also be a tough task to recover any data from the corrupted disk image. Sort of funny but true. I was unable to determine the root cause and can only assume that it's due to hardware virtualization. The iPhone simulator architecture is actually x86, which suggests it is sharing the same CPU as the Mac, and any exception caused by the simulator will be escalated to the Mac if not handled properly.

        To work around this, I put all my projects in a VmWare shared folder that is linked to a folder the host's hard drive so that the projects are still intact even if the Mac drive is corrupted. I also save working snapshots of the system that I can revert to in case something goes wrong. Most importantly, I add an exception breakpoint so that xCode will stop before an exception occurs, instead of letting it happen and crash the system:


        My 10.6.8 upgrade is now completed and my next attempt is to upgrade to Mac OS X Lion (10.7.0), which will be another article. Meanwhile, I can now happily develop iOS apps on my laptop without purchasing a Mac.

        "Scanner Error" on Xerox WorkCentre 3119

        $
        0
        0
        Well, if you get this error, or some other hardware-related errors such as PAPER JAM, DOOR OPEN and TONER ERROR out of nowhere, the first thing to do is to perform a restart and re-installation of paper tray and toner, which will help if the error is triggered by a stuck or dirty sensor or switch.

        However, for my case, there was also a continuous "tick-tock" noise as the device was trying to power up. The LCD showed "Warming Up..." for a very long time before reporting "Scanner Error". This error prevented the machine from being used for all purposes, even for non-scanning related tasks such as printing!

        The source of the noise was traced back to the belt that moves the scan head one pass across the scan glass plate as part of the initialization process. The belt moved but the scan head did not move properly and the lamp (as seen in the following photo) remained in the left position. The scanner attempted to continue moving the belt until timeout and reported "Scanner Error".


        My first thought was that the scanhead is unsure of its home position. There are 2 methods for a scan head to know its home position:

        1. using a sensor as an optical slit or a switch
        2. read a white band (made with a special paint) deposited on the scanner glass that sits parked in the scanner.
         
        There was nothing obvious on the glass plate or elsewhere that suggests a mechanical malfunction. Apart from this, I can only assume that the belt is out-of-alignment and will need to be reseated, perhaps by following the service instructions found in the Xerox WorkCentre 3119 manual (downloadable here).

        For now, I managed to bypass the error and allow the machine to be use for printing. I simply performed a CLEAR SETTINGS in the machine menu and rebooted the device. The device still attempted to initialize the scanner by illuminating the lamp but somehow did not attempt moving the scan head and will not stop at SCANNER ERROR. The error would however come back when photocopying/scanning is attempted.

        I guess it's time for me to purchase a new machine.

        Experimenting with Casio Portable Analog TVs from eBay

        $
        0
        0
        Recently I won an eBay Auction for 2 portable TVs, the EV-570P and the TV-880D. Although both are analog TVs with a 3" LCD screen, the EV-570P supports both VHF and UHF while the TV-880D supports UHF only, as indicated in the channel ruler below the LCD:


        Both sets have an automatic tuner and there is no option for manual tuning. Pressing the tuning buttons (next, previous) will scan and switch to the next available channel. A vertical scrolling bar (red for VHF, green for UHF) will be displayed showing the current channel (which is what the channel ruler is for).

        I was disappointed to find out that although both TV sets are able to tune into Singapore channels and display the picture properly, only the EV-570P is able to play audio while the TV-880D simply plays white noises. I remembered the auction description clearly stated that both sets support PAL, which is the analog TV standard in Singapore. So what is the problem? I soon learned my lesson by looking at the back of both sets and by reading this Wikipedia article about different PAL standards:


        The EV-570P supports PAL B/G/H/I while the TV-880D supports PAL I only. And Singapore is using PAL B/G standards. The following table from the above Wikipedia article explains why the TV-880D could not play the audio properly:


        While PAL B/G and PAL I are color-compatible, the audio is not as it is transmitted on a different subcarrier frequency (5.5 MHz for PAL B/G and 6MHz for PAL I). The set was attempting to play the audio from a non-existent frequency, resulting in white noise. Notice that while this difference prevents the TV-880D from receiving Singapore channels in PAL B/G, the composite input is unaffected and can be used with other portable devices that have composite output such as VCD or DVD players

        With some free time, I decided to disassemble the TV-880D to see if there is any hope of modifying it to support PAL B/G:


        I quickly identified a through-hole crystal (highlighted in RED). However, with my oscilloscope, the frequency measured is 4.43MHz, the PAL color subcarrier frequency, not the sound subcarrier frequency.

        My next attempt is to search for the service manual of the unit, which may offer some insights. I found manuals of other similar models, the TV-770B (for NTSC only), TV-770C/D/G (for PAL B/G/H, PAL I, PAL M respectively). The block diagrams of these models are quite similar and I can almost match it to my TV-880D:


        Further studying the part list, I learned that the only major difference between the PAL B/G/H/I/M or NTSC set is the tuner (highlighted in green):

        For TV-770B:



        For TV-770C/D/G:

         

        In other words, all that I was hoping to modify, the sound subcarrier frequency and the tuning range (VHF or UHF), is inside that "black box", the tuner. One of the replies to my post on this forum suggests that it may be possible to disassemble the tuner, change the crystal filters used for the audio subcarrier frequency and re-assemble it. However, as I found no elegant way to do that without break-opening the tuner metal can, I reassembled the unit unmodified and simply used it with my home circuit transmitting in PAL I.

        The service manuals of the TV-770 and other Casio portable TVs can be downloaded here. I hope this will help others with similar problems.

        See also:
        Casio Pocket TV

        Prolific USB-to-Serial driver on Windows 7

        $
        0
        0
        My Prolific USB-to-Serial converter has been working well on Windows XP but refuses to work on Windows 7 64-bit. Windows first complained that the driver is unsigned:

        and after that complained that the driver cannot be installed:


        The root cause is clear - the Prolific USB-to-Serial driver is not compatible with Windows 7 because it is unsigned. Despite me choosing to install the driver anyway, Windows still refused to install it. After half a day trying various suggestions, I finally came up with a solution

        1.  Go to the registry branch HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Driver Signing\BehaviorOnFailedVerify and set value as DWORD 0. This prevents Windows from rejecting unsigned drivers.

        2.  Open a command prompt and perform the following commands to enable Windows Test Mode, make use to use "Run as administrator":
        • bcdedit.exe -set loadoptions DDISABLE_INTEGRITY_CHECKS
        • bcdedit.exe -set TESTSIGNINGON
        3. Use this tool to sign the driver and allow it to be used when Windows is in test mode. This applies to all DLL and SYS files in the driver package.

        4. Reboot your machine and Windows should report that it is running in Test Mode at the bottom right corner:



        5. Proceed to install the driver as per normal. Windows should accept the driver and install successfully:



        The Prolific USB-to-serial driver can also be downloaded here, in case you're looking for it.
        Viewing all 63 articles
        Browse latest View live