J2i.Net

Nothing at all and Everything in general.

Controlling an RC car with a Windows Phone

Introduction

RCCarCode.zip (2.36 mb)

alt download site

Earlier in the 2013 year while working with the Emerging Experiences group at Razorfish I had the opportunity to do some work with the Netduino, Arduino, and several other technologies that seem to play a significant role in the Maker Movement. Among other things I had converted an RC car to be controlled over Bluetooth with a Windows Phone. A few months ago someone saw a video of the car and asked me how I did it. The comments section on a video wasn't large enough to contain what I thought to be a sufficient response, so I'm writing this article instead.

Recognizing that there's a spectrum of backgrounds and experience levels that one may have when approaching this I've decided to start over from square one and make some changes along the way. The original RC to Bluetooth conversion was done with a Netduino Plus 2. This time around I will be using the Arduino because it is more ubiquitous and generally less expensive. For this revision of the car I'm staying away from the other improvements that could be added for the sake of simplicity. I'm also keeping my focus narrow and staying on the path to get the car up and running. Right now the goal is to cover what is minimally sufficient to get the car running with an understanding of what is going on. In later writings I plan to make improvements on the UI of the control application and add more capabilities to the car.

Prerequisites

To understand this article you'll need to have an understanding of basic digital electronics and programming. You don't need to know or remember the difference between CMOS and TTL gates to understand whats being written here. I'm staying as basic as I can. You will want to have familiarity with one of the C based languages (C, C++, C#) to understand what is being written within this article. I'm using Windows Phone 8 for this first revision of the article but I may return to add Android and iOS in later revisions.

What is the Arduino

I'm going to borrow from a description of the Arduino that I gave before. The Arduino is a single board computer based on the 32-bit Amtel ARM processor. The development environment for it is free (C++ based) It has the support of a large community of hardware and software developers ranging from professionals to hobbiest. From the software side there’s a number of existing solution components that are included in the development software or are available for download. From the hardware side you’ll find a wide range of hardware additions and accessories that can be added to a solution by plugging them into the Arduino.

While there are several forms that are recognizable as an Arduino there are new variants being released be various companies and individuals all the time. Information on constructing them is readily available and the required parts are easily acquired. Most of the Arduinos available available preconstructed will take on a common form and have a name that indicates it's configuration. To avoid the inundating number a variants in the Arduino I'm going to only consider Arduino boards that are available through The Arduino site at the time of this writing.

Any of these can be called an Arduino

How is one Arduino Different from Another?

Just as PCs are available with different configurations (different amounts of storage, ports, so on) so are Arduinos. The differences tend to be in processor speed, the number of different types of ports, or other peripherials. Here are some of the hardware components that may be on an Arduino. Note that note all Arduinos will have all of these available. You can find a table of some of the available Arduino configurations on the Arduino site.

Input/Output Voltages

Many of the peripherals that you connect to are going to expect (or produce) input and output signals that are either 3.3 volts or 5 volts. Some devices can work either either, some cannot. So you'll want to make sure that the Arduino that you use is mated with peripherals that have agreable signal voltages. Some Arduinos will have a switch that will let you change whether it is operating in the 3.3 volt range or the 5.5 volt range. If you want to interface two devices that operate on different voltages without risking damage additional circuits will be needed.

The Seeeduino Arduino Mega Adk that I'm using runs in 3.3V or 5V mode. But I must remember to ensure the switch is set to the needed voltage.

Processor Clock Rates

The Arduino boards available presently range in speed from 8 MHz up to 84 MHz. 16 MHz is the most typical.

USB Ports

Most of the Arduino boards have a USB port for programming and for getting information back from the Arduino. When connected to your computer it will appear as another Serial port. So you could use any terminal software that uses a serial port for interacting with the Arduino. Some of the Arduinos can emulate other devices such as keyboards or mice. Some Arduinos also have a USB host port that will allow it to interact with other USB peripherals.

Digital Port

Quickly glancing at the Arduinos that I have on my desk right now the number of ports that they have range from a little more than 5 to a little under 50. The digital ports can act as both outputs or inputs. When running in output mode they can programmatically be set to either a high or low voltage. When operating as an input a program can see if something connected to the Arduino is outputting a high or a low voltage. This extremely basic ability is an important building block for other capabilities. Turning on a light or motor or even communicating with other devices can be done with basic operations over a digital port. Some of the digital ports also support interrupts. So you could associate that port with a routine that automatically gets called if the ports status changes.

Analog Port

If you need to set a pin's output to something between high and low then the analog port is what you'll want to use. This can be used to control the speed of a motor instead of turning it on or off, or to control the brightness of a light. When used as an input an analog port can be used to detect the position of a potentiometer or the intensity of light on a sensor .

PWM Port

The PWM ports are able to output square waves. In general the signals outputted on these ports will all have the same frequency. But the pulse width of the wave can be varied. The following two waves have the same frequency but the widths of the waves differ.

The percentage of time that the wave spends in its high state is also called the wave's duty cycle. When a PWM signal has a 0% duty cycle it is always off. When it has a 100% duty cycle it is always on. PWM signals can be used to control the speed of a motor or the brightness of a lights.

Communications Port

While it's possible to communicate with other hardware through careful timing of turning a port on and off you will generally not want to (or need to) do this yourself. The Arduino supports some of the standard communications protocols used by many other circuits and sensors that you may want to interact with. All of these communications ports work serially; they will send or receive a message one bit at a time.

  • Serial Port - Connects a single device to another. Uses two lines for communication, one for sending, another for receiving. Devices that use these ports will have a set speed at which they can send and receive bits (baud rate). Two devices connected with a serial port must agree on the speed at which they will transmit information (baud rate, ranging from 300 baud to 57600 baud) and how a sequesnce is to be terminated (number of stop bits). Devices using serial port communication are able to track time passed so that they can write to or read from the communications lines at the correct rate. Serial ports on an Arduino can either be implemented through hardware or software. Only specific pins can be used for hardware serial ports, but any two pins can be used for the software serial port. However the software serial port cannot send and receive at the same time while the hardware serial ports can.
  • I2C - Connects a device to multiple other devices. Like the serial port the I2C port uses two lines from the Arduino. But unlike the serial port (which connects the arduino to only one other device) the I2C lines can be connected to multiple devices. Each device connect to the I2C ports has an address. When interacting with one of the devices the Arduino must send the address of the device that it wishes to respond and only that device will respond. An I2C address is composed of either 7 or 10 bits. So either 128 or 1024 devices could be connected to an I2C lines. Timing for communication is controlled through a clock line (usually labeled SCL) and data, whether transmitted or received, travels over a single data line (labeled SDA). Unlike the Serial Port (which allows data to travel in both directions at the same time) I2C communication is one direction at a time. But the I2C bus speed on an Arduino is at 100 KHz.
  • SPI - connects one device to multiple othe rdevices. SPI communication uses four lines; one for clock synchronization, one for data from the master device, one for all the devices that may respond, and a device selection line. Instead of transmitting an address the selection line for the device that is to respond must be driven high (each device will have its own line). The speed of the SPI bus is going to depend on the clock speed of the Arduino and a clock divider value (possible values will depend on the Arduino board being used). The default values on most Arduinos will result in a communications rate of 4 MHz.

