The codebase to run the *spark d-fuser controller www.sparkav.co.uk/dvimixer

Dependencies:   SPK-TVOne DMX DmxArtNet NetServicesMin OSC PinDetect mRotaryEncoder iniparser mbed spk_oled_ssd1305 filter

Files at this revision

API Documentation at this revision

Comitter:
tobyspark
Date:
Thu Jul 19 10:46:53 2012 +0000
Parent:
4:d5ff91b66357
Child:
6:aca7c9e6894d
Commit message:
v18 - DMX

Changed in this revision

DMX.lib Show annotated file Show diff for this revision Revisions of this file
DmxArtNet.lib Show annotated file Show diff for this revision Revisions of this file
NetServicesMin.lib Show annotated file Show diff for this revision Revisions of this file
OSC.lib Show annotated file Show diff for this revision Revisions of this file
OSC/.lib Show diff for this revision Revisions of this file
OSC/example-processing.h Show diff for this revision Revisions of this file
OSC/example.h Show diff for this revision Revisions of this file
OSC/mbedOSC.cpp Show diff for this revision Revisions of this file
OSC/mbedOSC.h Show diff for this revision Revisions of this file
PinDetect.lib Show annotated file Show diff for this revision Revisions of this file
SPK-TVOne.lib Show annotated file Show diff for this revision Revisions of this file
mRotaryEncoder.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
mbed.lib Show diff for this revision Revisions of this file
spk_oled_ssd1305.lib Show annotated file Show diff for this revision Revisions of this file
spk_utils.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/DMX.lib	Thu Jul 19 10:46:53 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/okini3939/code/DMX/#f0d988e15810
--- a/DmxArtNet.lib	Mon Apr 23 09:30:50 2012 +0000
+++ b/DmxArtNet.lib	Thu Jul 19 10:46:53 2012 +0000
@@ -1,1 +1,1 @@
-http://mbed.org/users/okini3939/libraries/DmxArtNet/ly98qu
\ No newline at end of file
+http://mbed.org/users/okini3939/code/DmxArtNet/#c59dc374fc64
--- a/NetServicesMin.lib	Mon Apr 23 09:30:50 2012 +0000
+++ b/NetServicesMin.lib	Thu Jul 19 10:46:53 2012 +0000
@@ -1,1 +1,1 @@
-http://mbed.org/users/hlipka/libraries/NetServicesMin/lkscxf
\ No newline at end of file
+http://mbed.org/users/hlipka/code/NetServicesMin/#9d93f4dc2f46
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/OSC.lib	Thu Jul 19 10:46:53 2012 +0000
@@ -0,0 +1,1 @@
+OSC#2b9d407f0e7b
--- a/OSC/.lib	Mon Apr 23 09:30:50 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-http://mbed.org/users/tobyspark/libraries/OSC/m8izgx
\ No newline at end of file
--- a/OSC/example-processing.h	Mon Apr 23 09:30:50 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,52 +0,0 @@
-/* EXAMPLE SEND/RECEIVE on PROCESSING:
-
-// oscP5sendreceive by andreas schlegel
-// example shows how to send and receive osc messages.
-// oscP5 website at http://www.sojamo.de/oscP5
-
-*/
-
-import oscP5.*;
-import netP5.*;
-
-OscP5 oscP5;
-NetAddress myRemoteLocation;
-
-void setup() {
-  size(400,400);
-  frameRate(25);
-  // start oscP5, listening for incoming messages at port 12000
-  oscP5 = new OscP5(this,12000);
-
-  // myRemoteLocation is a NetAddress. a NetAddress takes 2 parameters,
-  // an ip address and a port number. myRemoteLocation is used as parameter in
-  // oscP5.send() when sending osc packets to another computer, device,
-  // application. usage see below. for testing purposes the listening port
-  // and the port of the remote location address are the same, hence you will
-  // send messages back to this sketch.
-  myRemoteLocation = new NetAddress("10.0.0.2",10000);
-}
-
-
-void draw() {
-  background(0);
-}
-
-void mousePressed() {
-  // in the following different ways of creating osc messages are shown by example
-  OscMessage myMessage = new OscMessage("/mbed/test1");
-
-  myMessage.add(123); // add an int to the osc message
-
-  // send the message
-  oscP5.send(myMessage, myRemoteLocation);
-}
-
-
-// incoming osc message are forwarded to the oscEvent method.
-void oscEvent(OscMessage theOscMessage) {
-  // print the address pattern and the typetag of the received OscMessage
-  print("### received an osc message.");
-  print(" addrpattern: "+theOscMessage.addrPattern());
-  println(" typetag: "+theOscMessage.typetag());
-}
--- a/OSC/example.h	Mon Apr 23 09:30:50 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,117 +0,0 @@
-#include "mbed.h"
-#include "mbedOSC.h"
-
-//// ETHERNET
-
-// Ethernet can be created with *either* an address assigned by DHCP or a static IP address. Uncomment the define line for DHCP
-//#define DHCP
-#ifdef DHCP
-EthernetNetIf eth;
-#else
-EthernetNetIf eth(
-    IpAddr(10,0,0,2), //IP Address
-    IpAddr(255,255,255,0), //Network Mask
-    IpAddr(10,0,0,1), //Gateway
-    IpAddr(10,0,0,1)  //DNS
-);
-#endif
-
-//// OSC
-
-// The object to do the work of sending and receiving
-OSCClass osc;
-
-// The message objects to send and receive with
-OSCMessage recMes;
-OSCMessage sendMes;
-
-// Setting - The port we're listening to on the mbed for OSC messages
-int  mbedListenPort  = 10000;
-
-// Setting - The address and port we're going to send to, from the mbed
-uint8_t destIp[]  = { 10, 0, 0, 1};
-int  destPort = 12000;
-
-//// mbed input
-
-DigitalIn button(p21);
-bool buttonLastState;
-
-//// Our messageReceivedCallback function
-void processOSC() {
-
-    // If this function has been called, the OSC message just received will have been parsed into our recMes OSCMessage object
-    // Note we can access recMes here, outside of the main loop, as we created it as a global variable.
-
-    // TASK: If this message one we want, do something about it.
-    // In this example we're listening for messages with a top address of "mbed".
-    // Note the strcmp function returns 0 if identical, so !strcmp is true if the two strings are the same
-    if ( !strcmp( recMes.getAddress(0) , "mbed" ) ) {
-        printf("OSC Message received addressed to mbed \r\n");
-        if ( !strcmp( recMes.getAddress(1) , "test1" ) )
-            printf("Received subAddress= test1 \r\n");
-
-        // Send some osc message:
-        sendMes.setTopAddress("/working...");
-        osc.sendOsc(&sendMes);
-    }
-}
-
-////  M A I N
-int main() {
-
-    //// TASK: Set up the Ethernet port
-    printf("Setting up ethernet...\r\n");
-    EthernetErr ethErr = eth.setup();
-    if (ethErr) {
-        printf("Ethernet Failed to setup. Error: %d\r\n", ethErr);
-        return -1;
-    }
-    printf("Ethernet OK\r\n");
-
-    //// TASK: Set up OSC message sending
-
-    // In the OSC message container we've made for send messages, set where we want it to go:
-    sendMes.setIp( destIp );
-    sendMes.setPort( destPort );
-
-    //// TASK: Set up OSC message receiving
-
-    // In the OSC send/receive object...
-    // Set the OSC message container for it to parse received messages into
-    osc.setReceiveMessage(&recMes);
-
-    // Tell it to begin listening for OSC messages at the port specified (the IP address we know already, it's the mbed's!).
-    osc.begin(mbedListenPort);
-
-    // Rather than constantly checking to see whether there are new messages waiting, the object can call some code of ours to run when a message is received.
-    // This line does that, attaching a callback function we've written before getting to this point, in this case it's called processOSC
-    // For more info how this works, see http://mbed.org/cookbook/FunctionPointer
-    osc.messageReceivedCallback.attach(&processOSC);
-
-    //// TASK: Prime button change detection
-    buttonLastState = button;
-
-    //// TASK: GO!
-
-    // We've finished setting up, now loop this forever...
-    while (true) {
-        // This polls the network connection for new activity, without keeping on calling this you won't receive any OSC!
-        Net::poll();
-
-        // Has the button changed?
-        if (button != buttonLastState) {
-            // If so, lets update the lastState variable and then send an OSC message
-            buttonLastState = button;
-            
-            sendMes.setTopAddress("/mbed");
-            sendMes.setSubAddress("/button");
-            sendMes.setArgs("i", (long)button); // The payload will be the button state as an integer, ie. 0 or 1. We need to cast to 'long' for ints (and 'double' for floats).// The payload will be the button state as an integer, ie. 0 or 1. We need to cast to 'long' for ints (and 'double' for floats).
-            osc.sendOsc(&sendMes);
-            
-            printf("Sent OSC message /mbed/button \r\n");
-        }
-
-        // ... Do whatever needs to be done by your mbed otherwise. If an OSC message is received, your messageReceivedCallback will run (in this case, processOSC()).
-    }
-}
\ No newline at end of file
--- a/OSC/mbedOSC.cpp	Mon Apr 23 09:30:50 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,401 +0,0 @@
-/*
- mbedOSC.cpp 
-*/                    
-   
-#include "mbed.h"
-#include "mbedOSC.h"
-#include "stdarg.h"
-
-OSCMessage::OSCMessage() {
- // Initialize host address and port by default (as if this where the receiver message):
- //    host=new Host(IpAddr(10, 0, 0, 1), DEFAULT_RECEIVE_PORT, NULL);
-}
-
-void OSCMessage::setPort(uint16_t _port){
-     host.setPort(_port);
-}
-
-
-void OSCMessage::setIp(uint8_t *_ip){
-    host.setIp(IpAddr(_ip[0], _ip[1], _ip[2], _ip[3]));
-}
-
-
-
-void OSCMessage::setIp(    uint8_t _ip1,
-                        uint8_t _ip2,
-                        uint8_t _ip3,
-                        uint8_t _ip4 ){
-    
-    host.setIp(IpAddr(_ip1, _ip2, _ip3, _ip4));
-}
-
-const IpAddr& OSCMessage::getIp(){
-    return host.getIp();
-}
-
-
- const int& OSCMessage::getPort(){
-    return host.getPort();
-}
-
-
-
-uint8_t    OSCMessage::getAddressNum(){
-    
-    return addressNum;
-}
-
-
-uint8_t    OSCMessage::getArgNum(){
-    
-    return argNum;
-}
-
-
-
-char * OSCMessage::getAddress(uint8_t _index){
-    if(_index>MAX_ADDRESS) _index=MAX_ADDRESS-1;
-    return address[_index];
-    
-}
-
-
-
-char * OSCMessage::getTopAddress(){
-    
-    return getAddress(0);
-    
-}
-
-
-char * OSCMessage::getSubAddress(){
-    
-    return getAddress(1);
-    
-}
-
-
-char  OSCMessage::getTypeTag(uint8_t _index){
-    if(_index>MAX_ARG) _index=MAX_ARG-1;
-    return typeTag[_index];
-}
-
-
-int32_t OSCMessage::getArgInt(uint8_t _index){
-    int32_t *value;
-    if(_index > argNum) _index=argNum;
-    value = (int32_t *)arg[_index]; // cast to int32_t
-    return *value;
-}
-
-
-double OSCMessage::getArgFloat(uint8_t _index){
-    double *value;
-    if(_index > argNum) _index=argNum;
-    value = (double *)arg[_index];
-    return *value;
-}
-
-
-void OSCMessage::setTopAddress(char *_address){
-    address[0]=_address;
-    address[1]=0;
-    addressNum=1; // Note: this "erases" the subaddress! (is this a good idea?)
-}
-
-
-void OSCMessage::setSubAddress(char *_address){
-    address[1]=_address;
-    addressNum=2; // Note: this assumes the top address was already set!
-}
-
-
-
-void OSCMessage::setAddress(char *_topAddress,char *_subAddress){
-    setTopAddress(_topAddress);
-    setSubAddress(_subAddress);
-    addressNum=2; // (unnecessary...)
-}
-
-
-void OSCMessage::setAddress(uint8_t _index, char *_address){
-    if(_index>MAX_ADDRESS) _index=MAX_ADDRESS-1;
-    address[_index]=_address;
-    addressNum=_index+1;
-}
-
-
-
-void OSCMessage::setArgs(char *types,...){
-    
-    va_list argList;
-    
-    argNum = strlen(types);
-    if(argNum>MAX_ARG) argNum=MAX_ARG-1;
-    
-    va_start( argList, types );
-    for(uint8_t i=0 ; i < argNum ; i++){
-        
-        typeTag[i]=types[i];
-        
-        switch(types[i]) {
-            case 'i':
-                arg[i]=(uint32_t *)va_arg(argList, uint32_t *);
-                break;
-            case 'f':
-                arg[i]=va_arg(argList, double *);
-                break;
-        }
-        
-    }
-    
-}
-
-// ================================================================================================================================================
-// ====================================  OSCClass for sending and receiving OSC messages using UDP protocol =======================================
-// ================================================================================================================================================
-//The class define an object wrapping the UDP functions to send and receive OSC messages
-
-OSCClass::OSCClass(){
-    udpRec.setOnEvent(this, &OSCClass::onUDPSocketEvent);
-    newMessage=false;
-}
-
-OSCClass::OSCClass(OSCMessage *_mes){
-    udpRec.setOnEvent(this, &OSCClass::onUDPSocketEvent);
-    receiverMessage = _mes; // note: receiverMessage MUST be a pointer to the message, because we will modify things in it
-    newMessage=false;
-}
-
-void OSCClass::begin()
-{    
-  // setup receiver udp socket:
-  udpRec.bind(receiverMessage->host);
-}
-
-
-void OSCClass::begin(uint16_t _recievePort)
-{
-  receiverMessage->host.setPort(_recievePort);
-  // setup receiver udp socket:
-  udpRec.bind(receiverMessage->host);
-}
-
-
-void OSCClass::setReceiveMessage(OSCMessage *_mes){
-    receiverMessage = _mes;
-}
-
-void OSCClass::onUDPSocketEvent(UDPSocketEvent e)
-{
-  switch(e)
-  {
-  case UDPSOCKET_READABLE: //The only event for now
-    //char buf[256] = {0};
-    Host auxhost;
-    buflength = udpRec.recvfrom( rcvBuff, 256, &auxhost ); // QUESTION: auxhost should be equal to the receiver host I guess...
-    if ( buflength > 0 ) {
-      //printf("\r\nFrom %d.%d.%d.%d:\r\n", host.getIp()[0], host.getIp()[1], host.getIp()[2], host.getIp()[3]);   
-      decodePacket(receiverMessage); // convert to OSC message, and save it in receiverMessage
-      newMessage=true;
-      
-      messageReceivedCallback.call();
-    }
-  break;
-  }
-}
-
-/*
- Decode UDP packet and save it in the OSCMessage structure
- */
-void OSCClass::decodePacket( OSCMessage *_mes) {
-    
-    //uint16_t    lenBuff;
-    uint8_t        d;    
-    uint8_t        messagePos=0;    
-    uint8_t        adrCount=0;
-    uint8_t        adrMesPos=0;    
-    uint8_t        packetCount=0;
-    uint8_t        packetPos=4;
-    
-    
-    //W5100.writeSn(socketNo, SnIR, SnIR::RECV);
-    //lenBuff=recvfrom(socketNo, rcvBuff, 1, receiverMessage->ip, &receiverMessage->port);    
-    
-    receiverMessage->address[0]=tempAddress[0];
-
-    //(1) address process start =========================================
-    do{
-        d=rcvBuff[messagePos];
-
-        
-        if( (d=='/') && (messagePos>0) ){
-
-            if(adrCount<MAX_ADDRESS){
-                tempAddress[adrCount][adrMesPos]=0;
-
-                adrCount++;
-                adrMesPos=0;
-
-                receiverMessage->address[adrCount]=tempAddress[adrCount];
-            }
-
-        }
-        
-        if(adrCount<MAX_ADDRESS){
-        //Added this in to remove the slashes out of final output
-        if(d!='/'){
-        tempAddress[adrCount][adrMesPos]=d;            
-    
-        if(packetCount>3)  {
-            packetCount=0;
-            packetPos+=4;
-        }
-        
-        adrMesPos++;
-        }
-        }
-        messagePos++;
-        packetCount++;
-        
-    }while(d!=0);
-
-    
-    if(adrCount<MAX_ADDRESS) adrCount++;
-    receiverMessage->addressNum=adrCount;
-    
-    messagePos=packetPos;
-
-    //(2) type tag process starts =========================================
-    packetCount=0;
-    packetPos+=4;
-
-    uint8_t  typeTagPos=0;
-    uint8_t     tempArgNum=0;
-
-    while(rcvBuff[messagePos]!=0 ){
-            
-        if(rcvBuff[messagePos] != ',') {
-        
-                if(typeTagPos<MAX_ARG){
-                    receiverMessage->typeTag[tempArgNum]=rcvBuff[messagePos];
-                    tempArgNum++;
-                }
-                typeTagPos++;
-                
-            }
-        
-        packetCount++;
-        
-        if(packetCount>3)  {
-            packetCount=0;
-            packetPos+=4;
-        }
-        
-        messagePos++;
-    }
-    
-    receiverMessage->argNum=tempArgNum;
-
-    messagePos=packetPos;
-
-    //(3) tempArg process starts =========================================
-    for(int i=0;i<tempArgNum;i++){
-        
-        adrMesPos=3;
-
-        receiverMessage->arg[i]=tempArg[i];
-    
-        for(int j=0;j<4;j++){
-
-            tempArg[i][adrMesPos]=rcvBuff[messagePos];
-
-            messagePos++;
-            adrMesPos--;
-        }
-    
-    }
-}
-
-
-
-OSCMessage * OSCClass::getMessage(){
-    newMessage=false; // this indicate the user READ the message
-    return receiverMessage;
-}
-
-
-void OSCClass::sendOsc( OSCMessage *_mes )
-{
-    uint8_t lengthEnd;
-    uint8_t lengthStart;    
-    char  buff[128];
-    
-    sendContainer = _mes;
-    
-    //&#12496;&#12483;&#12501;&#12449;&#21021;&#26399;&#20516;
-    buff[0]=0;
-    
-    //1) Add name spaces:
-    for(int i=0;i<sendContainer->addressNum;i++){
-        
-        strcat(buff,sendContainer->address[i]); // note: an address is for instance: "/test" (including the "/")
-        
-    }
-
-    // pad with 0s to align in multiples of 4:
-    lengthStart=strlen(buff);
-    lengthEnd=lengthStart+(4-(lengthStart%4));
-    for(int i=lengthStart ; i<lengthEnd; i++){
-        buff[i]=0;  
-    }
-
-    lengthStart=lengthEnd;
-    
-    //2) Add TypeTag:
-    buff[lengthEnd++]=','; // Note: type tag is for instance: ",if"
-    for(int i=0;i<sendContainer->argNum;i++){
-        buff[lengthEnd++]=sendContainer->typeTag[i];
-    }
-    
-    // pad with 0s to align in multiples of 4:
-    lengthStart=lengthEnd;
-    lengthEnd=lengthStart+(4-(lengthStart%4));
-    for(int i=lengthStart ; i<lengthEnd; i++){
-        buff[i]=0;
-    }
-    
-    //3) add argument values (Note: here only big endian):
-    uint8_t *v;
-    for(int i=0;i<sendContainer->argNum;i++){
-        uint8_t valuePos=3;
-        v=(uint8_t *)sendContainer->arg[i];
-
-        buff[lengthEnd++]=v[valuePos--];
-        buff[lengthEnd++]=v[valuePos--];
-        buff[lengthEnd++]=v[valuePos--];
-        buff[lengthEnd++]=v[valuePos]; 
-        
-    }
-    
-    //4) Send udp packet: 
-    //sendto(    socketNo, (uint8_t *)buff, lengthEnd, sendContainer->ip, sendContainer->port );
-    udpSend.sendto(buff , lengthEnd, &(sendContainer->host));
-}
-
-
-/*
- flush a receive buffer
-void OSCClass::flush() {    
-    while ( available() ){}
-}
-*/
-
-
-void OSCClass::stop() {
-    //close( socketNo );
-    udpSend.resetOnEvent(); // disables callback
-}
-
-
--- a/OSC/mbedOSC.h	Mon Apr 23 09:30:50 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,312 +0,0 @@
-/* mbed OSC Library
- This is an Open Sound Control library for the mbed, created to be compatible with Recotana's OSCClass library (http://recotana.com) for the
- Arduino with Ethernet shield. It also uses parts of the OSC Transceiver(Sender/Receiver) code by xshige
- written by: Alvaro Cassinelli, October 2011
- tweaked by: Toby Harris / *spark audio-visual, March 2012
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License version 2.1 as published by the Free Software Foundation.
- Open Sound Control  http://opensoundcontrol.org/
-*/
-
-#ifndef mbedOSC_h
-#define mbedOSC_h
-
-#include "mbed.h"
-#include "EthernetNetIf.h"
-#include "UDPSocket.h"
-
-// setup IP of destination (computer):
-#define DEFAULT_SEND_PORT 12000
-//Host sendHost(IpAddr(10, 0, 0, 1), DEFAULT_SEND_PORT, NULL); // Send Port
-// set IP of origin of UDP packets - the mbed acts as a SERVER here, and needs to bind the socket to the "client" (the computer)
-#define DEFAULT_RECEIVE_PORT 57130
-//Host recHost(IpAddr(10, 0, 0, 1), DEFAULT_RECEIVE_PORT, NULL);  // Receive Port
-//UDPSocket udpRec,udpSend;
-
-
-#define MAX_ADDRESS    2
-#define MAX_ARG        2
-
-#define TYPE_INT    1
-#define TYPE_FLOAT    2
-
-
-/** Container class for OSC messages (receiving or sending)
- @note mbedOSC version 0.1 Specification (similar to Recotana's OSCClass library)
- Example of an OSC message: "/mbed/test1, if 50 32.4"
- ie. "Address TypeTag Args"
- Address : max 2
-    "/ard"
-    "/ard/output"
-    --address[0]="/ard"       :max 15character
-    --address[1]="/output"    :max 15character
- TypeTag : max 2
-    "i" - long or unsigned long
-    "f" - double
- arg    :    max 2
- (Note: The byte string as seen here is not sent as UDP packet directly - there are no spaces, and arguments are in binary, BIG ENDIAN)
-*/
-class OSCMessage{
-    
-    private:
-    
-        char        *address[MAX_ADDRESS]; // these are strings (as char*)
-        uint8_t         addressNum; // current number of addresses in the message (ex: "/ard/test" --> the number of the addresses is 2)
-    
-        char         typeTag[MAX_ARG];
-    
-        void        *arg[MAX_ARG];
-        uint8_t         argNum;
-    
-        // Information about the connection:    
-        //uint8_t         ip[4];            
-        //uint16_t     port;
-        Host host; 
-    
-    public:
-        /** Create a container for an OSC message to be received or sent */
-        OSCMessage();
-
-        /** Return the IpAddr object */   
-        const IpAddr& getIp();
-        /** Return the port */
-        const int&     getPort();
-    
-/** Gets the address string of the OSC message
- *
- * @param[in] _index The index of the address string (byte)
- * @return pointer of the address string (char *)
- * @note ex. "/ard/test"<br>
- * getAddress(0) = "/ard"<br>
- * getAddress(1) = "/test"
- * @attention It is maximum number of the addresses is 2<br>
- * In this case "/ard/test1/test2"<br>
- * ignore it after "/test2"
- */
-        char        *getAddress(uint8_t _index);    //retturn address
-        
-/** Gets the TopAddress string of the OSC message (this is just the address with index 0)
- @return pointer of the TopAddress string (char *), i.e. address[0]
- Example: In the case "/ard/test", getTopAddress() = "/ard" (WITH the slash "/") 
- */        
-        char        *getTopAddress();    //return address[0] :"/ard"
-
-/**
- Gets the "SubAddress" string of the OSC message (this is just the address with index 1)
- @return pointer of the SubAddress string (char *), i.e. address[1]
- Example: in the case "/ard/test", getSubAddress() = "/test" (WITH the slash "/") 
- */
-        char        *getSubAddress();    //return address[1] :"/test"
-
-/**
- Gets the number of the OSC message address
- @return number of the OSC message address (byte)
- Examples: "/ard"      --> the number of the addresses is 1
-           "/ard/test" --> the number of the addresses is 2
- Attention: the maximum number of addresses is 2 (MAX_ADDRESS)
-*/
-        uint8_t         getAddressNum();    //return 2        
-    
-/**
- Gets the TypeTag string (with index) of the OSC message
- @param[in] _index The index of the TypeTag string (byte)
- @return: TypeTag char (char)
- Example: in the case of a total typetag string equal to "if", getTypeTag(0) = 'i' and getTypeTag(1) = 'f'
- Attention: MAX_ARG is maximum number of the args, if the index argument is larger, it will be constrained to this max. 
- */
-        char         getTypeTag(uint8_t _index);    //_index=0 ->'i'
-                                                    //_index=1 ->'f'
-
-/**
- Gets the number of the OSC message args
- @return number of the args (byte)
- Example: "i" 123 --> number of the OSC message args is 1
-          "if" 123 54.24 --> number of the OSC message args is 2
- Attention: the maximum number of args is 2 (MAX_ARG)
- */
-        uint8_t         getArgNum();    //return 2
-    
-/**
- Get the args of the OSC message with an integer value
- @param[in] _index An int or uint8_t corresponding to the index of the args (byte)
- @return: integer value (long, or int32_t)
- Example: in the case "if" 123 54.24, getArgInt(0) = 123
- Noe: "i" is integer, but the return type is "long"
- Note: When a index is bigger than the number of the args, it is set to the number of the args
- */
-        int32_t         getArgInt(uint8_t _index);        //_index=0 -> 123
-
-/**
- Get the args of the OSC message with a float value
- @param[in] _index The index of the args
- @return: float value (double)
- note: In this case "if" 123 54.24, getArgFloat(1) = 54.24
- attention: arg declared as float, but return value cast as "double"
- attention: When index is bigger than the number of the args, it is set to the number of the args
- */
-        double         getArgFloat(uint8_t _index);    //_index=1 -> 54.21
-    
-    
-/**
- Set TopAddress string of OSC Message 
- @param[in] _address A string pointer for the TopAddress String (char *). NOTE: is this a good idea? why not pass as const, and do allocation here?
- Example: if the complete address string is "/ard/test", we set the topaddress as follows: char top[]="/ard" (allocation done here!), then setTopAddress(top)
- */
-        void setTopAddress(char *_address);        //set address[0]
-
-/**
- Set SubAddress string of the OSC Message
- @param[in] _address A string pointer for the SubAddress String (char *)
- Example:  if the complete address string is "/ard/test", we set the subaddress as follows: char sub[]="/test" (allocation done here!), then setSubAddress(sub)
- Attention: we should call first setTopAddress, and then setSubAddress. The order is important. This does not seems like a good idea...
- */
-        void setSubAddress(char *_address);        //set address[1]
-
-/**
- Set the complete Address string of the OSC Message (top and sub addresses)
- @param[in] _topAddress, _subAddress The string pointers to top and sub addresses (char *)
- Example: in the case "/ard/test", we need to do: char top[]="/ard", char sub[]="/test", and then setAddress(top,sub)
- Reminder: in this implementation, the maximum number of addresses is MAX_ADDRESS=2
- */
-        void setAddress(char *_topAddress,     
-                        char *_subAddress);
-
-/**
- Set address string using index (here 0 or 1)
- Example: "/ard/test", char adr[]="/ard", setAddress(0,adr), char adr2[]="/test", setAddress(1,adr)
- */
-        void setAddress(uint8_t _index,        //set 0,address[0]
-                        char *_address);    
-                                            //set 1,address[1]
-
-/**
- Set IP Address of the OSC Message (for SENDING messages - for receiving this will be done when receiving something ) 
- @param[in] _ip Pointer of IP Address array (byte *)
- Example: IP=192.168.0.99, then we have to do: ip[]={192,168,0,1}, then setIp(ip)
- */    
-        void setIp( uint8_t *_ip );    //set ip
-
-/**
- Set IP Address to the OSC Message container (not through pointer)
- Example: IP=192.168.0.99 => setIp(192,168,0,99)
- */    
-        void setIp(uint8_t _ip1,    //set(192,
-                   uint8_t _ip2,    //      168,
-                   uint8_t _ip3,    //    0,
-                   uint8_t _ip4);    //    100)
-
-        /*
-         Set PortNo for the OSC Message
-         @param[in] _port PortNo (unsigned int)
-         @return None
-         */
-        void setPort( uint16_t _port );
-    
-/**
- Set TypeTag and args to the OSC Message container
- @param[in] types TypeTag string "i"(integer) or"f"(float) (char *)
- @param[in] ... Pointer of the Args(variable argument) ..
- @Example: 
- (1) integer 123: (NOTE: integers are LONG)
- long v1=123; sendMes.setArgs("i",&v1)
- (2)integer:123 and float:52.14
- long v1=123; double v2=52.14; sendMes.setArgs("if",&v1,&v2)
- Attention: in this implementation, the maximum number of the args is 2
- (if setArgs("iff",&v1,&v2,&v3), data is ignored after &v3)
- */
-        void setArgs( char *types , ... );    //set ("if",&v1,&v2)
-    
-        friend class OSCClass;
-    
-};
-
-
-
-/* ====================================  OSCClass for sending and receiving OSC messages using UDP protocol ===================================== */
-
-#include "UDPSocket.h"
-
-/** Wraps the UDP functions to send and receive OSC messages */
-class OSCClass {
-    
-private:
-    
-    UDPSocket udpRec,udpSend;
-    char   rcvBuff[256]; // raw buffer for UDP packets (udpRec.recvfrom( buf, 256, &host ) ))
-    int   buflength;
-    
-    OSCMessage *receiverMessage;
-    OSCMessage *sendContainer;
-    
-    char         tempAddress[MAX_ADDRESS][16];
-    uint8_t      tempArg[MAX_ARG][4];    
-    
-    void onUDPSocketEvent(UDPSocketEvent e);
-    
-    void decodePacket( OSCMessage *_mes); // makes OSC message from packet
-
-public:
-    
-    friend class UDPSocket;
-    
-    /** Create an object to send and receive OSC messages */
-    OSCClass();
-    
-/**
- This sets "binds" the received message to the receiver container of the communication object
- @param[in] _mes A pointer to the "receiveing" OSC message (OSCMessage *)
- */
-    OSCClass(OSCMessage *_mes); // set the receiver message container
-        
-/**
- This initializes the OSC communication object with default receiving port (DEFAULT_REC_PORT) 
- */
-    void begin();
-
-/**
- Initialize an OSC object with arbitrary listening port
- @param[in] _recievePort The listening ("receiving") Port No (unsigned int)
- */
-    void begin(uint16_t _recievePort);
-
-/**
- Stop OSC communication (in fact, only the receiver - the server side)
- */
-    void stop();
-    
-/**
- Returns whether there is new OSC data in the receiver message container.
- */
-    bool newMessage;
-
-/**
- Set a OSC receive message container
- @param[in] _mes Pointer to the OSC receive message container (OSCMessage *)
- */
-    void setReceiveMessage( OSCMessage *_mes ); //set receive OSCmessage container (note: the message has a "host" object from which we get the upd packets)
-
-/**
- Get the received OSC message (note: this is another way to access the message directly from the OSCClass object).
- The advantage is that we will signal that we read the message, and will be able to query if a NEW message arrived
- (Alternatively, one could have a function pointer to pass to the OSC object, that will be called each time a new packet is received: TO DO) 
- */
-    OSCMessage    *getMessage();    //return received OSCmessage    
-    
-/**
- Send an OSC Message (message contain the host ip and port where the message data has to be sent)
- @param[in] _mes Pointer to the OSC message container (OSCMessage *)
- */
-    void sendOsc( OSCMessage *_mes ); //set&send OSCmessage (note: it will be sent to the host defined in the message container)
-
-/**
- A function pointer to be set by host program that will be called on receipt of an OSC message
- @code
- osc.messageReceivedCallback.attach(&processOSC);
- @endcode
- */
-    FunctionPointer messageReceivedCallback;
-};
-
-#endif
--- a/PinDetect.lib	Mon Apr 23 09:30:50 2012 +0000
+++ b/PinDetect.lib	Thu Jul 19 10:46:53 2012 +0000
@@ -1,1 +1,1 @@
-http://mbed.org/users/AjK/libraries/PinDetect/lkyxpw
\ No newline at end of file
+http://mbed.org/users/AjK/code/PinDetect/#cb3afc45028b
--- a/SPK-TVOne.lib	Mon Apr 23 09:30:50 2012 +0000
+++ b/SPK-TVOne.lib	Thu Jul 19 10:46:53 2012 +0000
@@ -1,1 +1,1 @@
-http://mbed.org/users/tobyspark/libraries/SPK-TVOne/m8i0mo
\ No newline at end of file
+http://mbed.org/users/tobyspark/code/SPK-TVOne/#533cfae24a1b
--- a/mRotaryEncoder.lib	Mon Apr 23 09:30:50 2012 +0000
+++ b/mRotaryEncoder.lib	Thu Jul 19 10:46:53 2012 +0000
@@ -1,1 +1,1 @@
-http://mbed.org/users/charly/libraries/mRotaryEncoder/lmcj2u
\ No newline at end of file
+http://mbed.org/users/charly/code/mRotaryEncoder/#75ddffaf3721
--- a/main.cpp	Mon Apr 23 09:30:50 2012 +0000
+++ b/main.cpp	Thu Jul 19 10:46:53 2012 +0000
@@ -12,7 +12,9 @@
 // v13 - Menu system for Resolution + Keying implemented, it writing to debug, it sending TVOne commands - Apr'11
 // v14 - Fixes for new PCB - Oct'11
 // v15 - TBZ PCB, OLED - Mar'12
