Subscribe via RSS
24Oct/190

Arduino Uno WiFi + TV Remote + LED Sign

Over the weekend, whilst watching TV, I realised that I needed some kind of sign to work out when trains were passing my apartment. There's a railway line right next to me and around four-or-more services pass daily. I'd prefer to be notified in advance and, since I have data sources to tell me when trains are about to come by, I want to make the most of it. Currently that's done by RSS both on my phone and PC, but the whole point is that I'm watching TV and don't want to have to be checking my phone every 2 seconds.

After getting the red LED marquee to work on the old ISA I/O card, I decided it was time to get it plugged into the Arduino. I actually already have an Arduino Uno Wifi next to my TV, which I've recently been using to translate my TV remote control codes (similar to what I did with the old B&O TV) into Yamaha remote control codes for control of volume with one remote. Adding the LED marquee would let me know when a button was successfully pressed ... and it would also tell me when trains were coming past!

I hadn't actually worked with the WiFi on the Arduino yet, so that was a bit of an experience. The RF side of things was working fine and I had already worked out the wiring requirements for the LED display thanks to the old I/O card.

Getting the ESP8266 Online

The Arduino Uno Wifi is an Arduino Uno board with an embedded ESP8299 microcontroller. The basic idea is that the two units talk serial to each other, when configured to do so. If you want to program one, or the other, you have to adjust the serial communications path on the board via a tiny row of switches. Jaycar has a minimal instruction sheet here, but it's enough to get you started. From the information, please set your Arduino Uno Wifi's tiny switch row to: 1:OFF,2:OFF,3:OFF,4:OFF - 5:ON,6:ON,7:ON - 8:OFF.

I would want this unit to act by itself as both a web server and web requestor, so I needed to find code for both. Before this we need to set up the Arduino IDE for use with the ESP8266. I found a great tutorial here, but otherwise, the steps are pretty simple. Open the Arduino IDE, go to Preferences and then paste this URL into to the additional boards list: http://arduino.esp8266.com/stable/package_esp8266com_index.json.

Screen Shot 2019-10-20 at 11.37.10 am

Once done, go to the board manager and search for ESP8266...

Screen Shot 2019-10-20 at 11.37.54 am

Install the relevant row and then restart the Arduino IDE. From here, you should have a new selection list in the boards drop-down...

Screen Shot 2019-10-20 at 11.39.41 am

...and then, once selected, a hideous amount of new options to adjust the programming!

Screen Shot 2019-10-20 at 11.44.27 am

The main advice is to not touch any of them, apart from the serial port. You'll need to work out which one your Arduino is connected to, but depending on if you even had serial ports in the first place, it should be pretty obvious. I'm working on a Mac Mini and my Arduino was connected via cu.usbserial-1460. From here, open the Serial Monitor and hit reset on the Arduino.

Screen Shot 2019-10-20 at 11.44.50 am

What garbage is that? I then started from the slowest and tested each baud... turns out if you set to 74880 then you'll get the following...

Screen Shot 2019-10-20 at 11.46.29 am

What a weird port number? It seems that just the initial header information is at that BAUD rate. Afterwards, it'll be at whatever you've set in the code you upload.

Running A Web Server

So, where were we? We have a connected device, so let's grab the first example from here and compile it. After installing the ESP8266 libraries, this code should compile with zero issues. If you happen to have any, then write a comment below, providing as much detail as possible. If it's worked, then check the code and adjust the Wifi SSID and password to match your local AP. Hit upload and cross your fingers and toes... hopefully you'll get the following output:

Screen Shot 2019-10-20 at 11.49.07 am

Yes! Now, you need to switch OFF switch 7 on the little switch header on the Arduino. This pin enables the programming mode and we now want it in the run mode. Note also that we've now set the baud to 115200, so change your serial monitor to that too... Do you get the following after hitting the reset key on the Arduino?

Screen Shot 2019-10-20 at 11.50.08 am

Associated! And with a nice IP! So what does the web browser say?

Screen Shot 2019-10-20 at 11.54.58 am

WIN!

HTTPS Web Requests with the ESP8266

The basic ESP8266 examples use WiFiClient, but this only works with HTTP requests. My server runs over HTTPS, so we need to use WifiSecureClient for secure web requests. To call an HTTPS service, you'll need to get the fingerprint from the SSL certificate. Browse to the site in a regular web browser and check out the properties of the lock next to the URL in the address bar. Somewhere in there you'll find the required data.

Screen Shot 2019-10-20 at 12.39.49 pm

And from there, edit the WifiClient Example to carry out an SSL request using these instructions:

#include <esp8266wifi .h>

const char* ssid = "********";
const char* password = "********";
const char* host = "api.github.com";
const char* fingerprint = "CF 05 98 89 CA FF 8E D8 5E 5C E0 C2 E4 F7 E6 C3 C7 50 DD 5C";

void setup()
{
  Serial.begin(115200);
  Serial.println();

  Serial.printf("Connecting to %s ", ssid);
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println(" connected");
}


void loop()
{
  WiFiClientSecure client;
  Serial.print("[connecting to ");
  Serial.println(host);
  if (client.connect(host, 443)) {
    Serial.println("connected]");
    if (client.verify(fingerprint, host)) {
      Serial.println("[certificate matches]");
    } else {
      Serial.println("[certificate doesn't match]");
    }
    Serial.println("[Sending a request]");
    client.print(String("GET /") + " HTTP/1.1\r\n" +
                 "Host: " + host + "\r\n" +
                 "Connection: close\r\n" +
                 "\r\n");
    Serial.println("[Response:]");
    while (client.connected() || client.available())
    {
      if (client.available())
      {
        String line = client.readStringUntil('\n');
        Serial.println(line);
      }
    }
    client.stop();
    Serial.println("\n[Disconnected]");
  }
  else
  {
    Serial.println("connection failed!]");
    client.stop();
  }
  delay(5000);
}

And hopefully, you'll get something similar to the following in your serial terminal.