What peripherals are Available for the Arduino

You can connect Arudinos to a wide range of products even if those products were not designed with the Arduino in mind. Your ability to do that is going to depend on your knowledge level with the Arduino. But what of the products that were made with the Arduino in mind or can be interfaced with litter effort? There are a number of products that can be used by aligning some pins and stacking them on top of the Arduino. Peripherals like this are referred to as "shields."

  • Wi-Fi and Ethernet Shields - host and consume simple web services or control your project over a network ( 1,2 )
  • GPRS Radio - have your circuite send text messages, make and receive calls, or access the Internet on the go (1)
  • Memory Shields - Read from and write to memory cards (a)
  • Bluetooth - One of the many ways that you can communicate with the Arduino wirelessly. One of the best options for devices controled by other mobile devices. (1).

There are other devices that while not made with the Arduino in mind interface to it with little effort because they implement a simple or common interface

  • Bluetooth
  • Servos
  • Relays
  • LCD Displays

Getting Started

Let's start working towards a "hello world". For the Arduino this will mean using it to turn on a light. You'll need the following

  • Computer (PC, Mac, Linux) with a free USB port
  • An Arduino board
  • Light emiting Diode
  • Resistor (about 220 Ohms)
  • Arduino IDE

Software Installation

The software is available for Linux, OS X, and Windows. I'm using the Windowa version which can be installed in one of two ways. The method I would suggest is downloading the "installer" version of the download. Like many other Windows installations the only thing the installer requires you to do is click on a "next" button a few times. The Zip version of the download will let you unzip the IDE to the arbitrary place of your choosing. After the installation has completed connect the Arduino board to your computer with a USB cable. Arduino's usually ship with a program preloaded that blinks a light on the board. Once plugged into the USB you should see the light on the Arduino strt to blink and the drivers should install.

It's possible that you might not be prompted for the drivers. I've connected the Arduino Mega to my computer and it wasn't recognized (unlike the other Arduinos it uses a different hardware component for it's connection). It originally showed up in the device manager as an unrecognized device. The drivers  can be found in the Arduino application folder. 

 

 

Creating a New Program

Start the Arduino IDE. By default the Arduino IDE will open blank and ready for you to start writing code. If you wanted to start another blank project selecting New from the File menu will open a new instance of the IDE. If you are using version 1.5.5 of the IDE (a beta at the time of this writing) then the window will open with two empty functions defined. If not then the window will be completely blank. If it's blank trype the following code.

void setup() {
  // put your setup code here, to run once:

}

void loop() {
  // put your main code here, to run repeatedly:

}

We are going to compile this code and upload it to the board. We'll need to tell the IDE what board that we have and which com port that it's attached to. Under the Tools menu there is a Board submenu that contains the Arduino Board models supported by the IDE. Select the board name that matches yours. You'll need to do the same thing for the port. If you don't know which port your Arduino is using unplug it and access the menu again to see which port name has disappeared from the listing. The one that has been removed is the one that your Arduino board is using.

In the toolbar there is a button that you can use to check to code for syntax errors (a check mark) and a button that can be used to upload the compiled program to the Arduino (an arrow).

Click on the arrow. If all goes well at the bottom of the IDE you will receive a message that says "Upload Successful" and the light should stop blinking. Let's update the program so that we can blink the light ourselves. To do this we need to configure a pin as an output pin. Many times you can use the same pins across different Arduino boards. It's a good practive to define the pins being used in a #define section or as a variable instead of using the literal pin number. If it never needs to be changed then it can be changed in one place. Pin 13 is usually connected to a led. Writing a HIGH value to it will turn the led on. So let's defined the pint that we are using to control the light as 13.

#define LIGHT_PIN 13

Then we write a HIGH or LOW value to it. Initialization steps are done in the setup function. Pin 13 could either be an input or output pin. We need to set it as an output pin using the pinMode function. When the device first starts (or is restart) it first runs the code in the setup() function. It will then run the code in the loop function until the device is turned off. In the loop we want to turn the light on, wait for a second (1000 ms), turn the light off, and then wait for another second.

#define LIGHT_PIN 13

void setup() {
    //set PIN 13 as a pin that we can write to
    pinMode(LIGHT_PIN, OUTPUT); 
}

void loop() {
    digitalWrite(LIGHT_PIN, HIGH);
    delay(1000);
    digitalWrite(LIGHT_PIN, LOW);
    delay(1000);
}

Deploy the application again. After a few seconds the light should start to blink. Congradulations! You've completed your first Arduino program. Before moving on let's make a small change. Instead of just turning it on and off let's adjust the brightness so that it fades in and out. For this we'll need to start adding external circuitry. For this next part you'll need a LED (light emitting diode), a resistor with a value in the range of 300 Ω to 1 KΩ value, and a breadboard. The resistor is for lowering the current that goes through the LED to ensure that we don't burn anything out with too much current. We are going to adjust the brightness of a led by using the analogWrite() function to change the amount of power supplied to the ligh. Pin 13 on many Arduinos doesn't support the analogWrite() function.

You need to look up which pins on the Arduino that you are using can be used for PWM output. Go to the Arduino Products Page and click on the model for the Arduino that matches the one you have. On the page that opens search the page for "Input and Output" and look for the line in that section about PWM. The pin numbers that you can use will be listed there. Below is the information for some of the arduino boards

Board Model Available Pins Resolution
Arduino Uno 3, 5, 6, 9, 10, and 11 8 bit
Due 2-13 8-12 bit
Mega ADK/Mega 2560 2-13, 44-46 8-bit
Yún 3, 5, 6, 9, 10, 11, and 13 8 bit
Nano 3, 5, 6, 9, 10, 11 8 bit
See analogWriteResolution() for information on changing resolution.

About using a Bread Board