-// v16 - Comms menu, OSC. There in theory: lots of trouble from EthernetNetIf. NetServices better. But still silently crashes on creation of EthernetNetIf, despite (now) ample memory and code tested elsewhere (inc OSC + spkOLED). 
+// v16 - Comms menu, OSC, ArtNet - April'12
+// v17 - RJ45 - May'12
+// v18 - DMX - July'12
 // vxx - TODO: EDID upload from USB mass storage
 // vxx - TODO: EDID creation from resolution
 
@@ -26,14 +28,43 @@
 #include "EthernetNetIf.h"
 #include "mbedOSC.h"
 #include "DmxArtNet.h"
+#include "DMX.h"
 
 #include <sstream>
 
+// MBED PINS
+
+#define kMBED_AIN_XFADE     p20
+#define kMBED_AIN_FADEUP    p19
+#define kMBED_DIN_TAP_L     p24
+#define kMBED_DIN_TAP_R     p23
+#define kMBED_ENC_SW        p15
+#define kMBED_ENC_A         p16
+#define kMBED_ENC_B         p17
+
+#define kMBED_RS232_TTLTX   p13
+#define kMBED_RS232_TTLRX   p14
+
+#define kMBED_OLED_MOSI     p5
+#define kMBED_OLED_SCK      p7
+#define kMBED_OLED_CS       p8
+#define kMBED_OLED_RES      p9
+#define kMBED_OLED_DC       p10
+
+#define kMBED_DIN_ETHLO_DMXHI       p30
+#define kMBED_DOUT_RS485_TXHI_RXLO  p29
+#define kMBED_RS485_TTLTX           p28
+#define kMBED_RS485_TTLRX           p27
+
+// DISPLAY
+
 #define kMenuLine1 3
 #define kMenuLine2 4
 #define kCommsStatusLine 6
 #define kTVOneStatusLine 7
 
