using System;
using System.Collections;
using System.Collections.Generic;
///
/// Summary description for Class1
///
namespace Sensor.Gateway.DataXfer
{
public class Decompressor
{
#region variables
private List _factories = new List();
private SortedList _packetIdentifiers = new SortedList();
private List _decompressedRecords = new List();
private List _flashRecords = new List();
private List _journalRecords = new List();
private ushort[] _lastSensorVals;
public ushort[] LastSensorVals
{
get { return _lastSensorVals; }
set { _lastSensorVals = value; }
}
private Int32 _sampleInterval;
private Int32 _localTime;
private Int32 _rebootCounter;
public Int32 SampleInterval{
get { return _sampleInterval; }
}
public Int32 LocalTime
{
get { return _localTime; }
set { _localTime = value; }
}
public Int32 RebootCounter
{
get { return _rebootCounter; }
set { _rebootCounter = value; }
}
private int _downloadId;
private ArrayList getRecordsOfType(Type t)
{
ArrayList ret = new ArrayList();
for (int k = 0; k < _decompressedRecords.Count; k++)
{
if (_decompressedRecords[k].GetType() == t)
{
ret.Add(_decompressedRecords[k]);
}
}
return ret;
}
internal ArrayList getGPSRecords()
{
return getRecordsOfType(Type.GetType("Sensor.Gateway.DataXfer.DecompressedGPSRecord"));
}
internal ArrayList getFlashRecords()
{
return getRecordsOfType(Type.GetType("Sensor.Gateway.DataXfer.FlashRecord"));
}
internal ArrayList getJournalRecords()
{
return getRecordsOfType(Type.GetType("Sensor.Gateway.DataXfer.JournalRecord"));
}
internal ArrayList getAnchorRecords()
{
return getRecordsOfType(Type.GetType("Sensor.Gateway.DataXfer.DecompressedAnchorRecord"));
}
private FlashRecord _lastRecord;
private int _nodeId;
public int NodeId
{
get { return _nodeId; }
}
#endregion variables
#region conversion
public static UInt64 convert64(int offset,
byte[] b)
{
UInt64 result = 0;
for (int k = 0; k < 8; k++)
{
result |= b[offset + k];
if(k!=7)
result <<= 8;
// result |= ((UInt64)b[offset + k]) << 56 - (8 * k);
}
return result;
}
public static UInt32 convert32(int offset, byte[] b)
{
UInt32 result = 0;
for (int k = 0; k < 4; k++)
{
result |= b[offset + k];
if(k != 3)
result <<= 8;
//result |= ((UInt32)b[offset + k]) << 24 - (8 * k);
}
return result;
}
public static UInt16 convert16(int offset, byte[] b)
{
UInt16 result = 0;
for (int k = 0; k < 2; k++)
{
result |= b[offset + k];
if (k != 1)
result <<= 8;
//result |= ((UInt32)b[offset + k]) << 24 - (8 * k);
}
//result = (b[offset]);// << 8;
return result;
}
#endregion conversion
public Decompressor(int downloadId_, FlashRecord lastRecord_, int nodeId){
_downloadId = downloadId_;
_localTime = 0;
_rebootCounter = -1;
_lastSensorVals = new ushort[10];
_lastRecord = lastRecord_;
_sampleInterval = 30*1024;
_nodeId = nodeId;
//_factories.Add(new RebootRecordFactory());
_factories.Add(new CRCRecordFactory());
_factories.Add(new AnchorRecordFactory());
//TODO: read record descriptors in from config file?
/*
_factories.Add(new SampleRecordFactory(new SampleRecordDescriptor(0xc0, new byte[] { 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 4)));
_factories.Add(new SampleRecordFactory(new SampleRecordDescriptor(0xd0, new byte[] { 0x08, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, 4)));
_factories.Add(new SampleRecordFactory(new SampleRecordDescriptor(0xe0, new byte[] { 0x08, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04 }, 4)));
_factories.Add(new SampleRecordFactory(new SampleRecordDescriptor(0xf0, new byte[] { 0x0C, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08 }, 4)));
_factories.Add(new SampleRecordFactory(new SampleRecordDescriptor(0x00, new byte[] { 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }, 8)));
*/
/* Olin
_factories.Add(new SampleRecordFactory(new SampleRecordDescriptor(0x50, new byte[] { 2, 2, 3, 5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 4)));
_factories.Add(new SampleRecordFactory(new SampleRecordDescriptor(0x60, new byte[] { 3, 3, 2, 4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 4)));
_factories.Add(new SampleRecordFactory(new SampleRecordDescriptor(0x70, new byte[] { 2, 2, 4, 4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 4)));
_factories.Add(new SampleRecordFactory(new SampleRecordDescriptor(0x80, new byte[] { 3, 3, 3, 3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 4)));
_factories.Add(new SampleRecordFactory(new SampleRecordDescriptor(0x90, new byte[] { 4, 4, 2, 2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 4)));
_factories.Add(new SampleRecordFactory(new SampleRecordDescriptor(0xa0, new byte[] { 5, 5, 4, 6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 4)));
_factories.Add(new SampleRecordFactory(new SampleRecordDescriptor(0xb0, new byte[] { 4, 5, 6, 5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 4)));
_factories.Add(new SampleRecordFactory(new SampleRecordDescriptor(0xc0, new byte[] { 3, 3, 7, 7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 4)));
_factories.Add(new SampleRecordFactory(new SampleRecordDescriptor(0xd0, new byte[] { 5, 5, 5, 5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 4)));
_factories.Add(new SampleRecordFactory(new SampleRecordDescriptor(0xe0, new byte[] { 11, 11, 11, 11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 4)));
_factories.Add(new SampleRecordFactory(new SampleRecordDescriptor(0x00, new byte[] { 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }, 8)));
*/
//Brazil
_factories.Add(new SampleRecordFactory(new SampleRecordDescriptor(0x50, new byte[] { 3, 3, 3, 3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 4)));
_factories.Add(new SampleRecordFactory(new SampleRecordDescriptor(0x60, new byte[] { 3, 3, 2, 4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 4)));
_factories.Add(new SampleRecordFactory(new SampleRecordDescriptor(0x70, new byte[] { 5, 5, 4, 6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 4)));
_factories.Add(new SampleRecordFactory(new SampleRecordDescriptor(0x80, new byte[] { 4, 4, 6, 6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 4)));
_factories.Add(new SampleRecordFactory(new SampleRecordDescriptor(0x90, new byte[] { 5, 5, 5, 5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 4)));
_factories.Add(new SampleRecordFactory(new SampleRecordDescriptor(0xa0, new byte[] { 4, 4, 4, 8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 4)));
_factories.Add(new SampleRecordFactory(new SampleRecordDescriptor(0xb0, new byte[] { 4, 4, 5, 7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 4)));
_factories.Add(new SampleRecordFactory(new SampleRecordDescriptor(0xc0, new byte[] { 6, 7, 7, 8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 4)));
_factories.Add(new SampleRecordFactory(new SampleRecordDescriptor(0xd0, new byte[] { 6, 6, 7, 9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 4)));
_factories.Add(new SampleRecordFactory(new SampleRecordDescriptor(0xe0, new byte[] { 6, 6, 6, 10, 0x00, 0x00, 0x00, 0x00, 0x00,0x00}, 4)));
_factories.Add(new SampleRecordFactory(new SampleRecordDescriptor(0xf0, new byte[] { 9, 9, 9, 9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, 4)));
_factories.Add(new SampleRecordFactory(new SampleRecordDescriptor(0x00, new byte[] { 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }, 8)));
_factories.Add(new GPSRecordFactory());
_factories.Add(new JournalRecordFactory());
}
internal void addLine(string line)
{
PacketIdentifier pi = new PacketIdentifier(_downloadId , line);
_packetIdentifiers.Add(pi._leftPtr, pi);
}
public void setCRCs(int bytesCovered, int index, bool passed)
{
IEnumerator iter = _packetIdentifiers.Values.GetEnumerator();
while (iter.MoveNext() && iter.Current.ByteStart < index)
{
IEnumerator inner = iter.Current.CompressedRecords.GetEnumerator();
while(inner.MoveNext()){
if (inner.Current.ByteStart >= index - bytesCovered)
{
inner.Current.CRC = passed;
}
}
}
}
internal void decompress()
{
List bl = new List();
foreach (PacketIdentifier pi in _packetIdentifiers.Values)
{
int byteStart = bl.Count;
pi.ByteStart = byteStart;
bl.AddRange(pi.Bytes);
}
int byteIndex = 0;
if (_lastRecord != null)
{
_localTime = _lastRecord.LocalClock;
_rebootCounter = _lastRecord.Reboots;
//System.Buffer.BlockCopy(_lastRecord.Measurement, 0, _lastSensorVals, 0, 20);//TODO: swap endian
for (int k = 0; k < 10; k++ )
{
byte[] tmp = Utils.ChangeEndian(_lastRecord.Measurement, 2 * k, 2);
System.Buffer.BlockCopy(tmp, 0, _lastSensorVals, 2*k, 2);
}
byteIndex = (int)(_lastRecord.RightPtr - _packetIdentifiers.Values[0]._leftPtr);
//hack!
//The problem is that when we compute leftptr/rightptr for samples, we assume that either:
//a. the sample being decompressed is the first sensor sample in the packet and we let leftptr=packet.leftpr
//b. the sample being decompressed is not the first, and we let leftptr = packet.leftptr + sum(lengths of the other compressed records)
//however, if this decompressor is starting at a partially-processed packet, there may be some non-sample records before the last record in the db
// and this means that we are going to get a different leftptr than we otherwise would (b/c it would be missing some of the "other compressed records" above)
_packetIdentifiers.Values[0].CompressedRecords.Add(new DummyCompressedRecord((int)(_lastRecord.RightPtr - _lastRecord.LeftPtr)));
_packetIdentifiers.Values[0].FirstLeftPtr = _lastRecord.LeftPtr;
//TODO: detect rubbish duplicates here?
}
// throw new Exception("Last record.rp " + _lastRecord.RightPtr + " pi.lp " + _packetIdentifiers.Values[0]._leftPtr + " index " + byteIndex);
byte[] byteArr = bl.ToArray();
// PacketIdentifier[] piArr = _packetIdentifiers.Values.;
IEnumerator iter = _packetIdentifiers.Values.GetEnumerator();
iter.MoveNext();
PacketIdentifier curPI = iter.Current;
while (byteIndex < byteArr.Length)
{
int startBI = byteIndex;
//keep correct packet identifier
for (; byteIndex > curPI.ByteStart + curPI.Bytes.Length; iter.MoveNext()) {
curPI = iter.Current;
curPI.FirstLeftPtr = curPI._leftPtr + (byteIndex - curPI.ByteStart);
}
foreach( RecordFactory rf in _factories){
if (rf.isMatch(byteIndex, byteArr))
{
//parse compressed record out of raw data
CompressedRecord cr = rf.build(byteIndex, byteArr, curPI);
//add the decompressed records to our array of all decompressed records
_decompressedRecords.AddRange(cr.decompress(this));
//add this compressed record to the packet it came from
curPI.CompressedRecords.Add(cr);
//move it on up
byteIndex += cr.Length;
break;
}
}
if (startBI == byteIndex)
{
throw new Exception("Unmatched record for index " + byteIndex + " byte " + byteArr[byteIndex] + " from packet " + curPI._nodeid + " " + curPI._leftPtr);
}
}
byteIndex = 0;
}
}
}