Cloning ThinkGeek’s Annoy-a-tron with a BASIC Stamp Homework Board

I’m working on a course at work right now that aims to get people (high school students in particular) interested in electronics. The project uses a BASIC Stamp homework board for projects, and one of the ideas I had for a project was a copy of ThinkGeek’s Annoy-a-tron. The kit I bought came with a piezo buzzer and PBASIC (the language used to program the Stamp) just so happens to have a FREQOUT command that you can use with it. I quickly got to work, coming up with this schematic:

Pin 11 is connected to the anode of the piezo buzzer. The cathode (which should cross the center of your homework board’s breadboard) is connected to Vss (the ground). Here’s what it actually looks like once it’s wired up:

With the (extremely simple) wiring complete, we can change our attention to the (almost equally simple) code. The Annoy-a-tron beeps once every 2-8 minutes at a frequency of either 2kHz or 12kHz. The speaker that came with the kit seems to perform best at around 4.5kHz so we’ll use that. As for the time, we have a problem. Why not just randomize a variable with time in it, pause for that long, then loop back again?

The trouble is that the largest data type that the Stamp I have supports is a 16-bit word, which has a maximum unsigned value of 65,535. The PAUSE command accepts an argument in milliseconds. Now what? Loop.

The solution I devised is able to replicate the Annoy-a-tron’s 2-8 minute random interval quite well. Here’s how it works:

  • The RANDOM command is used to obtain a random 16-bit value.
  • We then convert it to a value between 10,000 and 40,000 (in intervals of 10,000). How? The modulo (mod) operator, which is // in PBASIC. The modulo operation finds the remainder when one number is divided by another. A // N can have any value from 0 to N-1, so (A // N) + 1 can have any value from 1 to N. If that gets multiplied by 10,000, the result is any number from 10,000 to N(10,000).
  • Therefore, to get a random number from 10,000 to 40,000 in intervals of 10,000, we use the modulo operator on the random with an “N” value of 4, add 1 to it, and multiply by 10,000.
  • This number is used in a PAUSE command.
  • This pause command is looped 12 times.
  • The result can be 2, 4, 6, or 8 minutes.