+// NETWORKING
+
 #define kOSCMbedPort 10000
 #define kOSCMbedIPAddress 10,0,0,2
 #define kOSCMbedSubnetMask 255,255,255,0
@@ -43,46 +74,61 @@
 #define kArtNetBindIPAddress 2,0,0,100
 #define kArtNetBroadcastAddress 2,255,255,255
 
+#define kDMXInChannelXFade 0
+#define kDMXInChannelFadeUp 1
+#define kDMXOutChannelXFade 0
+#define kDMXOutChannelFadeUp 1
+
 //// DEBUG
 
 // Comment out one or the other...
-Serial *debug = new Serial(USBTX, USBRX); // For debugging via USB serial
-// Serial *debug = NULL; // For release (no debugging)
+//Serial *debug = new Serial(USBTX, USBRX); // For debugging via USB serial
+Serial *debug = NULL; // For release (no debugging)
 
 //// mBED PIN ASSIGNMENTS
 
 // Inputs
-AnalogIn xFadeAIN(p20);    
-AnalogIn fadeUpAIN(p19);
-DigitalIn tapLeftDIN(p24);
-DigitalIn tapRightDIN(p23);
+AnalogIn xFadeAIN(kMBED_AIN_XFADE);    
+AnalogIn fadeUpAIN(kMBED_AIN_FADEUP);
+DigitalIn tapLeftDIN(kMBED_DIN_TAP_L);
+DigitalIn tapRightDIN(kMBED_DIN_TAP_R);
 
