Time to broadcast, iPhone style

Ran into a need to dynamically determine the current UDP broadcast address for the WiFi interface on the ole’ iPhone. Since NSHost appears to be a private API even w/the 3.0 software, it seems one must go lower. I wrapped it up in a neat little bundle that seems fairly usable if not verbose and full of magic (but understandable) numbers.

A few things of note. en0 is the WiFi interface. There are others. Instrument the following code w/some debug to get them all out. The ip/netmask methods return nil when the WiFi interface is not active. I would also be shocked if there were no corner cases I am ignoring…

#include <arpa/inet.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <errno.h>
#include <ifaddrs.h>
#include <stdio.h>
 
static NSString *kWifiInterface = @"en0";
 
@implementation NetUtil
 
+ (NSString *)broadcastAddressForAddress:(NSString *)ipAddress withMask:(NSString *)netmask {
    NSAssert(nil != ipAddress, @"IP address cannot be nil");
    NSAssert(nil != netmask, @"Netmask cannot be nil");
    NSArray *ipChunks = [ipAddress componentsSeparatedByString:@"."];
    NSAssert([ipChunks count] == 4, @"IP does not have 4 octets!");
    NSArray *nmChunks = [netmask componentsSeparatedByString:@"."];
    NSAssert([nmChunks count] == 4, @"Netmask does not have 4 octets!");
 
    NSUInteger ipRaw = 0;
    NSUInteger nmRaw = 0;
    NSUInteger shift = 24;
    for (NSUInteger i = 0; i < 4; ++i, shift -= 8) {
        ipRaw |= [[ipChunks objectAtIndex:i] intValue] << shift;
        nmRaw |= [[nmChunks objectAtIndex:i] intValue] << shift;
    }
 
    NSUInteger bcRaw = ~nmRaw | ipRaw;
    return [NSString stringWithFormat:@"%d.%d.%d.%d", (bcRaw & 0xFF000000) >> 24,
            (bcRaw & 0x00FF0000) >> 16, (bcRaw & 0x0000FF00) >> 8, bcRaw & 0x000000FF];
}
 
+ (NSString *)ipAddressForInterface:(NSString *)ifName {
    NSAssert(nil != ifName, @"Interface name cannot be nil");
 
    struct ifaddrs *addrs = NULL;
    if (getifaddrs(&addrs)) {
        NSLog(@"Failed to enumerate interfaces: %@", [NSString stringWithCString:strerror(errno)]);
        return nil;
    }
 
    /* walk the linked-list of interfaces until we find the desired one */
    NSString *addr = nil;
    struct ifaddrs *curAddr = addrs;
    while (curAddr != NULL) {
        if (AF_INET == curAddr->ifa_addr->sa_family) {
            NSString *curName = [NSString stringWithCString:curAddr->ifa_name];
            if ([ifName isEqualToString:curName]) {
                char* cstring = inet_ntoa(((struct sockaddr_in *)curAddr->ifa_addr)->sin_addr);
                addr = [NSString stringWithCString:cstring];
                break;
            }
        }
        curAddr = curAddr->ifa_next;
    }
 
    /* clean up, return what we found */
    freeifaddrs(addrs);
    return addr;
}
 
+ (NSString *)ipAddressForWifi {
    return [NetUtil ipAddressForInterface:kWifiInterface];
}
 
