Previously, I mentioned a bit about the ancient termcap system which is used to send display codes (clear, move cursor, underline, blink) to terminals of different kinds. In this modern GUI world, none of this is necessary … folks pretty much have to rewrite the whole program to work with native Mac, Windows, Linux, Java, etc. I suppose the modern equivalent to termcap would be a cross platform GUI (kind of like a graphical termcap?) which turns things like “create a pop up window” or “create a menu with the following options” in to whatever it takes to display them on the end operating system.
I suppose that’s truly what I should be learning right now — my program could make use of graphics on the Linux-based Raspberry Pi, Windows or Mac. However, since my program is not intended to be a windows-based program (no pull down menus, no mouse, etc.) and really had no use for graphics, I decided to write everything using text.
My original prototype was rather bland, spitting out 80 column descriptive text. This was perfect for debugging, but certainly not what we want the end-user to have to deal with:
Prototype running in a Mac Terminal window.
By writing the application as a strict ANSI-C program, and just using text, it would compile and run on a Windows PC as well, in a DOS-style COMMAND window (CMD.EXE):
Prototype running in a Windows CMD.EXE window.
The target system for this project would be Raspberry Pis, the $25-$35 micro-Linux computer designed for educational use. We would be using the $35 model, which has more RAM (512mb) and USB/ethernet. The Pis support HDMI and composite video output. Instead of using large (pricy) HDMI TV/monitors, I found tiny composite color monitors for under $20 (4.3″, about the size of a GPS unit or large smartphone screen).
By setting the resolution of the Pi to match the display’s 480×272 resolution (/boot/config.txt: framebuffer_width=480 and framebuffer_height=272), and by choosing the largest font available (setfont /usr/share/consolefonts/Uni3-Terminus32x16.psf.gz) I was able to get a large, easy to read (on the tiny screen) 30×8 display. It would look something like this:
The actual screen ends up much wider than this text drawing, since the displays I am using are 16×9 widescreen.
Have you noticed the lack of mentioning Termcap so far? Let’s correct that now.
If I was going to be using this particular screen and run on just a Raspberry Pi, I could just hard-code everything to expect 30×8 characters, and whatever display codes were needed to clear the screen or change colors.
And that would be bad programming. Doing this “because this is all it is planned to ever run on” is like not having insurance because you never plan to get in an accident. It’s certainly fine to write anything for yourself any way you darn well please (I do that all the time, too), but I try to think ahead and write things to be as portable and as flexible as I can.
Fortunately, I wrote such portable code back around 1995. At the time, I had created a text-based user interface called EthaWin. It was written for OS-9 Level 2 on the Tandy Color Computer 3, and later ported to the OS-9/68000 MM/1 computer. The CoCo 3’s terminal window system supported all kinds of screen codes for basic things like color, blinking, move cursor, etc., much like ANSI graphics on a PC did. The MM/1 was meant to be a next generation replacement for the CoCo OS-9 users, so it’s K-Windows system replicated (and expanded upon) those same screen codes.
My EthaWin was not the “portable code” I am speaking of. It would only run on a CoCo or MM/1 under OS-9. When I began working for Microware, the company that had created OS-9, none of my stuff would run on the “headless” OS-9 computers in the building — most didn’t even have video displays. The way you accessed them was via an RS232 serial port and a hardware terminal (or software terminal program), or from telnetting in across the network.
OS-9, being created as a very Unix-like operating system, supported termcap, and text editors like vim, uMacs, etc. made use of this to give full screen editing. If I wanted EthaWin to work on these OS-9 machines, I was going to have to learn how termcap worked.
In the next installment, I will finally talk about termcap and show how very simple it is to do very simple things.
Before stand-alone computers became common, most computer time was spent in front of a dumb terminal — basically a keyboard and screen that would send whatever the user typed to a big computer somewhere, and display whatever it received back from the big computer:
http://en.wikipedia.org/wiki/Computer_terminal
As I mentioned in an earlier posting, my first interaction with a computer in the 1970s was via a printing terminal at my elementary school. The next time I used a computer, it was a TRS-80 at Radio Shack. I kind of missed the whole dumb terminal phase of computing, but I certainly spent endless time with my home computer acting as a dumb terminal as it dialed in across the phone lines to other computers running BBSes (bulletin board software).
In a way, this concept lives on via the Internet and cloud computing. Our computers are just far smarter “dumb terminals” when they display all the content generated from Facebook’s servers, or display virtual shopping catalogs that are indexed at Amazon.
I guess there really isn’t anything new.
While today, a modern smart “dumb terminal” may be running JavaScript or (can you believe it?) Flash, decades ago dumb terminals were doing similar rendering – though limited to simple things like moving a cursor around the screen, or turning on underlined text. Or blinking. Anyone remember when things blinked?
Frighteningly enough, you probably still see examples of this at some modern businesses. My car dealer still uses some text-based program in its service department, and it is not that uncommon to see the same in banks or other businesses.
Dedicated terminals were still alive and well in the mid-1990s when I took my first dream job and was teaching week-long OS-9 courses around America (and sometimes in Canada). I would arrive on Sunday night, and at the hotel would be a bunch of boxes that had been delivered. We would rent dumb terminals from local suppliers, and I would unbox and set up eight of them and wire them all up via RS232 serial cables up to the multi-user OS-9 computer I brought with me.
I would then go through the task of configuring the settings on each terminal (they were pretty smart for dumb terminals) to make sure all the settings matched what we would need for the class (like baud rate and serial port settings, as well as emulation mode).
Just like today, there were competing standards back then. A VT100 terminal might expect a particular series of bytes to indicate “clear the screen”, but a DEC terminal might use a different set. What a mess this must have been in the early years!
Fortunately, smart people came up with smart solutions to deal with all these different standards. One such solution was called Termcap – which stood for terminal capabilities.
http://en.wikipedia.org/wiki/Termcap
Created in 1978, termcap was a database of various terminal types with entries describing how each one did things like move the cursor or clear the screen. Programs could be written to use the termcap library and then, on startup, they would load the proper codes to match whatever terminal type the user was using — provided it was in the database.
This must have been a major breakthru for writing portable apps, much like Java was a breakthru to let the same app run on Mac, Unix and Windows… Today, HTML5 and JavaScript allow web content to run on desktops, tablets or phones.
I guess there really isn’t anything new.
During my OS-9 days, termcap was important since almost all connections were done via a terminal (or terminal/telnet program). Most industrial OS-9 machines did not have video screens. I found this surprising, since I had come from the hobbyist OS-9 world where all our systems (Radio Shack Color Computer, Delmar, Tomcat, MM/1, etc.) all had graphics and user interfaces. But in the embedded/industrial space, they were just a box of realtime computing, and if the user did need to interact with it, they hooked up a terminal.
But I digress.
Recently, I began working on a new ticket barcode project that would ultimately run on small Raspberry Pi computers. I was doing all the prototyping work on Windows, and also compiling the same for Mac. Since I do not know anything about writing GUI programs, let alone how I would write something that would work on Windows, Mac and ultimately Linux, I was writing everything as an old style text-mode program.
This was more than enough to test all the functions, even if ultimately we would be using small 7″ color displays at each system. (I sense that I will be writing some articles on Raspberry Pi video in the future.)
Because I am now at the stage where I want to do more than just scroll text, I decided to revisit the old Termcap system and see if I could at least write fancy text programs that could use color, and create fancier text screens, and actually work on all my development platforms. I actually looked in to termcap few months ago when I wanted to do something similar on Arduinos, but at the time I decided it was impossible due to limited memory. (Update: That may not actually be the case.)
My goals of the next few articles will be:
Explain how termcap works.
Explain how to get termcap running on a Windows system (as well as Mac, and Raspberry Pi).
Create a simple library of common screen features (actually based on code I wrote in late 1995, to convert my EthaWin OS-9 user interface to run on the OS-9 machines at work via termcap).
…and after all this, I think I will have a version that works on Arduino as well.
In my previous article, I rambled a bit about how I first learned to program in C in the late 1980s under the OS-9 operating system on a Radio Shack Color Computer 3. I mentioned this to point out that, even after 25 years, there were still things about C I had never used.
One of those things involves doing time math (adding or subtracting time). If you take a look at the various C related time functions (see time.h):
http://www.cplusplus.com/reference/ctime/
…you will see that the C library has two ways of representing time. One is a time_t value which is some value (but not defined by the standard as to what that value is), and a struct tm structure, which contains fields for things like hour, minute, second, day, month, year, etc. Some time functions work with time_t values, and some work with struct tm structures.
There are four main time functions. You can get the amount of processor time used by a program with clock(). You can get the current time using time() (as a time_t value of some sort). You can get the difference between two times using difftime(). And you can make a time using mktime().
The other time.h functions are conversion utilities: asctime() returns a string representing the current date/time (from a struct tm). ctime() returns a similar string but works on a time_t value. gmtime() converts a time_t value to a struct tm and adjusts the resulting to to be GMT (universal time zone, Greenwich Mean Time). localtime() is like gmtime but it returns a struct tm in local timezone. And lastly, strftime() is like a printf for time. It lets you create a custom string representation of date and time from a struct tm. This is useful if the asctime() and ctime() do not return the format you need.
The current project I am working on deals with event tickets, and the system needs to know when a ticket is valid. By default, a ticket is valid on the day it is activated and then it shuts off. The problem was that a ticket would stop working after midnight, so I needed to implement a grace period. I wanted to define a ticket good for “Today” (or “Friday” or “5/4/2015”) and have it know that even after midnight (when the day became Tomorrow, Saturday or 5/5/2015) it would still be accepted for a certain amount of time.
Almost all examples of handling time I could find relied on knowing something about what the time_t number was. If you *knew* that time_t was “number of seconds since January 1 1970”, all you would have to do is add or subtract a certain amount of seconds from that value and you would be done.
But, according to the ANSI C standard, time_t is implementation specific. If you really want to write portable ANSI C code, you can’t assume anything about time_t other than it being some number.
My program is currently being built for Windows, Mac and Raspberry Pi. All three of these systems seem to handle time_ t the same way, but what if my code gets ported later to some embedded operating system that did it some other way?
The good news is that it’s really not much work to do things the “proper” way, though I certainly understand the lazy programmer mentality of “if it works for me, ship it!”
Here is what I learned and what prompted me to write this article: you can create struct tm values with invalid values and the C time library functions can normalize them.
Here is an example… If you want to create a time of 2:30 a.m., the struct tm values would look like this:
tm_hour = 2;
tm_min = 30;
tm_min = 0;
If all the tm values are properly formatted, you can pass them in to functions like asctime() and they work.
BUT, you can also represent 2:30 a.m. as “150 seconds after midnight” like this:
tm_hour = 0;
tm_min = 0;
tm_sec = 150;
This tm structure appears to be invalid since minutes is listed as being 0-59 in the references I looked at. Because of this, it never dawned on me I might be able to pass in a value other than 0-59.
If you pass this invalid struct tm in to asctime(), it will fail. However, if you pass it in to mktime(), it will normalize the values (adjusting them to the proper hour, minute and second values) and return that as a time_t time. Interesting.
It seemed I might be able to add time simply by adding a number of seconds or hours. 2 hours in the future might be as simple as:
tm_hour = time_hour + 2;
…then I would use mktime() to get an adjust time_t that now represents the time 2 hours in the future.
A few quick tests showed that this did work. Unfortunately, the way I was approaching my ticket expiration task required me to look 2 hours in the past. It didn’t seem possible, since that would mean using negative numbers and surely that wouldn’t work.
Or would it?
I had noticed that the tm_xxx variables were “int” values rather than “unsigned int”. Why? If values are 0-59 (minutes) or 0-23 (hour) or 0-365 (days since January 1), why would it ever need to be a signed negative value? But since a value could clearly be greater than 59 for seconds, perhaps negative values worked as well and that’s why they were “ints”.
Indeed, this is the case. I had never known you could do something like this:
tm_hour = tm_hour - 2;
By doing that, then converting it using mktime() in to a time_t, you end up with a time_t representation of two hours in the past.
Simple, and portable, and “proper.” Even if it looks strange.
The only issue with doing it this way is you need a few more steps. In my case, I had a time_t value that represented when a ticket was activated. It began life as something like this:
time_t activationTime = time(NULL);
When I would be doing my time checks, I would need to know the current time:
time_t currentTime = time(NULL);
And since I was not concerned with the time of day of the activation, just the actual day (month/day/year), I would need to convert each of these in to tm structures so I could look at those values:
NOTE: I am copying the values in to my own local variables because localtime(), gmtime() and other calls return a pointer to static data contained inside those functions. If I were to do something like this:
…that might look proper, but each time localtime() is called, it handles the conversion and returns a pointer to the static memory inside the function. Every call to localtime() is returning the same pointer, so each call to localtime() updates that static memory.
activationTmPtr and currentTmPtr would both be the same address, and would both point to whatever the last localtime() conversion was.
Easy mistake to make, and one of the reasons returning pointers to static data is problematic. The caller has to understand this, and make copies of any data it wishes to keep. (Yeah, this is something I learned the hard way.)
With this in mind, I could get the parts of the local time the same way:
Now to see if Activation Day was the same as Today, I could just compare:
if ((currentDay==activationDay) && (currentMonth==activationMonth) && (currentYear==activationYear))
Simple. Though in my application, the ticket could also specify a day-of-week, so there could be a weekend pass active only on “Saturday” and “Sunday”, or a pass good for only “Thursday”. I would do this the same way, but I would use the tm_wday variable (day of week, 0-6).
To deal with a grace period, my logic looked like this:
Check current day (either month/day/year or day of week) against target valid day (again, either a month/day/year value, or a specific day of week).
If invalid, try the comparison again, but this time have “current day” be X hours earlier. If X was 2 hours, then I could test at 1:30 a.m. and it would be comparing as if the time was still 11:30 p.m. the previous day, and it would pass.
Easy peasy.
To do this, I simply created a special graceTime and graceTmPtr like this:
// Start with current time again and convert to a struct tm we can do math on.
graceTmPtr = localtime(¤tTime);
// Adjust the values to be 2 hours earlier.
gracetTmPtr->tm_hour = graceTmPtr->tm_hour - 2;
// We need to normalize this so we can get the real Month/Year/Day.
graceTime = mktime(graceTmPtr);
// And now we need it back as a struct tm so we can get to those elements.
graceTmPtr = localtime(&graceTime);
// And now we can get to those values.
graceMonth = graceTmPtr->tm_mon;
graceDay = graceTmPtr->tm_mday;
graceYear = graceTmPtr->tm_year;
After this, I could do the same check:
if ((graceDay==activationDay) && (graceMonth==activationMonth) && (graceYear==activationYear))
Problem solved.
Maybe this will help someone else. I know I spent far too much time searching for how to do this before I stumbled on some old post somewhere that mentioned this.
I started learning C in the late 1980s on a Tandy/Radio Shack (TRS-80) Color Computer 3. At the time, my college was teaching Pascal and BASIC, so I was learning everything on my own with the help of a friend of mine.
My friend Mark was a great Commodore 64 assembly programmer and he had began programming in C on the Amiga. He helped me with my first real C program which was a user-designed text adventure system for a BBS.
Special thanks goes to another friend of mine, Tim, who was the inspiration of this project. Tim (aka COCO KID) had ran the ADVENTURE SYSTEM BBS in Lufkin, Texas on a CoCo 1. It was set up like a text adventure. If you did “GO WEST” and there was nothing there, it would prompt you to create a room and enter information about it. You could wander around and check mail by doing “LOOK MAILBOX” and stuff. It was great fun, and I decided I wanted something like this for my OS-9 BBS I was running at the time. (This was probably the OS-9 Level 2 BBS by Keith Alphonso of Alpha Software in Louisana. I type things like this in so they show up in Google in case anyone else ever remembers the OS9L2BBS package.)
For learning C, I used the manual from the Microware OS-9 C Compiler and a Pocket C Reference Guide (not sure of the exact name of it, but I still have it somewhere). This was original K&C C — I wouldn’t see an ANSI-C compiler until I started working for Microware years later and began using their Ultra-C compiler. It was quite an experience starting out as a self-taught hobbyist using a company’s products, and eventually actually working for that company. My entire technical career is all based on me sticking with that 8/16-bit CoCo computer and learning OS-9 and C. I look back and imagine what would have happened if I would have just given in and became a DOS or Windows 3 user. Would I have even kept coding?
The reason I share this story is to point out that I started using C a very long time ago — before ANSI C (C89) or C++. I was away from C for some years, and when I started working with it again many things had changed — like the C99 standard finally offering a way to get an integer of a specific size. (“int” is 16-bits on one of the systems I program on at work, and 32-bits on another. Things like this always made writing architecturally portable code challenging.)
Recently, I began working on a new project — a barcode ticket system for a Halloween haunted house project. Since I know C the best, I have been writing it in C and within a few evenings had a working prototype that handled almost all the desired features.
Lest night, I was trying to work around a problem where the system would start rejecting tickets after midnight when the day changed. Normally, tickets sold are fully used up by the guest, but if they had to leave early or just ran out of time to visit all the attractions, the park lets them return on a Thursday or Sunday to use up the rest of their ticket.
My system was now validating the ticket against the current day, with a ticket being valid on the day it was sold, and then also on Thursdays or Sundays. While I was thinking about this, I realized that if a ticket was sold on Friday, and the park stayed open late that night, at midnight the day changed to Saturday and now the ticket would not be valid (since it would only be good on the day it was activated, or a Thursday or Sunday). Fortunately, I thought about this before writing any code. I am pretty sure there would be a lynching if my system suddenly started refusing admission to a park full of guests on a busy Friday night in October!
I proposed several simple solutions to this. One was simply having the system require being activated each day of operation, and recording that state. Tickets sold that day would be active until the system was shut down, or until the system was started up on a different day. This was very simple, but would mean yet another bit of information to keep in sync on about 12 different computer systems running throughout the park. The more parts, the more chance of failure. And failure was not an option (see “lynching” above).
Instead, I decided to simply allow the tickets to have a grace period before they truly expire. If this was set to two hours, the ticket would be valid within two hours of the end of the activation day. Thus, a ticket sold on Friday would be valid until 2am on Saturday morning. As long as the grace period were long enough to cover the latest hour of operation, but short enough that it didn’t overlap with opening time the next day, this would solve the problem. (The overlap issue was also something I thought about before coding. If a ticket were sold at midnight, and the grace period were 12 hours, that means it would still be honored by the system until noon the next day. If the park opened at 11am the next day, it would be allowing tickets for that first hour that really shouldn’t be allowed at all on that day.)
Normally we wouldn’t worry about situations like this, especially in a (mostly) controlled environment running 2-5 days a week from 7pm to midnight (or 1am-ish). But, if this system were used elsewhere, say, for Go Karts and Mini Golf and other activities, there could indeed be times when “Summer Fun Late NIght” tickets might overlap with “Early Bird Special” tickets the next day. I wanted to make sure my system was as flexible as possible.
But I digress…
The purpose of this article (and the next one) is to discuss something in C I had never done: subtracting time.
If a ticket was activated (sold) on a Friday, then it gets scanned when the system thinks it is Saturday (minutes after midnight on Friday). it would be rejected. I wanted to make it check the grace period by taking “current time minus 2 hours” (or whatever it is configured to) and see if that time would have worked. The logic would look like this:
if ticket is not valid for current day,
check to see if ticket is valid for current day – offset hours.
Simple.
But how do you do that? In C, the standard time.h functions let you represent time as either a time_t value, or a struct tm structure. The tm structure contains entries for hour, minute, seconds, year, month, day, etc. The time_t value is … something. Most systems treat it like the number of seconds since some date (like January 1, 1970). If this is the case, then subtracting six hours is really easy:
time_t timeNow;
time_t timeEarlier;
timeNow = time(NULL); // Get current time.
timeEarlier = timeNow – (2*60*60); // Subtract 2 hours of seconds.
Problem solved. Moving on…
But wait… That assumption, which might be the case on a Unix-style system, might not be the case everywhere. The C standard says that time_t is an “arithmetic type capable of representing times” but it doesn’t specify what that value actually is. It could be in seconds, microseconds, or metric seconds. It also does not state what date that time would be based off of.
Any C program that makes the assumption that time_t is “seconds since 1970” is not guaranteed to be portable to other C systems. Period.
Read that again and let it soak in.
I see C programs do math with time_t values all the time. If you are only writing for Windows, and Microsoft never changes this, you are fine. Ditto for folks who only write for Unix or Linux. But does QNX work this way? OS-9? OSE? PSOS? I really don’t know, and I don’t want to be lazy and write non-portable code when there is a “right way” to do this.
Unfortunately, I did not know the right way to do this. Even though I started programming in C in the late 1980s, and even though I had used C time functions before, I had never tried to subtract time from time.
Some Bing searches (Microsoft gives me Bing Rewards points which pay for my Hulu Plus subscription so I don’t have to – ask me if you want a referral link) led me to a number of discussions of people asking this very question, and many very bad answers to how to do it (like doing math on time_t values).
In the next part of this article, I will share with you some things about C’s time functions that I was not aware of, as well as provide example code on how it works.
Due to finances, about the only form of recreation I have these days is riding my bike. I like to take casual rides on the many trails here in Des Moines (Iowa is famous for it’s massive bike trail network).
A few years ago, I came across this neat LED display that attaches to a bike wheel and created images using persistence of image (i.e. lights flashing real fast as the wheel rotates, which the eye sees as a complete, though flickering, image):
http://www.ladyada.net/make/spokepov/
Go there and look at the pictures and watch the videos. It is able to display full color and even animate images (I love the Pac-Man and Ghost images they show). It works by having a row of LEDs that flicker on and off as the wheel spins. The wheel has to spin very fast to show an image, so they sell kits with multiple circuit boards of LEDs. The more on the wheel, the slower it has to turn to show an image.
It looked really cool, but it came in a kit, and I am not really that capable of an electronics person. Plus, the kit with three circuit boards was $113.
A found similar (much cheaper) devices on Amazon, though most of them just did preset patterns and didn’t let you load your own. You can find some simple LED wheel lights at Amazon for around $13 that can display short text messages:
Do some searching and you will find all kinds of cheap POV displays for bike wheels. I even found one for around $12 that was programmable via USB:
None of these are anywhere near as cool as the Adafruit SPOKEPOV kit, but they might be pretty neat for the money.
Then, I came across this one on from an e-Bay store:
It had two rows of LEDs and could attach to the hub of the bike and display messages or graphics. At the time I found it, there was a seller auctioning them off, and I picked one up for $6 (shipped from the US, even). Unfortunately, the device was not like the pictures show — it was not in color, just blue (the description says this, but all the listings, including Amazon, use pictures showing one with color).
Also, the device would not fit the hub of my bike (the bolts were too short), nor the sensor on the frame (the bracket was too small). I am not sure what tiny little bikes these were made for, but my old 1998 Trek wasn’t one of them.
However, with a bit of rigging, it was easy to attach the device to the spokes of my bike (rather than clamping it around the hub) using some tape, and then I could do some quick experiments.
If I get time, I would like to experiment with a very low-cost version of this, using an Arduino-style device and a strip of the high speed LPN8806 addressable LEDs. An Arduino in a plastic enclosure with batteries could easily power two segments of 32 LEDs (wider spacing than the commercial units, though) and do full color. The only other hardware would be a magnet and a sensor so the device can tell when the led strips circle around.
Sound fun? More to come… (I already have created JavaScript code that lets me load in an image in a web browser and convert it to the format that this device would need to display it.)
I recently ran in to an issue at my day job where I had to write some time functions for a project. My work system did not have <time.h> and related functions like gmtime(), which I needed.
Unfortunately, once I implemented my version of gmtime() routine (based on some code I found online), I found it did not work on my target system. Testing on a PC using GNU-C worked fine, so I expected it had something to do with the code not being written for systems with 16-bit “ints” — like the Arduino.
I narrowed down the problematic code, and used the Arduino to test it. Here is the sample:
#define SECS_DAY (24*60*60)
void setup()
{
long time;
unsigned long dayclock;
Serial.begin(9600);
time = 1396342111;
dayclock = (unsigned long)time % SECS_DAY;
Serial.println(time);
Serial.println(dayclock);
}
void loop()
{
}
On the PC, dayclock would print as 31711. On an Arduino, it would print as 18911. Initially I just tried to cast things to “unsigned long” but that did nothing. When I realized my mistake, I felt rather dumb since I learned this long ago.
Numeric constants, like that #define, are treated as “int” values meaning that on the PC (where int is 32-bits) they were different than on my target system (where int is 16-bit).
When dealing with long constants, you add “L” to the number like this:
The code I used as reference was written by someone who probably only considered it running on machines with 32-bit ints. Most desktop (PC/Mac/etc.) programmers tend to code this way.
Maybe this reminder will help someone else as they try to port code to an Arduino project.
Side note: Rather than use “int” and “long”, if you use a new enough compiler (C99 standard), include and use the actual type you want, such as uint8_t, uint16_t, or uint32_t. As you can see, “int” on the PC would be 32-bits, and “int” on Arduino (or MSP430, or…) would be 16-bits. It’s not portable code that way, and the C standard has finally solved this challenge.
Here’s another example for you to try… It should print out 86400 (24*60*60), which it does on a PC/32-bit system, but not on a system where ints are 16-bits. Have fun!
// This will fail (ints, 16-bit)
#define SECS_DAY (24*60*60)
// This works (longs, 32-bit)
//#define SECS_DAY (24L*60L*60L)
void setup()
{
Serial.begin(9600);
Serial.println(SECS_DAY);
}
void loop()
{
}
With the recent news that Facebook is buying a Virtual Reality headset company for 2 billion dollars, it seems I can’t get away from coverage on V.R. For some of us that are older than Facebook, and who experienced commercial V.R. over 20 years ago, I say: bring it on! Or rather, bring it back.
This is nothing new. But it should be improved: higher resolution graphics, and faster framerate.
My first experience with V.R. was a Virtuality “Dactyl Nightmare” arcade game in Dallas. My friend Larry took me on a road trip from East Texas to Dallas to check out a few places – including the defunct Incredible Universe store (look them up sometime for a mind blowing retail experience years ahead of its time). We also visited some placed called Dave and Busters which was, at the time, known as a place for V.R. type games.
Dactyl Nightmare was powered by Commodore Amigas, and thus was vastly more advanced than what any non-Amiga owner has seen. (Remember, it took the PC world YEARS to even remotely catch up to what the Amiga was doing in the 1980s.)
You stood on a small circular platform with a round railing around it, and put on a large headset (like a motorcycle helmet) and a belt. In your hand was a simple controller with a trigger switch button and a thumb button. In the game, you could see yourself inside of an Escher-like playfield with stairs and platforms. You would press the thumb button to walk forward in whatever direction you were facing, and use the trigger button to fire.
Above you flew a pterodactyl that you could shoot at. You could see a digital representation of your arm in front of you. You could hear yourself walking. It was a very intense few minutes inside this virtual world, and when the game was over, my heart was pounding and I had broken in to a sweat.
It was amazing.
A few years later, during a business trip to Canda, I encountered a later version of the Virtuality system running Missile Command V.R. It was an update to the classic Missile Command arcade game from the 80s, but you were seeing things from one of the missile launching stations and had to look up and all around to target incoming missiles and fire at them.
It also was amazing, but wasn’t as fun of a game (to me) as the original. The graphics were better.
Atari released a home version of Missile Command 3-D for their Jaguar system, though playing it on a TV wasn’t quite the same. Atari had plans to release a V.R. helmet, and even showed it off at a trade show, but it never made it to release.
Sega also was working on a V.R. project, and a friend of mine was one of the developers working on three launch titles. Google “Iron Hammer Sega” on YouTube and you will see footage of this old V.R. system.
Around 1994 or 1995, Disney’s Epcot was presenting an Imagineering exhibit on DisneyVision – their attempt to enter the V.R. world. They gave daily presentations where a few lucky audience members we brought up on stage and hooked up to the Aladdin’s Magic Carpet V.R. experience, while the rest of us watched the game play on overhead monitors.
A short time after this, that game was sitting at the Disneyland Tomorrowland arcade with a cast member. I believe it was $3 to play, which I did. The graphics were great and light years beyond Dactyl Nightmare. The goal was to fly on a magic carpet and collect gold pieces or jewels or something. I only played it once, but it was great. You sat down (on your magic carpet, though straddling it like a motorcycle), and you held the edges of the carpet (like motorcycle handlebars). Somehow I think they may have used a motorcycle game as a reference.
There were even home V.R. helmets. I bought a StuntMaster helmet for less than $100. It was a simple non-3-D LCD display in a helmet, and you would clip a rod to your shoulder sleeve. This rod was attached to the helmet, and as you looked left and right, it would rotate an analog input so the game would get LEFT and RIGHT motion. It was barely 3-D, but you could use it on a Sega Genesis or other home systems and turn your head left and right instead of pressing a joypad left or right.
There were many other higher end V.R. helmets being sold during those days, and games for them.
Nintendo even tried to get in to the home console action, like Sega and Atari were, and unlike those two, Nintendo actually shipped their product… As the VirtualBoy. Which sat on a table. And you looked in to the goggles, and couldn’t move them. Bascially, it was a 3-D Nintendo you had to stick your face in, and didn’t qualify as any kind of V.R. system (even the StuntMaster was better than that).
Google it if you haven’t heard about it.
Was V.R. ahead of its time back then? It was more than playable, and amazingly fun. Perhaps if the games were a quarter instead of $3 it would have stayed around longer… But even the .25 arcade games went away. Perhaps if the home helmets were $50 instead of $500 it would have stayed around longer… But larger and larger TVs came out and gaming when super sized…
Will it work this time? Have we lost 20 years of advances because of lack of development?
I can’t wait to find out.
It’s so retro, it might even be cooler this time around.
The first computer I ever used was in the 1970s at L.F. Smith Elementary School in Pasadena, Texas. The “computer room” was a small closet with a printing terminal in it. We would go in, pick up the old rotary phone and dial a number. Once we heard the computer answer the phone, we would set the phone handset down in to these small cups and then the computer would start printing.
We had notes of what we were supposed to type to get the computer going. I seem to recall playing a math game and some football game. I still have a roll of yellow paper that is the entire session of a football game I got to play on this machine once.
But what was this system? A few years later I would have my own home computer (a VIC-20) and then a second computer (a TRS-80 Color Computer) and would even be borrowing a 300 baud acoustic coupled modem to dial in to BBSes in Houston. Thus, I did learn that the “computer” I used in elementary school was just a terminal, and it was dialing in to the actual computer elsewhere.
Today, I looked up my old school and sent an e-mail to see if anyone there could tell me just what we were using. I am hopeful they can find someone who knows. It seems the principal I had during the 70s retired in 1995. I suppose I should have tried to look this up years ago when some of the folks were still there.
I should really find that old printout and scan it as a historical document of my first encounter with a “computer.” I know it led me to typing things in on a TRS-80 (probably a Model 1 or 3) at a Radio Shack, and then being interested in my friend’s TI-99 when I moved to Mesquite, Texas around 1979-1980 (his mom worked for Texas Instruments). It seems it took another year or two before I would actually have a computer of my own.
I regret not begging for one a few years earlier.
Nothing to read here. Move along…
UPDATE: A response from the current principal (via her husband who attended an area school) reveals that the machine being used may have been a Teletype Model 33:
http://en.wikipedia.org/wiki/Teletype_Model_33
Wow. That certainly looks like the type of thing I remember. This machine was introduced in 1963, so it would still have been “new-ish” in the 70s. (Think back: it would be about as new as the original iPod from 2001 is today.) Amazing.
Hopefully some more details will come through on what we were dialing in to. If only I had known computer commands back then — maybe I could have typed LIST and gotten to see the source code to that football program?
* The tutorial on the Adafruit site indicates the number should be 128. As of yet, I do not know what the 64 and 128 represent, but I assume it’s some kind of bit mapped status.
Resending the HEX string:
OK
Mapping:
* Not the missing “Set” but the space in front of “Mapping” is still there, and no status number. Maybe I dropped some data (it happens every time) or maybe it’s some missing stuff in the EZ-Key firmware.
At this point, I reset the EZ-Key if I wish to remap again. I am not sure (yet) if the second remapping takes effect (I will test and update this page).
When a switch is used, a key down message is sent, and then a key up message is sent when the switch is released. I’ll go through this when I get a moment and document the bits (I think I have a typo in this initial list).
K 0xFEF ... input 0 (1111 1110 1111) pressed
K 0xFFF ... input 0 (1111 1111 1111) released
K 0xFDF ... input 1 (1111 1101 1111)
K 0xFFF
K 0xFFB ... input 2 (1111 1111 1011)
K 0xFFF
K 0xF7F ... input 3 (111 0111 1111)
K 0xFFF
K 0xFEF ... input 4 (1111 1110 1111)
K 0xFFF
K 0xFDF ... input 5 (1111 1101 1111)
K 0xFFF
K 0xFBF ... input 6 (1111 1011 1111)
K 0xFFF
K 0xF7F ... input 7 (1111 0111 1111)
K 0xFFF
K 0xEFF ... input 8 (1110 1111 1111)
K 0xFFF
K 0xDFF ... input 9 (1101 1111 1111)
K 0xFFF
K 0xBFF ... input 10 (1011 1111 1111)
K 0xFFF
K 0x7FF ... input 11 (0111 1111)
K 0xFFF
Others – to be documented next update:
Adafruit Bluefruit HID v1.2 11/30/2013
No devices, making discoverable
Discoverable
…or…
Adafruit Bluefruit HID v1.2 11/30/2013
No devices, making discoverable
Discoverable
Connecting to host xxxx,xx,xxxxxx
Exit discoverable
Connected
And…
Adafruit Bluefruit HID v1.2 11/30/2013
Attempt to connect to xxxx,xx,xxxxxx
Failed to connect
Previously, I discussed the Adafruit Bluefruit EZ-Key module. This device comes factory-programmed to send specific key sequences via Bluetooth when one of the 12 inputs is selected. Software is available to change these key sequences, but this software runs on a host computer and requires installing an older version of a development environment called Processing.
Since it appears that the remapping is done simply by sending a text HEX sequence with a checksum to the EZ-Key, I thought it might be easier to just do this on an Arduino with a simple text user interface – no special installs needed.
I did a bit of work on this, and wanted to share my work-in-progress and maybe get some feedback on the interface.
Basically, for each of the 12 inputs you can specify a modifier (SHIFT, CTRL, ALT, etc.) plus up to 6 keycodes which will be sent out (with a Keys-Down) via Bluetooth. When the input is released, a matching Keys-Up message is sent.
To customize, you simply need to specify an input (0-11) and then a modifier (8 available choices) and then up to 6 keycodes (about 112 options available, such as ARROW UP or “k” or numeric keypad minus). I put together a very quick user interface, and here is a sample session, with comments on what is going on:
Adafruit Bluefruit EZ-Key Remapper 0.00 by Allen C. Huffman (alsplace@pobox.com)
Enter input to configure (0-11), [L)ist, [U)pdate or [Q)uit: L
* Here, I select "L" to list the current input config.
Input Key Codes:
----- ----------
0. ARROW_UP
1. ARROW_DOWN
2. ARROW_LEFT
3. ARROW_RIGHT
4. RETURN
5. SPACE
6. 1
7. 2
8. W
9. A
10. S
11. D
Enter input to configure (0-11), [L)ist, [U)pdate or [Q)uit: 6
* I select "6" to change input 7 (currently sends "1").
Editing Input 6 Configuration:
Modifier: NONE - Enter new modifier # (0-8), [L)ist, [ENTER)Skip or [Q)uit: L
* To see a list of available modifiers, I select "L".
0. NONE 3. ALT_LEFT 6. SHIFT_RIGHT
1. CTRL_LEFT 4. GUI_LEFT 7. ALT_RIGHT
2. SHIFT_LEFT 5. CTRL_RIGHT 8. GUI_RIGHT
Modifier: NONE - Enter new modifier # (0-8), [L)ist, [ENTER)Skip or [Q)uit: 1
Setting new modifier value to: CTRL_LEFT
* By selecting "1", I am choosing the modifier to be "CTRL_LEFT".
Modifier: CTRL_LEFT - Enter new modifier # (0-8), [L)ist, [ENTER)Skip or [Q)uit:
* It shows the Modifier line again, and by pressing ENTER, it skips and moves to the next item - Keycodes 0-5:
Keycode0: 1 - Enter new key code # (0-111), [L)ist, [ENTER)Skip or [Q)uit: 0
* By entering "0", I am selecting "KEY_NONW" - no key. In this example, I am making this input simply send the left CTRL key.
Setting new keycode value to: NONE
Keycode0: NONE - Enter new key code # (0-111), [L)ist, [ENTER)Skip or [Q)uit:
* By pressing ENTER five more times, it skips over key codes 1, 2, 3, 4 and 5, leaving them to their current values of "NONE".
Keycode1: NONE - Enter new key code # (0-111), [L)ist, [ENTER)Skip or [Q)uit:
Keycode2: NONE - Enter new key code # (0-111), [L)ist, [ENTER)Skip or [Q)uit:
Keycode3: NONE - Enter new key code # (0-111), [L)ist, [ENTER)Skip or [Q)uit:
Keycode4: NONE - Enter new key code # (0-111), [L)ist, [ENTER)Skip or [Q)uit:
Keycode5: NONE - Enter new key code # (0-111), [L)ist, [ENTER)Skip or [Q)uit:
Enter input to configure (0-11), [L)ist, [U)pdate or [Q)uit: L
* Now I use "L" to list the input config again, and can see that input 6 is now set to send the left CTRL key:
Input Key Codes:
----- ----------
0. ARROW_UP
1. ARROW_DOWN
2. ARROW_LEFT
3. ARROW_RIGHT
4. RETURN
5. SPACE
6. CTRL_LEFT
7. 2
8. W
9. A
10. S
11. D
Enter input to configure (0-11), [L)ist, [U)pdate or [Q)uit: 7
* I then change input 7:
Editing Input 7 Configuration:
Modifier: NONE - Enter new modifier # (0-8), [L)ist, [ENTER)Skip or [Q)uit: L
* I want to make this input send ALT-Q, but I forgot what modifiers are available so I "L" to list them again.
0. NONE 3. ALT_LEFT 6. SHIFT_RIGHT
1. CTRL_LEFT 4. GUI_LEFT 7. ALT_RIGHT
2. SHIFT_LEFT 5. CTRL_RIGHT 8. GUI_RIGHT
Modifier: NONE - Enter new modifier # (0-8), [L)ist, [ENTER)Skip or [Q)uit: 3
* "3" is the left ALT key.
Setting new modifier value to: ALT_LEFT
Modifier: ALT_LEFT - Enter new modifier # (0-8), [L)ist, [ENTER)Skip or [Q)uit:
* Then I press ENTER, and it goes to key code 0, which is currently the "2" key. I want to change that.
Keycode0: 2 - Enter new key code # (0-111), [L)ist, [ENTER)Skip or [Q)uit: L
* But since I don't know what key codes are available, I choose "L" to get a huge list of all of them.
0. NONE 28. 2 56. F2 84. KEYPAD_PLUS
1. A 29. 3 57. F3 85. KEYPAD_ENTER
2. B 30. 4 58. F4 86. KEYPAD_1
3. C 31. 5 59. F5 87. KEYPAD_2
4. D 32. 6 60. F6 88. KEYPAD_3
5. E 33. 7 61. F7 89. KEYPAD_4
6. F 34. 8 62. F8 90. KEYPAD_5
7. G 35. 9 63. F9 91. KEYPAD_6
8. H 36. 0 64. F10 92. KEYPAD_7
9. I 37. RETURN 65. F11 93. KEYPAD_8
10. J 38. ESCAPE 66. F12 94. KEYPAD_9
11. K 39. BACKSPACE 67. PRINT_SCREEN 95. KEYPAD_0
12. L 40. TAB 68. SCROLL_LOCK 96. KEYPAD_PERIOD
13. M 41. SPACE 69. PAUSE 97. EUROPE_2
14. N 42. MINUS 70. INSERT 98. APPLICATION
15. O 43. EQUAL 71. HOME 99. POWER
16. P 44. BRACKET_LEFT 72. PAGE_UP 100. KEYPAD_EQUAL
17. Q 45. BRACKET_RIGHT 73. DELETE 101. F13
18. R 46. BACKSLASH 74. END 102. F14
19. S 47. EUROPE_1 75. PAGE_DOWN 103. F15
20. T 48. SEMICOLON 76. ARROW_RIGHT 104. CONTROL_LEFT
21. U 49. APOSTROPHE 77. ARROW_LEFT 105. SHIFT_LEFT
22. V 50. GRAVE 78. ARROW_DOWN 106. ALT_LEFT
23. W 51. COMMA 79. ARROW_UP 107. GUI_LEFT
24. X 52. PERIOD 80. NUM_LOCK 108. CONTROL_RIGHT
25. Y 53. SLASH 81. KEYPAD_SLASH 109. SHIFT_RIGHT
26. Z 54. CAPS_LOCK 82. KEYPAD_* 110. ALT_RIGHT
27. 1 55. F1 83. KEYPAD_MINUS 111. GUI_RIGHT
Keycode0: 2 - Enter new key code # (0-111), [L)ist, [ENTER)Skip or [Q)uit: 17
* Since I want to send a "q" key, that is 17.
Setting new keycode value to: Q
Keycode0: Q - Enter new key code # (0-111), [L)ist, [ENTER)Skip or [Q)uit:
* Above, it confirms that key code 0 is now "Q". I can then press ENTER to skip the next five optional key codes for this input.
Keycode1: NONE - Enter new key code # (0-111), [L)ist, [ENTER)Skip or [Q)uit:
Keycode2: NONE - Enter new key code # (0-111), [L)ist, [ENTER)Skip or [Q)uit:
Keycode3: NONE - Enter new key code # (0-111), [L)ist, [ENTER)Skip or [Q)uit:
Keycode4: NONE - Enter new key code # (0-111), [L)ist, [ENTER)Skip or [Q)uit:
Keycode5: NONE - Enter new key code # (0-111), [L)ist, [ENTER)Skip or [Q)uit:
Enter input to configure (0-11), [L)ist, [U)pdate or [Q)uit: L
* Back to the main menu, I do an "L" to list the current input config.
Input Key Codes:
----- ----------
0. ARROW_UP
1. ARROW_DOWN
2. ARROW_LEFT
3. ARROW_RIGHT
4. RETURN
5. SPACE
6. CTRL_LEFT
7. ALT_LEFT + Q
8. W
9. A
10. S
11. D
Enter input to configure (0-11), [L)ist, [U)pdate or [Q)uit: U
* And they look good. Input 6 is now left CTRL, and input 7 is now left ALT + the Q key. Cool. Selecting "U" will update the EZ-Key to use this new config.
...update device here...
…and there you have it. A very simple and easy-to-use “BIOS-like” interface to remap the Adafruit EZ-Key directly from an Arduino, without touching a line of source code or installing anything special.
Does this seem useful? Should I polish it up and post it? I just created it because I was too lazy to download stuff and writing my own seemed more fun.