PlowmanPlow

ESP8266 LED Colors

Apr 24th, 2019
108
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #include <Arduino.h>
  2. #include <ESP8266WiFi.h>
  3. #include <WiFiUdp.h>
  4. #include <stdlib.h>
  5.  
  6. #include <DNSServer.h>
  7. #include <ESP8266WebServer.h>
  8. #include <WiFiManager.h>
  9.  
  10. // The GPIO pin numbers for the three colors. Make sure these match your wiring/schematic.
  11. #define GPIO_RED 13
  12. #define GPIO_GREEN 12
  13. #define GPIO_BLUE 15
  14.  
  15. // The target ID of this device on the network if ID_SWITCHED is false
  16. // Commands sent to target ID 0 (zero) will be executed by ALL targets
  17. #define TARGET_ID_FIXED 1
  18.  
  19. // If a 4-position dip switch is present and tied to 4 GPIO pins, set ID_SWITCHED to true and put the pin numbers in the ID_BIT_? settings
  20. #define ID_SWITCHED true
  21. #define ID_BIT_0 16
  22. #define ID_BIT_1 14
  23. #define ID_BIT_2 4
  24. #define ID_BIT_3 5
  25.  
  26. // Used to turn debug serial output on/off
  27. #define DEBUG false
  28.  
  29. // UDP Command values
  30. #define CMD_OFF         0x00
  31. #define CMD_SETLEVELS   0x01
  32. #define CMD_AUTOPATTERN 0x02
  33. #define CMD_AUTODISABLE 0x03
  34.  
  35. // Auto-cycler state conditions
  36. #define AUTO_DISABLED   0x00
  37. #define AUTO_ACTIVE     0x01
  38.  
  39. // Maximum analog output level
  40. #define MAX_ANALOG 1023
  41.  
  42. // ID Numbers for the UDP Packet filter
  43. #define PACKET_FILTER_1 4039196302
  44. #define PACKET_FILTER_2 3194769291
  45.  
  46. // Set up this reference so we can put the huge array definition at the end
  47. extern const uint16_t gamma10[];
  48.  
  49. // Variables for tracking blue LED blink state during initialization
  50. volatile bool blueInitState = false;
  51. volatile unsigned long blueFlashCount;
  52.  
  53. // Struct for storing color value sets
  54. // Colors are obvious. restDuration is how long to rest on this color.
  55. struct colorTriplet {
  56.    short red;
  57.    short green;
  58.    short blue;
  59.    unsigned long restDuration;
  60.  
  61.    colorTriplet() {
  62.       red = 0;
  63.       green = 0;
  64.       blue = 0;
  65.       restDuration = 0;
  66.    }
  67. };
  68.  
  69. // This gets dynamically reset in setup() from the DIP switch or the #define at the top of the sketch so make sure this is set to 0 (zero)
  70. byte myTargetID = 0;
  71.  
  72. // Variables for keeping the state of automatic color switching
  73. byte autoMode = AUTO_DISABLED;
  74. bool autoActive = false;
  75.  
  76. // For storing automatic color values
  77. #define MAX_AUTO_COLORS 35
  78. unsigned int rampDuration;
  79. byte numAutoColors = 0;
  80. struct colorTriplet autoColors[MAX_AUTO_COLORS];
  81. byte autoColorTargetIndex = 0;
  82. short redStatic = 0;
  83. short greenStatic = 0;
  84. short blueStatic = 0;
  85. bool resting = false;
  86.  
  87. // Debugging crap
  88. String rampValues[200] = {""};
  89. int rampValuesIndex = 0;
  90.  
  91. // We're going to listen on port 6565
  92. WiFiUDP listener;
  93.  
  94. // Variables to track message IDs so we don't process duplicate messages
  95. unsigned int lastMessageID = 0;
  96. unsigned int curMessageID = 0;
  97.  
  98. // Reset function
  99. void(* resetFunc) (void) = 0;
  100.  
  101. void inline blueBlinkISR(void) {
  102.    blueInitState = !blueInitState;
  103.    if ( blueInitState ) {
  104.       analogWrite(GPIO_BLUE, 0);
  105.       blueFlashCount++;
  106.       if ( blueFlashCount >= 15 ) {
  107.          delay(60000);
  108.          resetFunc();
  109.       }
  110.    } else {
  111.       analogWrite(GPIO_BLUE, MAX_ANALOG);
  112.    }
  113.    timer0_write(ESP.getCycleCount() + 40000000);
  114. }
  115.  
  116. // Set up our initial states and WiFi
  117. void setup() {
  118.    // Set the three color PWM pins to output
  119.    pinMode(GPIO_RED, OUTPUT);
  120.    pinMode(GPIO_GREEN, OUTPUT);
  121.    pinMode(GPIO_BLUE, OUTPUT);
  122.  
  123.    // If ID_SWITCHED is true then set myTargetID from the dip switch, otherwise set it from TARGET_ID_FIXED
  124.    if ( ID_SWITCHED ) {
  125.       pinMode(ID_BIT_0, INPUT_PULLUP);
  126.       pinMode(ID_BIT_1, INPUT_PULLUP);
  127.       pinMode(ID_BIT_2, INPUT_PULLUP);
  128.       pinMode(ID_BIT_3, INPUT_PULLUP);
  129.       bitWrite(myTargetID, 0, ((digitalRead(ID_BIT_0) == HIGH) ? 1 : 0));
  130.       bitWrite(myTargetID, 1, ((digitalRead(ID_BIT_1) == HIGH) ? 1 : 0));
  131.       bitWrite(myTargetID, 2, ((digitalRead(ID_BIT_2) == HIGH) ? 1 : 0));
  132.       bitWrite(myTargetID, 3, ((digitalRead(ID_BIT_3) == HIGH) ? 1 : 0));
  133.       //pinMode(ID_BIT_1, INPUT);
  134.    } else {
  135.       myTargetID = TARGET_ID_FIXED;
  136.    }
  137.  
  138.    // Start up the serial console output
  139.    Serial.begin(115200);
  140.    Serial.println("--- Serial Output Started ---");
  141.    delay(10);
  142.  
  143.    WiFiManager wifiManager;
  144.    //wifiManager.resetSettings();
  145.    noInterrupts();
  146.    timer0_isr_init();
  147.    timer0_attachInterrupt(blueBlinkISR);
  148.    timer0_write(ESP.getCycleCount() + 1000);
  149.    interrupts();
  150.    wifiManager.autoConnect("JaJLEDController");
  151.  
  152.    // Show our ID!
  153.    Serial.println();
  154.    Serial.print("My target ID: ");
  155.    Serial.println(myTargetID);
  156.  
  157.    // Turn off blue LED and disable interrupt
  158.    timer0_detachInterrupt();
  159.    analogWrite(GPIO_BLUE, 0);
  160.  
  161.    Serial.println("");
  162.    Serial.println("WiFi connected");
  163.    Serial.println("IP address: ");
  164.    Serial.println(WiFi.localIP());
  165.  
  166.    // Start listening for packets on port 6565 (yes, this should probably be defined at the top)
  167.    listener.begin(6565);
  168. }
  169.  
  170. bool processMessage() {
  171.    struct colorTriplet colorBlank;
  172.    byte command;
  173.    uint32 messageTargetID = 0;
  174.  
  175.    // Read in the packet data to buff (up to 1024 bytes which is way more than we would ever need)
  176.    char buff[1024];
  177.    listener.read(buff, 1024);
  178.    listener.flush();
  179.  
  180.    // Check for the Packet Filter ID values and skip packet if not matched
  181.    unsigned int filter1, filter2;
  182.    memcpy(&filter1, (char*)buff, 4);
  183.    memcpy(&filter2, (char*)buff + 4, 4);
  184.    if ( (filter1 != PACKET_FILTER_1) || (filter2 != PACKET_FILTER_2) ) {
  185.       if ( DEBUG ) {
  186.          Serial.println("Filter Fail: " + String(filter1) + ", " + String(filter2));
  187.       }
  188.       return false;
  189.    }
  190.  
  191.    // Parse out the messageID field
  192.    memcpy(&curMessageID, (char*)buff + 8, 4);
  193.    // If we've seen the message before, skip it, otherwise update lastMessageID
  194.    if ( curMessageID == lastMessageID ) return false;
  195.    lastMessageID = curMessageID;
  196.  
  197.    // Parse out the command and target ID fields
  198.    memcpy(&command, (char*)buff + 12, 1);
  199.  
  200.    memcpy(&messageTargetID, (char*)buff + 13, 4);
  201.  
  202.    // If this packet isn't destined for ID=0 (all targets) or ID=TARGET_ID (our ID) then stop processing
  203.    if ( (myTargetID != 0 ) && (messageTargetID != 0) && (messageTargetID != myTargetID) ) {
  204.       if ( DEBUG ) {
  205.          Serial.println("Got packet for different ID! Mine=" + String(myTargetID) + " Target=" + String(messageTargetID));
  206.       }
  207.       return false;
  208.    }
  209.  
  210.    if ( DEBUG ) Serial.println("Got UDP packet!");
  211.  
  212.    // Clear out the global autoColors[] array
  213.    memset(autoColors, 0, sizeof(autoColors));
  214.  
  215.    // If we get a CMD_SETLEVELS then disable autoMode, set the new static values and ramp to that color
  216.    if ( command == CMD_SETLEVELS ) {
  217.       autoMode = AUTO_DISABLED;
  218.       numAutoColors = 1;
  219.       autoColorTargetIndex = 0;
  220.       memcpy(&rampDuration, (char*)buff + 17, 4);
  221.       memcpy(&autoColors[0].red, (char*)buff + 21, 1);
  222.       memcpy(&autoColors[0].green, (char*)buff + 22, 1);
  223.       memcpy(&autoColors[0].blue, (char*)buff + 23, 1);
  224.       autoColors[0].red = map(autoColors[0].red, 0, 255, 0, 1023);
  225.       autoColors[0].green = map(autoColors[0].green, 0, 255, 0, 1023);
  226.       autoColors[0].blue = map(autoColors[0].blue, 0, 255, 0, 1023);
  227.       redStatic = autoColors[0].red;
  228.       greenStatic = autoColors[0].green;
  229.       blueStatic = autoColors[0].blue;
  230.       if ( DEBUG ) {
  231.          String debugOutput = "Setting Levels: ";
  232.          debugOutput += String(redStatic) + ", ";
  233.          debugOutput += String(greenStatic) + ", ";
  234.          debugOutput += String(blueStatic) + ", ";
  235.          debugOutput += String(rampDuration);
  236.          Serial.println(debugOutput);
  237.       }
  238.       return true;
  239.    }
  240.  
  241.    // If we get a CMD_AUTOPATTERN then build up the autoColors array and set autoMode to AUTO_ACTIVE
  242.    if ( command == CMD_AUTOPATTERN ) {
  243.       String debugOutput = "";
  244.       autoMode = AUTO_ACTIVE;
  245.       autoColorTargetIndex = 0;
  246.       memcpy(&rampDuration, (char*)buff + 17, 4);
  247.       memcpy(&numAutoColors, (char*)buff + 21, 1);
  248.       if ( numAutoColors > MAX_AUTO_COLORS ) numAutoColors = MAX_AUTO_COLORS;
  249.       if ( DEBUG ) debugOutput += "New AutoPattern " + String(numAutoColors) + ": ";
  250.       for ( int i=0; i<numAutoColors; i++ ) {
  251.          memcpy(&autoColors[i].red, (char*)buff + 22 + (i*7), 1);
  252.          memcpy(&autoColors[i].green, (char*)buff + 23 + (i*7), 1);
  253.          memcpy(&autoColors[i].blue, (char*)buff + 24 + (i*7), 1);
  254.          memcpy(&autoColors[i].restDuration, (char*)buff + 25 + (i*7), 4);
  255.          autoColors[i].red = map(autoColors[i].red, 0, 255, 0, 1023);
  256.          autoColors[i].green = map(autoColors[i].green, 0, 255, 0, 1023);
  257.          autoColors[i].blue = map(autoColors[i].blue, 0, 255, 0, 1023);
  258.          if ( DEBUG ) {
  259.             debugOutput += String(i) + "=[";
  260.             debugOutput += String(autoColors[i].red) + ", ";
  261.             debugOutput += String(autoColors[i].green) + ", ";
  262.             debugOutput += String(autoColors[i].blue) + ", ";
  263.             debugOutput += String(autoColors[i].restDuration) + "], ";
  264.          }
  265.       }
  266.       if ( DEBUG ) {
  267.          debugOutput += "Ramp=" + String(rampDuration);
  268.          Serial.println(debugOutput);
  269.       }
  270.       return true;
  271.    }
  272.  
  273.    // If we get a CMD_AUTODISABLE then disable autoMode and ramp back to the last static color levels
  274.    if ( command == CMD_AUTODISABLE ) {
  275.       autoMode = AUTO_DISABLED;
  276.       numAutoColors = 1;
  277.       autoColorTargetIndex = 0;
  278.       autoColors[0].red = redStatic;
  279.       autoColors[0].green = greenStatic;
  280.       autoColors[0].blue = blueStatic;
  281.       rampDuration = 1000;
  282.       if ( DEBUG ) {
  283.          String debugOutput = "Resetting Levels to static: ";
  284.          debugOutput += String(redStatic) + ", ";
  285.          debugOutput += String(greenStatic) + ", ";
  286.          debugOutput += String(blueStatic) + ", ";
  287.          debugOutput += "Ramp=" + String(rampDuration);
  288.          Serial.println(debugOutput);
  289.       }
  290.       return true;
  291.    }
  292.  
  293.    // If we get a CMD_OFF then set the levels to zero and ensure autoMode is disabled
  294.    // The rampDuration is set to the same value as the step value during ramping (yes, this should probably be a constant or a #define)
  295.    if ( command == CMD_OFF ) {
  296.       autoMode = AUTO_DISABLED;
  297.       numAutoColors = 1;
  298.       autoColorTargetIndex = 0;
  299.       rampDuration = 10;
  300.       autoColors[0].restDuration = 10000;
  301.       redStatic = 0;
  302.       greenStatic = 0;
  303.       blueStatic = 0;
  304.       if ( DEBUG ) Serial.println("Shutting off LEDs");
  305.       return true;
  306.    }
  307.  
  308.    return false;
  309. }
  310.  
  311. void loop() {
  312.    static short redTarget = 0, greenTarget = 0, blueTarget = 0;
  313.    static short redInitial = 0, greenInitial = 0, blueInitial = 0;
  314.    static short redPrevious = 0, greenPrevious = 0, bluePrevious = 0;
  315.    static short redLevel = 0, greenLevel = 0, blueLevel = 0;
  316.    static bool newColor = false;
  317.    static unsigned long nextDIPSample = 0;
  318.    unsigned long nowMillis = millis();
  319.    static unsigned long nextRampMillis;
  320.    static unsigned long rampStartMillis;
  321.    static unsigned long restingEndMillis;
  322.    static unsigned long reportMillis = 0;
  323.    static unsigned long repCount = 0;
  324.  
  325.    if ( nowMillis >= reportMillis ) {
  326.       repCount++;
  327.       //Serial.print("Still alive... ("); Serial.print(repCount); Serial.println(")");
  328.       reportMillis = nowMillis + 1000;
  329.    }
  330.  
  331.    // Check to see if we have a new packet waiting and parse it out if we do
  332.    int packetSize = listener.parsePacket();
  333.    if ( packetSize ) {
  334.       if ( processMessage() ) {
  335.          // Always reset newColor and resting states when we get a new UDP color command
  336.          newColor = true;
  337.          resting = false;
  338.       }
  339.    }
  340.  
  341.    if ( newColor ) {
  342.       // Reset rampColors Debugging
  343.       for ( int i=0; i<200; i++ ) { rampValues[i] = ""; };
  344.       rampValuesIndex = 0;
  345.       // If the incoming auto-color pattern (from a CMD_AUTOPATTERN) has a single all zero color,
  346.       // and autoMode is AUTO_ACTIVE then generate colors randomly instead of from the pattern
  347.       if ( (autoMode == AUTO_ACTIVE) && (numAutoColors == 1) && (autoColors[0].red == 0) && (autoColors[0].green == 0) && (autoColors[0].blue == 0) ) {
  348.          //redTarget = pgm_read_word(&gamma10[random(0, MAX_ANALOG)]);
  349.          //greenTarget = pgm_read_word(&gamma10[random(0, MAX_ANALOG)]);
  350.          //blueTarget = pgm_read_word(&gamma10[random(0, MAX_ANALOG)]);
  351.          redTarget = gamma10[random(0, MAX_ANALOG)];
  352.          greenTarget = gamma10[random(0, MAX_ANALOG)];
  353.          blueTarget = gamma10[random(0, MAX_ANALOG)];
  354.       } else {
  355.          //redTarget = pgm_read_word(&gamma10[autoColors[autoColorTargetIndex].red]);
  356.          //greenTarget = pgm_read_word(&gamma10[autoColors[autoColorTargetIndex].green]);
  357.          //blueTarget = pgm_read_word(&gamma10[autoColors[autoColorTargetIndex].blue]);
  358.          redTarget = gamma10[autoColors[autoColorTargetIndex].red];
  359.          greenTarget = gamma10[autoColors[autoColorTargetIndex].green];
  360.          blueTarget = gamma10[autoColors[autoColorTargetIndex].blue];
  361.       }
  362.       redInitial = redLevel;
  363.       greenInitial = greenLevel;
  364.       blueInitial = blueLevel;
  365.       newColor = false;
  366.       rampStartMillis = nowMillis;
  367.       nextRampMillis = rampStartMillis;
  368.       if ( DEBUG ) {
  369.          String debugOutput = "Switching to new color: C=";
  370.          debugOutput += String(redInitial) + "," + String(greenInitial) + "," + String(blueInitial) + " ";
  371.          debugOutput += "T=" + String(redTarget) + "," + String(greenTarget) + "," + String(blueTarget) + " ";
  372.          debugOutput += "Index=" + String(autoColorTargetIndex) + " Ramp=" + String(rampDuration);
  373.          Serial.println(debugOutput);
  374.       }
  375.    }
  376.  
  377.    if ( (redLevel != redTarget) || (greenLevel != greenTarget) || (blueLevel != blueTarget) ) {
  378.       // Calculate the current rampInterval (how many milliseconds between start of ramp and now)
  379.       unsigned long rampInterval = nowMillis - rampStartMillis;
  380.  
  381.       // If nowMillis wrapped around the max INT32 we will just go straight to the last iteration of the ramp
  382.       if ( rampInterval > rampDuration ) rampInterval = rampDuration;
  383.  
  384.       // If we aren't at the target values yet, map the current number of milliseconds
  385.       // into the ramp (rampInterval) to the (color)Initial -> (color)Target values
  386.       if ( redLevel != redTarget ) {
  387.          redLevel = map(rampInterval, 0, rampDuration, redInitial, redTarget);
  388.       }
  389.       if ( greenLevel != greenTarget ) {
  390.          greenLevel = map(rampInterval, 0, rampDuration, greenInitial, greenTarget);
  391.       }
  392.       if ( blueLevel != blueTarget ) {
  393.          blueLevel = map(rampInterval, 0, rampDuration, blueInitial, blueTarget);
  394.       }
  395.       if ( (nowMillis >= nextRampMillis) || ((redLevel == redTarget) && (greenLevel == greenTarget) && (blueLevel == blueTarget)) ) {
  396.          if ( redLevel != redPrevious ) {
  397.             analogWrite(GPIO_RED, redLevel);
  398.             redPrevious = redLevel;
  399.          }
  400.          if ( greenLevel != greenPrevious ) {
  401.             analogWrite(GPIO_GREEN, greenLevel);
  402.             greenPrevious = greenLevel;
  403.          }
  404.          if ( blueLevel != bluePrevious ) {
  405.             analogWrite(GPIO_BLUE, blueLevel);
  406.             bluePrevious = blueLevel;
  407.          }
  408.          //rampValues[rampValuesIndex] = (String)"(" + (nowMillis - nextRampMillis) + "," + rampValuesIndex + ")" + "(" + redLevel + "," + greenLevel + "," + blueLevel + "),";
  409.          //rampValuesIndex++;
  410.          nextRampMillis = nowMillis + 15;
  411.       }
  412.    // If all the colors are at their targets and we aren't resting, then start resting
  413.    } else if ( !resting ) {
  414.       resting = true;
  415.       restingEndMillis = nowMillis + autoColors[autoColorTargetIndex].restDuration;
  416.       if ( DEBUG ) {
  417.          String debugOutput = "Now resting for: ";
  418.          debugOutput += String(autoColors[autoColorTargetIndex].restDuration) + " on ";
  419.          debugOutput += String(autoColorTargetIndex);
  420.          Serial.println(debugOutput);
  421.          //Serial.print("rampValues=[");
  422.          //for ( int i=0; i<rampValuesIndex; i++ ) Serial.print(rampValues[i]);
  423.          //Serial.println("]");
  424.       }
  425.    // If we are resting and the restingEndMillis passes then it is time to ramp to
  426.    // the next color IF AND ONLY IF we are in a pattern (i.e. don't keep ramping if we're on a static color)
  427.    } else if ( (nowMillis >= restingEndMillis) && (autoMode == AUTO_ACTIVE) ) {
  428.       resting = false;
  429.       newColor = true;
  430.       autoColorTargetIndex = (autoColorTargetIndex < (numAutoColors - 1)) ? autoColorTargetIndex + 1 : 0;
  431.    }
  432.  
  433.    // If the DIP switches change, go ahead and adjust myTargetID accordingly. Saves having to restart.
  434.    // In order to save clock cycles this is only done every 10 seconds.
  435.    if ( ID_SWITCHED && (nowMillis >= nextDIPSample) ) {
  436.       byte newVal = 0;
  437.       bitWrite(newVal, 0, ((digitalRead(ID_BIT_0) == HIGH) ? 1 : 0));
  438.       bitWrite(newVal, 1, ((digitalRead(ID_BIT_1) == HIGH) ? 1 : 0));
  439.       bitWrite(newVal, 2, ((digitalRead(ID_BIT_2) == HIGH) ? 1 : 0));
  440.       bitWrite(newVal, 3, ((digitalRead(ID_BIT_3) == HIGH) ? 1 : 0));
  441.       if ( myTargetID != newVal ) {
  442.          myTargetID = newVal;
  443.          if ( DEBUG ) {
  444.             Serial.println("BIT_0: " + String(digitalRead(ID_BIT_0)));
  445.             Serial.println("BIT_1: " + String(digitalRead(ID_BIT_1)));
  446.             Serial.println("BIT_2: " + String(digitalRead(ID_BIT_2)));
  447.             Serial.println("BIT_3: " + String(digitalRead(ID_BIT_3)));
  448.             Serial.println("New Target ID Detected: " + String(myTargetID));
  449.          }
  450.       }
  451.       nextDIPSample = nowMillis + 10000; // Sample the DIP switches every 10 seconds
  452.    }
  453.  
  454.    yield();
  455. }
  456.  
  457. //const uint16_t PROGMEM gamma10[] {
  458. const uint16_t gamma10[] {
  459. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  460. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  461. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  462. 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
  463. 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,
  464. 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  465. 1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,
  466. 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
  467. 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,
  468. 4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,
  469. 5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,
  470. 6,6,6,7,7,7,7,7,7,7,7,7,8,8,8,
  471. 8,8,8,8,8,9,9,9,9,9,9,9,9,10,10,
  472. 10,10,10,10,10,11,11,11,11,11,11,12,12,12,12,
  473. 12,12,12,13,13,13,13,13,13,14,14,14,14,14,15,
  474. 15,15,15,15,15,16,16,16,16,16,17,17,17,17,17,
  475. 18,18,18,18,18,19,19,19,19,20,20,20,20,20,21,
  476. 21,21,21,22,22,22,22,23,23,23,23,24,24,24,24,
  477. 25,25,25,25,26,26,26,26,27,27,27,27,28,28,28,
  478. 29,29,29,29,30,30,30,31,31,31,31,32,32,32,33,
  479. 33,33,34,34,34,35,35,35,35,36,36,36,37,37,37,
  480. 38,38,38,39,39,40,40,40,41,41,41,42,42,42,43,
  481. 43,43,44,44,45,45,45,46,46,46,47,47,48,48,48,
  482. 49,49,50,50,50,51,51,52,52,52,53,53,54,54,55,
  483. 55,55,56,56,57,57,58,58,58,59,59,60,60,61,61,
  484. 62,62,63,63,63,64,64,65,65,66,66,67,67,68,68,
  485. 69,69,70,70,71,71,72,72,73,73,74,74,75,75,76,
  486. 76,77,77,78,79,79,80,80,81,81,82,82,83,83,84,
  487. 85,85,86,86,87,87,88,89,89,90,90,91,92,92,93,
  488. 93,94,95,95,96,96,97,98,98,99,99,100,101,101,102,
  489. 103,103,104,105,105,106,106,107,108,108,109,110,110,111,112,
  490. 112,113,114,115,115,116,117,117,118,119,119,120,121,122,122,
  491. 123,124,124,125,126,127,127,128,129,130,130,131,132,132,133,
  492. 134,135,136,136,137,138,139,139,140,141,142,143,143,144,145,
  493. 146,146,147,148,149,150,151,151,152,153,154,155,155,156,157,
  494. 158,159,160,161,161,162,163,164,165,166,167,167,168,169,170,
  495. 171,172,173,174,175,175,176,177,178,179,180,181,182,183,184,
  496. 185,186,186,187,188,189,190,191,192,193,194,195,196,197,198,
  497. 199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,
  498. 214,215,216,217,218,219,220,221,222,223,224,225,226,228,229,
  499. 230,231,232,233,234,235,236,237,238,239,241,242,243,244,245,
  500. 246,247,248,249,251,252,253,254,255,256,257,259,260,261,262,
  501. 263,264,266,267,268,269,270,272,273,274,275,276,278,279,280,
  502. 281,282,284,285,286,287,289,290,291,292,294,295,296,297,299,
  503. 300,301,302,304,305,306,308,309,310,311,313,314,315,317,318,
  504. 319,321,322,323,325,326,327,329,330,331,333,334,336,337,338,
  505. 340,341,342,344,345,347,348,349,351,352,354,355,356,358,359,
  506. 361,362,364,365,366,368,369,371,372,374,375,377,378,380,381,
  507. 383,384,386,387,389,390,392,393,395,396,398,399,401,402,404,
  508. 405,407,408,410,412,413,415,416,418,419,421,423,424,426,427,
  509. 429,431,432,434,435,437,439,440,442,444,445,447,448,450,452,
  510. 453,455,457,458,460,462,463,465,467,468,470,472,474,475,477,
  511. 479,480,482,484,486,487,489,491,493,494,496,498,500,501,503,
  512. 505,507,509,510,512,514,516,518,519,521,523,525,527,528,530,
  513. 532,534,536,538,539,541,543,545,547,549,551,553,554,556,558,
  514. 560,562,564,566,568,570,572,574,575,577,579,581,583,585,587,
  515. 589,591,593,595,597,599,601,603,605,607,609,611,613,615,617,
  516. 619,621,623,625,627,629,631,633,635,637,640,642,644,646,648,
  517. 650,652,654,656,658,660,663,665,667,669,671,673,675,678,680,
  518. 682,684,686,688,690,693,695,697,699,701,704,706,708,710,712,
  519. 715,717,719,721,724,726,728,730,733,735,737,739,742,744,746,
  520. 749,751,753,755,758,760,762,765,767,769,772,774,776,779,781,
  521. 783,786,788,790,793,795,798,800,802,805,807,810,812,814,817,
  522. 819,822,824,827,829,831,834,836,839,841,844,846,849,851,854,
  523. 856,859,861,864,866,869,871,874,876,879,881,884,887,889,892,
  524. 894,897,899,902,905,907,910,912,915,918,920,923,925,928,931,
  525. 933,936,939,941,944,947,949,952,955,957,960,963,965,968,971,
  526. 973,976,979,982,984,987,990,992,995,998,1001,1004,1006,1009,1012,
  527. 1015,1017,1020,1023 };
RAW Paste Data