If you've used a bread boardbefore you can skip this section. Breadboards allow you to prototype a circuit more quickly and reduce the amount of wires that you would need to construct the same circuite without a breadboard. Underneath the holes in the breadboard are conductors that electrically connect components. The The conductors all run paralle to each other and are usually perpendicular to the length of the breadboard. The exception being the powerlines which run down the length of the board. There's a depression down the center of  the board. The conductors do not cross this depression. Any components that are inserted on the same row (the rows are numbered) that are on the same side of the depression are connected. jumper wires need to be plugged in to connect components that are not on the same row and the same side of the divide.

Closeup of a breadboard. The red outline mars sets of holes that have a common conductor underneath.

Wiring the LED to the Arduino

LEDs will only work if current passes through them in the correct direction. There are two wires on the LED that are of different length. The longer of the two wires must be connected to a positive source while the shorter to a negative. Use a jumper to connect one of the pins labeled GND  to a row of wires on the bread board. Plug the LED into the board so that the shorter wire is in the same row as the GND wire. Connect the resistor into the board so that one of the wires is in the same row as the long wire of the LED and the other end is in an unoccupied row of the breadboard. Using a second jumper wire to connect the other end of the resistor to the pin that you are using for PWM.

Analog Code

Once the circuit is wired we can write the code to control the brightness of the led. When we wrote the previous program it was necessary to use use pinMode to set the pin to output mode before controlling it. It isn't necessary to do this when using analogWrite on a pin. We'll use the PWM port in 8-bit mode (which is much more widely supported than 10-bit mode). The variable containing the value to be written to the pin is going to start at 0, count up to 255, and then back down to zero. Each new value will be sent to the PWM pin. The result is that the LED will grow bright and then dim in cycles.

//Change the following to the pin number that
//matches the one that you are using. 

#define LIGHT_PIN 13

int brightness = 0;
int delta = 1;


void setup() {
}

void loop() {
    analogWrite(LIGHT_PIN, brightness);    
    brightness+= delta;
    if(brightness == 255)
      delta = -1;
    else if(brightness == 0)
      delta = 1;    
    delay(10);
}

Input and Output with the Serial Port

The serial port can be used to communicate with peripherals connected to the Arduino or to communicate back to the computer. There will be 1 to 4 hardware serial ports on your Arduino board. They will be named Serial, Serial1, Serial2, and Serial3. Each of these ports (if present in Arduino board) will be assigned to specific sets of pins. You can also instantiate software serial ports. Software serial ports can be assigned to any two pins. The hardware and software serial ports appear similar in capabilities. But the software serial port can only send or receive at any given point in time but can't do both simultaniously. The hardware serial serial port can do both at the same time.

The port Serial is connected to the computer. Communication between your computer and the Arduino occurs through this port when your programs are uploaded to the Arduino. You can also make your own applications on a computer that interact with a connected Arduino by opening the appropriate port. The computer and the Arduino will need to agree on a baud rate (data transfer speed).

Method Description
int available() Gets the number of bytes available for reading
void begin(baudRate) Sets the baud rate for the serial port and opens it for reading and writing.
void print(value) closes the port and disables the pins for communication.
void print(value) Writes a string to the port. Numbers and floats printed to the port will be converted to strings first.
char read() reads a byte from the serial port
readBytes(buffer, length) Reads characters from the serial port into a buffer
void write(byte) Writes a byte value to the serial port

The Arduino IDE has an interface called the Serial Monitor (can be opened by pressing CTRL+Shift+M or from the menu path Tools->Serial Monitor) that can be used to see the values coming back from the serial port or being written to it. For a simple demonstration we'll have the arduino count from one to one hundred and output it to the serial port.

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}

void loop() {
  for(int i=0;i<=100;++i)
  {
    Serial.println(i);    
    delay(100);
  }
}

After you upload the program open the serial port monitor. You'll see the stream of numbers coming back.  Here I want to point out that there's a difference in behavior in how the Arduino Yun, Micro  and Arduingo Leonardo behave when compared to the other Arduinos. Many of the other Arduinos use a chip that is separate from the main processor for handling communication between the computer and the Arduino's processor. When you open the Serial Port Monitor on these boards the device will reset. So you'll be able to catch all of the information that the devices outputs from begining to end. On the Leonardo, Micro and the Yun the serial communication is not being handled by a separate chip. The Amtega processor in these devices have a built in USB interface that presents itself as a serial port and can also present itself as a mouse, mouse, and serial port. While the serial connection can remain open on the other devices when they are reset if the processor is reset on the Yun, Mico, or Leonardo the virtual serial port would disappear while it restarts and the computer's connection to it will be lost. So these devices do not reset when you open a serial connection from your computer and the first few numbers that are written will not show up in the serial monitor. You could have the processor wait until the serial port is open before it starts writing numbers with a slight modification to the program. The statement if(Serial) wrapped around the code we just wrote to prevent it from executing until the serial port is open.

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
}

void loop() {
  if(Serial)
  {
    for(int i=0;i<=100;++i)
    {
      Serial.println(i);  
    delay(200);  
    }
  }
}

All the programs we have done until now have been non-interactive. We are about to do our first interactive program. In this one the Arduino will listen for text to come in over the serial port and will turn the light on or off in response to it. The program will also send a small bit of feedback on what it's doing. In the updated program the delta variable is going to default to zero. So the light's brightness will not start changing as soon as the program starts up. Instead when this program received the character '1' on the Serial object it will change delta to one so that the brightness will grow until it reaches its maximum value (then delta is reset back to 0 to prevent the brightness level from changing). When the program receives the value '0' it will set delta to -1 until the brightness variable reaches its minimum value. All other characters received through the Serial object will be ignored. When the program does receive a value that it's processing it will print back a message that will show up on the computer. Here is the source code to the updated program.

#define LIGHT_PIN 13

int brightness = 0;
int delta = 0;


void setup() {
  Serial.begin(9600);
}

void loop() {
    if(Serial.available())
    {
      char c = Serial.read();
      if((c == '1')&&(brightness!=255))
      {
        delta = 1;
        Serial.println("Turning Light On");
      }
      else if((c=='0')&&(brightness!=0))
      {
        delta = -1;
        Serial.println("Turning Light Off");
      }
    }
    brightness+= delta;
    analogWrite(LIGHT_PIN, brightness);    

    if(brightness == 255)
      delta = 0;
    else if(brightness == 0)
      delta = 0;    
    delay(10);
}

