   return level;
 }
 
-
+/**
+ * CCIT CRC-32 (Autodin II) Polynomial
+ */
+uint32_t CRC32 (uint32_t crc, uint8_t *buf, uint16_t len) {
+  while (len--) {
+    crc = crc ^ *buf++;
+    for (uint8_t i = 0; i < 8; ++i) {
+      if (crc & 1) {
+        crc = (crc >>1) ^ 0xEDB88320;
+      } else {
+        crc = crc >> 1;
+      }
+    }
+  }
+}
+
+/**
+ * Calculate CRC32 for calibration data
+ */
+uint32_t calibrationCRC32 (Calibration *cal) {
+  // Non crc32 parts of calibration structure are 22 floats = 88 bytes
+  const uint8_t len = 88;
+  // Initial value for CRC
+  uint32_t crc32 = 0xFFFFFFFF;
+  // temporary data buffer
+  uint8_t buf[len]; 
+  
+  // Copy calibration data to byte array
+  memcpy(buf, cal, len);
+  
+  // Calculate CRC
+  crc32 = CRC32(crc32, buf, len);
+
+  return crc32;
+}
 
 /**
  * Internal getters and setters

// Correlated color temperature (in Kelvins)
int T_;


// Calibration coefficients with default values

// Luminous fluxes
float redLum_ = 0.5;
float greenLum_ = 1.0;
float blueLum_ = 0.75;
float maxLum_ = redLum_ + greenLum_ + blueLum_;

// LED u', v' coordinates
Luv redUv_ = {100, 0.5535, 0.5170};
Luv greenUv_ = {100, 0.0373, 0.5856};
Luv blueUv_ = {100, 0.1679, 0.1153};

// Mixing fit coefficients
float redToGreenFit_[] = {2.9658, 0.0, 1.9658};
float greenToBlueFit_[] = {1.3587, 0.0, 0.3587};
float blueToRedFit_[] = {-0.2121, 0.2121, 0.2121};



/**
 * Utility functions

  float B;
};

struct Calibration {
  // Luminous fluxes
  float redLum;
  float greenLum;
  float blueLum;
  float maxLum;
  
  // LED u', v' coordinates
  Luv redUv;
  Luv greenUv;
  Luv blueUv;
  
  // Mixing fit coefficients
  float redToGreenFit[3];
  float greenToBlueFit[3];
  float blueToRedFit[3];

  // Checksum
  uint32_t crc32;
};

// Is the light on?
bool onOff_;

// Raw PWM values
RGB raw_;