-SPKRotaryEncoder menuEnc(p17, p16, p15);
+SPKRotaryEncoder menuEnc(kMBED_ENC_A, kMBED_ENC_B, kMBED_ENC_SW);
+
+DigitalIn rj45ModeDIN(kMBED_DIN_ETHLO_DMXHI);
 
 // Outputs
 PwmOut fadeAPO(LED1);
 PwmOut fadeBPO(LED2);
 
+DigitalOut dmxDirectionDOUT(kMBED_DOUT_RS485_TXHI_RXLO);
+
 // SPKTVOne(PinName txPin, PinName rxPin, PinName signWritePin, PinName signErrorPin, Serial *debugSerial)
-SPKTVOne tvOne(p13, p14, LED3, LED4, debug);
+SPKTVOne tvOne(kMBED_RS232_TTLTX, kMBED_RS232_TTLRX, LED3, LED4, debug);
 
 // SPKDisplay(PinName mosi, PinName clk, PinName cs, PinName dc, PinName res, Serial *debugSerial = NULL);
-SPKDisplay screen(p5, p7, p8, p10, p9, debug);
+SPKDisplay screen(kMBED_OLED_MOSI, kMBED_OLED_SCK, kMBED_OLED_CS, kMBED_OLED_DC, kMBED_OLED_RES, debug);
 
 // Menu 