Run the program and open the Serial Port Monitor. From the monitor type the value 1 and press enter. You'll receive a confirmation back and will see the light's brightness begin to grow. Send it a 0 and you'll see the light's brightness diminish until it's extinguished.

Servos

There is only one more concept to cover before we are ready to interface to the car. And that is the concept of the servo. Servo is short for servomechanism. The term can refer to any device that uses negative feedback to correct its performance in achieving its built in function. Most of the time when some one mentions a servo in the context of an Arduino the person is refering to a servomotor. Servomotors receive a signal that coresponds to a desired position. The servo will rotate its shaft until the desired position is reached and will hold its position. RC (Remote Control) servos receive the position signal as a PWM signal. While you could directly send the PWM value for a desired position using analogWrite it is usually easier to use the <Servo.h> library instead. It will take care of the mappings between the angular position that we want and the value that would need to be sent through analogWrite() for that position. Just as analogWrite() will only work on certain ports the <Servo.h> library will only work on certain ports. Also note that with the exception of the the Arduino Mega use of the <Servo.h> library will disable the use of analogWrite() on ports 9 and 10, even if you are not using those ports to control a servo.

Method Description
void attach(pin, [max, min]) Attach the servo variable to a pin. One of the overloaded versions of this method can be used to adjust the minimum and maximum pulse width.
void write(angle) Writes a value to the servo setting the shaft position accordingly.
int read() Returns the last value written to the servo.
void detach() Detaches the servo object from the pin.

RC servos have three wires. Two of the wires will be for power. A red wire must be connected to a positive power source and the black or brown wire must be connected to the ground (GND). The third wire is connected to the PWM source. If you are going to drive several motors you will want to have the motors connected to a power source that can handle enough current. But we can connect a small servo to the Arduino without much concern.

This program will be much like the previous one. Only instead of controlling brightness we will be controlling the position of the motor. Servos generally have a range of 180 degrees. The minimum value is 0, the maximum value is 180, and middle value is 90. The exact range of your servo may vary. Don't try to drive the servo past its physical limit. Doing so can cause the servo to overheat. Confession: I burned out somewhat expensive servo this way when I was first programming with on.

In the previous program I used a delta variable to increment or decrement the brightness value. While you could do this for the Servo it is not necessary unless you need to control the rate of the turn. For light brightness jumping from one value to another will result in what looks like a simultanious change in brightness. The servo moves at a limited speed. Jumping from one value to another will result in in the servo changing position over time. There's no instantanious transition in position. So in this program we will not worry about incrementing the position over time and will just jump to the position that we need. Because there are positions between absolute left and absolute right in which we will have interest this program will respond to values between 0-9 instead of just 0 and 1.

//Change the following to the pin number that
//matches the one that you are using. 
#include <Servo.h>

#define MOTOR_PIN 13

Servo steeringServo;

void setup() {
  Serial.begin(9600);
  steeringServo.attach(MOTOR_PIN);
}

void loop() {
  if(Serial.available())
  {
    char c = Serial.read();
    switch(c)
    {
      case '0': steeringServo.write(0); break;
      case '1': steeringServo.write(20); break;
      case '2': steeringServo.write(40); break;
      case '3': steeringServo.write(60); break;
      case '4': steeringServo.write(80); break;
      case '5': steeringServo.write(100); break;
      case '6': steeringServo.write(120); break;
      case '7': steeringServo.write(140); break;
      case '8': steeringServo.write(160); break;
      case '9': steeringServo.write(180); break;      
      default:
      break;
    }
  }
  else
    delay(100);
}

Connect a servo to your Arduino. The red wire should be connected to the pin labeled 5V and the black/brown wire should be connected to one of the pins labeled GND. The remaining wire is to be connected to the PWM pin that you are using. Run the program and open the serial monitor. As you are sending the values keep an eye on your servo to ensure it's not trying to go past it's physical range. If it does immediately return it back to a position that is within its range.

Controlling the Drive Motor

Something to keep in mind before you start activating the drive motor on your vehicle. Make sure you lift the drive wheels so that they are not touching anything. Last thing you'd want to happen is for the car to take off at full speed while it's still connected to your computer or on a desk. Depending on your car you may be able to do this by turning it upside down. I took some camera rig parts that I had laying around and assembled them to support the vehicle.

RC car supported by camera rig pieces.