After the delay, a beep is played for a enough time to be annoying but not long enough to be discovered. I decided on 1.5 seconds (1500ms). The code was easy to write once I figured out how the loop would work:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
' {$STAMP BS2}
' {$PBASIC 2.5}
DEBUG "Running." ' Avoid error on some PCs' debuggers.
time VAR Word ' Used to store time interval.
i VAR Nib ' Used for the FOR...NEXT loop.
FREQOUT 11, 1500, 4500 ' I like having a startup beep.
DO
  RANDOM time ' Store a random 16-bit value in time
  time = ((time // 4) + 1) * 10000 ' Get the random interval. Will be between 10 and 40s
  FOR i = 1 TO 12 ' We start at 1 because 12 is included; this will be executed 12x.
    PAUSE time ' We pause for the same 10-40 second interval 12 times to yield 2-8 min.
  NEXT
  FREQOUT 11, 1500, 4500 ' Play the annoying tone.
LOOP ' Start the whole thing over.
END

There you have it! Run this code on your BASIC Stamp, hide your enormous board, and hope nobody smashes it! I have not used this long enough to know how long a 9v battery can power it, but I am sure it is a more-than-adequate amount of time to get your point across. The biggest issue I have seen with this code is that the Stamp’s pseudo-random number generator isn’t very good. In fact, it generates numbers in the same exact order every time. You’ll never be surprised. Still, for being so simple, this circuit is a heck of a lot of fun. Happy annoying!

Multiple File Upload Made Easy!

Uploading one file to a server is beyond easy with the help of ASP.NET, but when you add more than one file to the mix, things start getting tricky. I ran into multi-upload related issues on a recent in-company project at RMC, and rather than using a plugin, I decided to see if I could come up with something quick-and-dirty with minimal effort.

My project involved migrating a single upload to multiple uploads, so the my first step was to update my server code. Using an HttpFileCollection to retrieve files from a request will work when there is a single .NET file uploader or multiple HTML file input boxes. Here’s how you do it:

HttpFileCollection files = Request.Files;

It’s that easy. The next step is to loop through the uploaded files and save them. You can put the following in a submit button event handler:

HttpFileCollection files = Request.Files;
for(int i = 0; i < files.Count; i++)
{
    files[i].SaveAs(NameOfTheFile);
}

The server-sided piece is done. Next comes the client side. For that, we will use jQuery. I realize the way I have gone about doing this isn’t the best jQuery-wise, but it is simple and it works. We will have two helper methods: one to add a file upload box and one to remove it. When we add a file upload box, we just append the relevant HTML to a parent element. When we remove a file element box, we remove the p element from its parent div. Simple enough, right?

    function AddBox(parent){
        // Add HTML for another file upload box to the DOM
        parent.append('<p>input type="file" runat="server" /><a onclick="RemoveBox(this);" href="#">Remove</a></p>');
    }
    function RemoveBox(aContext) {
        // Get jQuery instance of "this" from the link, get its parent element
        // and remove that parent from the DOM.
        $(aContext).parent().remove();
}

Note the ‘runat=”server”‘ in AddBox. When I tested this, the files did not show up on the server without the ‘runat=”server”‘ in the input box.

All that is left now is to plug the JavaScript into your ASPX page. You’re good to go with almost no code! The only real issue with this is that if your page has to do a postback to validate, the boxes will not persist (and neither will the selected files) – this could be a big annoyance to your users. The upload will not be asynchronous, either. However, this does the trick if you need a quick, easy solution.

Here’s an example to get you started:

<div id="upload">
    <input type="button" onclick="AddBox($('upload'));" value="Add File Box" />
</div>

Unlose Yourself!

In the app I’m working on this summer, I am using GPS functionality pretty extensively. The now-web-standard JavaScript interface is the same as it is in PhoneGap (now Apache Cordova), so I have been able to test on my desktop PC (and you can too). The problem is that your GPS can’t tell you what town you’re in or much more than your latitude and longitude. I needed more than that for my app, so it was jQuery to the rescue.

I apologize in advance for some of my coding practices – writing JavaScript feels a lot like writing Spanish to me, so feel free to alert me of any bad habits I have. Remember what I said in my first post!

Now then, the first thing I did was to write a method to get location XML from PlaceFinder. But how? Yahoo’s documentation has the answer with this example request:

http://where.yahooapis.com/geocode?q=38.898717,+-77.035974&gflags=R&appid=[yourappidhere]

Easy enough, right? All we have to do is register for an app ID, get our coordinates, build the request, and use AJAX to do the rest of our bidding. We will also have a success callback so the resulting XML can be parsed – you’ll see in a moment.

var lat, long;
var appid = 'YOUR APPID HERE';
function getLocationXML(successCallback) {
    // Get the position
    // Build URL
    // AJAX
}

Now we have to start coding. To get the current position, just call navigator.getlocation.getCurrentPosition, which can take three possible arguments. We will use the first two, which are the success callback and the failure callback. The success callback takes a position as an argument and the error callback takes the exception as an argument.

function getLocationXML(successCallback) {
    navigator.geolocation.getCurrentPosition(function(position) {
        lat = position.coords.latitude;
        long = position.coords.longitude; // Cordova documentation might be helpful here
        // Build URL
        // AJAX
    },
    function (error) {
        $.error('GPS error (' + error.code + '):' + error.message); // Throw the exception to be handled elsewhere
    });
}

Right, now we need to build the URL. We will just get string versions of our latitude and longitude and plug them into a variable called URL. This step is simple enough that I feel like I can also cover the AJAX request here. We will use a HTTP GET request (jQuery’s get() method makes this a breeze) to get the data from the Yahoo servers. The AJAX request needs a success callback, for which we will make an anonymous function that calls the successCallback getLocationXML was called with and passes it the data from the AJAX request.

function getLocationXML(successCallback) {
    navigator.geolocation.getCurrentPosition(function(position) {
        lat = position.coords.latitude;
        long = position.coords.longitude; // Cordova documentation might be helpful here
        var url = 'http://where.yahooapis.com/geocode?q=' + lat.toString() + ',+' + long.toString()
            + '&amp;gflags=R&amp;appid=' + appid; // Create formatted URL that we can use for AJAX
 
        // Now we get PlaceFinder data
        $.get(url, function (data) {
            successCallback(data); // call successCallback with what we got from Yahoo
        }, 'xml');
    },
    function (error) {
        $.error('GPS error (' + error.code + '):' + error.message); // Throw the exception to be handled elsewhere
    });
}

Great, we’re done with the hard part. Now we just have to interpret what Yahoo gives us. First, we will write an XML parser method that takes the XML document Yahoo sends us and retrieve the value of a node:

function xmlParse(xml, node) {
    var d = $(xml); // jQuery version of our XML document
    return d.find(node).text(); // Grab the node text and return.
}

This may seem overly simplistic to you, but when you look at what Yahoo PlaceFinder sends back (in this case, for 1600 Pennsylvania Avenue), you don’t need anything more complex:

0
No error
us_US
99
1
 
99
38.898717
-77.035974
38.898717
-77.035974
500
38.898717, -77.035974
1600 Pennsylvania Ave NW
Washington, DC 20006
 
United States
1600
Pennsylvania Ave NW
 
20006
 
Washington
District of Columbia
District of Columbia
United States
US
DC
DC
 
12765843
11
20006

We’re pretty much done. Here’s some example usage in the head of an HTML document:

$(document).ready(function () {
    var sCallback = function(data) {
        console.log(xmlParse(data, 'city')) // Get information from city node
                                            // In above XML, prints "Washington" in console log.
    }
    getLocationXML(sCallback); // Get the XML and then run the callback when that's done.
});

That’s it! You can figure out the name of your location with your phone and a little JavaScript. That’s pretty cool.

Introducing Myself

Little is more important than a first impression, and this post is exactly that – a giant “Hello, World!” I’ve begun several blogs in the past and have written some articles that based on the occasional comments have proven useful to a few (lucky) people. I aim to do better this time. This blog will be updated regularly with interesting, relevant information about a wide variety of my musings, from what I am doing at work to code to electronics to robotics. Who knows, I might throw in the occasional sports or car post. My interests are varied enough that there ought to be something on this blog for everyone (once I’ve written it). Heck, I even play golf.

I hope you will enjoy what I write here and provide feedback on my projects. Constructive criticism never hurts; no one ever improved by being told he is great when in reality he is not. As much as I want to help the Internet community, I would like the Internet community to help me.

Now, a little about me. In my biography on this site, I wrote about how I am an information technology intern at RMC Research Corporation in Portsmouth, New Hampshire. I worked there in the summer of 2011 and I decided to come back to do more. Last year, I worked on two main projects:

  1. Student Voice, a jQTouch-based mobile web application to improve communication between teachers and students. In hindsight, jQuery Mobile would have been a much better idea to use due to jQTouch’s bugs and lack of active development. Both the teacher portal and mobile web app are currently in in-house alpha stage and we will be seeking feedback on our prototype soon.
  2. SendTo, a small C#-based web application that makes sending large files over email an easier task for RMC employees. Before SendTo, people in the company used FTP to send files that were too big to attach to emails, which would have been fine were it not for the non-technical background of most RMC employees. File transfer support calls have been cut significantly.

One of the best parts of my internship at RMC is that it is meant to be as beneficial for me as it is for the company. That is, I am free to work on personal projects as well as work-related projects and I have been tasked with finding company-benefiting tasks that are interesting to me. Thus, I also worked on many small, side projects last summer.

This year, I will be developing a course about a BASIC Stamp microcontroller, working on a PhoneGap app built with jQuery Mobile, completing day-to-day tech department tasks, and continuing to work on personal projects.