kopia lustrzana https://github.com/mobilinkd/tnc3-firmware
				
				
				
			
		
			
				
	
	
		
			321 wiersze
		
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
			
		
		
	
	
			321 wiersze
		
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
// Copyright 2020 Rob Riggs <rob@mobilinkd.com>
 | 
						|
// All rights reserved.
 | 
						|
 | 
						|
#include "Fsk9600Demodulator.hpp"
 | 
						|
#include "Goertzel.h"
 | 
						|
#include "AudioInput.hpp"
 | 
						|
#include "GPIO.hpp"
 | 
						|
#include "Log.h"
 | 
						|
#include "power.h"
 | 
						|
 | 
						|
namespace mobilinkd { namespace tnc {
 | 
						|
 | 
						|
hdlc::IoFrame* Fsk9600Demodulator::operator()(const q15_t* samples)
 | 
						|
{
 | 
						|
    hdlc::IoFrame* result = nullptr;
 | 
						|
 | 
						|
    auto filtered = demod_filter.filter(const_cast<q15_t* >(samples));
 | 
						|
 | 
						|
    for (size_t i = 0; i != ADC_BLOCK_SIZE; ++i)
 | 
						|
    {
 | 
						|
        auto sample = filtered[i];
 | 
						|
 | 
						|
        bool bit = sample >= 0;
 | 
						|
        auto pll = pll_(bit);
 | 
						|
 | 
						|
        if (pll.sample)
 | 
						|
        {
 | 
						|
            locked_ = pll.locked;
 | 
						|
 | 
						|
            // We will only ever get one frame because there are
 | 
						|
            // not enough bits in a block for more than one.
 | 
						|
            if (result) {
 | 
						|
                auto tmp = hdlc_decoder_(nrzi_.decode(lfsr_(bit)), locked_);
 | 
						|
                if (tmp) hdlc::release(tmp);
 | 
						|
            } else {
 | 
						|
                result = hdlc_decoder_(nrzi_.decode(lfsr_(bit)), locked_);
 | 
						|
#ifdef KISS_LOGGING
 | 
						|
                if (result) {
 | 
						|
                    INFO("samples = %ld, mean = %d, dev = %d",
 | 
						|
                        snr_.samples, int(snr_.mean), int(snr_.stdev()));
 | 
						|
                    INFO("SNR = %dmB", int(snr_.SNR() * 100.0f));
 | 
						|
                    snr_.reset();
 | 
						|
                }
 | 
						|
#endif
 | 
						|
            }
 | 
						|
 | 
						|
#ifdef KISS_LOGGING
 | 
						|
            if (hdlc_decoder_.active())
 | 
						|
            {
 | 
						|
                if (!decoding_)
 | 
						|
                {
 | 
						|
                    snr_.reset();
 | 
						|
                    decoding_ = true;
 | 
						|
                }
 | 
						|
                snr_.capture(float(abs(sample)));
 | 
						|
            } else {
 | 
						|
                decoding_ = false;
 | 
						|
            }
 | 
						|
#endif
 | 
						|
        }
 | 
						|
 | 
						|
    }
 | 
						|
    return result;
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 * Return twist as a the difference in dB between mark and space.  The
 | 
						|
 * expected values are about 0dB for discriminator output and about 5.5dB
 | 
						|
 * for de-emphasized audio.
 | 
						|
 */
 | 
						|
float Fsk9600Demodulator::readTwist()
 | 
						|
{
 | 
						|
    TNC_DEBUG("enter Fsk9600Demodulator::readTwist");
 | 
						|
 | 
						|
    float g120 = 0.0f;
 | 
						|
    float g4800 = 0.0f;
 | 
						|
 | 
						|
    GoertzelFilter<ADC_BLOCK_SIZE, SAMPLE_RATE> gf120(120.0, 0);
 | 
						|
    GoertzelFilter<ADC_BLOCK_SIZE, SAMPLE_RATE> gf4800(4800.0, 0);
 | 
						|
 | 
						|
    const uint32_t AVG_SAMPLES = 160;
 | 
						|
 | 
						|
    startADC(416, ADC_BLOCK_SIZE);
 | 
						|
 | 
						|
    for (uint32_t i = 0; i != AVG_SAMPLES; ++i)
 | 
						|
    {
 | 
						|
        uint32_t count = 0;
 | 
						|
        while (count < ADC_BLOCK_SIZE)
 | 
						|
        {
 | 
						|
            osEvent evt = osMessageGet(adcInputQueueHandle, osWaitForever);
 | 
						|
            if (evt.status != osEventMessage)
 | 
						|
                continue;
 | 
						|
 | 
						|
            auto block = (audio::adc_pool_type::chunk_type*) evt.value.p;
 | 
						|
            uint16_t* data = (uint16_t*) block->buffer;
 | 
						|
            gf120(data, ADC_BLOCK_SIZE);
 | 
						|
            gf4800(data, ADC_BLOCK_SIZE);
 | 
						|
 | 
						|
            audio::adcPool.deallocate(block);
 | 
						|
 | 
						|
            count += ADC_BLOCK_SIZE;
 | 
						|
        }
 | 
						|
 | 
						|
        g120 += (gf120 / count);
 | 
						|
        g4800 += (gf4800 / count);
 | 
						|
 | 
						|
        gf120.reset();
 | 
						|
        gf4800.reset();
 | 
						|
    }
 | 
						|
 | 
						|
    IDemodulator::stopADC();
 | 
						|
 | 
						|
    g120 = 10.0f * log10f(g120 / AVG_SAMPLES);
 | 
						|
    g4800 = 10.0f * log10f(g4800 / AVG_SAMPLES);
 | 
						|
 | 
						|
    auto result = g120 - g4800;
 | 
						|
 | 
						|
    INFO("9600 Twist = %d / 100 (%d - %d)", int(result * 100), int(g120 * 100),
 | 
						|
        int(g4800 * 100));
 | 
						|
 | 
						|
    TNC_DEBUG("exit Fsk9600Demodulator::readTwist");
 | 
						|
    return result;
 | 
						|
}
 | 
						|
 | 
						|
uint32_t Fsk9600Demodulator::readBatteryLevel()
 | 
						|
{
 | 
						|
#ifndef NUCLEOTNC
 | 
						|
    return read_battery_level();
 | 
						|
#else
 | 
						|
    return 0;
 | 
						|
#endif
 | 
						|
}
 | 
						|
 | 
						|
const Fsk9600Demodulator::bpf_bank_type Fsk9600Demodulator::bpf_bank = {{
 | 
						|
    // -3dB
 | 
						|
    {{
 | 
						|
            1,     0,     0,     0,     0,     0,    -1,    -1,    -1,    -1,     0,     0,
 | 
						|
            0,     0,     1,     2,     2,     3,     2,     2,     0,     0,    -2,    -3,
 | 
						|
           -4,    -4,    -3,    -1,     3,     9,    17,    27,    38,    48,    58,    65,
 | 
						|
           68,    67,    60,    46,    25,    -1,   -32,   -67,  -102,  -135,  -160,  -175,
 | 
						|
         -174,  -153,  -110,   -41,    54,   178,   327,   500,   692,   897,  1109,  1318,
 | 
						|
         1518,  1700,  1857,  1981,  2067,  2110,  2110,  2067,  1981,  1857,  1700,  1518,
 | 
						|
         1318,  1109,   897,   692,   500,   327,   178,    54,   -41,  -110,  -153,  -174,
 | 
						|
         -175,  -160,  -135,  -102,   -67,   -32,    -1,    25,    46,    60,    67,    68,
 | 
						|
           65,    58,    48,    38,    27,    17,     9,     3,    -1,    -3,    -4,    -4,
 | 
						|
           -3,    -2,     0,     0,     2,     2,     3,     2,     2,     1,     0,     0,
 | 
						|
            0,     0,    -1,    -1,    -1,    -1,     0,     0,     0,     0,     0,     1
 | 
						|
    }},
 | 
						|
    // -2dB
 | 
						|
    {{
 | 
						|
            1,     0,     0,     0,     0,    -1,    -1,    -1,    -1,    -1,    -1,    -1,
 | 
						|
            0,     0,     1,     1,     2,     2,     1,     0,     0,    -1,    -3,    -5,
 | 
						|
           -6,    -6,    -5,    -1,     3,    10,    20,    31,    42,    54,    64,    72,
 | 
						|
           75,    72,    63,    46,    21,   -11,   -49,   -92,  -135,  -175,  -208,  -229,
 | 
						|
         -233,  -216,  -173,  -102,     0,   131,   293,   481,   691,   915,  1147,  1378,
 | 
						|
         1598,  1799,  1971,  2108,  2203,  2251,  2251,  2203,  2108,  1971,  1799,  1598,
 | 
						|
         1378,  1147,   915,   691,   481,   293,   131,     0,  -102,  -173,  -216,  -233,
 | 
						|
         -229,  -208,  -175,  -135,   -92,   -49,   -11,    21,    46,    63,    72,    75,
 | 
						|
           72,    64,    54,    42,    31,    20,    10,     3,    -1,    -5,    -6,    -6,
 | 
						|
           -5,    -3,    -1,     0,     0,     1,     2,     2,     1,     1,     0,     0,
 | 
						|
           -1,    -1,    -1,    -1,    -1,    -1,    -1,     0,     0,     0,     0,     1
 | 
						|
    }},
 | 
						|
    // -1dB
 | 
						|
    {{
 | 
						|
            1,     0,     0,     0,     0,    -1,    -1,    -2,    -2,    -2,    -2,    -1,
 | 
						|
           -1,     0,     0,     0,     1,     1,     0,     0,    -1,    -3,    -5,    -7,
 | 
						|
           -8,    -8,    -6,    -2,     3,    11,    22,    34,    48,    60,    72,    80,
 | 
						|
           82,    78,    66,    45,    15,   -22,   -68,  -119,  -171,  -221,  -262,  -291,
 | 
						|
         -300,  -286,  -244,  -170,   -62,    79,   255,   460,   689,   936,  1191,  1445,
 | 
						|
         1688,  1909,  2100,  2251,  2356,  2410,  2410,  2356,  2251,  2100,  1909,  1688,
 | 
						|
         1445,  1191,   936,   689,   460,   255,    79,   -62,  -170,  -244,  -286,  -300,
 | 
						|
         -291,  -262,  -221,  -171,  -119,   -68,   -22,    15,    45,    66,    78,    82,
 | 
						|
           80,    72,    60,    48,    34,    22,    11,     3,    -2,    -6,    -8,    -8,
 | 
						|
           -7,    -5,    -3,    -1,     0,     0,     1,     1,     0,     0,     0,    -1,
 | 
						|
           -1,    -2,    -2,    -2,    -2,    -1,    -1,     0,     0,     0,     0,     1
 | 
						|
    }},
 | 
						|
    // 0dB
 | 
						|
    {{
 | 
						|
            1,     0,     0,     0,    -1,    -1,    -2,    -2,    -3,    -3,    -3,    -2,
 | 
						|
           -2,    -1,     0,     0,     0,     0,     0,    -1,    -3,    -5,    -7,    -9,
 | 
						|
          -10,   -10,    -7,    -3,     3,    13,    25,    39,    53,    68,    80,    88,
 | 
						|
           91,    85,    70,    45,     9,   -35,   -90,  -150,  -212,  -272,  -323,  -359,
 | 
						|
         -376,  -366,  -324,  -247,  -132,    21,   212,   436,   688,   959,  1240,  1520,
 | 
						|
         1789,  2034,  2244,  2412,  2528,  2587,  2587,  2528,  2412,  2244,  2034,  1789,
 | 
						|
         1520,  1240,   959,   688,   436,   212,    21,  -132,  -247,  -324,  -366,  -376,
 | 
						|
         -359,  -323,  -272,  -212,  -150,   -90,   -35,     9,    45,    70,    85,    91,
 | 
						|
           88,    80,    68,    53,    39,    25,    13,     3,    -3,    -7,   -10,   -10,
 | 
						|
           -9,    -7,    -5,    -3,    -1,     0,     0,     0,     0,     0,    -1,    -2,
 | 
						|
           -2,    -3,    -3,    -3,    -2,    -2,    -1,    -1,     0,     0,     0,     1
 | 
						|
    }},
 | 
						|
    // 1dB
 | 
						|
    {{
 | 
						|
            1,     1,     0,     0,    -1,    -2,    -2,    -3,    -3,    -4,    -4,    -3,
 | 
						|
           -3,    -2,    -1,    -1,    -1,    -1,    -1,    -3,    -5,    -7,    -9,   -11,
 | 
						|
          -12,   -12,    -9,    -4,     3,    14,    28,    43,    60,    76,    89,    98,
 | 
						|
          100,    93,    75,    45,     3,   -50,  -114,  -185,  -258,  -329,  -390,  -437,
 | 
						|
         -460,  -454,  -413,  -333,  -209,   -43,   164,   409,   686,   984,  1295,  1604,
 | 
						|
         1901,  2173,  2406,  2592,  2721,  2786,  2786,  2721,  2592,  2406,  2173,  1901,
 | 
						|
         1604,  1295,   984,   686,   409,   164,   -43,  -209,  -333,  -413,  -454,  -460,
 | 
						|
         -437,  -390,  -329,  -258,  -185,  -114,   -50,     3,    45,    75,    93,   100,
 | 
						|
           98,    89,    76,    60,    43,    28,    14,     3,    -4,    -9,   -12,   -12,
 | 
						|
          -11,    -9,    -7,    -5,    -3,    -1,    -1,    -1,    -1,    -1,    -2,    -3,
 | 
						|
           -3,    -4,    -4,    -3,    -3,    -2,    -2,    -1,     0,     0,     1,     1
 | 
						|
    }},
 | 
						|
    // 2dB
 | 
						|
    {{
 | 
						|
            1,     1,     0,     0,    -1,    -2,    -3,    -4,    -4,    -5,    -5,    -4,
 | 
						|
           -4,    -3,    -3,    -2,    -2,    -2,    -3,    -5,    -7,    -9,   -12,   -14,
 | 
						|
          -15,   -14,   -11,    -5,     3,    15,    31,    49,    67,    85,   100,   109,
 | 
						|
          110,   101,    80,    45,    -3,   -66,  -141,  -223,  -309,  -393,  -467,  -523,
 | 
						|
         -555,  -554,  -513,  -429,  -297,  -116,   110,   379,   684,  1013,  1356,  1699,
 | 
						|
         2028,  2329,  2588,  2794,  2937,  3010,  3010,  2937,  2794,  2588,  2329,  2028,
 | 
						|
         1699,  1356,  1013,   684,   379,   110,  -116,  -297,  -429,  -513,  -554,  -555,
 | 
						|
         -523,  -467,  -393,  -309,  -223,  -141,   -66,    -3,    45,    80,   101,   110,
 | 
						|
          109,   100,    85,    67,    49,    31,    15,     3,    -5,   -11,   -14,   -15,
 | 
						|
          -14,   -12,    -9,    -7,    -5,    -3,    -2,    -2,    -2,    -3,    -3,    -4,
 | 
						|
           -4,    -5,    -5,    -4,    -4,    -3,    -2,    -1,     0,     0,     1,     1
 | 
						|
    }},
 | 
						|
    // 3dB
 | 
						|
    {{
 | 
						|
            2,     1,     0,     0,    -1,    -3,    -4,    -4,    -5,    -6,    -6,    -5,
 | 
						|
           -5,    -4,    -4,    -3,    -3,    -4,    -5,    -7,    -9,   -12,   -15,   -17,
 | 
						|
          -18,   -17,   -13,    -6,     3,    17,    35,    55,    75,    95,   111,   121,
 | 
						|
          122,   111,    86,    45,   -12,   -85,  -171,  -267,  -367,  -465,  -552,  -620,
 | 
						|
         -661,  -665,  -626,  -537,  -395,  -199,    49,   346,   681,  1045,  1425,  1805,
 | 
						|
         2170,  2504,  2792,  3021,  3179,  3261,  3261,  3179,  3021,  2792,  2504,  2170,
 | 
						|
         1805,  1425,  1045,   681,   346,    49,  -199,  -395,  -537,  -626,  -665,  -661,
 | 
						|
         -620,  -552,  -465,  -367,  -267,  -171,   -85,   -12,    45,    86,   111,   122,
 | 
						|
          121,   111,    95,    75,    55,    35,    17,     3,    -6,   -13,   -17,   -18,
 | 
						|
          -17,   -15,   -12,    -9,    -7,    -5,    -4,    -3,    -3,    -4,    -4,    -5,
 | 
						|
           -5,    -6,    -6,    -5,    -4,    -4,    -3,    -1,     0,     0,     1,     2
 | 
						|
    }},
 | 
						|
    // 4dB
 | 
						|
    {{
 | 
						|
            2,     1,     0,    -1,    -2,    -3,    -4,    -5,    -6,    -7,    -7,    -7,
 | 
						|
           -6,    -6,    -5,    -5,    -5,    -6,    -7,    -9,   -12,   -15,   -18,   -20,
 | 
						|
          -21,   -20,   -16,    -8,     3,    19,    39,    61,    85,   107,   125,   135,
 | 
						|
          135,   122,    92,    44,   -21,  -105,  -205,  -316,  -432,  -546,  -648,  -729,
 | 
						|
         -780,  -791,  -752,  -658,  -505,  -291,   -18,   308,   679,  1082,  1502,  1924,
 | 
						|
         2330,  2701,  3021,  3275,  3452,  3542,  3542,  3452,  3275,  3021,  2701,  2330,
 | 
						|
         1924,  1502,  1082,   679,   308,   -18,  -291,  -505,  -658,  -752,  -791,  -780,
 | 
						|
         -729,  -648,  -546,  -432,  -316,  -205,  -105,   -21,    44,    92,   122,   135,
 | 
						|
          135,   125,   107,    85,    61,    39,    19,     3,    -8,   -16,   -20,   -21,
 | 
						|
          -20,   -18,   -15,   -12,    -9,    -7,    -6,    -5,    -5,    -5,    -6,    -6,
 | 
						|
           -7,    -7,    -7,    -6,    -5,    -4,    -3,    -2,    -1,     0,     1,     2
 | 
						|
    }},
 | 
						|
    // 5dB
 | 
						|
    {{
 | 
						|
            2,     1,     0,    -1,    -2,    -4,    -5,    -6,    -7,    -8,    -8,    -8,
 | 
						|
           -8,    -8,    -7,    -7,    -7,    -8,    -9,   -11,   -14,   -18,   -21,   -24,
 | 
						|
          -25,   -23,   -19,    -9,     3,    21,    44,    69,    95,   119,   139,   151,
 | 
						|
          150,   134,    99,    44,   -31,  -128,  -243,  -371,  -505,  -636,  -756,  -852,
 | 
						|
         -914,  -931,  -894,  -795,  -629,  -394,   -94,   265,   676,  1122,  1589,  2058,
 | 
						|
         2508,  2921,  3277,  3560,  3757,  3858,  3858,  3757,  3560,  3277,  2921,  2508,
 | 
						|
         2058,  1589,  1122,   676,   265,   -94,  -394,  -629,  -795,  -894,  -931,  -914,
 | 
						|
         -852,  -756,  -636,  -505,  -371,  -243,  -128,   -31,    44,    99,   134,   150,
 | 
						|
          151,   139,   119,    95,    69,    44,    21,     3,    -9,   -19,   -23,   -25,
 | 
						|
          -24,   -21,   -18,   -14,   -11,    -9,    -8,    -7,    -7,    -7,    -8,    -8,
 | 
						|
           -8,    -8,    -8,    -7,    -6,    -5,    -4,    -2,    -1,     0,     1,     2
 | 
						|
    }},
 | 
						|
    // 6dB
 | 
						|
    {{
 | 
						|
            2,     1,     0,    -1,    -3,    -4,    -6,    -7,    -9,   -10,   -10,   -10,
 | 
						|
          -10,    -9,    -9,    -9,    -9,   -10,   -12,   -14,   -18,   -21,   -25,   -28,
 | 
						|
          -29,   -27,   -22,   -11,     3,    24,    49,    77,   107,   134,   156,   168,
 | 
						|
          167,   148,   107,    44,   -43,  -154,  -286,  -432,  -586,  -738,  -876,  -989,
 | 
						|
        -1064, -1089, -1053,  -947,  -767,  -510,  -180,   218,   672,  1168,  1687,  2208,
 | 
						|
         2709,  3169,  3565,  3881,  4100,  4212,  4212,  4100,  3881,  3565,  3169,  2709,
 | 
						|
         2208,  1687,  1168,   672,   218,  -180,  -510,  -767,  -947, -1053, -1089, -1064,
 | 
						|
         -989,  -876,  -738,  -586,  -432,  -286,  -154,   -43,    44,   107,   148,   167,
 | 
						|
          168,   156,   134,   107,    77,    49,    24,     3,   -11,   -22,   -27,   -29,
 | 
						|
          -28,   -25,   -21,   -18,   -14,   -12,   -10,    -9,    -9,    -9,    -9,   -10,
 | 
						|
          -10,   -10,   -10,    -9,    -7,    -6,    -4,    -3,    -1,     0,     1,     2
 | 
						|
    }},
 | 
						|
    // 7dB
 | 
						|
    {{
 | 
						|
            3,     1,     0,    -1,    -3,    -5,    -7,    -9,   -10,   -11,   -12,   -12,
 | 
						|
          -12,   -11,   -11,   -11,   -11,   -12,   -14,   -17,   -21,   -26,   -30,   -33,
 | 
						|
          -34,   -32,   -25,   -13,     3,    27,    55,    87,   120,   150,   174,   188,
 | 
						|
          185,   163,   116,    43,   -56,  -183,  -334,  -501,  -678,  -852, -1012, -1143,
 | 
						|
        -1232, -1266, -1231, -1119,  -923,  -641,  -276,   164,   668,  1219,  1796,  2376,
 | 
						|
         2934,  3446,  3888,  4240,  4484,  4609,  4609,  4484,  4240,  3888,  3446,  2934,
 | 
						|
         2376,  1796,  1219,   668,   164,  -276,  -641,  -923, -1119, -1231, -1266, -1232,
 | 
						|
        -1143, -1012,  -852,  -678,  -501,  -334,  -183,   -56,    43,   116,   163,   185,
 | 
						|
          188,   174,   150,   120,    87,    55,    27,     3,   -13,   -25,   -32,   -34,
 | 
						|
          -33,   -30,   -26,   -21,   -17,   -14,   -12,   -11,   -11,   -11,   -11,   -12,
 | 
						|
          -12,   -12,   -11,   -10,    -9,    -7,    -5,    -3,    -1,     0,     1,     3
 | 
						|
    }},
 | 
						|
    // 8dB
 | 
						|
    {{
 | 
						|
            3,     1,     0,    -2,    -4,    -6,    -8,   -10,   -12,   -13,   -14,   -14,
 | 
						|
          -14,   -14,   -13,   -13,   -14,   -15,   -17,   -21,   -25,   -30,   -35,   -38,
 | 
						|
          -39,   -36,   -29,   -16,     3,    30,    62,    97,   134,   168,   195,   209,
 | 
						|
          206,   180,   127,    43,   -71,  -216,  -388,  -579,  -780,  -980, -1164, -1316,
 | 
						|
        -1421, -1464, -1431, -1311, -1097,  -787,  -383,   104,   664,  1277,  1919,  2565,
 | 
						|
         3187,  3758,  4251,  4643,  4916,  5055,  5055,  4916,  4643,  4251,  3758,  3187,
 | 
						|
         2565,  1919,  1277,   664,   104,  -383,  -787, -1097, -1311, -1431, -1464, -1421,
 | 
						|
        -1316, -1164,  -980,  -780,  -579,  -388,  -216,   -71,    43,   127,   180,   206,
 | 
						|
          209,   195,   168,   134,    97,    62,    30,     3,   -16,   -29,   -36,   -39,
 | 
						|
          -38,   -35,   -30,   -25,   -21,   -17,   -15,   -14,   -13,   -13,   -14,   -14,
 | 
						|
          -14,   -14,   -13,   -12,   -10,    -8,    -6,    -4,    -2,     0,     1,     3
 | 
						|
    }},
 | 
						|
    // 9dB
 | 
						|
    {{
 | 
						|
            3,     2,     0,    -2,    -4,    -7,    -9,   -12,   -14,   -15,   -16,   -17,
 | 
						|
          -17,   -16,   -16,   -16,   -17,   -18,   -21,   -25,   -30,   -35,   -40,   -44,
 | 
						|
          -45,   -42,   -33,   -18,     3,    33,    69,   109,   151,   189,   218,   234,
 | 
						|
          230,   199,   138,    42,   -88,  -253,  -448,  -666,  -895, -1123, -1334, -1510,
 | 
						|
        -1633, -1687, -1656, -1527, -1293,  -951,  -504,    37,   659,  1341,  2056,  2777,
 | 
						|
         3470,  4107,  4658,  5095,  5400,  5556,  5556,  5400,  5095,  4658,  4107,  3470,
 | 
						|
         2777,  2056,  1341,   659,    37,  -504,  -951, -1293, -1527, -1656, -1687, -1633,
 | 
						|
        -1510, -1334, -1123,  -895,  -666,  -448,  -253,   -88,    42,   138,   199,   230,
 | 
						|
          234,   218,   189,   151,   109,    69,    33,     3,   -18,   -33,   -42,   -45,
 | 
						|
          -44,   -40,   -35,   -30,   -25,   -21,   -18,   -17,   -16,   -16,   -16,   -17,
 | 
						|
          -17,   -16,   -15,   -14,   -12,    -9,    -7,    -4,    -2,     0,     2,     3
 | 
						|
    }}
 | 
						|
}};
 | 
						|
 | 
						|
}} // mobilinkd::tnc
 | 
						|
 |