Wednesday, January 18, 2012

How to disassemble and clean Game & Watch multiscreen

I've gotten a few Game & Watch games off Ebay. Like most retro gear, they are usually sold "as is". These arrive in different conditions. If you're lucky, they come pretty clean. More often than not, though they arrive with different "marks" and dirt all over them.

There could be drinks accidentally spilled on the unit, even if wiped clean the liquid may have been inside the unit. Often, there are years worth of dirt stuck around the control buttons. These can manifest in several ways: Button could be sluggish to return after being pressed, Button may need to be pressed hard to activate. There could also be obvious things like droplets and things behind the screen. Possibly stuff on the screen surface itself. There are also some owners who write their names or signature somewhere on the game itself. And the worst one, someone engraves their name on the plastic with a soldering iron (no, we can't clean these ones up, sorry).

What we have here is your typical Donkey Kong multi screen (DK-52).


Its previous owner had taken the liberty to write his funny looking signature on the front plate:

The serial number is missing and there's lots of gunk on the battery compartment:


The inside is pretty clean looking. It must have been stored with the lid closed. Although the directional pad needs a bit of hard pressing in order to get to certain directions (right and up).


On to disassembly.

First remove the 5 screws at the bottom:




Then lift the back panel up halfway and remove the 5 screws on the bottom pcb.





Lift up the bottom pcb over the upper screen. It is very likely the flexible pcb (white plastic with black lines on it) and/or LCD will still be attached to the board. Take care while handling this as it can tear easily.




Then remove the 4 screws on the top screen

One thing to remember about the screws. The 9 longer screws go to where they are externally accessible. All the "internal" screws are the shorter one

Then carefully lift up the PCB and set aside the buttons and other things that fall out.


You should have:
D pad

D pad's rubber
jump button

Game A/B/TIME rubber
2 small circular metal discs for Alarm and ACL

If the unit has not been previously disassembled, the lower display would most likely be still stuck to the PCB. Carefully bend up the LCD until it is separated.

The screen will be composed of the following (in order from top to bottom):
front polarizer
front graphic
the LCD glass part
back graphic
back reflector

Besides those you may find a small rubber "ring" and 2 rectangular transparent "things"
These are for holding the LCD steady. If you lose or do not find these, it is okay, Some unit have these, some don't. They would work fine without them.

The PCB is still connected to the back case by 2 wires for the "speaker". Use a soldering iron and carefully desolder these 2 wires.

Take off the 4 (long) screws holding the upper screen in place.



Now, carefully pry up the upper screen (near the locking clasp). This will reveal 5 more "short" screws:

Remove the 5 screws.





There will be a similar set of accessories on the upper LCD. Instead of a PCB, you will find an aluminum plate. And unlike the lower screen, the flexible wire should come right off.




Fill up the sink with warm soapy water (use dishwashing liquid). On everything except the PCB, LCD and accesories, use a toothbrush to brush off dirt and rinse. Set aside on a towel to dry. Do not lose any of the small parts.

If your unit had something written on the top plate with a permanent marker you can try some rubbing alcohol on it:
If that does not work, you can use some nail polish remover. If you go this way, be extra careful not to get the nail polish remover in contact with any plastic parts as this can melt plastic. Nail polish remover would erase something written with a marker, but leave the original printed markings intact.





For permanent marker writings on plastic parts, never use nail polish remover on them. You can try some toothpaste and brush.
Toothpaste is a bit abrasive so be careful when doing this as it may cause the brushed area to be shinier than the rest.


For the LCD and accessories you would need to carefully wash it by hand. It would be handy to blow out water with a lens blower so that it does not leave water marks on the surface. Do not forget which way the parts go. The front polarizer in particular will only go properly one way. If you have it the wrong way, all the white will turn black, and vice versa. The graphic transparencies should be a little more obvious how they go.


After everything is dried, assemble the LCD first on the plastic tray that it goes to. This is where the black "ring" and 2 rectangular "things" go:

Put all the buttons back in their respective places,

Do the same for the upper screen
Put the screws back on the upper screen. Now here's a secret when returning screws. Before you screw them in, turn the screw counter-clockwise until it "clicks", then screw it in. This makes sure the screw goes back into the thread it came from.

Put the PCB back over the lower screen and the screws. Before you proceed, go put in some batteries and make sure everything is back.

Also press the buttons and make sure they are now responsive.
If all is well, go and re solder the speaker back on.


Put all the long screws on the top screen back on, and at the back of the unit.




Monday, October 10, 2011

Erlang: Supervising two processes from a single supervisor

Only because this ate over an hour of my day today.

Below is a shell example of a supervisor that starts two child processes which are also supervisors.

-module(arti_sup).

-behaviour(supervisor).

%% API
-export([start_link/0]).

%% Supervisor callbacks
-export([init/1]).

%% Helper macro for declaring children of supervisor
-define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}).

%% ===================================================================
%% API functions
%% ===================================================================