-
 SPKMenu *selectedMenu;
 SPKMenu *lastSelectedMenu;
 SPKMenuOfMenus mainMenu;
 SPKMenuPayload resolutionMenu;
 SPKMenuPayload mixModeMenu;
+enum { blend, additive, lumaKey, chromaKey1, chromaKey2, chromaKey3 }; // additive will require custom TVOne firmware.
+int mixMode = blend;
 SPKMenuPayload commsMenu;
+enum { commsNone, commsOSC, commsArtNet, commsDMXIn, commsDMXOut};
+int commsMode = commsNone;
 
-// Comms Objects
+// RJ45 Comms
+enum { rj45Ethernet = 0, rj45DMX = 1}; // These values from circuit
+int rj45Mode = -1;
 EthernetNetIf *ethernet = NULL;
 OSCClass *osc = NULL;
 OSCMessage recMessage;
 DmxArtNet *artNet = NULL;
+DMX *dmx = NULL;
 
 // Fade logic constants
 const float xFadeTolerance = 0.05;
@@ -93,8 +139,7 @@
 int fadeBPercent = 0;
 
 // Tap button states
-bool tapLeftPrevious = false;
-bool tapRightPrevious = false;
+bool tapLeftWasFirstPressed = false;
 
 // Key mode parameters
 int keyerParamsSet = -1; // last keyParams index uploaded to unit 