{ll⸮⸮|⸮d⸮|⸮d⸮b|⸮⸮⸮⸮s⸮b⸮c⸮⸮'o⸮dg'⸮⸮⸮cp⸮⸮dsdrlx⸮o⸮⸮d⸮⸮co⸮|l⸮⸮c⸮⸮go⸮d⸮⸮$`⸮'o$`gs⸮⸮⸮ob⸮$;⸮⸮gc⸮l⸮⸮dl⸮⸮d`⸮⸮'⸮

Connecting ...
scandone
........scandone
.scandone
state: 0 -> 2 (b0)
state: 2 -> 3 (0)
state: 3 -> 5 (10)
add 0
aid 1
cnt 

connected with COMEGETSOME, channel 6
dhcp client start...
ip:192.168.1.121,mask:255.255.255.0,gw:192.168.1.1

Connected to COMEGETSOME
IP address:	192.168.1.121
mDNS responder started

connecting to api.github.com
Using fingerprint '59 74 61 88 13 CA 12 34 15 4D 11 0A C1 7F E6 67 07 69 42 F5'
requesting URL: /repos/esp8266/Arduino/commits/master/status
request sent
headers received
esp8266/Arduino CI has failed
reply was:
==========
{"state":"pending","statuses":[],"sha":"1e17dddd895883806c9bfd3dd7b7042aa813d94f","total_count":0,"repository":{"id":32969220,"node_id":"MDEwOlJlcG9zaXRvcnkzMjk2OTIyMA==","name":"Arduino..."}
==========
closing connection

Nice, we can successfully pull data from a HTTPS source. Let's rig up a polling system to get the data each minute.

Polling for Data + Extra Buttons

So, we're able to pull data from the internet, but I also want this unit to be a mini webserver. If I used Delay() to spread out the web-polling calls, then I'd halt the entire unit. We can't have it wait when it needs to be handling button presses from the web interface. Instead, we'll take a snapshot of the current internal millisecond counter using millis() and then check how many milliseconds have passed to work out if we should try and grab new data.

#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WiFiMulti.h> 
#include <ESP8266mDNS.h>
#include <ESP8266WebServer.h>   // Include the WebServer library

ESP8266WiFiMulti wifiMulti;     // Create an instance of the ESP8266WiFiMulti class, called 'wifiMulti'
ESP8266WebServer server(80);    // Create a webserver object that listens for HTTP request on port 80

void handleRoot();              // function prototypes for HTTP handlers
void handleNotFound();
void handleRemote();
unsigned long lastMillis;
const char* host = "trainfinder.otenko.com";
const int httpsPort = 443;
const char fingerprint[] PROGMEM = "BC 9C 56 D5 8E 7A FE CC 0C F7 A2 21 1F C5 7B 9A C0 FA 15 41";
String last_line = "";

void setup(void) {
  Serial.begin(9600);
  delay(100);
  Serial.println("\n!START");
  wifiMulti.addAP("COMEGETSOME", "blahblahblah");
  while (wifiMulti.run() != WL_CONNECTED) { delay(250); }
  Serial.println(WiFi.SSID());
  Serial.println(WiFi.localIP());

  server.on("/", HTTP_GET, handleRoot);
  server.on("/buttons", HTTP_POST, handleRemote);
  server.onNotFound(handleNotFound);
  server.begin();
  
  lastMillis = millis();
}

void loop(void){
  server.handleClient();
  if ((millis() - lastMillis) > (60 * 1000)) {
    WiFiClientSecure client;
    client.setFingerprint(fingerprint);
  
    if (!client.connect(host, httpsPort)) {
      Serial.println("!FAILED");
    } else {
      String url = "/some/cool/url";    
      client.print(String("GET ") + url + " HTTP/1.1\r\nHost: " + host + "\r\nConnection: close\r\n\r\n");
      while (client.connected()) {
        String line = client.readStringUntil('\n');
        if (line == "\r") break;
      }
      bool foundLastLine = false;
      String line = "";
      while(client.available()) {   
        line = client.readStringUntil('\n');
        if (last_line.equals("") || foundLastLine) {
          Serial.println(line);
          last_line = String(line);
          delay(6500); //space out the data to the Arduino
        }
        if (last_line.equals(line)) {
          foundLastLine = true;
        }
      }
      if (!foundLastLine) last_line = line;
    }
    lastMillis = millis();
  }
}

void handleRoot() {
  server.send(200, "text/html", "<form action='/buttons' method='POST'>" \
      "<input type='submit' name='pwr_plz' value='PWR!'/>" \
      "<input type='submit' name='vol_dn' value='VOL-'/>" \
      "<input type='submit' name='vol_up' value='VOL+'/>" \ 
    "</form><br/><br/>Last Line: <pre>" + last_line + "</pre>");   
}

void handleRemote() {
  if (server.hasArg("vol_up")) {
    Serial.println("!VOLUP");
  } else if (server.hasArg("vol_dn")) {
    Serial.println("!VOLDN");
  } else if (server.hasArg("pwr_plz")) {
    Serial.println("!POWER");
  }
  server.sendHeader("Location","/");
  server.send(303);
}

void handleNotFound(){
  server.send(404, "text/plain", "404: Not found");
}

Just for fun, here's the first shot of me writing the code. Instead of 'text/html', I was still outputting 'text/plain' and, well, as expected, got the following...

Screen Shot 2019-10-20 at 12.04.08 pm

After fixing that, the screenshot below was taken. Of course, it doesn't match the code above, but you get the idea.

Screen Shot 2019-10-20 at 12.06.02 pm

The basic idea is to print out the raw html to the browser. From here there's a form that has the buttons which post back to the ESP8266. The controller then sees the post, sends the command via Serial to the Arduino and then redirects the user back to the main form.

Screen Shot 2019-10-20 at 12.06.05 pm

Now to get the Arduino to consume it.

ESP8266 to Arduino

We've currently had the ESP8266 piped directly out the USB Serial port. Now we want it to talk to the Arduino internally. To do this, the tiny onboard switch needs to have all switches off except for 1 and 2. This then routes the RX/TX directly from the ESP8266 to the Arduino. From here though, the unit becomes a black-box. We have no idea what the ESP8266 is saying to the Arduino, and vice-versa, as the connection via the USB serial port has been severed. We can only hope that the data we're sending through is what we want!

If you check the shots above of the data the ESP8266 sends, you can see that we want to skip a bit of the earlier stuff. To do this, I defined a "!START" command which the Arduino should look for before bothering to deal with any of the data from the serial channel. From there, anything starting with a "!" is a command, whereas anything else is to be printed to the LED Display.

Oh yeah, that TV Remote bit

I previously had an amplifier that ran over ARC over HDMI and also received controls... but half the time it'd switch on to Optical and just would not switch back to ARC without a lot of screwing around. No amount of power cycling, cable switching or button pressing would get it back. So it went to the farm. Instead, I purchased a beautiful old Yamaha amp for AUD$5 and then realised I had to get up and control it by hand. Not optimal, so I search google for the remote codes.... they didn't exist, so I search eBay for a spare remote... they didn't exist... but one guy in Spain had a company that programmed third-party remotes and had one for this amp!

It arrived, and I plugged it through the same code I used for the B&O TV. Over the serial, the codes and bits were reported, showing me that it used the "NEC" protocol. I recorded the codes for the buttons I wanted. I then did the same with my Sony TV Remote for buttons that I wanted to re-purpose. The goal was to have the TV Volume buttons also trigger the amp volume. This worked nicely, via an external IR LED that sits in front of the amp.

Of course, the TV volume still shifts, so I made the amp volume shift 4 times per button press... meaning the surround is always louder than the TV. Doesn't hurt to have a little bit of tinny sound from the TV also... a second center channel?

To make everything compile, install Ken Shirrif's IRremote library, available via the Arduino GUI...

Screen Shot 2019-10-20 at 2.31.18 pm

The code is in the next segment.

Hooking up the LED Sign

I've used a font found online, but it seems that Arduino has one built-in? 5x7 font. Either way, the 3 data lines and 7 row-enable pins need to find homes in the Arduino digital IO pins. Make sure you don't use digital pin 0 or 1 as that's the serial channel to the ESP8266. I found this out later below...

Once hooked up, just use a similar loop process as per any LED display: Disable all rows, send out the columns to be lit for the first row, enable that row and quickly disable it. Then do the same for the next 6 rows. As quickly as possible! More information on lighting this sign is over here.

#include <IRremote.h>
#include "myfont.h"
#include "digitalWriteFast.h"

int RECV_PIN = 13;
IRrecv irrecv(RECV_PIN);
decode_results results;
IRsend irsend;

void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver

  pinModeFast(0, OUTPUT);
  digitalWriteFast(0, LOW);
  pinModeFast(2, OUTPUT);
  digitalWriteFast(2, LOW);
  pinModeFast(12, OUTPUT);
  digitalWriteFast(12, LOW);

//matrix led row drivers
  for (int p = 0; p <= 11; p++) {
    pinModeFast(p, OUTPUT);
    digitalWriteFast(p, LOW);
  }
}

unsigned long last_time = millis();
unsigned long scroll_time = millis();
unsigned long scroll_pause = millis();
bool is_off = true;
int loop_count = 0;
String serialString = " Warming up..";
bool found_start = false;
int charOffset = 0;
int ccol;

void loop() {
  if (irrecv.decode(&results)) {    
    loop_count = 0;
    switch (results.value) {
      case 4841:
      case 0xA90:
        irsend.sendNEC(0xDE21807F, 32);
        if (is_off) {
          serialString = " Power ON!";
          is_off = false;
        } else {
          serialString = " GOOD BYE!";
          is_off = true;
        }
        break;
      case 0x490:
        irsend.sendNEC(0xDE21B04F, 32);
        delay(50);
        irsend.sendNEC(0xDE21B04F, 32);
        delay(50);
        irsend.sendNEC(0xDE21B04F, 32);
        serialString = " VOLUME UP!";
        break;
      case 0xC90:
        irsend.sendNEC(0xDE21708F, 32);
        delay(50);
        irsend.sendNEC(0xDE21708F, 32);
        delay(50);
        irsend.sendNEC(0xDE21708F, 32);
        serialString = " VOLUME DOWN!";
        break;
      case 0xFFFFFFFF:
        irsend.sendNEC(0xFFFFFFFF, 32);
        break;
        //sony teletext red
      case 21225:
        irsend.sendNEC(3726721215, 32);
        serialString = " INPUT!";
        //sony teletext green
      case 13033:
        irsend.sendNEC(3726717135, 32);
        serialString = " MODE UP!";
        break;
        //sony teletext yellow
      case 29417:
        irsend.sendNEC(3726735495, 32);
        serialString = " MODE DOWN!";
        break;
      default:
        Serial.println(results.value);
        Serial.println(results.bits);
        break;
    }
    delay(250);
    irrecv.enableIRIn();
    irrecv.resume(); // Receive the next value
  }

  if (charOffset == 0 && Serial.available() && ((millis() - last_time) > 4000)) {
    last_time = millis();
    serialString = Serial.readStringUntil('\n') + '\0';
    loop_count = 0;
    scroll_pause = millis();
  }
  
  //draw LEDs
  for (int row = 0; row < 7; row++) 
  {
    for (int col = 0; col < 90; col++) {
      if (((col / 5) + charOffset) < 60) {
        ccol = (charOffset * 5) + col;
        digitalWriteFast(2, ((font[serialString[ccol / 5]][ccol % 5] & (1 << (6 - row))) > 0) ? HIGH : LOW);
      } else {
        digitalWriteFast(2, LOW);
      }
      digitalWriteFast(12, HIGH);
      delayMicroseconds(5);
      digitalWriteFast(12, LOW);
    }
    digitalWriteFast(row + 5, HIGH);
    delayMicroseconds(75);
    digitalWriteFast(row + 5, LOW);
  }
  
  if ((millis() - scroll_pause > 2500)) {
    if ((serialString.length() > 18)) {
      if (millis() - scroll_time > 180) {
        charOffset++;
        if (charOffset > serialString.length()) {
          charOffset = 0;
          loop_count++;
          scroll_pause = millis();
          if (loop_count > 10) serialString = "";
        }
        scroll_time = millis();
      }
    } else {
      loop_count++;
      if (loop_count > 100) serialString = "";
      charOffset = 0;
    }
  }
}

Overloading Arduino Pins

Anyone watching above, or in the previous post where I hooked the display up to the old PC, was probably screaming in their seats. It's well known that you should NOT draw too much current through the pins on any microprocessor. As soon as I started hooking up more modules onto this unit, things started going haywire and it quickly dawned on me. My seven line-enable pins were being brought LOW to enable the rows... but these were actually working as the single GND conduit for the entire bloody LED display!

DSC01969

I quickly referred to the previous module that ran this sign and saw there was a 74LS145 binary counter in between the Atmel Microcontroller and the 7 enable rows. A quick review of the datasheet shows that this chip can 'sink' up to 15v and is 'great for driving LEDs'. Right... they were properly routing the GND wires away from the microcontroller and using the 145 as a set of transistors. They even saved 3 data lines in the process! I only had a ULN2003 (which would still use 7 lines) and there were no 74LS145 to be found at Jaycar!

DSC01988

This now directed the current away from the microcontroller... but didn't enhance the brightness.

Speeding up the Refresh Rate

It occurred to me that my refresh rates weren't anywhere near as good as the original controller that the sign contained. My loop is busy checking clocks, serial ports and mucking around, so it was never going to actually go fast enough. The code above could run a single segment OK, but started to scale worse as the bit shifting got longer. One trick, which is actually already implemented in the source above is to use an external library to make the digital pin manipulation faster.

With this implemented, there was less flickering and I found that three segments (90 LEDs per row) looked good. One final note is that you shouldn't really use pins 0 or 1 if you've got the serial enabled. They actually present the TX/RX lines and the serial data and the serial data to the Arduino is visible on them. In this case, it was the serial data to/from the ESP8266. In the case below, I had the three data lines required to drive the display on digital pins 0,1,2...

DSC01980

Shifting those to spare pins higher...

DSC01983

Yessssss! It works really nicely.

Filed under: Arduino No Comments
17Oct/190

Red LED Shop Display

Found this thing at the flea markets on the weekend. It's a standard LED marquee/shop display with two cables hanging out one side. One looks like a power cable, the other data with an RJ45 phone plug on the end. Manufactured by Data Signs Australia, there's no mention of this relic on their site... seems they only care about road signs now!

DSC01945

As you can see, it's what's on the inside that counts. At the end there seems to be a controller board with an Atmel microcontroller. This is then connected to five display modules, all on a standard bus. The build of the headers is nice as it all connects seamlessly together to give one full display. It looks like the wiring of the phone jack goes straight into a MAX232... so we can talk serial to this thing. I'll do that later though, I'm more interested in the display modules.

DSC01957

DSC01959 DSC01960 DSC01967

DSC01969

DSC01965 DSC01966 DSC01971

Each module contains six 5x7 LED matrices. These are powered by TIP125 transistors and data is driven by MC14015BCP shift registers connected in series. The data bus on the side has 2 lines at either end for VCC and GND. The pins in the middle are then Clock, Data, Reset (for the shift registers) and then enable lines for the 7 matrix rows.

DSC01940

Hacking started in earnest to work out the pinout...

Lighting it up

For any LED matrix, the basic idea is to send data really quickly to them and 'emulate' that all LEDs are on at one time. Whenever you try to take photos of LED lights, be that traffic lights, train destination boards, etc... you'll find that, unless your shutter speed is slow, you don't get the entire set of 'lit' LEDs visible at once. Here's a good example:

DSC08481

Not the clearest example... blame the snow in early November... but you can see that the LEDs in the destination board aren't of a consistent illumination. The microcontroller is still busy rendering the screen and the frame is 75% drawn.

Microcontrollers 'print' the LED signal across the matrices to get them to light up. They do this so quickly, that to the naked eye, the LEDs are always lit. We're going to have to do this here as well. I've decided to use that huge IO board I investigated recently to drive this thing.

Based on the datasheet for the MC14015BCP shift registers, as the clock signal is driven high, whatever is on the data line will be fed into the first parallel data out line. These shift registers contain two sets of 4-bit outputs. Following the wiring on the card, the final bit of the first 4-bit output is chained to the data input of the second register. The final bit of that is then chained to the next shift register IC's data in. The clocks are all tied together, meaning that any data fed in to the clock/data lines on the bus at the side of the board will eventually trickle down all the way through the board, and then to any boards attached further. Quite the shift-register-centipede!

Writing some code...

Thanks to the previous work with this IO card, the interfacing would be quite simple. Clock, Data and Reset would be pins 1,2,3 on the first block-of-eight at the base IO address. I then put the 7 row-enable pins on the second block-of-eight. This meant less bit-twiddling. QBasic allows a nice mechanism to record data that can then be read into arrays. The data happens to be the pin value of the data pin, so here "2" will set the second pin HIGH when sent to the port, meaning that the data line will be high for the shift registers and therefore illuminating the LED in that column. I then just need to enable the first pin briefly to send through that number. Of course, I'd send a 0 (or LOW) to pin 2 to send a 0 through the shift registers, thereby turning that column's LED off.

The above needs to be done for each row. i.e. I have to send out 30 values (length of one row on one module) then 'flicker' the enable row. Then I need to send the next 30 values and 'flicker' the second enable row. The speed at which the row enable pin is 'flickered' is also an issue... if it's too slow, then you just get one line of LEDs and it's very jittery... but if it's too fast the LEDs start to dim, as they're starved of power to actually illuminate!

OUTDATA# = &H410
OUTLINES# = &H411
OUT &H413, 0
OUT &H413, 0
CLOCKBIT = 1
DATA 30, 8
DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,2,2,2,0,2,2,2,0,2,2,2,0,2,2,2,0,2,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,2,0,0,2,0,0,0,2,0,0,0,0,2,0,0,2,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,2,0,0,2,2,2,0,2,2,2,0,0,2,0,0,2,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,2,0,0,2,0,0,0,0,0,2,0,0,2,0,0,0,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,2,0,0,2,2,2,0,2,2,2,0,0,2,0,0,2,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
READ DATALENGTH
READ DATAHEIGHT
DIM DATAPIXELARRAY((DATALENGTH - 1), (DATAHEIGHT - 1)) AS INTEGER
FOR Y = 0 TO (DATAHEIGHT - 1)
	FOR X = 0 TO (DATALENGTH - 1)
		READ DATAPIXELARRAY(X, Y)
	NEXT X
NEXT Y
DO
	FOR ROWS = 0 TO (DATAHEIGHT - 1)
		FOR DOT = 0 TO (DATALENGTH - 1)
			BIT = DATAPIXELARRAY(DOT, ROWS)
			OUT OUTDATA#, BIT
			OUT OUTDATA#, (BIT + CLOCKBIT)
			OUT OUTDATA#, 0
		NEXT DOT
		OUT OUTLINES#, 255 - (2 ^ ROWS)
		FOR i = 0 TO 10
		NEXT i
		OUT OUTLINES#, 255
	NEXT ROWS
LOOP UNTIL INKEY$ = "q"

DSC01951

The only real trickery in the code above is the two zeroes sent out to 0x413 at the start... it seemed to be required to get the IO card to treat the ports as output and pull them to ground by default. Otherwise, data is defined and loaded into the array. A non-stop loop (unless you press "q") is then started where we load a single row of dots and then trigger the row enable pin. Each row-enable pin needs to be brought low to activate the LEDs, hence the 255 - (2 ^ rownumber). Finally, that crappy little for-loop is there to provide a mini delay so that the LEDs get a chance to light up.

Let's make a marquee

Right, a display of static pixels is fine, but what if you want one of those really ugly perpetually-scrolling marquees that are seen in every $2 (100-yen) shop? Should be pretty simple, just throw in an offset and increment it at every loop. That'll work, but then once it's off the screen it'll start back at '0' which happens to be fully-on-screen. That jump is a little jarring, so instead you need to actually shift it width-of-data off the start. For now, we'll just wrap it without padding in the middle.

OUTDATA# = &H410
OUTLINES# = &H411
OUT &H413, 0
OUT &H413, 0
CLOCKBIT = 1

DATA 30, 8
DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,2,2,2,0,2,2,2,0,2,2,2,0,2,2,2,0,2,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,2,0,0,2,0,0,0,2,0,0,0,0,2,0,0,2,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,2,0,0,2,2,2,0,2,2,2,0,0,2,0,0,2,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,2,0,0,2,0,0,0,0,0,2,0,0,2,0,0,0,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,2,0,0,2,2,2,0,2,2,2,0,0,2,0,0,2,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

READ DATALENGTH
READ DATAHEIGHT
DIM DATAPIXELARRAY((DATALENGTH - 1), (DATAHEIGHT - 1)) AS INTEGER
FOR Y = 0 TO (DATAHEIGHT - 1)
   FOR X = 0 TO (DATALENGTH - 1)
      READ DATAPIXELARRAY(X, Y)
   NEXT X
NEXT Y

DIM SCROLLOFFSET AS INTEGER
DIM LOOPCOUNTER AS INTEGER

SCROLLOFFSET = 0
LOOPCOUNTER = 0

DO
	FOR ROWS = 0 TO (DATAHEIGHT - 1)
		FOR DOT = SCROLLOFFSET TO (DATALENGTH - 1)
			BIT = DATAPIXELARRAY(DOT, ROWS)
			OUT OUTDATA#, BIT
			OUT OUTDATA#, (BIT + CLOCKBIT)
			OUT OUTDATA#, 0
		NEXT DOT
		FOR DOT = 0 TO (SCROLLOFFSET - 1)
			BIT = DATAPIXELARRAY(DOT, ROWS)
			OUT OUTDATA#, BIT
			OUT OUTDATA#, (BIT + CLOCKBIT)
			OUT OUTDATA#, 0
		NEXT DOT
		OUT OUTLINES#, 255 - (2 ^ ROWS)
		FOR i = 0 TO 10
		NEXT i
		OUT OUTLINES#, 255
	NEXT ROWS
	LOOPCOUNTER = LOOPCOUNTER + 1
	IF LOOPCOUNTER > 10 THEN
		LOOPCOUNTER = 0
		SCROLLOFFSET = SCROLLOFFSET + 1
		IF SCROLLOFFSET > DATALENGTH THEN
			SCROLLOFFSET = 0
		END IF
	END IF
LOOP UNTIL INKEY$ = "q"

TEST!

I'm sure there's some MOD function I can use to prevent the need for two loops, but it works! Of course, it only works as long as the data is the length of the screen! What happens when I hook up the other modules?...

Oh... that's no good... it's offsetting by 1 row per module? What's the go there? Let's edit the code to fill the entire row.

OUTDATA# = &H410
OUTLINES# = &H411
OUT &H413, 0
OUT &H413, 0
CLOCKBIT = 1

DIM ACTUALDISPLAYWIDTH AS INTEGER
ACTUALDISPLAYWIDTH = 60

DATA 30, 8
DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,2,2,2,0,2,2,2,0,2,2,2,0,2,2,2,0,2,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,2,0,0,2,0,0,0,2,0,0,0,0,2,0,0,2,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,2,0,0,2,2,2,0,2,2,2,0,0,2,0,0,2,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,2,0,0,2,0,0,0,0,0,2,0,0,2,0,0,0,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,2,0,0,2,2,2,0,2,2,2,0,0,2,0,0,2,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

READ DATALENGTH
READ DATAHEIGHT
DIM DATAPIXELARRAY((DATALENGTH - 1), (DATAHEIGHT - 1)) AS INTEGER
FOR Y = 0 TO (DATAHEIGHT - 1)
   FOR X = 0 TO (DATALENGTH - 1)
      READ DATAPIXELARRAY(X, Y)
   NEXT X
NEXT Y

DIM SCROLLOFFSET AS INTEGER
DIM LOOPCOUNTER AS INTEGER

SCROLLOFFSET = 0
LOOPCOUNTER = 0

DO
	FOR ROWS = 0 TO (DATAHEIGHT - 1)
		FOR DOT = SCROLLOFFSET TO (ACTUALDISPLAYWIDTH - 1)
			IF (DOT >= DATALENGTH) THEN
				BIT = 0
			ELSE
				BIT = DATAPIXELARRAY(DOT, ROWS)
			END IF
			OUT OUTDATA#, BIT
			OUT OUTDATA#, (BIT + CLOCKBIT)
			OUT OUTDATA#, 0
		NEXT DOT
		FOR DOT = 0 TO (SCROLLOFFSET - 1)
			IF (DOT >= DATALENGTH) THEN
				BIT = 0
			ELSE
				BIT = DATAPIXELARRAY(DOT, ROWS)
			END IF
			OUT OUTDATA#, BIT
			OUT OUTDATA#, (BIT + CLOCKBIT)
			OUT OUTDATA#, 0
		NEXT DOT
		OUT OUTLINES#, 255 - (2 ^ ROWS)
		FOR i = 0 TO 10
		NEXT i
		OUT OUTLINES#, 255
	NEXT ROWS
	LOOPCOUNTER = LOOPCOUNTER + 1
	IF LOOPCOUNTER > 5 THEN
		LOOPCOUNTER = 0
		SCROLLOFFSET = SCROLLOFFSET + 1
		IF SCROLLOFFSET >= ACTUALDISPLAYWIDTH THEN
			SCROLLOFFSET = 0
		END IF
	END IF
LOOP UNTIL INKEY$ = "q"

So now we have a ACTUALDISPLAYWIDTH variable that tells us how much space we actually need to fill. Using the SCROLLOFFSET, we then start printing out the data array and, if we're past it then just zeroes. Once we've gotten to our full width, we then go back to the array and attack it from the start.

And if we increase to three panels and up the width to 90?

Gosh, it's getting slow loading that full row each time... maybe time to switch to an Arduino? Before we do that... here's a typewriter...

OUTDATA# = &H410
OUTLINES# = &H411
OUT &H413, 0
OUT &H413, 0
CLOCKBIT = 1

DIM ACTUALDISPLAYWIDTH AS INTEGER
ACTUALDISPLAYWIDTH = 90

DATA 104, 8
DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DATA 0,2,2,2,0,2,2,0,0,2,2,2,0,2,2,0,0,2,2,2,0,2,2,2,0,2,2,2,0,2,0,2,0,2, 2,2,0,0,2,2,0,2,0,2,0,2,0,0,0,2,0,2,0,2,2,0,0,0,2,0,0,2,2,2,0,2,2,2,0,2, 2,2,0,2,2,2,0,2,2,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,2,2
DATA 0,2,0,2,0,2,0,2,0,2,0,0,0,2,0,2,0,2,0,0,0,2,0,0,0,2,0,0,0,2,0,2,0,0, 2,0,0,0,0,2,0,2,0,2,0,2,0,0,0,2,2,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2, 0,2,0,2,0,0,0,0,2,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,0,0,2
DATA 0,2,2,2,0,2,2,0,0,2,0,0,0,2,0,2,0,2,2,2,0,2,2,2,0,2,0,2,0,2,2,2,0,0, 2,0,0,0,0,2,0,2,2,0,0,2,0,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,2,2,0,2,0,2,0,2, 2,2,0,2,2,2,0,0,2,0,0,2,0,2,0,2,0,2,0,2,2,2,0,0,2,0,0,0,2,0,0,0,2,0
DATA 0,2,0,2,0,2,0,2,0,2,0,0,0,2,0,2,0,2,0,0,0,2,0,0,0,2,0,2,0,2,0,2,0,0, 2,0,0,2,0,2,0,2,0,2,0,2,0,0,0,2,0,2,0,2,0,2,0,2,0,2,0,2,0,0,0,2,2,2,0,2, 2,0,0,0,0,2,0,0,2,0,0,2,0,2,0,2,0,2,0,2,2,2,0,2,0,2,0,0,2,0,0,2,0,0
DATA 0,2,0,2,0,2,2,0,0,2,2,2,0,2,2,0,0,2,2,2,0,2,0,0,0,2,2,2,0,2,0,2,0,2, 2,2,0,0,2,0,0,2,0,2,0,2,2,2,0,2,0,2,0,2,0,2,0,0,2,0,0,2,0,0,0,2,2,2,0,2, 0,2,0,2,2,2,0,0,2,0,0,2,2,2,0,0,2,0,0,2,0,2,0,2,0,2,0,0,2,0,0,2,2,2
DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

READ DATALENGTH
READ DATAHEIGHT
DIM DATAFONTARRAY((DATALENGTH - 1), (DATAHEIGHT - 1)) AS INTEGER
FOR y = 0 TO (DATAHEIGHT - 1)
   FOR X = 0 TO (DATALENGTH - 1)
      READ DATAFONTARRAY(X, y)
   NEXT X
NEXT y

DIM ACTUALPIXELBUFFER(ACTUALDISPLAYWIDTH - 1, DATAHEIGHT - 1) AS INTEGER

DIM SCROLLOFFSET AS INTEGER
DIM LOOPCOUNTER AS INTEGER

SCROLLOFFSET = 0
LOOPCOUNTER = 0

DO
	FOR ROWS = 0 TO (DATAHEIGHT - 1)
		FOR DOT = 0 TO (ACTUALDISPLAYWIDTH - 1)
			BIT = ACTUALPIXELBUFFER(DOT, ROWS)
			OUT OUTDATA#, BIT
			OUT OUTDATA#, (BIT + CLOCKBIT)
			OUT OUTDATA#, 0
		NEXT DOT
		OUT OUTLINES#, 255 - (2 ^ ROWS)
		FOR i = 0 TO 10
		NEXT i
		OUT OUTLINES#, 255
	NEXT ROWS
	LOOPCOUNTER = LOOPCOUNTER + 1
	pressedchar$ = INKEY$
	IF (LEN(pressedchar$) = 1) THEN
		lastchar = ASC(pressedchar$)
		lastchar = lastchar - 97
		IF (lastchar >= 0) THEN
			FOR c = 0 TO 3
				FOR y = 0 TO 6
					ACTUALPIXELBUFFER(c + offset, y) = DATAFONTARRAY((lastchar * 4) + c, y)
				NEXT y
			NEXT c
			offset = offset + 4
			IF ((offset + 4) >= ACTUALDISPLAYWIDTH) THEN
				offset = 0
			END IF

		END IF
	ELSE
		REM lastchar = ASC(RIGHT$(pressedchar$, 1))
	END IF
	PRINT lastchar
	IF LOOPCOUNTER > 200 THEN
		LOOPCOUNTER = 0
		SCROLLOFFSET = SCROLLOFFSET + 1
	END IF
LOOP WHILE INKEY$ <> "."

Hah... that worked better than expected...

15Oct/190

Apple G4 iBook

After a lovely drive into the Dandenong Ranges to check out some tulips (and eat oliebollen) (thanks Mum!), it was time to venture home... but who could resist not visiting the tip-shop along the way? After a quick look around the shop, it felt like they'd stopped stocking electrical components... but then I stumbled across this, sitting in the wrong area, but looking in really-great condition!

DSC01907

DSC01906 DSC01908 DSC01910

Check out that keyboard! It's still in perfect condition and clean? How on earth... anyway, I took it to the counter and asked for the price. The checkout-chick had to flip through a book of standard prices before responding with AUD$10. I giggled and kept shopping, hoping to find the power supply... no luck there though!

DIY Power Supply

These iBooks need a 24v DC power supply. The plug is a little adventurous on Apple's behalf. Initially it looks like an RCA composite plug, but then you realise that the central pin is actually a 2.5mm stereo jack. Without the outer shield, I can imagine it would be very easy to short the plug. Either way, it's a bit of a lets-take-two-things-off-the-shelf and combine them to make a proprietary socket that no one else can copy. Or can we? (alternative source)

Turns out that you only really need to apply VCC and GND to a standard 2.5mm jack and it'll work. The very tip is not connected, the middle band is GND and the base, closest to the wiring, is +24v DC.

DSC01914

Jaycar didn't have any full-metal-casing plugs, so I had to live with the cheap plastic plugs. Soldered up, I got the following...

DSC01920

DSC01921 DSC01925 DSC01926

DSC01927

The next morning, at the local flea market, I found this cheap and nasty power supply. It says it produces 21-24v? Seems to have a 4-pin plug, so hopefully one of the wires is the full 24v.

DSC01928

DSC01929 DSC01930 DSC01932

Oh right, that's just a two-wire cable split into pairs. So the 4-pin is a double-adaptor. Not handy... and the voltage is hardly at 22v. Will the PowerBook survive?

DSC01933

DSC01934 DSC01937 DSC01939

Sure did! And the battery even started charging!

Filed under: Apple No Comments
7Oct/190

103 Series Final Run, Osaka – June, 2019

This was officially the third final run 'seen' in one trip to Japan! First I got to see Ohmi Railway's 700 Series do its last run. Secondly, although not the final-final, I saw/rode Kumamoto Dentetsu's 200 Series during it's last month of operations. Finally, we have the Osaka Loop Line special: an orange-liveried 103-Series EMU. Starting in 2016, JR West put a lot of money into the Osaka Power Loop marketing campaign which saw new EMUs and new liveries on the Loop Line. This therefore meant a phasing out of the older rolling-stock.

Just my luck, the final run of the last running orange 103-series happened in early June. Unfortunately, I was working from the apartment and hadn't paid enough attention to when the final run would actually be! It turns out it was a single lap in the early morning peak! The train then retired to the yards near Osaka-Jo. I had actually gone out for a lap of the loop at around 3pm, waiting around Bentencho Station for the train to pass... after a while I google'd, only to find out that I was too late and therefore decided to head to the yards at Morinomiya. Before that though, there were some cool sites to be seen!

DSC01712

DSC01717 DSC01720 DSC01733

DSC01731

DSC01728 DSC01735 DSC01737

DSC01741

DSC01742 DSC01745 DSC01749

DSC01753

And, of course, my goal had been to catch the last-run and freight... so at least I was in one correct spot at one correct time!

DSC01759

DSC01763

The yard is located to the south of Kyobashi Station on the eastern side of the Osaka Loop Line. Morinomiya is the station directly south of the yard. The yard's entrance is on the north side and all operations are visible from the southern end of the Kyobashi Station platforms. To see parked trains though, I'd recommend walking from Morinomiya Station. It seems that everyone else had the same idea!

DSC01768

So, the train was in the yard and the wall was high and secure. If you look in the photo above, there was a poor little kid who'd ridden his bicycle down and tried to use it as a pedestal to see over the wall. Unfortunately, he still wasn't tall enough to take a photo with his Nintendo 3DS. I didn't ask why he was using that... but I guess he was too young to have a phone?

I took the following photo over the wall...

DSC01773

And then the poor kid looked up at me ... totally distraught. What else was there to do? I grabbed him and lifted him up high enough to take photos with his Nintendo! Made his day! On the way back, I stopped through Kyobashi Station as I wanted to actually check out the area. Whilst alighting, I grabbed a few shots of the local rolling-stock.

DSC01774 DSC01775 DSC01778

I was pretty sad... this was my second-last day of a 5-week trip.

Filed under: JPN No Comments
4Oct/190

Flea Markets, Osaka – May, 2019

There's nothing better than queuing (queueing?) up at the entrance of a Flea Market... there could be any amount of treasure inside, so you'll never know what you might find. One also doesn't want others to steal said treasure, so one must be early! In Japan, just like most other countries, there's a lust for flea markets and there's always someone selling something which piques one's interest.

Banpaku Recycle Fair - Expo Park

This flea market, named Banpaku Recycle Fair, is held twice a month at Expo Park in North Osaka. Getting there from Shin-Osaka was very easy, taking the subway and the Osaka Monorail.

After getting off at Expo Memorial Park Station, exit to the east and then cross under the monorail lines. The entrance is well organised, and really, you just need to head towards this guy to find it...

DSC07550

DSC07545 DSC07546 DSC07547

The park is used for a lot of events, even just families going for a picnic. The weather was perfect for a picnic also, but that's not what I was there for. Following the main path around to the left, you'll find the flea market.

DSC07553

DSC07554 DSC07555 DSC07557

DSC07558

From here, the browsing commenced! I ended up picking up a Famicom and a few n-gauge trains.

DSC07564

DSC07561 DSC07567 DSC07566

DSC07565

That Tower of the Sun God is ever-so-daunting.

Ohatsu Tenjin Shrine Flea Market

This one is nicely tucked away behind the busy streets of Umeda. It's a little bit south-east of the main JR Osaka Station, but within easy walking distance.

The temple itself is beautiful, a complete relic nestled in amongst a ring of skyscrapers. The area is connected to the Sonezaki Ohatsu Tenjin Dori Shopping Street (Shoutengai) which also offers some vintage and retro stores... if they're open when you're at the market!

DSC07507

DSC07502 DSC07508 DSC07503

I managed to pick up a really nice Sony Walkman-style personal recorder. It had all the right inputs and looked like it might be able to be connected to an MSX/C64/etc.. for data recording.

DSC07510 DSC07506 DSC07512

Don't forget to actually check out the shrine itself! Make a wish if you want!

Shi-Tennoji Flea Market

This market was huge! It's on the grounds of the Shi-Tennoji Temple and it's quite an effort to navigate the layout. You can access this market via the Tanimachi Subway Line at Shitennoji-mae Yuhigaoka Station or by walking north from JR Tennoji Station.

DSC 0006

If you're walking from the Subway station, you'll find the residents have their own stalls in the street leading to the main market. I don't know how by-the-book this is, but they've made the most of the traffic that comes through!

DSC 0007

DSC 0008 DSC 0011 DSC 0012

Wandering around, the usual trinkets were to be seen... until I saw this!

DSC 0013

It's a vintage model maglev Linear Shuttle! Opening the box to check the contents proved that it wasn't in the best condition.

DSC 0014

There seems to be a small oil tube included, which makes me think that the vehicle isn't always levitating... a quick google indicated that it actually only levitates on one section of track which then propels it around the loop. The loop is also vertical, as in a loop-the-loop, and not a flat circuit. The metal was also quite corroded... so I passed on it... but I had been pretty damn keen!

DSC 0016

Don't forget to say Hi! to the turtles in the middle of the temple yard. And the dancing monkey! I just missed the show.

DSC 0022

DSC 0017 DSC 0019 DSC 0020

Some stall holders happily dumped their wares on their tarpaulins... others were a lot more organised.

DSC 0021

And yeah... there's a lot of the above as well... it's always fun to check out the customers of such wares!

Shin-Osaka Station - East Gate

This small market is open every Saturday morning. Markets are pretty-much always on Sundays in Australia, so it was fun to come across this randomly when heading to the station to meet friends. Fortunately, there wasn't anyting that interesting... so I didn't have to lug anything around all day.

DSC 0079 DSC 0080 DSC 0081

It was also extremely hot... so anything you see above has probably already melted!

Filed under: JPN No Comments
1Oct/190

Suita Yard, Osaka – May, 2019

Thanks to the time of year, the sun was already starting to set later in the evening during May. I used the opportunities, when it wasn't raining, to venture out to the freight areas along the JR Kyoto Line. I'd visited Takatsuki the night before and realised, on the way back to Shin-Osaka, that I'd never really investigated the freight yard in Suita. The yard is officially located between Suita Station and Kishibe Station and there's a locomotive depot on the southern side of the line. I chose to proceed to Kishibe Station on train and then walk back to Suita.

DSC01631

Approaching from the east, I was instantly happy with my timing. The sun was setting perfectly, pointing straight at the faces of quite a lot of freight locomotives! Not only that, the variety was quite surprising. There were even some EF200s ready to be chopped up!

DSC01633

From the east side, there's a gate to the yard. This area provides a great vantage point to watch anything shunting around. It just so happens that a new HD300 was doing the honours with a set of KOKI flats. I don't actually remember the note of the engine as it was shunting, but for the life of me I don't think it sounded any less diesel! Shouldn't it have been more hybrid?

DSC01652 DSC01653 DSC01649

An EF63 then came through and parked into a free road in the yard. It had actually just come from Hirano, where I'd seen it earlier passing through!

DSC01634 DSC01637 DSC01640

DSC01645

Waaaay up the back of the yard there was also a standard YO5000 black guards van.

DSC01654

I continued to walk around to the other side of the yard. A lot of the length is just the side of the engine shed, in which I could here a lot of work being done, but couldn't really see it. And then there was some treasure on the side of the road... wouldn't fit in the suitcase though... might have been handy to test the famicom tho!

DSC01659 DSC01668DSC01661

Things got more interesting on the other side of the yard... EF66s! My favourite!

DSC01662

DSC01667 DSC01665 DSC01671

And then, after a bit more of a walk, there was an open gate with a perfectly framed view straight into the yard.

DSC01680 DSC01681 DSC01682

DSC01677

What an awesome line up! The lighting wasn't too bad either. Finally, down the very western end, is the entrance to the offices. They've mounted a 52 Series EMU (KuMoHa 52001) in their yard!

DSC01683 DSC01684 DSC01686

DSC01685

Nice surprise! I totally recommend anyone in the area to go for a walk and check this place out.

Filed under: JPN No Comments