The drive motor on the car that I'm uses uses an ESC (Electronic Speed Control) unit. The ESC does a couple of things. It contains a power regulator that's outputting 5 volts from the 7.2 voltage from the battery and it activates the drive motor. The 5 volt output is also routed to the steering servo and the radio receiver/control circuit. We are unplugging the car's receiver and connecting the Arduino in it's place. If we use the same program that we used to control the servo but connect the arduino to the ESC instead of the servo we can use it to control the motor's speed. We are going to wire the two together a little differently this time. The ESC is going to need to be connected to it's own power source (the car's battery). There Arduino would not be able to power the drive motor. For this test you do not need to connect the red wire. If you want to connect the red wire anyway connect it to the VIN pin so that the voltage from the ESC is passed through the Arduino's voltage regulator.

After you are done with the wiring run the program again. This time you should be able to make the car's drive motor go in forward and reverse. If your ESC behaves as mine does if you try to go from forward to reverse without going through the neutral position the ESC will interpret it to mean you want the vehicle to brake. So you may need to select the neutral position before you change directions.

The ESC that I am using is the Dynamite Tazer 15T. Despite documentation that is available on the Internet (PDF) this ESC does not allow any calibration. If you are using another esc calibration may be required so that the esc knows what speeds />directions to map to the range of values that it needs to work with. Since I don't have an ESC that supports calibration I won't be able to address that myself within this document.

The Dynamite Tazer 15T

Bluetooth Communication

There are a number of Bluetooth solutions available that will work with the Arduino. Some are available as shields. I didn't want to use a shield as a solution since it would restrict which pins that I could use for bluetooth communication. I used one that needed to have its pins connected to the arduino individually. Most of these will have 4 connections that you'll care about. Two of them are for power. They will need to be connected to the 5 volt line and the GND. The other two lines are for data to be sent and data received. We are also finally to the point where we are going to make use of the Windows Phone. Before we get started with coding go ahead and connect your power and GND to power it up and pair your phone with it. On the bluetooth device that I'm using the pairing code is 1234. You'll need to check with the documentation for the Bluetooth circuit that you are using to know what code to use.

Picture of the Bluetooth Module that I am using

Picture of the Bluetooth Module that I am using

You'll need to write code that will do a a few things

  1. Get a list of the paired bluetooth devices
  2. Select the paired device to be used for communication
  3. Open streams to the device for listening and sending information

For getting a list of the Bluetooth devices paired with the phone Microsoft has provided the PeerFinder

class. You'll need to add the Proximity permission to your application to use this class. The list of devices paired with the phone can be retrieved with two lines of code.

PeerFinder.AlternateIdentities["Bluetooth:Paired"] = "";
var pairedDevices = await PeerFinder.FindAllPeersAsync();

For the sake of improving the user's experience you would probably want to give your Bluetooth receiver a distinct name that the application could look for to distinguish it from the other Bluetooth devices. On many of the Bluetooth receivers it's possible to change the name that the device uses. On the one that I have handy I've noticed that the company that produces it seems to have explicitly stricken out the portion of the documentation that explained how to change my adapter's ID (probably appropriate, as the device isn't responding to name change commands). I'm going to stick with the name that seems to be burned into my device, linvor. Check the documentation in your Bluetooth adapter to see what name you need to use.

The pairedDevices collection in the above code will contain PeerInformation instances. Grab the one that represents your device and use it to create a new Socket object. The Socket will be used for reading from and writing to the Bluetooth adapter.

_socket = new StreamSocket();
await _socket.ConnectAsync(_selectedDevice.HostName, "1");

Now we can send and receive messages between the Windows Phone and the car circuit. Read and write operations are asynchronous. Using the InputStream member of the socket we can initiate a read operation. If there is nothing to read the call will [perceivably] wait until there is data available to be read (the nuances of what really goes on while interesting is beyond the scope of this document). Once the bytes are available and read I'm converting them to a string for later processing.

byte[] bytes = new byte[128];
await socket.InputStream.ReadAsync(bytes.AsBuffer(),(uint)bytes.Length, InputStreamOptions.Partial);
bytes = bytes.TakeWhile((v, index) => bytes.Skip(index).Any(w => w != 0x00)).ToArray();
string str = Encoding.UTF8.GetString(bytes, 0, bytes.Length);
OnMessageReceived(str);

For this first iteration of the project the car doesn't need to send back any vital data. It's only going to be listening for instructions for what it should be doing. For now the only instructions to send are of what the state of the throttle and the steering servo should be. I'm sending the commands in strings that look like a REST request.

public void TransmitState()
{
    if ((_communicationController != null)&&(_communicationController.IsConnected))
    {
        _communicationController.Write(String.Format("/car/throttle/{0}\r\n", ThrottleValue));
        _communicationController.Write(String.Format("/car/steering/{0}\r\n", SteeringValue));
    }
}

With that the basics of what need to happen on the Windows Phone side for communicating with the car have been covered. There is still work to on deciding on a user interface in the application. Let's go back to the car to implement the code for responding to the received commands.

Don't Let the Car Get Away!

Since we are approaching a point at which the car is almost prepared to be sat down on the ground to be driven there's something I want to address. You must be prepared to respond to a loss of a connection. If you don't the car could end up continuing to do the last thing that it was doing until it gets a connection again. If the last thing it was doing was going ahead full throttle chances are you won't be able to reestablish a connection without sprinting after the car. There are a couple of solutions that come to mind to handle this. On many of the Bluetooth receivers that I've seen there is an additional line that connects to a led that will change its blinking sequence to indicate whether or not the Bluetooth receiver has a connection. It's possible to connect to this and put the car in a neutral state if it indicates that the Bluetooth connection has dropped. Another method (the one that I will go with) is to keep track of how long it's been since an instruction was received. If more than a certain amount of time passes and no instructions are received stop the car.

The millis() function returns how much time has passed since the Arduino was started in milliseconds. Every time an instruction is received we can save the value returned by this function and use it as a reference for knowing how long it's been since an instruction was received. With each execution of the main loop the the millis() function is called again and compared to the saved value. The difference between the two values is the amount of time passed since the last instruction. Once the difference has become greater than a certain amount we know it's been a while since an instruction was received. The car will be put in a neutral state. If an instruction is received before this condition occurs then the saved value would have been updated so the difference between the saved time value and the current time value would not be great enough to reach the expiration period.

Parsing the Commands

Parsing is easy since all the commands are being sent in what looks like a rest request. Each segment of the path in the REST like request is associated with a method. Each time an instruction is received it is passed to ProcessCommand(string) which will parse out the first segment and use it to decide which method to call next. Right now all of the instructions will start with /car/. The root level method in the processing call stack only checks to see if an instruction starts this way and does nothing if the command is something else.

void ProcessCommand(String command)
{
  int startPosition, endPosition;
  String segment;

  startPosition =  command.indexOf('/', 0);
  endPosition = command.indexOf('/', startPosition+1);
 
  if((startPosition>-1) && (endPosition == -1))
  {
      segment = command.substring(startPosition + 1, endPosition - startPosition+1);
      startPosition = endPosition + 1;
  }
  if(segment == "car")
     ProcessCarCommand(command.substring(endPosition));
}

The ProcessCarCommand() method is similar. It is testing to see if the next part of the instruction is "throttle" or "steering" and called the ProcessThrottle() or ProcessSteering() methods respectively.

void ProcessCarCommand(String command)
{
  int startPosition, endPosition;
  String segment;

  startPosition =  command.indexOf('/', 0);
  endPosition = command.indexOf('/', startPosition+1);

  if((startPosition>-1) && (endPosition>-1))
  {
       segment = command.substring(startPosition + 1, endPosition - startPosition);//.
  }

  if(segment=="throttle")
     ProcessThrottleCommand(command.substring(endPosition));
  else if (segment=="steering")
    ProcessSteeringCommand(command.substring(endPosition));
}

The methods that follow are finally getting to where the rubber meets the road; they are controlling the steering and throttle lines. Their implementation is almost identical. They strip the numeric value off the end of the command (which will be between the values of -1 and 1). The value of 1 for the throttle represents full throttle forward, -1 would be for full reverse, and 0 for neutral. Similarly -1 for the steering is full left, 1 is full right, and 0 is straight ahead. These values are being scaled and shifted before being sent to the Servo object. The continuous value range of -1 to +1 needs to be remapped to the the values 0 to 180. The Arduino function library already contains a function for doing this appropriatenamed map. It takes 5 arguments. The first is the value to be remapped. The next two are the lower and uper range for the value. The fourth and fifth are the range to which the value needs to be mapped. For our specific case the call will look like map(value,-1,1,0,180). The mapped value is then written to the servo object for either the steering or throttle. The code for the two functions follows.

float StringToFloat(String str)
{
  char buf[str.length()];
  str.toCharArray(buf, str.length());
  float retVal = atof(buf);
  return retVal; 
}
void ProcessThrottleCommand(String command)
{
  if(command.length() < 2) return;
                         float newthrottlevalue=StringToFloat(command.substring(1));
                         if ((newthrottlevalue < -1)&&(newThrottleValue > 1))
   return;
   int servoValue =(int) map(newThrottleValue,-1,1,0,180); 
   throttleESC.write( servoValue );
}
void ProcessSteeringCommand(String command)
{
  Serial.println("Processing Steering Command");
  if(command.length() < 2) return;
                         float newsteeringvalue=StringToFloat(command.substring(1));
                         if((newsteeringvalue < -1) && (newSteeringValue > 1))
    return;
  int servoValue = map(newSteeringValue,-1,1,0,180);
  steeringServo.write( servoValue );
}

Control Interface

All the code needed for sending control signals to the car and to have the car interpret and act on them has been presented. I skipped over discussing a user interface for controlling the car though. Some of the other phone controlled systems I've seen use the accelrometer for control. This is a matter of personal preference, but I don't like the accelerometer based approaches. When playing games on my phone the method of control that prefer second is the virtual joystick with a dead zone that is centered on whereever one's finger happen come in contact with the screen. My most preferred method of control is a physical controller.

I made an extremely simple virtual joystick for the phone in the form of a user control. When some one first place their finger down on the control that point becomes the new center point for the dead zone. Sliding ones finger will move the virtual joystick out of the dead zone and be registered as a direction. Lifting one's finger off of the control will set the virtual joystick back to it's neutral position.

Second best isn't bad, but we can do better. I've got a Moga bluetooth game controller that is compatible with Windows Phone. So I've added support for that too. Normally I would have the code organized so that there are a number of logical joysticks (whether physical or virtual) and then some mechanism for deciding which one of the joysticks will be listened to. I'm avoiding that organization in this article for the sake of simplicity. The code handling input from the Moga is in the same class as the virtual joy stick and there's absolutely no resulution implemented for what to do if some one decides to use both the touch screen and the game controller at the same time.

Moga Bluetooth controller.

There's an SDK at Moga's web site that contains an assembly (Moga.Windows.Phone) that simplifies interaction with the Moga controller. There are two modes of interaction with the controller, polling and listening. In polling mode every time the code wants to know the state of the controller it will need to query the controller. In listening mode as the state of the controller changes methods on your code are called through an interface indicating what has changed. Xaml based programs will usually want to use the listening mode while DirectX based programs will use polling. To use listening mode my VirtualJoyStick class implements the IControllerListener interface. More development information on the Moga series of controllers can be found on their site.

IControllerListener methods
Method Description
void OnMotionEvent(MotionEvent e) One of the analog inputs on the controller has changed. This includes both thumb sticks and the the analog triggers.
void OnStateEvent(StateEvent e) Indicates the connection and battery state of the controller.
void OnKeyEvent(KeyEvent e) The pressed state of one of the buttons has changed.

Remember what I said earlier about responding to the potential loss of the connection between the phone and the car? That also applies to the connection between the phone and the game controller. If the connection to the controller drops (battery goes dead, or the user walks away from the phone) the code on the phone needs to be prepared to start transmitting a neutral state. Otherwise the phone will continue to transmit what ever the last known state of the game controller indicated. One of the IControllerListener events is used for this, OnStateEvent(StateEvent e).

public void OnStateEvent(StateEvent e)
{
    if (e.StateKey == ControllerState.Connection)
    {
        if(e.StateValue == ControllerResult.Disconnected)
        {
            SetNeutralState();
        }
    }
}

I've decided to use the left thumb stick for steering and the right thumb stick for the throttle. I'm ignoring the buttons all together.

public void OnMotionEvent(MotionEvent e)
{
    this.Dispatcher.BeginInvoke(() => { 
        if(e.Axis==Axis.Z)
        {
            Y = e.AxisValue;
            OnVirtualJoystickUpdated();
        }
        else if(e.Axis == Axis.X)
        {
            X = e.AxisValue;
            OnVirtualJoystickUpdated();
        }
    });
}

Loose Connections

I've said next to nothing about the physical assembly of the finished product. In part I've done this because it's not my final design. Dependind on the car that you have you may be able to screw the Arduino in place on the vehicle. You are not going to want to use loose wires to connect the servo and ESC to the Arduino though; with just a little bit of strees the wires would come loose. Instead check out your local electronics store or other provider to see what prototype shields are available. Using one of those you may be able to securly hold the connections in place through either soldering or with screws.

What's Next

Writing additional code so that the car can be controlled by an Android phone isn't much effort. The same concepts carry over. When time allows I may update this article or add another one to explain what needs to be done to control the car with an Android phone. Also keep in mind that my personal goal is to make the car more autonomous. This means that the car must be able to know something about it's environment and position. In the next update I plan to walk through the various sensors that will be attached to the car and how to use them. These include GPS, distance sensors, and motion sensors such as an accelerometer and gyrometer/rate sensor. Because of the low distance range on bluetooth radios I'll be using a different radio (Wi-Fi) so that more distance can be put between the phone and the car. I may eventually move up to adding a GSM radio.

Revision History

  • 2014 February 12 - Initial Publication

 

RCCarCode.zip (2.36 mb)

alt download site

Windows Mobile Current Directory

Another area when programming on Windows CE/Mobile devices is "How do I find the current directory?"  CE devices don't have a concept of a current directory.  This means that relative paths don't have meaning on a CE device (all paths are absolute).  Because of the lack or relative paths  some files (such as help files) are loaded to the Windows directory (personally I absolutly hate copying anything specific to an application to the Windows Directory).

It follows that since there is no concept of a current directory on a Windows Mobile device how would one locate a resource for which only a relative path is known?  A .Net program always has access to the modules of which it is composed (usually a .Net component is composed of one module packaged in a DLL or EXE file). The following line will return the absolute path to the currently executing assembly.

 string modulePath = this.GetType().Assembly.GetModules()[0].FullyQualifiedName;

 To get the absolute path to the folder that contains the assembly simple string manipulation is required.  The assembly name appears after the last directory seperator. While the directory seperator is usually the backslash (\) character, for better compatibility across other operating systems that may run .Net (ex: Mono[^] on Linux, OS X, or Solaris) use System.IO.Path.DirectorySeparator to represent the directory separator charactor.

string solutionFolder = modulePath.Substring(0, modulePath.LastIndexOf(Path.DirectorySeparatorChar) );

Once the folder to your program is known use Path.Combine to build the fully qualified file name for files in your folder.  Path.Combine takes into account the directory separator for the operating system on which your program is run.  So if you had data in a file named MyFile.txt you would use

string myFilePath = Path.Combine(solutionFolder,"MyFile.txt");

Update 1 : I received a simpler way to accomplish the same thing from John Spraul in the comment section.  Thanks. John!

Update 2: If you are developing using the native APIS use the following:
GetModuleFileName(GetModuleHandle(NULL),    pszFullPath, MAX_PATH);

Path.GetDirectoryName(this.GetType().Assembly.GetModules()[0].FullyQualifiedName)

or

Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetModules()[0].FullyQualifiedName)

if you do not want to load the type.

Autolaunching an Application on Windows Mobile

I submitted an article to codeproject.com a little over a month ago about automatically starting an application base on an event or a schedule. I posted the content of the article here.  To get the source code visit http://www.codeproject.com/script/Articles/Article.aspx?aid=27917

Introduction

Figuring out how to make an application automatically start up had long been a mystery to me. The information was scattered and a bit of research was needed to collect all of. During my research I placed all of my notes in a various documents and have decided to organize them into a single document and share with all. The information presented here was tested on Windows Mobile 5 and Windows Mobile 6 devices but can also be applied to several versions of Windows CE (The OS from which Windows Mobile is derived).

It's possible to achieve similar functionality by making your own executable that watches system changes through the SystemState class and responding accordingly, but that would cause your program to have a larger footprint.

About the Code

The first methods of automatically starting a program are centered in what I will call configuration tasks; making shortcuts, registry entries, or placing files in specific locations. For these methods I do not provide code examples. Later within this article I discuss methods of automatically launching applications that are setup through code. For these methods I include example code within the article and full source attached to the article.

The code examples rely on some Win32 functions that are called through P/Invoke. Both code examples refer to a project named Win32 which contains the references to these functions. Additionally Win32 also contain a structure and an enumeration needed to properly pass information to the WinAPI functions. To run the code examples you will need a Windows Mobile device (or emulator) and Visual Studio 2008.

Remember that on Windows Mobile devices you should prevent more than one instance of your program from existing in memory (if a second instance is started it should notify the first instance and then immediatly terminate).

What is meant be “auto-start?”

When I use the phrase auto-start I use it to refer to the launching of any program based on an event (other than the user clicking on the program’s icon). A program can be automatically started in one of four ways.

  • A program on a memory card runs as soon as the card is inserted
  • A program is scheduled to start at a predetermined time
  • A program is launched in response to a system change
  • A program launches at device power up

AutoRun from a Memory Card

The user inserting a memory card can cause an application to launch in one of two ways. The memory card could have a program on it that launches upon insertion of the Windows Mobile device could start a program that is already present in its main storage in response to the memory card being inserted. The later would be implemented by registering an application to start on a system change (discussed later).

When a memory card is inserted into a Windows Mobile / Windows CE device the OS automatically looks in a certain folder for a program named Autorun.exe. If that program is found then it is immediately run. The folder in which the OS looks is going to depend on what type of processor that the device has. For an overwhelming majority of Windows Mobile devices that folder will be “/2577”. Here is a table of the possible folder names for other Windows CE devices.

ProcessorFolder Name
ARM 720 1824
Arm 820 2080
ARM 920 2336
ARM 7TDMI 70001
Hitachi SH3 10003
Hitachi SH3E 10004
Hitachi SH4 10005
Motorola 821 821
SH3 103
SH4 104
Strongarm 2577

f you already have an application on a memory card that you wanted to autorun.exe but you did not want to rename the executable or place it in this folder then you can always make a second executable whose purpose is to launch your first executable.

Startup Shortcut

A shortcut can be made to an application that you wish to startup automatically and placed in \Windows\StartUp. Use this method if you have a single executable that needs to be started that has no dependencies on other executables. The format of shortcuts on windows mobile devices is simple. It will always be in the form of 00#”<\program Files\path>” where 00 is replaced with the number of characters that appear after the ‘#’ sign, the ‘#’ is a delimiter, and then the complete path to the executable. The following is an example of a shortcut to Windows Media Player.

23#“\windows\wmplayer.exe”

You don't have to manually create the shortcut though. There is a native API call SHCreateShortcut that will create a shortcut for you. The first argument is the full path to the shortcut to be created and the second arguement is the full path to the file to which the shortcut points.

Starting an Application at Bootup

For Windows Mobile devices the location for autostart entries is HKEY_LOCAL_MACHINE\Init. Unlike the startup entries on a desktop machine (which only require the path to the executable to start) the entries for Windows Mobile devices are a little more structured. There are two keys associated with an application that needs to start up automatically, a LaunchXX key and an optional DependXX key. The XX would be replaced with a number. This number is also called the sequence number The value of LaunchXX is a string value (REG_SZ) that contains the path to the executable to be started. The DependXX key is used to specify on what applications that the current application has dependencies (and thus in what order the applications must be launched). The DependXX key contains a list of word (2 bytes) values that contain the sequence number values of the required applications.

The following screenshot is of the registry on my Windows Mobile 5 phone. Launch21 refers to an application named “coldinit.” If we look at Depend21 we see that “coldinit.exe” has a dependency on an application identified by 0x14 (20 decimal). So “coldinit.exe” must be launched after the app identified in Launch20, “Device.exe.”

Screen shot of Windows Mobile Registry

Applications launched using this method must notify the application of successful startup by calling the SignalStarted(DWORD) function. This function is a native call. For C programs the header to this function is defined in Winbase.h and in the library Coredll.lib. Developers using managed code will need to P/Invoke this method. The functions only argument is the sequence number of the executable. The sequence number is passed to the application as its only command argument. Note that the sequence number is the only argument that the application will be able to receive through the command line arguments. Any other information that must be passed to the application should be passed through configuration files or registry keys.

Starting a Program at a Specified Time

The Windows CE / Windows Mobile OS contains functionality for automatically starting a program at a specified time. The functionality is available through a call to CeRunApAtTime from the CoreDLL library. As mentioned by Jim Wilson in many of his “How Do I” video post on MSDN, this function expects the start time to be specified in the WinAPI SystemTime structure instead of the DateTime structure (CeRunAppAtTime is an unmanaged function called using the platform invoke functionality). Converting a time from a DateTime to a SystemTime is not difficult; there are already WinAPI functions that do this for you. To make calling this function easier I have placed the following code in my Win32Helper class. I’ve also provided an overloaded function to allow the time to be passed as an offset from the current time with a TimeSpan object.

public static void RunAppAtTime(string applicationEvent, DateTime startTime)
{
    long fileTimeUTC = startTime.ToFileTime();
    long fileTimeLocal = 0 ;
    SystemTime systemStartTime = new SystemTime();
    CoreDLL.FileTimeToLocalFileTime(ref fileTimeUTC, ref fileTimeLocal);
    CoreDLL.FileTimeToSystemTime(ref fileTimeLocal, systemStartTime);
    CoreDLL.CeRunAppAtTime(applicationEvent, systemStartTime);
}
public static void RunAppAtTime(
     string applicationEvent, 
     TimeSpan timeDisplacement
)
{
    DateTime targetTime = DateTime.Now + timeDisplacement;
    RunAppAtTime(applicationEvent, targetTime);
}

Where applicationEvent is the full path to the application to start and startTime is the time at which the application should be executed. There’s also an overloaded version of the method that accepts a TimeSpan object instead of a DateTime if you wanted to specify the start time relative to the current time.

If an application were attempting to schedule itself to be restarted at a later time it will need to be able to pass it’s complete path. I used reflection to find that path.

Module[] m = this.GetType().Assembly.GetModules();
target = m[0].FullyQualifiedName;

Screenshot of timed start program

Running the Program because of a System Change

There are a number of system changes that can be used to trigger the execution of a program. The WinAPI function CeRunAppAtEvent is used to associate a program with an event. Once associated that program will be launched every single time that the event occurs! So you must also remember to disassociate the program with the event when you no longer want it to automatically start.

I have created the enumeration in the Win32 class named WhichEvent that contains the ID numbers for the events that can be used to trigger program execution.

When a program is started because of a change in system state a single argument is passed to the program to indicate the state change that triggered the programs execution. (I don't discuss the details of how to do that here). For a complete list of the possible arguments see the example cod in AutoStartArgumentString.cs.

Enumeration ElementDescription

NOTIFICATION_EVENT_NONE

Used to clear all events associated with a program

NOTIFICATION_EVENT_TIME_CHANGE

NOTIFICATION_EVENT_SYNC_END

ActiveSync synchronization has completed on the device

NOTIFICATION_EVENT_ON_AC_POWER

The unit’s charger is connected

NOTIFICATION_EVENT_OFF_AC_POWER

The unit’s charger is disconnected

NOTIFICATION_EVENT_NET_CONNECT

The device is connected to a network

NOTIFICATION_EVENT_NET_DISCONNECT

The device is disconnected from a network

NOTIFICATION_EVENT_DEVICE_CHANGE

A memory card or other device was inserted or removed

NOTIFICATION_EVENT_IR_DISCOVERED

The device has detected another infrared device

NOTIFICATION_EVENT_RS232_DETECTED

The device has been connected to an RS232 device

NOTIFICATION_EVENT_RESTORE_END

A full restore of the device has completed

NOTIFICATION_EVENT_WAKEUP

The device has come out of a suspended state

NOTIFICATION_EVENT_TZ_CHANGE

The time zone of the device has changed

NOTIFICATION_EVENT_MACHINE_NAME_CHANGE

The name of the device has changed

I have created a class simple named Core for declaring platform invoked methods from the CoreDLL.dll library and declared the CeRunApAtEvent function within it. The following schedules the the windows calculator to start when the device comes out of the suspended state.

CoreDLL.CeRunAppAtEvent(@"\Windows\Calc.exe", (int)WhichEvent.NOTIFICATION_EVENT_DEVICE_CHANGE);

After that call the windows calculator will start every single time that the device is woken up. To prevent the calculator from starting up a second call is necessary.

CoreDLL.CeRunAppAtEvent(@"\Windows\Calc.exe", (int)WhichEvent.NOTIFICATION_EVENT_NONE);

Included with this article is an example application that can be used to cause an application to launch for various events. Originally this program would only register a program to start upon wakeup. But I've extended the program so that it can also start programs in response to other events. Note that by changing the value in the call to CERunAppAtEvent that you can use the program cause an executable to launch for bcause of some other event (such as a memory card being inserted or ActiveSync completing its synchronization).

WakeupStart.png

When a program is autostarted a string is passed to it through the command line indicating the event that started it. I've included a program named ShowCommandLine with the source code that does nothing more than display the command line arguments that it received. From the screen shot below you can see the command line argument that was received when the program was started upon connecting to a network connection.

ShowCommandLine.png

Preventing Multiple Instances

Normally the .Net framework will take care of ensuring that multiple instances of your program are not running. This doesn't always work for programs that are started because of a system event. Several system events can be fired in rapid succession or the same event can be fired twice (for some odd reason the wakeup event is usually fired twice). The first time I tried scheduling the ShowCommandLine program to start on wakeup and another event I ended up with several instances of it running.

MultiInstance.png

To get around this I create an event object (using P/Invoke) before loading the form. If several instances of the program are started in rapid succession then the creation of the event will fail, and we can use this failure to know that the this is not the first instance of the program and immediatly unload it.

static void Main()
{
    IntPtr eventHandle = IntPtr.Zero;
    const string ApplicationEventName = "ShowCommandLineEvent";  //We will use this as our handle to 
                                                                 //to ensure only one instance of the
                                                                 //program is started            
    try
    {
        //Try to create the event.  If the creation fails then it is 
        //because another instance of this application is already 
        //running. If another instance exists then this instance
        //should immediatly terminate.
        eventHandle = CoreDLL.CreateEvent(IntPtr.Zero, true, false, ApplicationEventName);
        int lastError = Marshal.GetLastWin32Error();
        //MessageBox.Show(String.Format("event handle {0}",eventHandle));
        
        if (0 == lastError)
        {
            Application.Run(new Form1());
        }
    }
    finally
    {
        //When the application is no longer running it should release the event
        if (eventHandle != IntPtr.Zero)
            CoreDLL.CloseHandle(eventHandle);
    }
}

When multiple instances of a program are created in this manner you may want to send a notification to the first instance of the program so that it can respond to the event.

 

 

What's Next?

This article is largly the result of research I am doing in preperation for software solution that I plan to design. In the next part of my research I will develop a solution for making the phone respond to other events not exposed directly through the the CeRunAppAtEvent function.

History

  • 19 July 2008 - Initial Publication
  • 31 July 2008 - Added reference to SHCreateShortcut (Thanks Zoomesh!)