+ (NSString *)netmaskForInterface:(NSString *)ifName {
    NSAssert(nil != ifName, @"Interface name cannot be nil");
 
    struct ifreq ifr;
    strncpy(ifr.ifr_name, [ifName UTF8String], IFNAMSIZ-1);
    int fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (-1 == fd) {
        NSLog(@"Failed to open socket to get netmask");
        return nil;
    }
 
    if (-1 == ioctl(fd, SIOCGIFNETMASK, &ifr)) {
        NSLog(@"Failed to read netmask: %@", [NSString stringWithCString:strerror(errno)]);
        close(fd);
        return nil;
    }
 
    close(fd);
    char *cstring = inet_ntoa(((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr);
    return [NSString stringWithCString:cstring];
}
 
+ (NSString *)netmaskForWifi {
    return [NetUtil netmaskForInterface:kWifiInterface];
}
 
@end

NSURLConnection + startImmediately:NO == boom?

Having issues creating NSURLConnections using initWithRequest:delegate:startImmediately?

NSURLConnection *c = [[NSURLConnection alloc] initWithRequest:[NSURLRequest requestWithURL:url]
                                                     delegate:self
                                             startImmediately:NO];

Apparently when not using the simpler initWithRequest:delegate:, or even startImmediately:YES, the connection does not get scheduled in the current run loop. And again apparently, this causes unhappiness to occur when you eventually get around to calling start.

Simple fix, just stuff it in the current run loop before calling start and everyone gets along just fine.

[c scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[c start];

If there is something I am doing wrong or something I can do to prevent this, I’d like to know. Alas, the API is fairly brief on NSURLConnection, I don’t think I’m missing anything. This seems consistent with Cocoa, Cocoa Touch.

Some Airsoft Turret play

Been toying with the idea of making an Airsoft Gun controller wirelessly via Wii Remote.  Inspired by a previous DefconBots challenge.  Just managed to get control of 2 servos via a ATMega8, serial link to a PC and a Wii Remote talking to said PC via BlueTooth.  Pretty hacky but it works, and it’s way easier than grokking BlueTooth on the MCU for now.

First video is of 1 servo working with really jittery input.

Second video is 2 servos on X and Y axis with smoothed input.  Much nicer.

Using libwiimote on the host side for Wii Remote interfacing.

Python SubWCRev

Fired out a little Python script for exercise…

pysubwcrev is a Python version of TortoiseSVN’s SubWCRev app. SubWCRev is a windows-only console app, pysubwcrev is a command-line argument compatible replacement that is Python-based, and therefore runs on any platform with an available Python interpreter and pysvn. Currently only Linux is tested.

The code is hosted @ Google Code. Currently no packaged release exists but it is (should be?) feature complete in svn.

Note: This is just a hack at playing w/Python, jabs and criticism w/the style can come in the form of patches.

Mr. Baybus 3 Preview

Yet another digital baybus.  The original Mr. Baybus, then Mr. Baybus 2, and now this one with PC control and a graphical LCD!

Currently only a few shots of some basic functionality, nothing concrete to announce or deliver unfortunately.

Screen Images

Splash screen

Splash screen

Fans

Fans

Lights

Lights

Temperatures

Temperatures

Application Screenshots

Main Menu

Fan Controls

Lighting Controls

Temperatures

Conditional Jumping in PIC16 Assembly

PIC Microcontrollers have a funky way of handling conditionals. I’d like to present a set of macros I’ve made to make this easier to use, as well as explain the basics behind the technique in general.

Most MCU’s I’ve worked with before PICs had nice simple conditional statements… The mnemonic was usually to the effect of “branch if x to destination”. Not so on the PICs.

On a PIC, we have to do an operation between the data to test, then either skip the next instruction or not, based on the results of this test.

Take the instruction “BTFSS” meaning “Bit-test F, Skip if Set”. This instruction takes a register and a bit number, and will jump over the next instruction if that bit number in the register is set. For example:

We have 2 registers, REG1 and REG2. We want to know if the value in REG1 equals the value in REG2. A quick, simple way to do this is first to load one into W, then subtract the other from it, with the result going in to W as not to destroy one of the variables. This sets the “ZERO” bit in the STATUS register to either 1 if the operation resulted in a 0, or 0 otherwise. We know if the operation resulted in 0 the two values are equal, so we can code like so:

TESTIFZERO
  movf REG1, w
  subwf REG2, w
  btfss STATUS, Z
    goto NOTEQUAL
EQUAL
  ; they were equal
  goto DONETESTING
NOTEQUAL
  ; they weren't equal

So we can test for equality.

We can also macro-ize it for ease of use…

BEQ macro REG1, REG2, DEST	; branch if REG1 == REG2
  movf REG2, W			; W &lt;- REG2
  subwf REG1, W			; W &lt;- REG1 - REG2
  btfsc STATUS, Z		; if result was nonzero: skip out
    goto DEST			; otherwise jump
  endm

This gives us a macro we can call with 2 registers and a destination, and have it jump there if the condition ends up being true, and just pass on through if it’s not true. Much, much easier to use.

The other tests: inequality, less than, greater than, less than or equal to, greater than or equal to and so on follow a similar pattern. They are all covered in the “conditionals.inc” file I use quite often. I have both register-register comparisons and register-literal comparisons in there. Feel free to grab a copy and use it in your next project.

Downloads

Mr. Baybus 2

After such a good response to Mr. Baybus, I decided to up the ante. I wanted temperature sensing and light control, as well as a more refined interface. I also wanted a chance to write much, much better code as Mr. Baybus was most definitely a kludge. This led to the design of Mr. Baybus 2.

Mr. Baybus had a few problems I wanted to take care of. One being price, it cost way too much compared to its utililty value, which is normal for projects like this, but still…

Mr. Baybus 2 uses a much more sophisticated microcontroller, a PIC 16F870. This is a 28-pin SDIP style chip, lots more I/O pins, an onboard UART, and even an ADC. This little guy also has twice the instruction memory, so I had more freedom to make the interface somewhat more sleek, and add more features. The benefit of more pins is CHEAPER LCD. The previous serial LCD ran about $42 shipped, which is semi-high for a serial LCD in general, but it was a CrystalFontz so at least it was high quality. Anyways, now I can move to a simple HD44780 based parallel LCD (by CrystalFontz, of course). These run around $20 shipped, and even less from other places selling generics.

Features

  • Three On/Off Fan controls
  • One 12V Light control (Neons, etc)
  • Two centrigrade temperature sensors
  • 20×2 screen (any HD44780 compatible will work)
  • Simple, menu-driven style interface
  • Stores fan status in non-volatile memory

Display Images

Splash screen

Fan status

Fan status

Fan status w/selection

Fan status w/selection

Lighting status

Lighting status

Temperatures

Temperatures

Unit Images

High view of the front

High view of the front

High view of the back

High view of the back

Back view

Back view

Underneath

Underneath

Version 2.1

A slight update to the original. I decided I wanted to re-write it in C as an exercise. While I was at it, I figured I’d add a feature or two.

Pretty basic, a complete re-write in C, Hi-Tech PICC to be exact. It’s a great compiler for the PICs and gave me opportunities to re-write the LCD, ADC and DELAY libraries in C.

New Features

  • New program-loop idea, worked well
  • Strobe mode for Light output
  • Temperatures in Celcius or Fahrenheit

Downloads

All files for Mr. Baybus 2 are distributed under a BSD-style license.