/***************************************************************************** * steim2.cc * * Steim2 encoder * * (c) 2004 Andres Heinloo, GFZ Potsdam * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2, or (at your option) any later * version. For more information, see http://www.gnu.org/ * * ================ * Change log * =============== * * 01.01.2013 Adapted code to CAPS client library requirements (gempa GmbH) *****************************************************************************/ #include "../log.h" #include #include #include #include #include namespace Gempa { namespace CAPS { template Steim2Encoder::~Steim2Encoder() { if ( _format ) { delete _format; } } template void Steim2Encoder::updateSpw(int bp) { assert(_bp < 7); if ( _buf[_bp] < -536870912 ) { CAPS_WARNING("%s.%s.%s.%s: value %d is too large for Steim2 encoding", _format->networkCode.c_str(), _format->stationCode.c_str(), _format->locationCode.c_str(), _format->channelCode.c_str(), _buf[_bp]); _buf[_bp] = -536870912; _spw = 1; return; } if ( _buf[_bp] > 536870911 ) { CAPS_WARNING("%s.%s.%s.%s: value %d is too large for Steim2 encoding", _format->networkCode.c_str(), _format->stationCode.c_str(), _format->locationCode.c_str(), _format->channelCode.c_str(), _buf[_bp]); _buf[_bp] = 536870911; _spw = 1; return; } int spw1 = 7; if ( _buf[_bp] < -16384 || _buf[_bp] > 16383 ) spw1 = 1; else if ( _buf[_bp] < -512 || _buf[_bp] > 511 ) spw1 = 2; else if ( _buf[_bp] < -128 || _buf[_bp] > 127 ) spw1 = 3; else if ( _buf[_bp] < -32 || _buf[_bp] > 31 ) spw1 = 4; else if ( _buf[_bp] < -16 || _buf[_bp] > 15 ) spw1 = 5; else if ( _buf[_bp] < -8 || _buf[_bp] > 7 ) spw1 = 6; if ( spw1 < _spw ) _spw = spw1; } template void Steim2Encoder::store(int32_t value) { assert(_bp < 7); _buf[_bp] = value - _lastSample; _lastSample = value; updateSpw(_bp); ++_bp; } template void Steim2Encoder::initPacket() { int i; int32_t begin_sample = _lastSample; for ( i = 1; i < _bp; ++i ) { begin_sample -= _buf[i]; } reset(); _currentPacket.data[0].sampleWord[0] = htonl(begin_sample); _frameCount = 0; _nibbleWord = 0; _fp = 2; } template void Steim2Encoder::finishPacket() { int i; int32_t endSample = _lastSample; for ( i = 0; i < _bp; ++i ) { endSample -= _buf[i]; } _currentPacket.data[0].sampleWord[1] = htonl(endSample); } template void Steim2Encoder::updatePacket() { unsigned int nibble = 0; u_int32_t sampleWord = 0; assert(_bp < 8); int used = _bp; while ( used > _spw ) { --used; _spw = 7; for ( int i = 0; i < used; ++i ) { updateSpw(i); } } _spw = used; switch ( _spw ) { case 7: nibble = 3; sampleWord = (2U << 30) | ((_buf[0] & 0xf) << 24) | ((_buf[1] & 0xf) << 20) | ((_buf[2] & 0xf) << 16) | ((_buf[3] & 0xf) << 12) | ((_buf[4] & 0xf) << 8) | ((_buf[5] & 0xf) << 4) | (_buf[6] & 0xf); break; case 6: nibble = 3; sampleWord = (1U << 30) | ((_buf[0] & 0x1f) << 25) | ((_buf[1] & 0x1f) << 20) | ((_buf[2] & 0x1f) << 15) | ((_buf[3] & 0x1f) << 10) | ((_buf[4] & 0x1f) << 5) | (_buf[5] & 0x1f); break; case 5: nibble = 3; sampleWord = ((_buf[0] & 0x3f) << 24) | ((_buf[1] & 0x3f) << 18) | ((_buf[2] & 0x3f) << 12) | ((_buf[3] & 0x3f) << 6) | (_buf[4] & 0x3f); break; case 4: nibble = 1; sampleWord = ((_buf[0] & 0xff) << 24) | ((_buf[1] & 0xff) << 16) | ((_buf[2] & 0xff) << 8) | (_buf[3] & 0xff); break; case 3: nibble = 2; sampleWord = (3U << 30) | ((_buf[0] & 0x3ff) << 20) | ((_buf[1] & 0x3ff) << 10) | (_buf[2] & 0x3ff); break; case 2: nibble = 2; sampleWord = (2U << 30) | ((_buf[0] & 0x7fff) << 15) | (_buf[1] & 0x7fff); break; case 1: nibble = 2; sampleWord = (1U << 30) | (_buf[0] & 0x3fffffff); break; default: assert(0); break; } _nibbleWord |= (nibble << (30 - ((_fp + 1) << 1))); _spw = 7; for ( int i = 0; i < _bp - used; ++i ) { _buf[i] = _buf[i + used]; updateSpw(i); } _bp -= used; _sampleCount += used; _currentPacket.data[_frameCount].nibbleWord = htonl(_nibbleWord); _currentPacket.data[_frameCount].sampleWord[_fp] = htonl(sampleWord); if ( ++_fp < 15 ) { return; } _nibbleWord = 0; _fp = 0; ++_frameCount; return; } template void Steim2Encoder::queuePacket(MSEEDEncoderPacket &pckt) { _format->updateBuffer(pckt.record, _sampleCount, _frameCount + (_fp > 0)); Packet *packet = new Packet(DataRecordPtr(pckt.record), _format->networkCode, _format->stationCode, _format->locationCode, _format->channelCode); _packetQueue.push_back(PacketPtr(packet)); pckt.reset(); reset(); } template void Steim2Encoder::push(void *value) { int32_t sample_val = *static_cast(value); store(sample_val); _clk.tick(); while ( _bp >= _spw ) { if ( !_currentPacket.valid() ) { _currentPacket = getPacket(); initPacket(); } updatePacket(); if ( _frameCount == numberOfFrames(_currentPacket) ) { finishPacket(); queuePacket(_currentPacket); } } } template void Steim2Encoder::flush() { while ( _bp ) { if ( !_currentPacket.valid() ) { _currentPacket = getPacket(); initPacket(); } updatePacket(); if ( _frameCount == numberOfFrames(_currentPacket) ) { finishPacket(); queuePacket(_currentPacket); } } if ( _currentPacket.valid() ) { finishPacket(); queuePacket(_currentPacket); } } } }