@@ -147,13 +192,45 @@
 
 void processArtNet(float &xFade, float &fadeUp) {
 
-
     screen.clearBufferRow(kCommsStatusLine);
     screen.textToBuffer("ArtNet activity", kCommsStatusLine);
     screen.sendBuffer();
     if (debug) debug->printf("ArtNet activity");
 }
 
+void processDMXIn(float &xFade, float &fadeUp) {
+
+    std::stringstream statusMessage;
+
+    int xFadeDMX = dmx->get(kDMXInChannelXFade);
+    int fadeUpDMX = dmx->get(kDMXInChannelXFade);
+
+    xFade = (float)xFadeDMX/255;
+    fadeUp = (float)fadeUpDMX/255;
+
+    screen.clearBufferRow(kCommsStatusLine);
+    statusMessage << "DMX In: xF " << xFadeDMX << " fUp " << fadeUpDMX;
+    screen.textToBuffer(statusMessage.str(), kCommsStatusLine);
+    screen.sendBuffer();
+    if (debug) debug->printf(statusMessage.str().c_str());
+}
+
+void processDMXOut(float &xFade, float &fadeUp) {
+
+    std::stringstream statusMessage;
+
+    int xFadeDMX = xFade*255;
+    int fadeUpDMX = fadeUp*255;
+    
+    dmx->put(kDMXOutChannelXFade, xFadeDMX);
+    dmx->put(kDMXOutChannelFadeUp, fadeUpDMX);
+    
+    screen.clearBufferRow(kCommsStatusLine);
+    statusMessage << "DMX Out: xF " << xFadeDMX << " fUp " << fadeUpDMX;
+    screen.textToBuffer(statusMessage.str(), kCommsStatusLine);
+    screen.sendBuffer();
+    if (debug) debug->printf(statusMessage.str().c_str());
+}
 
 inline float fadeCalc (const float AIN, const float tolerance) {
     float pos ;
@@ -202,11 +279,11 @@
     // Splash screen
     screen.imageToBuffer(spkDisplayLogo);
     screen.textToBuffer("SPK:D-Fuser",0);
-    screen.textToBuffer("SW beta.15",1);
+    screen.textToBuffer("SW beta.18",1);
+    screen.sendBuffer();
     
     // Set menu structure
     mixModeMenu.title = "Mix Mode";
-    enum { blend, additive, lumaKey, chromaKey1, chromaKey2, chromaKey3 }; // additive will require custom TVOne firmware.
     mixModeMenu.addMenuItem("Blend", blend, 0);
     mixModeMenu.addMenuItem("LumaKey", lumaKey, 0);
     mixModeMenu.addMenuItem("ChromaKey - Blue", chromaKey1, 0);
@@ -223,12 +300,12 @@
     resolutionMenu.addMenuItem(kTV1ResolutionDescriptionDualHeadXGAp60, kTV1ResolutionDualHeadXGAp60, 0);
     resolutionMenu.addMenuItem(kTV1ResolutionDescriptionTripleHeadVGAp60, kTV1ResolutionTripleHeadVGAp60, 0);
 
-    commsMenu.title = "Network Mode";
-    enum { commsNone, commsOSC, commsArtNet, commsDMX}; 
+    commsMenu.title = "Network Mode"; 
     commsMenu.addMenuItem("None", commsNone, 0);
     commsMenu.addMenuItem("OSC", commsOSC, 0);
     commsMenu.addMenuItem("ArtNet", commsArtNet, 0);
-    commsMenu.addMenuItem("DMX", commsDMX, 0);
+    commsMenu.addMenuItem("DMX In", commsDMXIn, 0);
+    commsMenu.addMenuItem("DMX Out", commsDMXOut, 0);
 
     mainMenu.title = "Main Menu";
     mainMenu.addMenuItem(&mixModeMenu);
@@ -278,9 +355,29 @@
     while (1) {
 
         //// Task background things
-        if (commsMenu.selectedPayload1() == commsOSC || commsMenu.selectedPayload1() == commsArtNet)
+        if (ethernet && rj45Mode == rj45Ethernet)
+        {
+            if (debug) debug->printf("net poll");
+            Net::poll();
+        }
+
+        //// RJ45 SWITCH
+        
+        if (rj45ModeDIN != rj45Mode)
         {
-            Net::poll();
+            // update state
+            rj45Mode = rj45ModeDIN;
+            if (rj45Mode == rj45Ethernet) commsMenu.title = "Network Mode [Ethernet]";
+            if (rj45Mode == rj45DMX) commsMenu.title = "Network Mode [DMX]";
+            
+            // cancel old comms
+            commsMode = commsNone;
+            commsMenu = commsMode;
+            
+            // refresh display
+            if (selectedMenu == &commsMenu) screen.textToBuffer(selectedMenu->title, kMenuLine1);
+            if (rj45Mode == rj45Ethernet) screen.textToBuffer("RJ45: Ethernet Engaged", kCommsStatusLine);
+            if (rj45Mode == rj45DMX) screen.textToBuffer("RJ45: DMX Engaged", kCommsStatusLine);
         }
 
         //// MENU
@@ -299,7 +396,6 @@
             screen.textToBuffer(selectedMenu->selectedString(), kMenuLine2);
             
             if (debug) debug->printf("%s \r\n", selectedMenu->selectedString().c_str());
-
         }
         
         // Action menu item
@@ -352,6 +448,8 @@
             // With that out of the way, we should be actioning a specific menu's payload?
             else if (selectedMenu == &mixModeMenu)
             {
+                mixMode = mixModeMenu.selectedPayload1();
+            
                 bool ok = false;
                 std::string sentOK;
                 std::stringstream sentMSG;
@@ -414,19 +512,31 @@
             }
             else if (selectedMenu == &commsMenu)
             {
-                std::string commsType = "Network: --";
+                std::string commsTypeString = "Network: --";
                 std::stringstream commsStatus;
             
                 // Tear down any existing comms
                 // This is the action of commsNone
                 // And also clears the way for other comms actions
-                if (osc) {delete osc; osc = NULL;}  
-                if (ethernet) {delete ethernet; ethernet = NULL;}
-                if (artNet) {delete artNet; artNet = NULL;}
-
-                if (commsMenu.selectedPayload1() == commsOSC) 
+                if (osc)        {delete osc; osc = NULL;}  
+                if (ethernet)   {delete ethernet; ethernet = NULL;}
+                if (artNet)     {delete artNet; artNet = NULL;}
+                if (dmx)        {delete dmx; dmx = NULL;}
+                
+                // Ensure we can't change to comms modes the hardware isn't switched to
+                if (rj45Mode == rj45DMX && (commsMenu.selectedPayload1() == commsOSC || commsMenu.selectedPayload1() == commsArtNet))
                 {
-                    commsType = "OSC: ";                    
+                    commsTypeString = "RJ45 not in Ethernet mode";
+                }
+                else if (rj45Mode == rj45Ethernet && (commsMenu.selectedPayload1() == commsDMXIn || commsMenu.selectedPayload1() == commsDMXOut))
+                {
+                    commsTypeString = "RJ45 not in DMX mode";
+                }
+                // Action!
+                else if (commsMenu.selectedPayload1() == commsOSC) 
+                {
+                    commsMode = commsOSC;
+                    commsTypeString = "OSC: ";                    
                     
                     ethernet = new EthernetNetIf(
                     IpAddr(kOSCMbedIPAddress), 
@@ -440,7 +550,7 @@
                     {
                         if (debug) debug->printf("Ethernet setup error, %d", ethError);
                         commsStatus << "Ethernet setup failed";
-                        // commsMenu = commsNone; //FIXME: this should set the selected menu item to none, but errors. wtf?
+                        commsMenu = commsNone;
                         // break out of here. this setup should be a function that returns a boolean
                     }
 
@@ -452,7 +562,8 @@
                 }
                 else if (commsMenu.selectedPayload1() == commsArtNet) 
                 {
-                    commsType = "ArtNet: ";                    
+                    commsMode = commsArtNet;
+                    commsTypeString = "ArtNet: ";                    
 
                     artNet = new DmxArtNet();
                     
@@ -470,13 +581,27 @@
                     
                     commsStatus << "Listening";
                 }
-                else if (commsMenu.selectedPayload1() == commsDMX) 
+                else if (commsMenu.selectedPayload1() == commsDMXIn) 
                 {
+                    commsMode = commsDMXIn;
+                    commsTypeString = "DMX In: ";
                     
+                    dmxDirectionDOUT = 0;
+                    
+                    dmx = new DMX(kMBED_RS485_TTLTX, kMBED_RS485_TTLRX);
                 }
-                
+                else if (commsMenu.selectedPayload1() == commsDMXOut) 
+                {
+                    commsMode = commsDMXOut;
+                    commsTypeString = "DMX Out: ";
+                    
+                    dmxDirectionDOUT = 1;
+                    
+                    dmx = new DMX(kMBED_RS485_TTLTX, kMBED_RS485_TTLRX);
+                }
+                                
                 screen.clearBufferRow(kCommsStatusLine);
-                screen.textToBuffer(commsType + commsStatus.str(), kCommsStatusLine);
+                screen.textToBuffer(commsTypeString + commsStatus.str(), kCommsStatusLine);
             }
             else
             {
@@ -486,9 +611,9 @@
         
         // Send any updates to the display
         screen.sendBuffer();
-       
+        
         
-        //// MIX MIX MIX MIX MIX MIX MIX MIX MIXMIX MIX MIXMIX MIX MIXMIX MIX MIXMIX MIX MIXMIX MIX MIX
+        //// MIX MIX MIX MIX MIX MIX MIX MIX MIX MIX MIX MIXMIX MIX MIXMIX MIX MIX MIX MIX MIXMIX MIX MIX
 
         bool updateFade = false;
         float xFade = 0;
@@ -497,32 +622,39 @@
         //// TASK: Process control surface
         
         // Get new states of tap buttons, remembering at end of loop() assign these current values to the previous variables
-        const bool tapLeft = (tapLeftDIN) ? false : true;
-        const bool tapRight = (tapRightDIN) ? false : true;
+        const bool tapLeft = !tapLeftDIN;
+        const bool tapRight = !tapRightDIN;
         
         // We're going to cache the analog in reads, as have seen wierdness otherwise
-        const float xFadeAINCached = xFadeAIN.read();
+        const float xFadeAINCached = 1-xFadeAIN.read();
         const float fadeUpAINCached = fadeUpAIN.read();
         
         // When a tap is depressed, we can ignore any move of the crossfader but not fade to black
         if (tapLeft || tapRight) 
         {
-            // If both are pressed, which was not pressed in the last loop?
+            // If both are pressed, take to the one that is new, ie. not the first pressed.
             if (tapLeft && tapRight) 
             {
-                if (!tapLeftPrevious) xFade = 0;
-                if (!tapRightPrevious) xFade = 1;
+                xFade = tapLeftWasFirstPressed ? 1 : 0;
             }
-            // If just one is pressed, is this it going high or the other going low?
-            else if (tapLeft && (!tapLeftPrevious || tapRightPrevious)) xFade = 0;
-            else if (tapRight && (!tapRightPrevious || tapLeftPrevious)) xFade = 1;
-        } 
+            // If just one is pressed, take to that and remember which is pressed
+            else if (tapLeft) 
+            {
+                xFade = 0;
+                tapLeftWasFirstPressed = 1;
+            }
+            else if (tapRight) 
+            {
+                xFade = 1;
+                tapLeftWasFirstPressed = 0;
+            }
+        }
         else xFade = fadeCalc(xFadeAINCached, xFadeTolerance);
 
         fadeUp = 1.0 - fadeCalc(fadeUpAINCached, fadeUpTolerance);
 
         //// TASK: Process Network Comms
-        if (commsMenu.selectedPayload1() == commsOSC)
+        if (commsMode == commsOSC)
         {
             if (osc->newMessage) 
             {
@@ -531,11 +663,21 @@
             }
         }
 
-        if (commsMenu.selectedPayload1() == commsArtNet)
+        if (commsMode == commsArtNet)
         {
             if (artNet->Work()) processArtNet(xFade, fadeUp);
         }
 
+        if (commsMode == commsDMXIn)
+        {
+            processDMXIn(xFade, fadeUp);
+        }
+
+        if (commsMode == commsDMXOut)
+        {
+            processDMXOut(xFade, fadeUp);
+        }
+
         // WISH: Really, we should have B at 100% and A fading in over that, with fade to black implemented as a fade in black layer on top of that correct mix.
         // There is no way to implement that though, and the alphas get messy, so this is the only way (afaik).
         
@@ -543,7 +685,7 @@
         int newFadeAPercent = 0;
         int newFadeBPercent = 0;
 
-        switch (mixModeMenu.selectedPayload1()) {
+        switch (mixMode) {
         case blend:
         case additive: 
             newFadeAPercent = (1.0-xFade) * fadeUp * 100.0;
@@ -581,9 +723,6 @@
             debug->printf("xFade = %3f   fadeUp = %3f \r\n", xFadeAINCached, fadeUpAINCached);
             debug->printf("xFade = %3f   fadeUp = %3f   fadeA% = %i   fadeB% = %i \r\n", xFade, fadeUp, fadeAPercent, fadeBPercent);
         }
-        
-        // END OF LOOP - Reset
-        tapLeftPrevious = tapLeft;
-        tapRightPrevious = tapRight;
+
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Thu Jul 19 10:46:53 2012 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/10b9abbe79a6
\ No newline at end of file
--- a/mbed.lib	Mon Apr 23 09:30:50 2012 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-http://mbed.org/projects/libraries/svn/mbed/trunk@43
\ No newline at end of file
--- a/spk_oled_ssd1305.lib	Mon Apr 23 09:30:50 2012 +0000
+++ b/spk_oled_ssd1305.lib	Thu Jul 19 10:46:53 2012 +0000
@@ -1,1 +1,1 @@
-http://mbed.org/users/tobyspark/libraries/spk_oled_ssd1305/m8i8mv
\ No newline at end of file
+http://mbed.org/users/tobyspark/code/spk_oled_ssd1305/#8187d69071f8
--- a/spk_utils.h	Mon Apr 23 09:30:50 2012 +0000
+++ b/spk_utils.h	Thu Jul 19 10:46:53 2012 +0000
@@ -67,8 +67,10 @@
     
     std::string title;
     
-    void operator = (int newIndex) {
+    // not carried into subclass... whats the c++ way of doing this?
+    SPKMenu& operator = (const int &newIndex) {
         selected = newIndex;
+        return *this;
     }
     
     void operator ++ () {
@@ -143,7 +145,13 @@
     int32_t selectedPayload2() {
         return payload2[selected.index()];
     }
-        
+    
+    SPKMenuPayload& operator = (const int &newIndex) {
+        selected = newIndex;
+        return *this;
+    }
+    
+               
 private:
     vector<int32_t> payload1;
     vector<int32_t> payload2;