// Construct a Packet public Packet(DateTime timestamp, ushort deviceId, byte version, ushort battery, ushort adcSample, ushort sequenceId, byte format, ushort sampleCount, DateTime rawTimestamp, int unsent, int temp, int light, int humidity, ushort[] pir, ushort[] audio, Sample[] samples, ushort parentAddress, ushort parentAltAddress) { Timestamp = timestamp; DeviceId = deviceId; Version = version; Battery = battery; AdcSample = adcSample; SequenceId = sequenceId; Format = format; SampleCount = sampleCount; RawTimestamp = rawTimestamp; Unsent = unsent; Temp = temp; Light = light; Humidity = humidity; Pir = pir; Audio = audio; Samples = samples; ParentAddress = parentAddress; ParentAltAddress = parentAltAddress; }
public void AddSamples(Sample[] samples) { UpdateTime = DateTime.UtcNow; if (samples == null || samples.Length == 0) { return; } // If the last index of the new samples is the same as the last index seen -- duplicate packet (ignore) if ((int)samples[samples.Length - 1].Index == LastIndex && LastIndex != 0) { Console.WriteLine("WARNING: Duplicate packet detected (last index: " + LastIndex + ") - ignoring."); return; } // If not a duplicate, and the first index of the new samples is earlier than the last index seen -- must be restart if ((int)samples[0].Index < LastIndex && LastIndex != 0) { // Must have re-started broadcast, clear history //if (LastIndex - (int)samples[0].Index > 20) Console.WriteLine("WARNING: Restart detected (index: " + samples[0].Index + ", last index: " + LastIndex + ") - clearing history."); Clear(); LastIndex = (int)samples[0].Index - 1; } // Calculate number of missed packets int numMissed = (int)(samples[0].Index - LastIndex - 1); if (numMissed < 0) { numMissed = 0; } if (numMissed > 1000) { numMissed = 1000; } if (numMissed > 0) { Console.WriteLine("WARNING: Dropped packet(s) detected, missing samples: " + numMissed); } // Add any missing samples Sample[] missedSamples = new Sample[numMissed]; for (int i = 0; i < missedSamples.Length; i++) { missedSamples[i] = new Sample((uint)++LastIndex); } Samples.AddRange(missedSamples); // Add samples int firstIndex = Samples.Count; int length = samples.Length; Samples.AddRange(samples); // Update last index LastIndex = (int)(Samples[Samples.Count - 1].Index); // Trim to maximum samples range if (Samples.Count > MaxHistory) { firstIndex -= Samples.Count - MaxHistory; if (firstIndex < 0) { length += firstIndex; firstIndex = 0; } Samples.RemoveRange(0, Samples.Count - MaxHistory); } }
/* // The time is this time divided by number of ticks per millisecond protected static long time() { return DateTime.UtcNow.Ticks / TimeSpan.TicksPerMillisecond; } public Sample? LastValidSample { get { Sample? lastValidSample = null; foreach (Sample sample in Samples) { if (sample.valid) { lastValidSample = sample; } } return lastValidSample; } } // Checksum - 16-bit word-size addition private static ushort WordSum(byte[] buffer) { int len = buffer.Length; int words = (len / 2); ushort value = 0x0000; // Initial sum of zero for (int i = 0; i < words; i++) { value += (ushort)(buffer[2 * i] + (buffer[2 * i + 1] << 8)); } if ((len & 1) != 0) { value += buffer[len - 1]; } // Add odd byte return value; //return (~value) + 1; // To calculate the checksum, take bitwise NOT of sum, then add 1 (total sum of words including checksum will be zero) } */ public static Packet PacketFromStomp(Hashtable data) { long timestampReceivedLong = 0; long timestampEstimatedLong = 0; ushort deviceId = 0; byte version = 0; ushort battery = 0; ushort sequence = 0; ushort unsent = 0; ushort temp = 0; ushort light = 0; ushort humidity = 0; ushort sampleCount = 0; ushort[] pir = new ushort[0]; ushort[] audio = new ushort[0]; Sample[] samples = new Sample[0]; ushort parentAddress = 0xffff; ushort parentAltAddress = 0xffff; // Check for "TEDDI" packet type, or no type info (old packets), if (data != null && (!data.ContainsKey("Type") || data["Type"].ToString() == "TEDDI")) { if (data.ContainsKey("TimestampEstimated")) { timestampEstimatedLong = (long)(double)Double.Parse(data["TimestampEstimated"].ToString()); } if (data.ContainsKey("TimestampReceived")) { timestampReceivedLong = (long)(double)Double.Parse(data["TimestampReceived"].ToString()); } if (data.ContainsKey("DeviceId")) { deviceId = (ushort)(double)Double.Parse(data["DeviceId"].ToString()); } if (data.ContainsKey("Version")) { version = (byte)(double)Double.Parse(data["Version"].ToString()); } if (data.ContainsKey("SampleCount")) { sampleCount = (ushort)(double)Double.Parse(data["SampleCount"].ToString()); } if (data.ContainsKey("Sequence")) { sequence = (ushort)(double)Double.Parse(data["Sequence"].ToString()); } if (data.ContainsKey("Unsent")) { unsent = (ushort)(double)Double.Parse(data["Unsent"].ToString()); } if (data.ContainsKey("Temp")) { temp = (ushort)(double)Double.Parse(data["Temp"].ToString()); } if (data.ContainsKey("Light")) { light = (ushort)(double)Double.Parse(data["Light"].ToString()); } if (data.ContainsKey("Battery")) { battery = (ushort)(double)Double.Parse(data["Battery"].ToString()); } if (data.ContainsKey("Humidity")) { humidity = (ushort)(double)Double.Parse(data["Humidity"].ToString()); } if (data.ContainsKey("Samples") && data["Samples"] is ArrayList) { ArrayList sampleList = (ArrayList)data["Samples"]; samples = new Sample[sampleList.Count]; pir = new ushort[sampleList.Count]; audio = new ushort[sampleList.Count]; for (int i = 0; i < sampleList.Count; i++) { if (sampleList[i] is ArrayList && ((ArrayList)sampleList[i]).Count >= 3) { ArrayList al = (ArrayList)sampleList[i]; long ts = 0; uint idx = 0; pir[i] = 0; audio[i] = 0; ts = (long)(double)al[0]; idx = (uint)(sequence * sampleCount + i); pir[i]= (ushort)(double)al[1]; audio[i] = (ushort)(double)al[2]; samples[i] = new Sample(DateTime.FromBinary(ts), (uint)idx, (short)pir[i], (short)temp, (short)light, (short)humidity, (ushort)audio[i], battery); } } } if (data.ContainsKey("ParentAddress")) { parentAddress = (ushort)(double)Double.Parse(data["ParentAddress"].ToString()); } if (data.ContainsKey("ParentAltAddress")) { parentAltAddress = (ushort)(double)Double.Parse(data["ParentAltAddress"].ToString()); } } else { Console.Error.Write("[STOMP:null]"); } return new Packet(DateTime.FromBinary(timestampEstimatedLong), deviceId, version, battery, 0, sequence, 0, sampleCount, DateTime.FromBinary(timestampReceivedLong), unsent, temp, light, humidity, pir, audio, samples, parentAddress, parentAltAddress); }
// Method to return a Packet, or null if invalid byte array public static Packet PacketFromBinary(byte[] buffer, DateTime timestamp) { Packet packet = null; if (buffer != null && buffer.Length > 0) { if (buffer.Length >= 5 && buffer[0] == 0x12 && buffer[1] == 0x54) // USER_REPORT_TYPE && TEDDI (ASCII 'T') { /* unsigned char reportType; // @0 [1] = 0x12 (USER_REPORT_TYPE) unsigned char reportId; // @1 [1] = 0x54 (ASCII 'T') unsigned short deviceId; // @2 [2] = Short device identifier (16-bit) [doesn't have to be part of the payload, but this format is the same as the WAX] unsigned char version; // @4 [1] = (0x02 = format [seq/temp/ldr/audio/pir : short]) */ ushort deviceId = (ushort)(buffer[2] | (((ushort)buffer[3]) << 8)); byte version = buffer[4]; if (((version & 0x0f) == 0x03 || (version & 0x0f) >= 0x04) && buffer.Length >= 18) { /* unsigned char reportType; // @ 0 [1] USER_REPORT_TYPE (0x12) unsigned char reportId; // @ 1 [1] Report identifier (0x54, ASCII 'T') unsigned short deviceId; // @ 2 [2] Device identifier (16-bit) unsigned char version; // @ 4 [1] Low nibble = packet version (0x3), high nibble = config (0x0) unsigned char sampleCount; // @ 5 [1] Sample count (default config is at 250 msec interval with an equal number of PIR and audio samples; 20 = 5 seconds) unsigned short sequence; // @ 6 [2] Sequence number (16-bit) unsigned short unsent; // @ 8 [2] Number of unsent samples (default config is in 250 msec units) unsigned short temp; // @10 [2] Temperature (0.2 Hz) unsigned short light; // @12 [2] Light (0.2 Hz) unsigned short battery; // @14 [2] Battery (0.2 Hz) unsigned short humidity; // @16 [2] Humidity [V4] (0.2 Hz) -- or [V3] 16-bit checksum to make packet zero-sum unsigned char data[BITPACK10_SIZEOF(DATA_MAX_INTERVAL * 2)]; // @18 [50] PIR and audio energy (4 Hz, 20x 2x 10-bit samples) unsigned short parentAddress; // @ADDITIONAL_OFFSET+0 [2] (optional) Parent address unsigned short parentAltAddress; // @ADDITIONAL_OFFSET+2 [2] (optional) Parent alt. address */ byte config = (byte)(buffer[4] >> 4); byte sampleCount = (byte)(buffer[5]); ushort sequence = (ushort)(buffer[6] | (((ushort)buffer[7]) << 8)); ushort unsent = (ushort)(buffer[8] | (((ushort)buffer[9]) << 8)); ushort temp = (ushort)(buffer[10] | (((ushort)buffer[11]) << 8)); ushort light = (ushort)(buffer[12] | (((ushort)buffer[13]) << 8)); ushort battery = (ushort)(buffer[14] | (((ushort)buffer[15]) << 8)); ushort humidity = (ushort)(buffer[16] | (((ushort)buffer[17]) << 8)); ushort[] pir = new ushort[sampleCount]; ushort[] audio = new ushort[sampleCount]; ushort parentAddress = 0xffff; ushort parentAltAddress = 0xffff; if ((version & 0x0f) == 0x03) { humidity = 0; } int[] teddiFrequency = new int[] { 4, 8, 16, 32, 64, 128, 256, 512, 1, 1, 1, 1, 1, 1, 1, 2 }; ushort sampleInterval = (ushort)(1000 / teddiFrequency[config]); try { // Unpack PIR for (int i = 0; i < sampleCount; i++) { pir[i] = BitUnpack_uint10(buffer, i, 18); } // Unpack Audio for (int i = 0; i < sampleCount; i++) { audio[i] = BitUnpack_uint10(buffer, sampleCount + i, 18); } // For V3 data, divide temp/light/battery measurement down if ((version & 0x0f) <= 0x03 && sampleCount > 0) { temp /= sampleCount; light /= sampleCount; battery /= sampleCount; humidity /= sampleCount; } // Check for additional data int additionalIndex = 18 + BITPACK10_SIZEOF(sampleCount * 2); if (additionalIndex + 4 <= buffer.Length) { parentAddress = (ushort)(buffer[additionalIndex + 0] | (((ushort)buffer[additionalIndex + 1]) << 8)); parentAltAddress = (ushort)(buffer[additionalIndex + 2] | (((ushort)buffer[additionalIndex + 3]) << 8)); Console.WriteLine("SENSOR: #" + deviceId + ", parent " + parentAddress + " (" + parentAltAddress + " = #" + Device.RouterAltId(parentAltAddress) + ")."); } // Create samples from the measurement data: deviceId, temp, light, humidity, pir[], audio[] Sample[] sampleData = new Sample[sampleCount]; for (uint i = 0; i < sampleCount; i++) { sampleData[i] = new Sample(timestamp - TimeSpan.FromMilliseconds((unsent + sampleCount - 1 - i) * sampleInterval), (ushort)(sequence * sampleCount) + i, (short)pir[i], (short)temp, (short)light, (short)humidity, audio[i], battery); } packet = new Packet(timestamp - TimeSpan.FromMilliseconds((unsent + sampleCount - 1) * sampleInterval), deviceId, 1, 0, 0, (ushort)(sequence * sampleCount), 0, sampleCount, timestamp, unsent, temp, light, humidity, pir, audio, sampleData, parentAddress, parentAltAddress); } catch (IndexOutOfRangeException ex) { Console.Error.Write("EXCEPTION: " + ex + " while parsing packet."); } } else { Console.Error.Write("[T?]"); // Unknown TEDDI packet type } } else { //Console.Error.Write("[?]"); // Unknown packet type } } return packet; }