start_link() ->
    supervisor:start_link({local, ?MODULE}, ?MODULE, []).

%% ===================================================================
%% Supervisor callbacks
%% ===================================================================

init([]) ->
    Hip_Sup = ?CHILD(parser_sup , supervisor),
    ServiceSup = ?CHILD(service_sup , supervisor),

    Children = [ Hip_Sup, ServiceSup ],
    RestartStrategy = { one_for_one , 4, 9600},
    {ok, { RestartStrategy, Children } }. 

 
I have to other supervisors parser_sup and  and service_sup.

If you find that no matter what you change in this file doesn't seem to make a difference to which supervisor is being called, check that this supervisor itself is being started from the application filename_app.erl ,

If all goes well, you can use the sasl application to check the supervisor / launch information.

1> application:start(sasl).
ok

=PROGRESS REPORT==== 11-Oct-2011::01:59:07 ===
          supervisor: {local,sasl_safe_sup}
             started: [{pid,<0.41.0>},
                       {name,alarm_handler},
                       {mfargs,{alarm_handler,start_link,[]}},
                       {restart_type,permanent},
                       {shutdown,2000},
                       {child_type,worker}]
 

<removed for brevity...>


2> application:start(myapplication).
INIT parser supervisor
INIT service supervisor

=PROGRESS REPORT==== 11-Oct-2011::01:59:14 ===
          supervisor: {local,human_input_parser_sup}
             started: [{pid,<0.51.0>},
                       {name,human_input_parser_srv},
                       {mfargs,{human_input_parser_srv,start_link,[]}},
                       {restart_type,permanent},
                       {shutdown,5000},
                       {child_type,worker}]

=PROGRESS REPORT==== 11-Oct-2011::01:59:14 ===
          supervisor: {local,arti_sup}
             started: [{pid,<0.50.0>},
                       {name,human_input_parser_sup},
                       {mfargs,{human_input_parser_sup,start_link,[]}},
                       {restart_type,permanent},
                       {shutdown,5000},
                       {child_type,supervisor}]

=PROGRESS REPORT==== 11-Oct-2011::01:59:14 ===
          supervisor: {local,service_sup}
             started: [{pid,<0.53.0>},
                       {name,service_srv},
                       {mfargs,{service_srv,start_link,[]}},
                       {restart_type,permanent},
                       {shutdown,5000},
                       {child_type,worker}]

=PROGRESS REPORT==== 11-Oct-2011::01:59:14 ===
          supervisor: {local,arti_sup}
             started: [{pid,<0.52.0>},
                       {name,service_sup},
                       {mfargs,{service_sup,start_link,[]}},
                       {restart_type,permanent},
                       {shutdown,5000},
                       {child_type,supervisor}]

=PROGRESS REPORT==== 11-Oct-2011::01:59:14 ===
         application: arti
          started_at: nonode@nohost
ok

You can also use appmon to get a visualization of the supervisor tree with the command

3> appmon:start().
{ok,<0.55.0>}


This should present a graphical application which shows the supervisor/process trees currently running and is updated in real time.

Saturday, October 1, 2011

Rust basics: Numbers

Rust is a systems level language, it is my understanding that it provides the basic "types" of numbers that most system languages do.

There are two types of numbers that can be used by rust:
 
Integer literals, floating point literals.


Integer Literals

I figured that quoting from the authoritative spec means I can't be too wrong, it says:


An integer literal has one of three forms:
  1. A decimal literal starts with a decimal digit and continues with any mixture of decimal digits and underscores.
  2. A hex literal starts with the character sequence U+0030 U+0078 ("0x") and continues as any mixture hex digits and underscores.
  3. A binary literal starts with the character sequence U+0030 U+0062 ("0b") and continues as any mixture binary digits and underscores.
I don't understand the interest of allowing underscores,  I guess this means programmers can make values like 0xDEAD_BEEF_BABE or 0b_1111_0000 more readable.

Ah, but you can also specify the container (bitsize) size  of the object by  appending an integer suffix.  

  • The u suffix gives the literal type uint.
    The g suffix gives the literal type big.
  • "Signed" types i8, i16, i32 and i64
  • "unsigned" types u8, u16, u32, u64.

An example would be 0xDEAD_u32 or 18_i64 .  If you believe it the underscores can be placed anywhere that the programmer likes to make the values more readable.


Floating Point Literals

And again from the spec:

 A floating-point literal has one of two forms:
  1. Two decimal literals separated by a period character U+002E (’.’), with an optional
    exponent trailing after the second decimal literal.
  2. A single decimal literal followed by an exponent.

Nothing too exciting here, things like 0.01 and 99.999999 and 0.99.  You can also add two optional floating suffix values for your enjoyment.

  • The f32 suffix
  • The f64 suffix


These are  unsurprisingly specify the size of the container storing your value.



Example time !

So for a basic example:

use std;
import std::io;

