/* * ZMHW Project: Map * * A device to give you a visual representation of what Monitors * are active in your camera network. * * SteakElectronics, December 2018 * Rare steak, well done electronics. * * Based on: telnet client * * Requires: UIPEthernet library * * Nice to haves in future: * PWM dimming, after alarms are off, so you know what was recently on. * Blinking on active alarms, instead of solid light, maybe. * Faster direct port access than digitalwrite. There are some libraries * but I don't know if they support the Mega. Instead, I'm going to rebuild the board * with a led matrix, and then use pwm pins, and I will deal with it then. * EDIT: instead maybre I'll use two 0402 resistors, and make a voltage divider, to allow for * dimmer led, with hardware instead of software. * * Troubleshooting Programming: When connecting, it can take 30-60 seconds * to speed this up, run the test suite telnet connect and it should connect * immediately after. The idea is that, it seems to connect as soon as a packet is * sent from zmtrigger. So send a test telnet packet, then it will connect after. */ /* Telnet client This sketch connects to a a telnet server (http://www.google.com) using an Arduino Wiznet Ethernet shield. You'll need a telnet server to test this with. Processing's ChatServer example (part of the network library) works well, running on port 10002. It can be found as part of the examples in the Processing application, available at http://processing.org/ Circuit: * Ethernet shield attached to pins 10, 11, 12, 13 created 14 Sep 2010 modified 9 Apr 2012 by Tom Igoe */ #include #include #define DEBUGMODE 0 // 1:on 0:off #define DEBUGMODE2 0 // Enter a MAC address and IP address for your controller below. // The IP address will be dependent on your local network: byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x41 }; IPAddress ip(192, 168, 78, 60); // Enter the IP address of the server you're connecting to: IPAddress server(192, 168, 78, 123); // Port of ZMTrigger #define ZMTRIGGERPORT 6802 // Initialize the Ethernet client library // with the IP address and port of the server // that you want to connect to (port 23 is default for telnet; // if you're using Processing's ChatServer, use port 10002): EthernetClient client; //Make a server //Not currently working. #define LISTENPORT 80 // (port 80 is default for HTTP) EthernetServer server2 = EthernetServer(LISTENPORT); //Globals char* zmtrigarray[50] = {0}; uint8_t x = 0; uint8_t y = 0; uint8_t Mon1 = 0; uint8_t Mon2 = 0; uint8_t MonFIN = 0; char mask = 0x0F; //get last nibble uint8_t Mon1Nib = Mon1 & mask; uint8_t Mon2Nib = Mon2 & mask; char on = 0b01101110; //n (ascii) char off = 0b01100110; //f (ascii) int value = 0; int ADD = 3; //We start at digital pin 4. so add 3 to everything. //e.g. Monitor 3 is digital pin 6. uint8_t NEEDCOLOUR = 0; // Simple PWM //if this is 1, bypass interrupt / softpwm, else do softpwm uint8_t BypassSoftPWM[50] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; int ledState[50] = {0}; // ledState used to set the LED #define LEDTIME 10000 // 2000 comes out to about 8 seconds uint16_t onInterval[50] = {LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME,LEDTIME}; // How long to display dimmed led uint8_t FLIP[50] = {0}; uint8_t PWMCounter = 0; uint8_t OffOverride[50] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; uint8_t OffCtr[50] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; //during interrupt, we SoftPWM any LEDs that are ready to be done so ISR(TIMER3_COMPA_vect) { for(x=1;x<51;x++){ if(BypassSoftPWM[x] == 1){ //Serial.print("Bypass activated for monitor: "); //Serial.println(x); ///FLIP[x] = 0; if(onInterval[x] == LEDTIME){ //note: These serial prints, cause delays that mess up softpwm if(DEBUGMODE){ Serial.print(F("Turning on SoftPWM for Monitor: ")); Serial.println(x); } } //turn off //might be better to do equals for all cases if(PWMCounter < 7){ digitalWrite(x + ADD, 0); } //turn on //must be after turn off, otherwise, if before, it will //immediately be turned off if(PWMCounter > 7){ digitalWrite(x + ADD, 1); PWMCounter = 0; //Serial.print(F("Dim Led #: ")); //Serial.println(x); } PWMCounter = PWMCounter + 1; //Serial.print("PWM Count is: "); //Serial.println(PWMCounter); //This is only for debug. Slows delay down. //Serial.print("oninterval is:"); //Serial.println(onInterval[x]); onInterval[x] = onInterval[x] - 1; if (onInterval[x] == 0){ BypassSoftPWM[x] = 0; //note: These serial prints, cause delays that mess up softpwm if(DEBUGMODE){ Serial.print("Turning off softPWM on Monitor: "); Serial.println(x); } digitalWrite(x + ADD, 0); onInterval[x] = LEDTIME; //no need for softpwm override OffOverride[x] = 0; OffCtr[x] = 0; } } } } //Check if any monitors that didn't get the shutdown message ISR(TIMER4_COMPA_vect) { for(x=1;x<51;x++){ if (OffOverride[x] == 1){ OffCtr[x]++; if (OffCtr[x] == 50){ OffOverride[x] = 0; OffCtr[x] = 0; digitalWrite(x + ADD, 0); Serial.print(F("Turning off due to override. Monitor #: ")); Serial.println(x); sendPixel(0,10,10); } } } } void setup() { // in case we are restarting the setup loop because we didn't connect, // we don't want timer to interfere TCCR3A = 0; TCCR3B = 0; TCNT3 = 0; //RGB LED /*define Pin 2/PE4 as output*/ /*Libraries included w/arduino IDE*/ DDRE = 0b00010000; // Open serial communications and wait for port to open: Serial.begin(9600); while (!Serial) { ; // wait for serial port to connect. Needed for native USB port only } sendPixel(10,0,0); delay(500); sendPixel(0,10,0); delay(500); sendPixel(0,0,10); Serial.println("ZMHW Project: Map"); //Using pins 4 to 49 for (x=4;x<49;x++){ pinMode(x, OUTPUT); digitalWrite(x, LOW); } // start the Ethernet connection: Ethernet.begin(mac, ip); // give the Ethernet shield a second to initialize: delay(1000); Serial.println("connecting..."); // if you get a connection, report back via serial: if (client.connect(server, ZMTRIGGERPORT)) { Serial.println("connected"); //Test all LEDs for (x=4;x<49;x++){ digitalWrite(x, HIGH); delay(50); digitalWrite(x, LOW); } } else { // if you didn't get a connection to the server: Serial.println("connection failed"); for(int err = 0; err<3;err++){ sendPixel(0,10,0); delay(100); sendPixel(0,0,0); delay(100); } } // AVR Timer CTC Interrupts Calculator // v. 8 // http://www.arduinoslovakia.eu/application/timer-calculator // Microcontroller: ATmega2560 // Created: 2019-02-02T06:08:33.492Z //dimming is buggy. doesn't quite work. //problem is viewed with a scope, the timers seem to fault //only pwming on one led occasionally //setupTimer3(); sendPixel(0,10,10); setupTimer4(); } void loop() { // if there are incoming bytes available // from the server, read them and print them: //original /*if (client.available()) { char c = client.read(); Serial.print(c); }*/ //if (client.available()) { // char* zmtrigarray = client.read(); // Serial.print(zmtrigarray); //} if (client.available()){ for(int x=0;x<40;x++){ //there are two UIPClient.ccp client.read functions. this is the 2nd zmtrigarray[x] = client.read(); if(zmtrigarray[x] == 0b00001010){ //if line break is found in telnet y = x; goto PRINT; } } PRINT: uint8_t WhereInTheWorldIsThe1stLine = 0; uint8_t WhereInTheWorldIsThe2ndLine = 0; //Serial.println("Finished reading client"); if(DEBUGMODE){ for(int x=0;x 0) { char inChar = Serial.read(); if (client.connected()) { client.print(inChar); } } // if the server's disconnected, stop the client: if (!client.connected()) { Serial.println(); Serial.println("disconnecting."); client.stop(); // do nothing: //while (true); //GREEN to RED Error for(int err = 0; err<9;err++){ sendPixel(10,0,0); delay(100); sendPixel(0,10,0); delay(100); } //start over setup(); } } uint8_t LEDAlight (int Monitor, int Switch){ //Enable or Disable GPIO based on Monitor //and Switch value digitalWrite(Monitor, Switch); if (DEBUGMODE){ Serial.print(F("LED # has been switched: ")); Serial.print(Monitor); Serial.print(F(" ")); } if(Switch == 0xFF){ if (DEBUGMODE){ Serial.println(F(" On")); } } else{ if (DEBUGMODE){ Serial.println(F(" Off")); } } } //This will fade out the LED uint8_t SoftPWM_LED_dim (uint8_t Monbitbangpwm, uint16_t *ptr, uint8_t ptrarraynum){ //arrays start at 0 ptrarraynum = ptrarraynum - 1; if(DEBUGMODE){ //check I did my pointers right... Serial.println(F("SoftPWM: ....")); Serial.print(F("Mega Pin is:")); Serial.println(Monbitbangpwm); int TempMon = Monbitbangpwm - ADD; Serial.print(F("Monitor is:")); Serial.println(TempMon); Serial.print(F("Interval from within softPWM is:")); //It's easier to understand, if you call it pass reference to pointer, not pass by reference to pointer. //aka pointer can pass value (the value of the data, but not the original data), or pass reference (a reference to the original data) //that little "by" word, makes things much more incomprehensible. for( int x = 0 ; x <= 50 ; x++ ){ Serial.println( ptr[x], HEX ); //ptr[x] = ptr[x] + 1; //looks like by default arrays pass a reference to array //no need for ptr magic // https://forum.arduino.cc/index.php?topic=42546.0 } } if(DEBUGMODE) { Serial.println( ptr[ptrarraynum], DEC ); //Now start LED dimming timer //ptr[ptrarraynum] = 200; //Serial.println( "now 200: "); //Serial.println( ptr[ptrarraynum], DEC ); } //start LED dimming timer ptr[ptrarraynum] = 2000; Serial.println( ptr[ptrarraynum], DEC ); Serial.println( ptrarraynum, DEC ); Serial.println( "Is now at what was above the num."); } //interrupt 15hz //from https://www.arduinoslovakia.eu/application/timer-calculator //would be nice if it was downloadable... void setupTimer3() { noInterrupts(); // Clear registers TCCR3A = 0; TCCR3B = 0; TCNT3 = 0; /* // 15.00060002400096 Hz (16000000/((16665+1)*64)) OCR3A = 16665; // CTC TCCR3B |= (1 << WGM32); // Prescaler 64 TCCR3B |= (1 << CS31) | (1 << CS30); // Output Compare Match A Interrupt Enable TIMSK3 |= (1 << OCIE3A); */ /* // 60.00060000600006 Hz (16000000/((33332+1)*8)) OCR3A = 33332; // CTC TCCR3B |= (1 << WGM32); // Prescaler 8 TCCR3B |= (1 << CS31); // Output Compare Match A Interrupt Enable TIMSK3 |= (1 << OCIE3A); */ // 240.00960038401536 Hz (16000000/((8332+1)*8)) OCR3A = 8332; // CTC TCCR3B |= (1 << WGM32); // Prescaler 8 TCCR3B |= (1 << CS31); // Output Compare Match A Interrupt Enable TIMSK3 |= (1 << OCIE3A); interrupts(); } //using this to count 1hz, in case any buggy reports from telnet //sometimes i see a lot of monitors light up, then immediately turn off //on telnet, so accounting for that. void setupTimer4() { noInterrupts(); // Clear registers TCCR4A = 0; TCCR4B = 0; TCNT4 = 0; // 1 Hz (16000000/((15624+1)*1024)) OCR4A = 15624; // CTC TCCR4B |= (1 << WGM42); // Prescaler 1024 TCCR4B |= (1 << CS42) | (1 << CS40); // Output Compare Match A Interrupt Enable TIMSK4 |= (1 << OCIE4A); interrupts(); } void WebServer (void){ /********************SERVER STATUS PAGE*********************/ /* * With this, you can logon to the Sensor from your LAN to find * out just what device this IP address is, in case you happen to * forget. */ //Serial.println("In server"); //Server Status Page // listen for incoming clients EthernetClient client3 = server2.available(); if (client3) { Serial.println(F("web visitor")); // an http request ends with a blank line boolean currentLineIsBlank = true; while (client3.connected()) { if (client3.available()) { char c = client3.read(); Serial.write(c); // if you've gotten to the end of the line (received a newline // character) and the line is blank, the http request has ended, // so you can send a reply if (c == '\n' && currentLineIsBlank) { // send a standard http response header client3.println("HTTP/1.1 200 OK"); client3.println("Content-Type: text/html"); client3.println(); client3.println(""); client3.println("
");
          client3.println("Steak Electronics");
          client3.println("\"Steak it One Steak at a time.\"");
          client3.println("");
          //client.println("IP Address:");
          //client.println(Ethernet.localIP());
          //client.print("Sensor Location:");
          //client.println(LOCATIONOFSENSOR);
          client3.print("Type:");
          client3.println("ZMHW Map");
          client3.print("Last Activity was Monitor: ");
          client3.println(MonFIN);
          client3.println("
"); break; } if (c == '\n') { // you're starting a new line currentLineIsBlank = true; } else if (c != '\r') { // you've gotten a character on the current line currentLineIsBlank = false; } } } // give the web browser time to receive the data delay(1); // close the connection: client.stop(); Serial.println(F("web visitor disconnected")); } } void PixZero (void){ PORTE = 0b00010000; //_delay_us(0.25); PORTE = 0x00; //_delay_us(0.25); } void PixOne (void){ PORTE = 0b00010000; //_delay_us(0.55); _delay_us(0.55); PORTE = 0x00; } void PixBit (bool res){ if (res == false){ PixZero(); } if (res == true){ PixOne(); } } void PixByte (char input){ uint8_t changer = 0; //WS2812 reads bits as left is lowest (high in first), so go backwards for(changer=8;changer>0;changer--){ PixBit(bitRead(input, changer)); //input <<= 1; //Atmega didn't like this, so instead, using changer //instead of shifting input } } void sendPixel(uint8_t g, uint8_t r, uint8_t b){ /*ws2812, reads bits left side as lowest*/ /*PixByte(0b10100000); //This is dim green PixByte(0b00000000); PixByte(0b00000000); PixByte(0b00000000); //no white on my LED*/ PixByte(g); PixByte(r); PixByte(b); //PixByte(w); PORTE = 0x00; } void PulseRGB_g (uint8_t max, uint8_t r, uint8_t b){ int rgbfunc = 0; for (rgbfunc = 0; rgbfunc < max; rgbfunc++){ sendPixel(rgbfunc,r,b); delay(22); } for (rgbfunc = max; rgbfunc > 0; rgbfunc--){ sendPixel(rgbfunc,r,b); delay(22); } } void PulseRGB_r (uint8_t max, uint8_t g, uint8_t b){ int rgbfunc = 0; for (rgbfunc = 0; rgbfunc < max; rgbfunc++){ sendPixel(g,rgbfunc, b); delay(22); } for (rgbfunc = max; rgbfunc > 0; rgbfunc--){ sendPixel(g,rgbfunc, b); delay(22); } } void PulseRGB_b (uint8_t max, uint8_t g, uint8_t r){ int rgbfunc = 0; for (rgbfunc = 0; rgbfunc < max; rgbfunc++){ sendPixel(g,r,rgbfunc); delay(22); } for (rgbfunc = max; rgbfunc > 0; rgbfunc--){ sendPixel(g,r,rgbfunc); delay(22); } }