Microcontroller Code network.h: #ifndef NETWORK #define NETWORK //network header #include "msgConstants.h" #define true 1 #define false 0 static unsigned char msg[MSGLEN]; //the message array used for received and sending messages static unsigned char nodeID; //this gets set to a unique value per network to identify that node static unsigned char nodeType; //value denotes what type of node this node is, ie master, power switch, toaster, whatever void receiveBit(); void receiveInterrupt(unsigned char receive_byte); //void resetReceive(); void transmit(); void transmitCPU(); //slightly different transmission when talking to the cpu, skips start bytes and such void transmitBit(); void transmitInterrupt(unsigned char uartType); //function holding the transmit interrupt code void setUartForTransmit(unsigned char uartType, unsigned char value); //writes to either hardware or software uart void initialize(); inline void createMsg(char command, char dest); void zeroCrossing(); //called to interpret the message after receiving unsigned char interpretMessage(); void tMaster(); void tLight(); #endif network.c: #include #include #include "network.h" #include "msgConstants.h" //#include "interpreter.h" //#include "io.h" //#define DEBUG 1 #define NUMSTARTBYTES 8 //6 the default number of start bytes in a message #define MINSTARTRECEIVE 3 //3 the number of start bytes we must receive (-1) to consider msg valid, actually 4 but first one isn't counted #define NUMHARDWARESTART 4 //the number of bytes sent including ff which are for hardware attenuation and frame alignment #define ACKDELAY 50 //the number of milliseconds waited before an ack is sent int ackTime; //the timer for counting when to send an ack unsigned char receivedMsg; #ifndef(DEBUG) #define DEBOUNCETIME 60 //number of milliseconds between debounce calls //Debounce states #define NoPush 0 #define MaybePush 1 #define Pushed 2 #define MaybeNoPush 3 unsigned char debounceState; unsigned char time1; unsigned char lastPush; unsigned char buttonPress; int sendTime; #define SENDDELAY 750 #endif unsigned char msgIndex=0; //the index into the msg unsigned char startByte_count=0; //the number of start bytes received or sent unsigned char lastReceived_byte = 0; //the last byte which we received unsigned char oldRx = 0x80; //the old value of Rx that transmit restores when finished transmitting, init to on //Dimming unsigned char dimTimer=0; unsigned char dimDelay=0; //Tracks the delay between zero crossing and when light will turn on // 0 -> fully on (no dimming) //Flags unsigned char Rx_completeF =false; unsigned char Tx_completeF =false; //Receive timeout flag nad timer //#define TIMEOUTTIME 100 //number of milliseconds between timeout //unsigned char timeoutCount = 0; //unsigned char timeoutOn = 0; /********************Software UART variables and constants *********************/ //Vars for software Rx Uart #define UART_IDLE 0 #define UART_GETDATA 1 //for 19.2k baud //OCR1AL = 52; // interrupt goes off every ~= 0.052 ms w/ prescalar 8 (what we need for 19.2 baude rate) (ends up being 14.7k) //OCR1AL = 32; // interrupt goes off every ~= .033 ms w/ prescalar 8 this is for <29.4k baud rate...slightly more than twice as fast for double samping //With Prescalar = 8, RX_COMPARENUM 27 and TX_COMPARENUM 64 #define RX_COMPARENUM 216 //value given to OCR1AL, sets how often timer1 goes off, this value is for the software receive #define TX_COMPARENUM 512 //same but for transmit // 14.29k baud???? this is pretty close to what the "14.4" pc sends at unsigned char Uart_state=0; unsigned char Uart_rxData=0; unsigned char Uart_bitCount=0; //used for sampling rate twice every cycle unsigned char Uart_oldSample=0; //saves the value of the last sampling unsigned char Uart_sampleNum=0; //tells whether we are on the first (0) or second (1) sample for the bit unsigned char Uart_failedLastMatch=0; //if this is 1 it's because the last matching of bits failed //transmit software UART #define HARD 0 #define SOFT 1 unsigned char softUDR=0; //the variable that stores the next byte that should sent ont he software UART unsigned char Uart_bitCountT=0; unsigned char soft_rxOn=1; //flag for when receive is on, when 1, receive, when 0, transmit //Timer0 interrupt interrupt [TIM0_COMP] void timer0_compare(void) { //PORTD.7 = ~PORTD.7; if(time1 > 0) time1--; //Debounce if(ackTime > 0 ) ackTime--; //Delay between receive and ack #ifndef (DEBUG) if(sendTime > 0) sendTime--; //Continious sending #endif //timeout for receiving data (hardware and software) /*if(timeoutOn && timeoutCount > 0) timeoutCount--; //we have timed out and must reset receive to its base state else if (timeoutOn && timeoutCount <= 0) { //PORTB = ~0xf0; PORTB = ~msgIndex; resetReceive(); } */ } interrupt [TIM1_COMPA] void timer1_compare(void) { TCNT1 = 0; //PORTD.7 = ~PORTD.7; //used for dimming if (nodeType == TLIGHT) { if(dimTimer > 0) dimTimer--; if(dimTimer <= 0) { //I CAN'T BELEIVE YOU JUST SPENT 2 HOURS DEBUGGING THE DIMMER WHEN YOU KNEW THIS WAS COMMENTED OUT PORTD.7 = 0; //turn on light TIMSK = TIMSK & 0b11101111; //clear bit 4 -> turn off interrupt (don't care after light is on until next zero crossing } } //used for software Uart to communicate with the comport and CPU - will use PIND.2 for software Uart RX else if (nodeType == TMASTER) { //soft_rxOn is off when we transmit because we don't need to enter receive bit if (soft_rxOn) receiveBit(); else transmitBit(); } } //code for software transmitting UART to transmit a bit inline void transmitBit() { if(Uart_bitCountT == 0) { PORTD.3 = 0; //Send the start bit Uart_bitCountT++; } else if(Uart_bitCountT <= 8) { //send the 8 data bits PORTD.3 = softUDR & 0x01; softUDR = softUDR >> 1; Uart_bitCountT++; } else { PORTD.3 = 1; //send stop bit transmitInterrupt(SOFT); Uart_bitCountT =0; } } //code for software receiving UART to receive a bit inline void receiveBit() { unsigned char Uart_RxPin; Uart_RxPin = PIND.2; //read the bit value from the pin which acts like our Uart //PORTD.7 = ~PORTD.7; //2 samples per cycle, in this case we are looking at the first sample in the bit if (Uart_sampleNum == 0) { Uart_oldSample = Uart_RxPin; Uart_sampleNum = 1; } //this is the case where the second sample in the bit didn't match the first...drop the first and treat //this as the new first and continue else if(Uart_sampleNum == 1 && Uart_oldSample != Uart_RxPin) { //if we fail twice in a row we messed up a bit, restart everything if (Uart_failedLastMatch == 1) { PORTB = ~0x88; //resetReceive(); } Uart_oldSample = Uart_RxPin; Uart_failedLastMatch = 1; } //the success case, we found two samples in a row that matched, we take the current value as the //next bit to be read in else { //reset values for double sampling algorithm Uart_oldSample = 0; Uart_sampleNum = 0; Uart_failedLastMatch = 0; if(Uart_state == UART_IDLE && Uart_RxPin==0) { //RxPin = 0 means found a start bit Uart_state = UART_GETDATA; Uart_bitCount =0; Uart_rxData = 0; } else if(Uart_state == UART_GETDATA) { if(Uart_bitCount < 8) { //not the start or stop bit -> databits Uart_rxData = Uart_rxData | (Uart_RxPin << Uart_bitCount); //shift the incoming bit into the appropriate spot Uart_bitCount++; } else { //this should be the stop bit if(Uart_RxPin == 1) { receiveInterrupt(Uart_rxData); Uart_state = UART_IDLE; Uart_bitCount=0; Uart_rxData=0; } else { //Something bad happened -> drop the data we received Uart_state = UART_IDLE; Uart_rxData = 0; Uart_bitCount =0; } } } } } //Transmit interrupt interrupt [USART_TXC] void usart_transmit(void) { transmitInterrupt(HARD); } inline void transmitInterrupt(unsigned char uartType) { //adds start bytes onto the front of the message if(receivedMsg && nodeID != MASTERNODEID) setUartForTransmit(uartType, ~STARTBYTE); //Will send startbytes during ack delay to attune receivers else{ if(startByte_count < NUMSTARTBYTES) { if(startByte_count == NUMHARDWARESTART-1) setUartForTransmit(uartType,0xff);//UDR = 0xff; //send 0xff to force frame alignment else setUartForTransmit(uartType,STARTBYTE); //UDR = STARTBYTE; startByte_count++; } //transmit next byte of msg, up to and including the stop byte! else if (msgIndex <= msg[ILENGTH] && (msgIndex < MSGLEN) && !Tx_completeF){ setUartForTransmit(uartType,msg[msgIndex]);//UDR = msg[msgIndex]; //PORTB = ~msg[msgIndex]; //msg[msgIndex] = 0; msgIndex++; } /* //Exceeded maximum message length else if(msgIndex >= 100) { //Something Bad! }*/ //transmit complete. Turn off TXC interrupt and reset counters else { msgIndex = 0; startByte_count = 0; Tx_completeF = true; if(uartType == HARD) { UCSRB = (UCSRB & 0xb7) | oldRx; //sets bit7 -> restores RXC to previous value, clears bit6 -> disables TXC interrupt and transmit UART //master must turn on hardware receive interrupt to listen for acks, don't turn on if don't plan on listening for acks if (nodeType == TMASTER) { UCSRB = UCSRB | 0x80; //turn hardware receive on so we can receive acks } } else { soft_rxOn = 1; //turn softRX back on (turns off softTX) //reset the timer1 interrupt for softRX -> goes off 2x as fast as softTX OCR1AH = (RX_COMPARENUM >> 8) & 0x00ff; OCR1AL = RX_COMPARENUM & 0x00ff; // interrupt goes off every ~= .033 ms w/ prescalar 8 this is for <29.4k baud rate...slightly more than twice as fast for double samping } } } } //called in the function above, just sets the proper thing...software or hardware UART to the value to transmit inline void setUartForTransmit(unsigned char uartType, unsigned char value) { if (uartType == HARD) UDR = value; else softUDR = value; } //called to begin transmission of msg void transmit() { oldRx = UCSRB & 0x80; //Record whether the Receiver was on or off Tx_completeF = false; msgIndex = 0; startByte_count = 1; //because we send a startbyte immediately UDR = STARTBYTE; UCSRB = UCSRB & 0x7f | 0x48; //clears bit7 -> disable RXC sets bit6 -> enables TXC interrupt and transmit UART } //called when transmitting to the CPU, transmits on software UART and skips start bytes and such void transmitCPU() { //hardware transmit instead /* PORTD.1 = 1; //sets transmit to a 1 -> not in power saving mode for cpu transmission oldRx = UCSRB & 0x80; //Record whether the Receiver was on or off Tx_completeF = false; receivedMsg = 0; //turns off received message so there is no attenuation or other bs startByte_count = NUMSTARTBYTES; //we send no start bytes when talking to the CPU msgIndex = 1; UDR = msg[0]; //I THINK you need to put something in the UDR to make sure the interrupt goes off? //PORTB = ~msg[0]; UCSRB = UCSRB & 0x7f | 0x48; //clears bit7 -> disable RXC sets bit6 -> enables TXC interrupt and transmit UART */ //software transmit UCSRB = UCSRB & 0x7f; //turn off hardware receive UART since we do not need it anymore until nextime we transmit to nodes Tx_completeF = false; receivedMsg = 0; //turns off received message so there is no attenuation or other bs startByte_count = NUMSTARTBYTES; //we send no start bytes when talking to the CPU msgIndex = 1; softUDR = msg[0]; //I THINK you need to put something in the UDR to make sure the interrupt goes off? Uart_bitCountT =0; soft_rxOn = 0; OCR1AH = (TX_COMPARENUM >> 8) & 0x00ff; OCR1AL = TX_COMPARENUM & 0x00ff; // 14.29k baud???? this is pretty close to what the "14.4" pc sends at } //Receive interrupt interrupt [USART_RXC] void usart_receive(void) { //unsigned char receive_byte; //receive_byte = UDR; //store the received byte -> UDR can only be read once per byte receiveInterrupt(UDR); } inline void receiveInterrupt(unsigned char receive_byte) { //if we haven't started receiving a message we are waiting for start bytes, and if getting them //we increment the number we have gotten if(receive_byte == STARTBYTE && lastReceived_byte == STARTBYTE && msgIndex == 0) { startByte_count++; } //if we receive a non start byte before reaching min number of sequential start bytes, we reset number of //start bytes which we have seen back to 0 -> drop this message else if(receive_byte != STARTBYTE && startByte_count < MINSTARTRECEIVE) { startByte_count = 0; } //the correct stop case, we read a message and then received a stop byte else if (startByte_count >= MINSTARTRECEIVE && receive_byte == STOPBYTE && msgIndex < MSGLEN) { //timeoutOn = 0; //turn off timeout when we have received successfully msg[msgIndex] = receive_byte; msgIndex = 0; startByte_count = 0; Rx_completeF = true; //this causes receive() to be called UCSRB = UCSRB & 0x7f; //clears bit 7 -> disable RXC interupt while we process this message } //the standard receive case, we have received ample start bytes, and are now legally receiving the message else if(startByte_count >= MINSTARTRECEIVE && msgIndex < MSGLEN ) { //timeoutCount = TIMEOUTTIME; //timeoutOn = 1; msg[msgIndex] = receive_byte; msgIndex++; } //we may exceed message length before getting STOPBYTE if we missed the stop byte, in that case we just //reset and start over else { //timeoutOn = 0; //turn off timeout since we are have no longer passed start bytes msgIndex = 0; startByte_count = 0; } lastReceived_byte = receive_byte; } //called in the case of receive failure, basically restarts everything involving receive /*inline void resetReceive() { msgIndex = 0; startByte_count = 0; UCSRB = UCSRB | 0x80; //turn on hardware receive (in case it was turned off); timeoutOn = 0; //reset all receive bit stuff Uart_state=0; Uart_rxData=0; Uart_bitCount=0; Uart_oldSample=0; Uart_sampleNum=0; Uart_failedLastMatch=0; } */ //Called when entire message has been received /*void receive(){ unsigned char success; Rx_completeF = false; success = interpretMessage(); UCSRB = UCSRB | 0x80; //sets bit 7 -> enable RXC interrupt once we have finished processing the message //transmits message if its not the master node once done dealing with the message and executing the command //this is the ack and must always occur, no matter what the command is if (success && nodeType != TMASTER) { //Build ACK msg createMsg(cAck,MASTERNODEID); transmit(); } } */ //Formats the message for sending with a command and destination, cannot handle extra data inline void createMsg(char command, char dest) { msg[ICOMMAND] = command; msg[INODEID] = dest; msg[ILENGTH] = 3; msg[3] = STOPBYTE; } #ifndef(DEBUG) //Will debounce button presses (used for debugging) void debounce() { switch(debounceState){ case NoPush: if(PINA != 0xff){ //some button has been pressed lastPush = PINA; debounceState = MaybePush; } break; case MaybePush: if(PINA == lastPush){ debounceState = Pushed; buttonPress = 1; } else { debounceState = NoPush; lastPush = 0xff; } break; case Pushed: //Button press has been detected if(PINA != lastPush) { debounceState = MaybeNoPush; } break; case MaybeNoPush: if(PINA != lastPush) { debounceState = NoPush; lastPush = 0xff; } else { debounceState = Pushed; } break; } time1 = DEBOUNCETIME; } #endif void main () { #ifndef(DEBUG) unsigned char trans = 0; unsigned char command; unsigned char sendAlways =0; unsigned char index = 0; #endif unsigned char msgSuccess = false; initialize(); command = cOn; while(1) { //if (Rx_completeF) receive(); //when a message is received, interprets the message, then waits ACKDELAY milliseconds before sending an ack //for non master node, and before being able to receive anything again if (Rx_completeF) { if (nodeType == TMASTER) { UCSRB = UCSRB & 0x7f; //turn off (redundantly) hardware receive if we are master until after we transmit to nodes } msgSuccess = interpretMessage(); Rx_completeF = false; receivedMsg = true; ackTime = ACKDELAY; //UDR = ~STARTBYTE; //UCSRB = UCSRB & 0x7f | 0x48; //Turn transmitter on to warm it up -> may help ACK get through } //after the ACKDELAY is done send ack if not master, always enable receiving again if (receivedMsg && ackTime <= 0) { receivedMsg = false; //transmits message if its not the master node once done dealing with the message and executing the command //this is the ack and must always occur, no matter what the command is //only turn back on hardware receive if you are not a master node if (nodeType != TMASTER) { UCSRB = UCSRB | 0x80; //sets bit 7 -> enable RXC interrupt once we have finished processing the message } if (msgSuccess && nodeType != TMASTER) { //Build ACK msg createMsg(cAck,MASTERNODEID); transmit(); } } #ifndef(DEBUG) //checks if a button has been pressed if(time1 <= 0) debounce(); if(sendAlways && sendTime <= 0 && nodeType == TMASTER) { if(command == cOn) command = cOff; else if(command == cOff) command = cOn; createMsg(command, INIT_NODE_ID); PORTB = ~0x00; transmit(); sendTime = SENDDELAY; } if(buttonPress && nodeType == TMASTER) { /*//lets us scroll through the msg received from cpu if (~PINA == 0x01) {PORTB = ~msg[index];index++;} else if (~PINA == 0x02) {index = 0; PORTB = ~msg[index];} buttonPress = 0; */ //Build MSG to be sent if(~PINA == 0x08) {command = cOn; trans=1;} //PORTB = ~0x0a;}//0x01; else if(~PINA == 0x04) {command = cOff; trans=1;} //PORTB = ~0xff;} else if(~PINA == 0x02) {command = cAck; trans=1;} //PORTB = ~0xa0;} else if(~PINA == 0x01) {if(sendAlways==1) sendAlways=0;else sendAlways =1;} if (trans) { createMsg(command,INIT_NODE_ID); trans=0; PORTB = ~0x00; transmit(); } //PORTB = ~0xaa; buttonPress = 0; } //Added to test the dimmer (circuit) functionality -> light on when PORTD.7 = 0; /* else if(buttonPress && nodeType != TMASTER) { if(~PINA == 0x01) {dimDelay--;} //decrease light intensity else if(~PINA == 0x02) { dimDelay++; } //PORTB = ~dimDelay; buttonPress = 0; } */ //TURN ON ZERO CROSSING FOR DIMMING!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //poll to see if a zero crossing has occurred zeroCrossing(); // else if (buttonPress && nodeType != TMASTER) { // if (~PINA == 0x01) {PORTB = ~msg[index];index++;} // else if (~PINA == 0x02) {index = 0; PORTB = ~msg[index];} // buttonPress = 0; // } #endif } } void initialize () { //nodeID = INIT_NODE_ID; nodeType = TLIGHT; nodeID = MASTERNODEID; nodeType = TMASTER; //set up the ports DDRA=0x00; //PORT A is an input for buttons and other such things DDRC=0xff; DDRD=0b10111011; // -> PIND.1 = TXD which is an output , used expressly for receiver, PIND.2 = software Uart RX DDRB=0xff; //changed from 0xff for dimmingTest PORTB=~0x0f; UCSRB = 0b10010000; //0x98 enables interrupts and Rx, use: bit7 = Rx inter enable, bit6 = Tx inter enable UCSRC = 0b01000110; //0x46 selects parity, #stop bits, and Synch modes UBRRH = 0; //4 MSB of baud rate UBRRL = 0xcf; //sets the Baud rate -> 103 = 0x67 = 4800 baud @ 8MHz 155 = 0x9b = 3600 207 = 0xcf = 2400 baud @ 8MHz 51 = 0x33 = 9600baud // 12 = 0x0c - 38.4k baud 25 = 0x19 = 19.4k baud rate 34 = 0x22 = 14.4k baud 51 = 0x33 = 9.6k baud //TIMSK = 0b00000010; //if don't want dimming TIMSK= 0b00010010; //turn on timer1A cmp match and timer 0 cmp match ISR OCR0 = 125; //set the compare rg to 4 time ticks ~= 1 ms w/ prescalar=64 TCCR0=0b00001011; //prescalar to 64 and turn on clear-on-match /******** only include for LIGHT nodes that need dimming **********/ if (nodeType == TLIGHT) { OCR1AH = 0; OCR1AL = 16; // interrupt goes off every ~= 0.125 ms w/ prescalar=64 TCCR1B=0b00000011; //prescalar to 64 dimDelay = 0; } //used for software Uart to communicate with comport to talk to CPU else if (nodeType == TMASTER) { OCR1AH = 0; //these two lines from 38.4k baud rate //OCR1AL = 208; // interrupt goes off every ~= 0.026 ms w/o prescalar (what we need for 38.4k baude rate) //TCCR1B=0b00000001; //no prescalar //for 19.2k baud //OCR1AL = 52; // interrupt goes off every ~= 0.052 ms w/ prescalar 8 (what we need for 19.2 baude rate) (ends up being 14.7k) //OCR1AL = 32; OCR1AL = RX_COMPARENUM & 0x00ff; // interrupt goes off every ~= .033 ms w/ prescalar 8 this is for <29.4k baud rate...slightly more than twice as fast for double samping OCR1AH = (RX_COMPARENUM >> 8) & 0x00ff; TCCR1B = 1; //no prescalar //TCCR1B=0b00000010; // prescalar 8 soft_rxOn=1; //initialize soft Uart to receive PORTD.3 = 1; //initializes the soft transmit UART pin to idle state PORTD.7 = 0; //initializes light to ON //TURN OFF hardware receive UART, master ONLY turns it on when listening for ack, otherwise always off UCSRB = UCSRB & 0x7f; } ackTime = 0; receivedMsg = false; sendTime = SENDDELAY; #ifndef(DEBUG) //set up timer 0 debounceState = 0; time1 = DEBOUNCETIME; lastPush = 0xff; //buttons are active low -> start off with none pressed buttonPress = 0; #endif //crank up the ISRs #asm sei #endasm } /**************************************************************************************/ //Speciality node code inline void zeroCrossing(void) { if((nodeType == TLIGHT) && (PIND.6 == 1)) { //zero crossing detected -- CHANGE TO PIND.6 FOR SOLDERED BOARDS (PIND.5 usually)!!! PORTD.7 = 1; //Turn light off dimTimer = dimDelay; TIMSK = TIMSK | 0b00010000; //turn on TIM1_COMPA interrupt } } /**************************************************************************************/ //Interpreter code //So you can see it //#define ILENGTH 0 //index storing the message length //#define INODEID 1 //index storing the distination id //#define ICOMMAND 2 //index storing the command //#define IDATA 3 //index storing the start of the data in the message //given the received message, checks that the message is valid, and if so, //passes the message to the appropriate handler //returns true if successfully interpreted the message unsigned char interpretMessage() { //these must all be true for the message to be valid, if any are not function ends //the master will accept messages not meant for it....they are probably from the cpu going to a node...should have a way to tell if from CPU or not if ((msg[INODEID] == nodeID || (msg[INODEID] != nodeID && nodeType == TMASTER)) && msg[ILENGTH] == strlen(msg) && msg[msg[ILENGTH]] == STOPBYTE) { //msg[msg[ILENGTH]-1] == STOPBYTE) { //switch on the node type to deterimine what algorithm to run switch(nodeType) { case TMASTER: tMaster(); break; case TLIGHT: tLight(); break; default: break; } return 1; } return 0; } void tMaster() { switch(msg[ICOMMAND]) { case cAck: //received an ack back PORTB = ~0xff; transmitCPU(); break; case cEcho: //receives a command and echoes it back to the PC PORTB = ~0x66; msg[INODEID] = CPUID; transmitCPU(); break; // case cRelay: //simply sends whatever is in the data portion of the command our via RF // unsigned char msgLength = msg[ILENGTH]; // break; default: //most messages are meant for someone else and should be relayed on //msg[INODEID] = INIT_NODE_ID; transmit(); PORTB = ~msg[IDATA]; if (msg[ICOMMAND] != cEcho) { PORTB = ~msg[ICOMMAND]; } break; } } //code specific to the light node type - Receiver end void tLight() { switch(msg[ICOMMAND]) { case cOn: //turn light on PORTD.7 = 0; dimDelay = 0; PORTB = ~0x83; break; case cOff: PORTD.7 = 1; dimDelay = 70; PORTB = ~0x04; break; /* case cAck: PORTB = ~0x05; break; */ case cDim: dimDelay = msg[IDATA]; break; /* case cBright: dimDelay--; break; */ default: //dimDelay=msg[ICOMMAND]-2; //msg[ICOMMAND] = 0x03; //#ifndef(DEBUG) //PORTB = ~msg[ICOMMAND]; //#endif break; } } Shared Code msgconstant.h: #ifndef MSGCONSTANTS #define MSGCONSTANTS //header containing constants shared between the cpu and network code #define MSGLEN 100 //the max length of the message #define STARTBYTE 0xaa //byte of alternating 1's and 0's #define STOPBYTE 0 //the byte representing the end of a message //no node may use id numbers 0 1 or 2, which are reserved for the stop byte, cpu, and master #define CPUID 1 //the id for the cpu itself #define MASTERNODEID 2 //the master node which atatches directly to the cpu #define INIT_NODE_ID 5 //the node id of an unitialized node //Commands enum{cOn=1, cOff, cAck, cEcho, cRelay, cDim, cBright}; //cRelay makes the master node simply transmit whatever command is storred in the data portion of the PC command //and then relay whatever ack's it receives back enum NodeType{TMASTER, TLIGHT}; #define ILENGTH 0 //index storing the message length #define INODEID 1 //index storing the distination id #define ICOMMAND 2 //index storing the command #define IDATA 3 //index storing the start of the data in the message #endif PC Code ComHandle.h #ifndef COMHANDLE #define COMHANDLE #include #include using std::cerr; /* Wrapper class for the communication's port handle, mostly to avoid a reference to Windows.com in MasterCom */ class ComHandle { public: explicit ComHandle(char * port) : handle(CreateFile(port, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, NULL)) { if (handle == INVALID_HANDLE_VALUE) { cerr << "Could not open com port, failed with error " << GetLastError() << ", exiting"; exit(2); } } HANDLE & getHandle() {return handle;} ~ComHandle() {CloseHandle(handle);} private: ComHandle(const ComHandle &rhs); //private copy constructor and = operator ComHandle& operator=(const ComHandle& rhs); HANDLE handle; //the wrapped handle }; #endif Console.c #ifndef COMHANDLE #define COMHANDLE #include #include using std::cerr; /* Wrapper class for the communication's port handle, mostly to avoid a reference to Windows.com in MasterCom */ class ComHandle { public: explicit ComHandle(char * port) : handle(CreateFile(port, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, NULL)) { if (handle == INVALID_HANDLE_VALUE) { cerr << "Could not open com port, failed with error " << GetLastError() << ", exiting"; exit(2); } } HANDLE & getHandle() {return handle;} ~ComHandle() {CloseHandle(handle);} private: ComHandle(const ComHandle &rhs); //private copy constructor and = operator ComHandle& operator=(const ComHandle& rhs); HANDLE handle; //the wrapped handle }; #endif Device.h, Device.c #include "Device.hpp" #include "MasterCom.hpp" #include "msgConstants.h" Device::Device(unsigned char id):nodeID(id) {} Device::~Device() {} //sends a command on behalf of the device and deals with the output void Device::sendCmd(string & msg) { static char ack[MSGLEN]; MasterCom::getInstance().send(msg,ack); } #ifndef DEVICE #define DEVICE #include "msgConstants.h" #include using std::string; /* Pure virtual base class for all devices, contains some basic functionality that all devices have */ class Device { public: Device(unsigned char id=INIT_NODE_ID); Device(const Device & rhs) {} //public copy constructor virtual ~Device() = 0; //virtual destructor as this is a base class unsigned char getNodeID() {return nodeID;} //& Device operator=(const &Device rhs); //public equals operator //void updateStatus(vector &); //used to update the status of the device protected: //functions void sendCmd(string & msg); //sends a command on behalf of the device protected: //variables unsigned char nodeID; //the node id of the device represented }; #endif DLight.h, DLight.c #include "DLight.hpp" #include "MasterCom.hpp" void DLight::dimLight(unsigned char value) { if (value >= 0 && value <= 100) { string msg; unsigned char dValue = 100 - value; //lower dim delays are brighter, since delay before light turns back on dimValue = value; dValue /= 2; string msgValue; msgValue += dValue; MasterCom::getInstance().createMsg(msg,msgValue,cDim,nodeID); sendCmd(msg); } } #ifndef DLIGHT #define DLIGHT #include "DOutlet.hpp" /* Class representing a light device. Includes basic on off functionality, dimming functionality, and timer functionality A DLight contains all the functionality of a DOutlet plus additional dimming functionality */ class DLight : public DOutlet { public: DLight(unsigned char id):DOutlet(id),dimValue(100) {} virtual void dimLight(unsigned char); protected: unsigned char dimValue; //the current dim value }; #endif DOutlet.h, DOutlet.c #include "DOutlet.hpp" #include "MasterCom.hpp" void DOutlet::turnOn() { string msg; MasterCom::getInstance().createMsg(msg,"",cOn,nodeID); sendCmd(msg); } void DOutlet::turnOff() { string msg; MasterCom::getInstance().createMsg(msg,"",cOff,nodeID); sendCmd(msg); } #ifndef DOUTLET #define DOUTLET /* Probably the most basic of all devices, this class represents a simple outlet. Outlets have on off functionality as well as timer functionality, that's about it. */ #include "Device.hpp" class DOutlet : public Device { public: DOutlet(unsigned char id) :Device(id), stateOn(false) {} //virtual ~DOutlet() {} virtual void turnOn(); //turns on the outlet virtual void turnOff(); //turns off the outlet protected: bool stateOn; //whether the outlet is on or off }; #endif HomeNetGUI.h, HomeNetGUI.h // HomeNetGUI.cpp : Defines the class behaviors for the application. // #include "stdafx.h" #include "HomeNetGUI.h" #include "HomeNetGUIDlg.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // CHomeNetGUIApp BEGIN_MESSAGE_MAP(CHomeNetGUIApp, CWinApp) ON_COMMAND(ID_HELP, CWinApp::OnHelp) END_MESSAGE_MAP() // CHomeNetGUIApp construction CHomeNetGUIApp::CHomeNetGUIApp() { // TODO: add construction code here, // Place all significant initialization in InitInstance } // The one and only CHomeNetGUIApp object CHomeNetGUIApp theApp; // CHomeNetGUIApp initialization BOOL CHomeNetGUIApp::InitInstance() { // InitCommonControls() is required on Windows XP if an application // manifest specifies use of ComCtl32.dll version 6 or later to enable // visual styles. Otherwise, any window creation will fail. InitCommonControls(); CWinApp::InitInstance(); // Standard initialization // If you are not using these features and wish to reduce the size // of your final executable, you should remove from the following // the specific initialization routines you do not need // Change the registry key under which our settings are stored // TODO: You should modify this string to be something appropriate // such as the name of your company or organization SetRegistryKey(_T("Local AppWizard-Generated Applications")); CHomeNetGUIDlg dlg; m_pMainWnd = &dlg; INT_PTR nResponse = dlg.DoModal(); if (nResponse == IDOK) { // TODO: Place code here to handle when the dialog is // dismissed with OK } else if (nResponse == IDCANCEL) { // TODO: Place code here to handle when the dialog is // dismissed with Cancel } // Since the dialog has been closed, return FALSE so that we exit the // application, rather than start the application's message pump. return FALSE; } // HomeNetGUI.h : main header file for the PROJECT_NAME application // #pragma once #ifndef __AFXWIN_H__ #error include 'stdafx.h' before including this file for PCH #endif #include "resource.h" // main symbols // CHomeNetGUIApp: // See HomeNetGUI.cpp for the implementation of this class // class CHomeNetGUIApp : public CWinApp { public: CHomeNetGUIApp(); // Overrides public: virtual BOOL InitInstance(); // Implementation DECLARE_MESSAGE_MAP() }; extern CHomeNetGUIApp theApp; HomeNetGUI.rc // Microsoft Visual C++ generated resource script. // #include "resource.h" #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include "afxres.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (U.S.) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) #ifdef _WIN32 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US #pragma code_page(1252) #endif //_WIN32 #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE BEGIN "resource.h\0" END 2 TEXTINCLUDE BEGIN "#include ""afxres.h""\r\n" "\0" END 3 TEXTINCLUDE BEGIN "#define _AFX_NO_SPLITTER_RESOURCES\r\n" "#define _AFX_NO_OLE_RESOURCES\r\n" "#define _AFX_NO_TRACKER_RESOURCES\r\n" "#define _AFX_NO_PROPERTY_RESOURCES\r\n" "\r\n" "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" "LANGUAGE 9, 1\r\n" "#pragma code_page(1252)\r\n" "#include ""res\\HomeNetGUI.rc2"" // non-Microsoft Visual C++ edited resources\r\n" "#include ""afxres.rc"" // Standard components\r\n" "#endif\r\n" "\0" END #endif // APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDR_MAINFRAME ICON "res\\HomeNetGUI.ico" ///////////////////////////////////////////////////////////////////////////// // // Dialog // IDD_HOMENETGUI_DIALOG DIALOGEX 0, 0, 528, 375 STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_MINIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_APPWINDOW CAPTION "HomeNet" FONT 8, "MS Shell Dlg", 0, 0, 0x1 BEGIN CONTROL "",IDC_DIMSLIDER,"msctls_trackbar32",TBS_AUTOTICKS,360, 159,79,25,WS_EX_CLIENTEDGE | WS_EX_STATICEDGE EDITTEXT IDC_DIMTEXT,360,201,27,13,ES_CENTER | ES_AUTOHSCROLL | ES_NUMBER CTEXT "HOMENET",IDC_TITLE,98,12,342,52,SS_CENTERIMAGE | SS_SUNKEN,WS_EX_STATICEDGE PUSHBUTTON "ON",IDC_BON,239,117,79,28,NOT WS_TABSTOP PUSHBUTTON "STATUS",IDC_BSTATUS,239,201,79,28,NOT WS_TABSTOP PUSHBUTTON "DIM",IDC_BDIM,360,117,79,28,NOT WS_TABSTOP PUSHBUTTON "OFF",IDC_BOFF,239,159,79,28,NOT WS_TABSTOP CONTROL "",IDC_PROGRESS1,"msctls_progress32",WS_BORDER,373,359, 152,12 COMBOBOX IDC_NODECHOICE,17,117,101,80,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL LTEXT "Welcome to HomeNet",IDC_CONSOLE,98,243,342,92,0, WS_EX_CLIENTEDGE LTEXT "Comport:",IDC_COMPORTLABLE,44,310,31,8 COMBOBOX IDC_COMSELECT,44,322,38,100,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL EDITTEXT IDC_ADDNODETEXT,448,323,27,13,ES_AUTOHSCROLL | ES_NUMBER PUSHBUTTON "Add Node",IDC_BADDNODE,480,323,42,13,NOT WS_TABSTOP LTEXT "Current Node:",IDC_NODECHOOSERTEXT,19,104,95,11 END ///////////////////////////////////////////////////////////////////////////// // // Version // VS_VERSION_INFO VERSIONINFO FILEVERSION 1,0,0,1 PRODUCTVERSION 1,0,0,1 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x4L FILETYPE 0x1L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "040904e4" BEGIN VALUE "CompanyName", "TODO: " VALUE "FileDescription", "TODO: " VALUE "FileVersion", "1.0.0.1" VALUE "InternalName", "HomeNetGUI.exe" VALUE "LegalCopyright", "TODO: (c) . All rights reserved." VALUE "OriginalFilename", "HomeNetGUI.exe" VALUE "ProductName", "TODO: " VALUE "ProductVersion", "1.0.0.1" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x409, 1252 END END ///////////////////////////////////////////////////////////////////////////// // // Menu // IDR_MENU1 MENU BEGIN POPUP "File" BEGIN MENUITEM "exit", ID_FILE_EXIT END END ///////////////////////////////////////////////////////////////////////////// // // Dialog Info // IDD_HOMENETGUI_DIALOG DLGINIT BEGIN IDC_COMSELECT, 0x403, 5, 0 0x4f43, 0x314d, "\000" IDC_COMSELECT, 0x403, 5, 0 0x4f43, 0x324d, "\000" IDC_COMSELECT, 0x403, 5, 0 0x4f43, 0x334d, "\000" IDC_COMSELECT, 0x403, 5, 0 0x4f43, 0x344d, "\000" IDC_COMSELECT, 0x403, 5, 0 0x4f43, 0x354d, "\000" IDC_COMSELECT, 0x403, 5, 0 0x4f43, 0x364d, "\000" IDC_COMSELECT, 0x403, 5, 0 0x4f43, 0x374d, "\000" IDC_COMSELECT, 0x403, 5, 0 0x4f43, 0x384d, "\000" IDC_COMSELECT, 0x403, 5, 0 0x4f43, 0x394d, "\000" 0 END #endif // English (U.S.) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // #define _AFX_NO_SPLITTER_RESOURCES #define _AFX_NO_OLE_RESOURCES #define _AFX_NO_TRACKER_RESOURCES #define _AFX_NO_PROPERTY_RESOURCES #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) LANGUAGE 9, 1 #pragma code_page(1252) #include "res\HomeNetGUI.rc2" // non-Microsoft Visual C++ edited resources #include "afxres.rc" // Standard components #endif ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED HomeNetGUIDlg.h, HomeNetGUIDlg.c // HomeNetGUIDlg.cpp : implementation file // #include "stdafx.h" #include "HomeNetGUI.h" #include "HomeNetGUIDlg.h" #include ".\homenetguidlg.h" #include "DLight.hpp" #include "MasterCom.hpp" #include "NetworkDevices.hpp" #ifdef _DEBUG #define new DEBUG_NEW #endif // CHomeNetGUIDlg dialog CHomeNetGUIDlg::CHomeNetGUIDlg(CWnd* pParent /*=NULL*/) : CDialog(CHomeNetGUIDlg::IDD, pParent), curNode(INIT_NODE_ID),titleFont(0) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CHomeNetGUIDlg::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); /*DDX_Text(pDX, IDC_DIMTEXT, dimValue); dimInt = atoi(dimValue); DDV_MaxChars(pDX, dimValue, 3); DDX_Slider(pDX, IDC_DIMSLIDER, dimInt);*/ } BEGIN_MESSAGE_MAP(CHomeNetGUIDlg, CDialog) ON_WM_PAINT() ON_WM_QUERYDRAGICON() //}}AFX_MSG_MAP ON_EN_CHANGE(IDC_DIMTEXT, OnEnChangeEdit1) ON_WM_HSCROLL() ON_BN_CLICKED(IDC_BON, OnBnClickedBon) ON_BN_CLICKED(IDC_BOFF, OnBnClickedBoff) ON_BN_CLICKED(IDC_BDIM, OnBnClickedBdim) ON_CBN_SELCHANGE(IDC_COMSELECT, OnCbnSelchangeComselect) ON_BN_CLICKED(IDC_BADDNODE, OnBnClickedBaddnode) ON_CBN_SELCHANGE(IDC_NODECHOICE, OnCbnSelchangeNodechoice) END_MESSAGE_MAP() // CHomeNetGUIDlg message handlers BOOL CHomeNetGUIDlg::OnInitDialog() { CDialog::OnInitDialog(); // Set the icon for this dialog. The framework does this automatically // when the application's main window is not a dialog SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon // TODO: Add extra initialization here //dim slider initialization CSliderCtrl * cDimSlider = static_cast(GetDlgItem(IDC_DIMSLIDER)); cDimSlider->SetTicFreq(25); cDimSlider->SetRange(0,100,true); cDimSlider->SetPos(100); //dim textbox initialization CEdit * cDimText = static_cast(GetDlgItem(IDC_DIMTEXT)); cDimText->SetLimitText(3); SetDlgItemText(IDC_DIMTEXT,"100"); //title initialization titleFont = new CFont; titleFont->CreateFont(80,0,0,0,700,0,0,0,ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,DEFAULT_PITCH|FF_DONTCARE,"times new roman"); CStatic * title = static_cast(GetDlgItem(IDC_TITLE)); title->SetFont(titleFont); //comport select initialization CComboBox * comSelect = static_cast(GetDlgItem(IDC_COMSELECT)); comSelect->SetCurSel(0); //node select drop down menu initialization { CComboBox * nodeSelect = static_cast(GetDlgItem(IDC_NODECHOICE)); nodeSelect->SetCurSel(0); char node[4]; int i = 0; NetworkDevices * devs = &NetworkDevices::getInstance(); Device * device = devs->getDeviceByList(i);; while (device) { sprintf(node,"%d",device->getNodeID()); nodeSelect->AddString(node); ++i; device = devs->getDeviceByList(i); } } return TRUE; // return TRUE unless you set the focus to a control } // If you add a minimize button to your dialog, you will need the code below // to draw the icon. For MFC applications using the document/view model, // this is automatically done for you by the framework. void CHomeNetGUIDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0); // Center icon in client rectangle int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // Draw the icon dc.DrawIcon(x, y, m_hIcon); } else { CDialog::OnPaint(); } } //this function deals with keyboard input BOOL CHomeNetGUIDlg::PreTranslateMessage(MSG* pMsg) { // TODO: Add your specialized code here and/or call the base class if(pMsg->message==WM_KEYDOWN) { if(pMsg->wParam==VK_RETURN || pMsg->wParam==VK_ESCAPE) pMsg->wParam=NULL ; } return CDialog::PreTranslateMessage(pMsg); } // The system calls this function to obtain the cursor to display while the user drags // the minimized window. HCURSOR CHomeNetGUIDlg::OnQueryDragIcon() { return static_cast(m_hIcon); } //called when a new value entered into the dim string field void CHomeNetGUIDlg::OnEnChangeEdit1() { CEdit * cDimText = static_cast(GetDlgItem(IDC_DIMTEXT)); char pos[4]; cDimText->GetLine(0,pos,3); int value = atoi(pos); //if the value is negative set it to 0 if (value < 0) { value =0; char * charValue = "0"; SetDlgItemText(IDC_DIMTEXT,charValue); } else if (value > 100) { value = 100; char * charValue = "100"; SetDlgItemText(IDC_DIMTEXT,charValue); } CSliderCtrl * pScrollBar = static_cast(GetDlgItem(IDC_DIMSLIDER)); pScrollBar->SetPos(atoi(pos)); } void CHomeNetGUIDlg::OnHScroll(UINT nSBCode,UINT nPos, CScrollBar* pScrollBar) { char value[4]; sprintf(value,"%d",((CSliderCtrl *)pScrollBar)->GetPos()); SetDlgItemText(IDC_DIMTEXT,value); } void CHomeNetGUIDlg::OnBnClickedBon() { //techincally should be a dynamic cast, not static DLight * light = static_cast(NetworkDevices::getInstance().getDevice(curNode)); if (light) { light->turnOn(); SetDlgItemText(IDC_CONSOLE,"On pressed!"); } } void CHomeNetGUIDlg::OnBnClickedBoff() { DLight * light = static_cast(NetworkDevices::getInstance().getDevice(curNode)); if (light) { light->turnOff(); SetDlgItemText(IDC_CONSOLE,"Off pressed!"); } } void CHomeNetGUIDlg::OnBnClickedBdim() { DLight * light = static_cast(NetworkDevices::getInstance().getDevice(curNode)); //retrieve the current dim setting if (light) { CSliderCtrl * pDimSlider = static_cast(GetDlgItem(IDC_DIMSLIDER)); int dimValue = pDimSlider->GetPos(); //send command //light->turnOn(); light->dimLight(dimValue); sprintf(consoleMsg, "Dim value set to %d", dimValue); SetDlgItemText(IDC_CONSOLE,consoleMsg); } } //called to select a new comport void CHomeNetGUIDlg::OnCbnSelchangeComselect() { CComboBox * comSelect = static_cast(GetDlgItem(IDC_COMSELECT)); char comport[5]; comSelect->GetLBText(comSelect->GetCurSel(),comport); string comString(comport); MasterCom::getInstance().setComPort(comString); sprintf(consoleMsg,"Comport set to %s",comport); SetDlgItemText(IDC_CONSOLE,consoleMsg); } //When this button is hit, a new node is added with the nodeID of the value in the text box next to the button void CHomeNetGUIDlg::OnBnClickedBaddnode() { CEdit * addText = static_cast(GetDlgItem(IDC_ADDNODETEXT)); char node[4]; addText->GetLine(0,node,3); unsigned char nodeID = static_cast(atoi(node)); if (nodeID >= INIT_NODE_ID && nodeID < 128) { if (NetworkDevices::getInstance().addLight(nodeID)) { //adds this node number to the drop down node choice CComboBox * nodeSelect = static_cast(GetDlgItem(IDC_NODECHOICE)); nodeSelect->AddString(node); sprintf(consoleMsg,"Successfully added a new light node with id %d",nodeID); } else sprintf(consoleMsg, "Failed to add a new light node with id %d, most likely because one with that id already exists",nodeID); } else { sprintf(consoleMsg,"Cannot add a node with id %d, please choose a number greater than %d and less than 128!",nodeID,INIT_NODE_ID-1); } SetDlgItemText(IDC_CONSOLE,consoleMsg); } //when someone chooses a different node, set current node to that void CHomeNetGUIDlg::OnCbnSelchangeNodechoice() { CComboBox * nodeSelect = static_cast(GetDlgItem(IDC_NODECHOICE)); char node[5]; nodeSelect->GetLBText(nodeSelect->GetCurSel(),node); curNode = atoi(node); sprintf(consoleMsg,"Current node is now set to %d",curNode); SetDlgItemText(IDC_CONSOLE,consoleMsg); } // HomeNetGUIDlg.h : header file // #pragma once // CHomeNetGUIDlg dialog class CHomeNetGUIDlg : public CDialog { // Construction public: CHomeNetGUIDlg(CWnd* pParent = NULL); // standard constructor ~CHomeNetGUIDlg() {delete titleFont;} // Dialog Data enum { IDD = IDD_HOMENETGUI_DIALOG }; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support // Implementation protected: HICON m_hIcon; // Generated message map functions virtual BOOL OnInitDialog(); virtual BOOL PreTranslateMessage(MSG*); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP() public: private: afx_msg void OnEnChangeEdit1(); afx_msg void OnHScroll(UINT nSBCode,UINT nPos, CScrollBar* pScrollBar); afx_msg void OnBnClickedBon(); afx_msg void OnBnClickedBoff(); afx_msg void OnBnClickedBdim(); private: int curNode; //the current node that is selected char consoleMsg[100]; //used for output to the console CFont * titleFont; //the font for the title public: afx_msg void OnCbnSelchangeComselect(); afx_msg void OnBnClickedBaddnode(); afx_msg void OnCbnSelchangeNodechoice(); }; Interpreter.h, Interpreter.c #include "Interpreter.hpp" #include "msgConstants.h" //static function for interpreting the response from the microcontroller void Interpreter::interpretResponse(char * ack, int ackSrc) { } //checks that the message is meant for here and that it is valid bool Interpreter::validateMessage(char * msg) { return msg[INODEID] == CPUID && msg[ILENGTH] == strlen(msg) && msg[msg[ILENGTH]] == STOPBYTE; } //void Interpreter::getData(char * msg, vector) { //} #ifndef INTERPRETER #define INTERPRETER #include /* Class in charge of interpreting the acknowledgements returned from the master node. This class basically makes the proper response depending on what the acknowledgement is or what it contains. */ class Interpreter { public: static void interpretResponse(char * ack, int ackSrc); //static function for interpreting the response from the microcontroller private: static bool validateMessage(char *); // static void getData(char *, vector); Interpreter() {} ~Interpreter() {} }; #endif MasterCom.h, MasterCom.c #ifndef MASTERCOM #define MASTERCOM #include "Singleton.hpp" #include //#include using std::string; class ComHandle; /* Class used for communication through the comport with the master node. This classes implementation does not matter to the rest of the program, which will always see the same public interface, no matter how the communication is handled */ class MasterCom : public Singleton { friend Singleton; public: bool send(const string & msg, char * ackMsg); //sends a message to the master node and returns the message that the master responds with void createMsg(string & msg, const string & data, char command, char dest); //used to create messages for sending void setComPort(string &port) {curComPort = port;} private: MasterCom(); //private constructor and destructor ~MasterCom(); void createComHandle(); void destroyComHandle(); //string &ack; //int msgLen[1]; ComHandle * comPort; string curComPort; //the string comport value //HANDLE handle; string startBytes; //this string holds the proper number of start bytes to send }; #endif #include "MasterCom.hpp" #include "ComHandle.hpp" #include "msgConstants.h" #include #include using std::cerr; using std::endl; using std::cin; using std::cout; #define NUMSTARTBYTES 4 bool MasterCom::send(const string & msg, char * ackArray) { static DWORD bytesInFlight = 0; bytesInFlight = 0; bool success = true; createComHandle(); //adds startbytes to the beginning of the message to make the microcontroller code happy startBytes.clear(); startBytes.reserve(NUMSTARTBYTES); startBytes.assign(NUMSTARTBYTES,STARTBYTE); cerr << startBytes.size() << endl; startBytes.append(msg); //printf("Start bytes: %x %x %x \n",startBytes[0],startBytes[1],startBytes[2]); //success = success && WriteFile(comPort->getHandle(),&startBytes, NUMSTARTBYTES, &bytesInFlight, NULL); //for (int i=0;igetHandle(),&STARTBYTE, 1, &bytesInFlight, NULL);\ //} //cerr << bytesInFlight << " is the number of start bytes sent" << endl; cerr << "bytes to be sent:" << endl; for (int i=0;igetHandle(),startBytes.c_str(), startBytes.size(), &bytesInFlight, NULL); cerr << "write file returned true?: " << success << endl; if (success && bytesInFlight == startBytes.size()) { cerr << "Successfully wrote " << bytesInFlight << " bytes to the comport" << endl; bytesInFlight = 0; //read the first character which is the length of the msg after this //unsigned char msgLen; success = success && ReadFile(comPort->getHandle(),ackArray,1,&bytesInFlight,NULL); cerr << "have we succeeded? " << success << " bytes in flight? " << bytesInFlight << " msglen: " << (int)ackArray[0] << endl; if (success && bytesInFlight == 1 && ackArray[0] > 0) { bytesInFlight = 0; //then read the proper length in and store it in the rest of ackArray success = success && ReadFile(comPort->getHandle(),ackArray+1,ackArray[0],&bytesInFlight,NULL); cerr << "bytes in flight of full read: " << bytesInFlight << endl; for (int i=0;igetHandle(),PURGE_RXCLEAR); destroyComHandle(); return false; } //Formats the message for sending with a command and destination, whatever string is passed in has the proper data prepended to it void MasterCom::createMsg(string & msg, const string & data, char command, char dest) { //cout << "Size of string to be sent without header: " << data.size() << endl; msg.clear(); //msg.resize(data.size() + 4); //4 = 1 for the stop byte + 3 for the header msg.resize(3); msg[ILENGTH] = 3+data.size(); //stop byte not included in the length msg[INODEID] = dest; msg[ICOMMAND] = command; //cout << "Message size is before: " << msg.size() << endl; msg.append(data); //msg.insert(msg.begin()+3,data.begin(),data.begin()+data.size()); //cout << "Message size is after: " << msg.size() << endl; msg.resize(msg.size()+1); msg[3+data.size()] = STOPBYTE; for (int i=0;i> comport; cout << endl; } if (baud == 0) { cout << "Please enter baud rate: "; string temp; cin >> temp; baud = atoi(temp.c_str()); cout << endl; }*/ comPort = new ComHandle(const_cast(curComPort.c_str())); //configure the connection DCB dcb; if (!GetCommState(comPort->getHandle(),&dcb)) { cerr << "Failed to read the configuration of the comport, GetCommState failed with error " << GetLastError() << endl; } dcb.BaudRate = 14400; // set the baud rate (19200) dcb.ByteSize = 8; // data size, xmit, and rcv dcb.Parity = NOPARITY; // no parity bit dcb.StopBits = ONESTOPBIT; // one stop bit if (!SetCommState(comPort->getHandle(), &dcb)) { cerr << "Failed to configure the comport, SetCommState failed with error " << GetLastError() << endl; } //set the timeout for read and write operations COMMTIMEOUTS lp; GetCommTimeouts(comPort->getHandle(),&lp); lp.ReadIntervalTimeout = 40/dcb.BaudRate; lp.ReadTotalTimeoutMultiplier = 2; lp.ReadTotalTimeoutConstant = 1000; lp.WriteTotalTimeoutMultiplier = 2; lp.WriteTotalTimeoutConstant = 1; if (!SetCommTimeouts(comPort->getHandle(),&lp)) { cerr << "Failed to configure comport, SetCommTimeouts failed with error " << GetLastError() << endl; } } void MasterCom::destroyComHandle() { delete comPort; comPort = 0; } MasterCom::MasterCom(): comPort(0), curComPort("COM1") {//,comPort(new ComHandle("COM1")) {// handle(CreateFile("COM1", GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, NULL)) {// //ack.reserve(MSGSIZE); startBytes.reserve(NUMSTARTBYTES); startBytes.assign(NUMSTARTBYTES,STARTBYTE); } MasterCom::~MasterCom() {destroyComHandle;} /*MasterCom::MasterCom() : comPort(CreateFile( com1, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0)) { if (comPort == INVALID_comPort->getHandle()_VALUE) { cerr << "Could not open com port, exiting"; exit(2); } } */ NetworkDevices.h, NetworkDevices.c #ifndef NETWORKDEVICES #define NETWORKDEVICES #include "Singleton.hpp" #include using stdext::hash_map; using namespace stdext; using namespace std; class Device; /* This class keeps an up to date record of what nodes are currently in the network. It also stores the objects representing each of the devices within the network. This class gets written to a file, storing state information from program session to session. */ class NetworkDevices : public Singleton { friend Singleton; typedef hash_map DeviceHash; typedef pair HashPair; public: bool addLight(unsigned char id); //adds a new light with id id bool addDevice(Device *); //adds a device to the collection of devices, returns true if successful Device * getDevice(unsigned char id); //returns the device with the given device id Device * getDeviceByList(int i); //returns the ith device in the hashmap private: NetworkDevices(); ~NetworkDevices(); DeviceHash devices; //the hash of all the devices on the network }; #endif #include "NetworkDevices.hpp" #include "msgConstants.h" #include "Device.hpp" #include "DLight.hpp" bool NetworkDevices::addDevice(Device * device) { return devices.insert(HashPair(device->getNodeID(),device)).second; } //returns the device with the given device id Device * NetworkDevices::getDevice(unsigned char id) { DeviceHash::iterator loc = devices.find(id); if (loc != devices.end()) { return loc->second; } else return 0; } bool NetworkDevices::addLight(unsigned char id) { DLight * light = new DLight(id); if (!addDevice(light)) { delete light; return false; } else return true; } Device * NetworkDevices::getDeviceByList(int i) { if (i < devices.size() && i >= 0) { DeviceHash::iterator it = devices.begin(); //shot me for writing this for (int j=0;jsecond; } else return 0; } /*void NetworkDevices::getFormattedDeviceList(string & deviceString) { for (DeviceHash::iterator i=devices.begin();i!=devices.end();++i) { deviceString += (i->second)->getNodeID() + ";"; } }*/ //constructor reads in saved devices from disk NetworkDevices::NetworkDevices() { } //destructor writes the current devices to disk NetworkDevices::~NetworkDevices() { //delete the network devices on exit DeviceHash::iterator k;DeviceHash::iterator j= devices.begin(); while (j != devices.end()) { k = j; ++j; delete k->second; } } resource.h //{{NO_DEPENDENCIES}} // Microsoft Visual C++ generated include file. // Used by HomeNetGUI.rc // #define IDD_HOMENETGUI_DIALOG 102 #define IDR_MAINFRAME 128 #define IDR_MENU1 129 #define IDC_DIMSLIDER 1001 #define IDC_DIMTEXT 1004 #define IDC_TITLE 1005 #define IDC_BON 1006 #define IDC_BSTATUS 1007 #define IDC_BDIM 1008 #define IDC_BOFF 1009 #define IDC_PROGRESS1 1016 #define IDC_NODECHOICE 1017 #define IDC_CONSOLE 1018 #define IDC_COMPORTLABLE 1019 #define IDC_COMSELECT 1020 #define IDC_ADDNODETEXT 1021 #define IDC_BADDNODE 1022 #define IDC_NODECHOOSERTEXT 1023 #define ID_FILE_EXIT 32771 // Next default values for new objects // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS #define _APS_NEXT_RESOURCE_VALUE 131 #define _APS_NEXT_COMMAND_VALUE 32772 #define _APS_NEXT_CONTROL_VALUE 1024 #define _APS_NEXT_SYMED_VALUE 101 #endif #endif Singleton.h #ifndef SINGLETON #define SINGLETON /* A base singleton class template, any singleton can inherit from it to gain singleton features the inheriting class must declare Singleton a friend so Singleton can instantiate the classes object This singleton class doesn't intiantiate the objects until someone calls getInstance */ template class Singleton { public: //the only way to get a reference to the singelton //will instantiate the instance the first time getInstance is called static inline T& getInstance() { static T uniqueInstance; return uniqueInstance; } protected: //static T *uniqueInstance; //the singleton object Singleton() {} //private constructor which can only be called internally virtual ~Singleton() {} //virtual destructor is private because no one is allowed to destroy the singleton publicly private: Singleton(const Singleton &rhs); //private copy constructor so no one can attempt to make a copy Singleton& operator=(const Singleton& rhs); //Singleton& operator=(const Singleton& rhs) {} //can't use = operator with a singleton }; #endif stdafx.h, stdafx.c // stdafx.h : include file for standard system include files, // or project specific include files that are used frequently, // but are changed infrequently #pragma once #ifndef VC_EXTRALEAN #define VC_EXTRALEAN // Exclude rarely-used stuff from Windows headers #endif // Modify the following defines if you have to target a platform prior to the ones specified below. // Refer to MSDN for the latest info on corresponding values for different platforms. #ifndef WINVER // Allow use of features specific to Windows 95 and Windows NT 4 or later. #define WINVER 0x0400 // Change this to the appropriate value to target Windows 98 and Windows 2000 or later. #endif #ifndef _WIN32_WINNT // Allow use of features specific to Windows NT 4 or later. #define _WIN32_WINNT 0x0400 // Change this to the appropriate value to target Windows 98 and Windows 2000 or later. #endif #ifndef _WIN32_WINDOWS // Allow use of features specific to Windows 98 or later. #define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later. #endif #ifndef _WIN32_IE // Allow use of features specific to IE 4.0 or later. #define _WIN32_IE 0x0400 // Change this to the appropriate value to target IE 5.0 or later. #endif #define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // some CString constructors will be explicit // turns off MFC's hiding of some common and often safely ignored warning messages #define _AFX_ALL_WARNINGS #include // MFC core and standard components #include // MFC extensions #include // MFC support for Internet Explorer 4 Common Controls #ifndef _AFX_NO_AFXCMN_SUPPORT #include // MFC support for Windows Common Controls #endif // _AFX_NO_AFXCMN_SUPPORT