fn main() {

    let stdout = io::stdout();

    let x = 127u;

    stdout.write_line(#fmt["X = %u", x]);
}

This as you'd expect outputs the number "127".  Nothing too complex.  We can see that the type of "x" is inferred as an unsigned integer.

So, lets do the usual thing and test assignment of a different type, does in infer correctly ?

$ rustc assignment.rs -o assignment
assignment.rs:10:6: 10:7 error: mismatched types: expected uint but found int (types differ)
assignment.rs:10         x = 5;

Rust fails the compile, and graciously gives you the opportunity to fix this bug.  The quick and dirty solution is to change the assignment value to 5u, but if this value was created by another function you'd have to do what other languages consider casting, using the as keyword.

So you'd do it like this:

use std;
import std::io;

fn main() {

    let stdout = io::stdout();

    let     x = 127u8;
       
            x = (x + 128u8 ) as u8;

    stdout.write_line(#fmt["X = %u", x as uint]);
}

The reason why the equation 127 + 128 was chosen is because 255 is the largest value that can be stored in a 8 bit unsigned value. 

The first "as" in the above example is superfluous, but it remains as an example of how you can cast/convert a value that may be converted or passed by another function or module that you didn't write.

Note that in the above example no data was lost.  However if the final value of x is over 255, in the assignment line ( x = (x + 128u8 ) as u8 ) this is where the x value will be 'overflowed' not in the final stdout.write_line() function.

Much like C, Fortran, Algol or any other language when you use specific types you must be careful about overflowing the maximum.  I was reading the source code and came across the auto-expanding "big" type, but I'll explore that for another day.

I guess that is as good of a start as any.  I probably should put something about "using crates" but I don't know enough about them to be useful yet.


Wednesday, September 28, 2011

Famicom Final Fantasy II Japanese to English Conversion

I have always been a big fan of native hardware. Sure, emulators to a certain extent would give you a "taste" of what the device can do. But as they say, nothing beats the real thing. It could be the grinding sound a floppy disk drive makes as the head tries to seek past track 0, or little things such as millisecond delay of a game controller compared to native hardware.

I have played a few of the Final Fantasy games. One day I decided I'd play through all of the games in the main series. Not on an emulator though. On the real thing.

For some reason some of the games in the series were only released in Japan. Since my grasp of the language is quite limited, I thought I would look for a fan translated version of the game.

In order to begin I set up my Family Computer (Japanese version of the NES). Found a copy of Final Fantasy II. First thing to do of course, was to make sure this cart is still working (it was). And after confirming that, it's time to take apart the cart. Famicom carts are held together by 4 plastic tabs, and it is very difficult to open up a cart and keep them intact. Super glue can restore broken off tabs.
Next we need to desolder the ROM chip(s). Final Fantasy II only uses 1 ROM chip. I carefully desoldered every pin and got the chip out. Next is to find some pinouts of the mask ROM, and how different it is from the EPROM I was planning to use (AM27C20). I found them here:

http://www.raphnet.net/electronique/nes_cart/nes_cart_en.php
http://nesdev.parodius.com/NES%20ROM%20Pinouts.txt
http://nintendoallstars.w.interia.pl/romlab/nesmod.htm

After modifying the board, this is how it looks:


And after burning the eprom and soldering it on:

Of course, I have to test it first before closing the case:

Moment of truth: (it works!)
The save files are still there too, and the names are now garbled:

Tuesday, September 27, 2011

Rust vim syntax and indent files.

I'm a bit of a vim junkie, and if you're like me, you'll almost definitely want to have your vim configured for the correct rust syntax.  Not just for the pretty colors but to let you know when you're missing a quote

Patrick Walton must be a vim user as he seems to have written the vim syntax file for rust, You can pull it from the rust source code or from the git repository, and put it in the relevant vim settings folder (.vim on unix)


After copying the files to this folder, add the following  line to your vimrc:

au BufRead,BufNewFile *.rs setfiletype rust

 (usually $HOME/.vimrc or $HOME/.gvimrc ).  Reload your vim settings or restart vim and open a rust source code file.

You should see your rust files in all their syntactic highlighted glory.

Sunday, September 25, 2011

Hello World in Rust

Rust is a low level systems language developed by Mozilla for future embedding into their browser and other tools.  I was first made aware of it a year ago on the programming subreddit, but it looked a little too abstract to be useful.

I stumbled across it again yesterday and decided to compile the language tool chain and give it another go.

The language seems to have some very nice functionality, a cross between erlang and C, which may suit my fancy.

The toolchain was a bit annoying to set up, and I might go harrass the #Rust irc channel to see if there is a simpler way to get started.

In the mean time, here is hello world.

-- hello-world.rs -- 

use std;
import std::io;

fn main(argv: [str]) {

    let out = io::stdout();

    out.write_line("Hello world");
   
}

I compiled it with the command:

$ rustc hello-world.rs -o hello-world -L /usr/local/lib/rust/

$ ./hello-world
Hello world

Fin.