CW Decoder (Morse code decoder) 1st release version. mbed = 131 revision (Not latest) is used. Only run on DISCO-F746NG mbed board.

Dependencies:   BSP_DISCO_F746NG F746_GUI F746_SAI_IO LCD_DISCO_F746NG TS_DISCO_F746NG UIT_FFT_Real mbed

Base on F746_Spectrogram program created by 不韋 呂-san.
/users/MikamiUitOpen/code/F746_Spectrogram/
Thanks 不韋 呂-san to use fundamental parts such as FFT, SAI, GUI and other useful subroutines.
You do NOT need any modification for mbed hardware and NO additional circuits.
The mbed board read CW tone from your receiver speaker via MEMES microphone (on board) and show it on the screen.

Files at this revision

API Documentation at this revision

Comitter:
kenjiArai
Date:
Sun Feb 05 07:49:54 2017 +0000
Commit message:
CW Decoder (Morse code decoder) 1st release version. mbed = 131 revision (Not latest) is used. Only run on DISCO-F746NG mbed board.

Changed in this revision

BSP_DISCO_F746NG.lib Show annotated file Show diff for this revision Revisions of this file
F746_GUI.lib Show annotated file Show diff for this revision Revisions of this file
F746_SAI_IO.lib Show annotated file Show diff for this revision Revisions of this file
LCD_DISCO_F746NG.lib Show annotated file Show diff for this revision Revisions of this file
MySpectrogram/AnalysisBase.cpp Show annotated file Show diff for this revision Revisions of this file
MySpectrogram/AnalysisBase.hpp Show annotated file Show diff for this revision Revisions of this file
MySpectrogram/FFT_Analysis.cpp Show annotated file Show diff for this revision Revisions of this file
MySpectrogram/FFT_Analysis.hpp Show annotated file Show diff for this revision Revisions of this file
MySpectrogram/Hamming.hpp Show annotated file Show diff for this revision Revisions of this file
MySpectrogram/MethodCollection.hpp Show annotated file Show diff for this revision Revisions of this file
TS_DISCO_F746NG.lib Show annotated file Show diff for this revision Revisions of this file
UIT_FFT_Real.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r e608fc311e4e BSP_DISCO_F746NG.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BSP_DISCO_F746NG.lib	Sun Feb 05 07:49:54 2017 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/teams/ST/code/BSP_DISCO_F746NG/#fe313c53cdb5
diff -r 000000000000 -r e608fc311e4e F746_GUI.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/F746_GUI.lib	Sun Feb 05 07:49:54 2017 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/MikamiUitOpen/code/F746_GUI/#551a5f1b52b9
diff -r 000000000000 -r e608fc311e4e F746_SAI_IO.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/F746_SAI_IO.lib	Sun Feb 05 07:49:54 2017 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/MikamiUitOpen/code/F746_SAI_IO/#25a9655d6a0e
diff -r 000000000000 -r e608fc311e4e LCD_DISCO_F746NG.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LCD_DISCO_F746NG.lib	Sun Feb 05 07:49:54 2017 +0000
@@ -0,0 +1,1 @@
+https://developer.mbed.org/teams/ST/code/LCD_DISCO_F746NG/#d44525b1de98
diff -r 000000000000 -r e608fc311e4e MySpectrogram/AnalysisBase.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MySpectrogram/AnalysisBase.cpp	Sun Feb 05 07:49:54 2017 +0000
@@ -0,0 +1,27 @@
+//-------------------------------------------------------
+//  Base abstract class for spectrum analysis
+//
+//  2016/07/23, Copyright (c) 2016 MIKAMI, Naoki
+//-------------------------------------------------------
+
+#include "AnalysisBase.hpp"
+
+namespace Mikami
+{
+    AnalyzerBase::AnalyzerBase(int nData, int nFft, int nUse)
+        : N_DATA_(nData), N_FFT_(nFft),
+          fft_(nFft), wHm_(nData-1, nUse),
+          xData_(nUse), wData_(nUse) {}
+
+    void AnalyzerBase::Execute(const float xn[], float db[])
+    {
+        // Differencing
+        for (int n=0; n<N_DATA_-1; n++)
+            xData_[n] = xn[n+1] - 0.8f*xn[n];
+            
+        // Windowing
+        wHm_.Execute(xData_, wData_);
+            
+        Analyze(wData_, db);
+    }
+}
diff -r 000000000000 -r e608fc311e4e MySpectrogram/AnalysisBase.hpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MySpectrogram/AnalysisBase.hpp	Sun Feb 05 07:49:54 2017 +0000
@@ -0,0 +1,50 @@
+//-------------------------------------------------------
+//  Base abstract class for spectrum analysis (Header)
+//
+//  2016/07/23, Copyright (c) 2016 MIKAMI, Naoki
+//-------------------------------------------------------
+
+#ifndef BASE_ANALYZER_HPP
+#define BASE_ANALYZER_HPP
+
+#include "Array.hpp"
+#include "fftReal.hpp"
+#include "Hamming.hpp"
+
+namespace Mikami
+{
+    class AnalyzerBase
+    {
+    public:
+        // nData: Number of data to be analyzed
+        // nFft:  Number of FFT points
+        // nUse:  FFT, cepstrum: window width + zero padding
+        //        Linear prediction: window width
+        AnalyzerBase(int nData, int nFft, int nUse);
+        virtual ~AnalyzerBase() {}
+        void Execute(const float xn[], float db[]);
+
+    protected:
+        const int N_DATA_;
+        const int N_FFT_;
+
+        FftReal fft_;
+                
+        float Norm(Complex x)
+        { return x.real()*x.real() + x.imag()*x.imag(); }
+
+    private:
+        HammingWindow wHm_;
+
+        Array<float> xData_;    // data to be analyzed
+        Array<float> wData_;    // windowd data
+
+        virtual void Analyze(const float wData[], float db[]) = 0;
+
+        // disallow copy constructor and assignment operator
+        AnalyzerBase(const AnalyzerBase& );
+        AnalyzerBase& operator=(const AnalyzerBase& );
+    };
+}
+#endif  // BASE_ANALYZER_HPP
+
diff -r 000000000000 -r e608fc311e4e MySpectrogram/FFT_Analysis.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MySpectrogram/FFT_Analysis.cpp	Sun Feb 05 07:49:54 2017 +0000
@@ -0,0 +1,23 @@
+//-------------------------------------------------------
+//  Class for spectrum analysis using FFT
+//
+//  2016/07/23, Copyright (c) 2015 MIKAMI, Naoki
+//-------------------------------------------------------
+
+#include "FFT_Analysis.hpp"
+
+namespace Mikami
+{
+    FftAnalyzer::FftAnalyzer(int nData, int nFft)
+        : AnalyzerBase(nData, nFft, nFft),
+          yFft_(nFft/2+1) {}
+
+    void FftAnalyzer::Analyze(const float xn[], float yn[])
+    {
+        fft_.Execute(xn, yFft_);    // Execute FFT
+        
+        // Translate to dB
+        for (int n=0; n<=N_FFT_/2; n++)
+            yn[n] = 10.0f*log10f(Norm(yFft_[n]));
+    }
+}
diff -r 000000000000 -r e608fc311e4e MySpectrogram/FFT_Analysis.hpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MySpectrogram/FFT_Analysis.hpp	Sun Feb 05 07:49:54 2017 +0000
@@ -0,0 +1,31 @@
+//-------------------------------------------------------
+//  Class for spectrum analysis using FFT (Header)
+//
+//  2016/07/23, Copyright (c) 2016 MIKAMI, Naoki
+//-------------------------------------------------------
+
+#ifndef FFT_ANALYZER_HPP
+#define FFT_ANALYZER_HPP
+
+#include "AnalysisBase.hpp"
+
+namespace Mikami
+{
+    class FftAnalyzer : public AnalyzerBase
+    {
+    public:
+        FftAnalyzer(int nData, int nFft);
+        virtual ~FftAnalyzer() {}
+
+    private:
+        Array<Complex> yFft_;   // output of FFT
+
+        virtual void Analyze(const float xn[], float yn[]);
+
+        // disallow copy constructor and assignment operator
+        FftAnalyzer(const FftAnalyzer& );
+        FftAnalyzer& operator=(const FftAnalyzer& );
+    };
+}
+
+#endif  // FFT_ANALYZER_HPP
diff -r 000000000000 -r e608fc311e4e MySpectrogram/Hamming.hpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MySpectrogram/Hamming.hpp	Sun Feb 05 07:49:54 2017 +0000
@@ -0,0 +1,48 @@
+//-------------------------------------------------------------------
+//  Hamming windowing with zero-padding
+//
+//  2016/07/23, Copyright (c) 2016 MIKAMI, Naoki
+//-------------------------------------------------------------------
+
+#ifndef HAMMING_WINDOW_HPP
+#define HAMMING_WINDOW_HPP
+
+#include "mbed.h"
+#include "Array.hpp"
+
+namespace Mikami
+{
+    class HammingWindow
+    {
+    public:
+        // Constructor
+        HammingWindow(uint16_t nData, uint16_t nFft)
+                : N_(nData), NFFT_(nFft), w_(nData)
+        {
+            float pi2L = 6.283185f/(float)nData;
+            for (int k=0; k<nData; k++)
+                w_[k] = 0.54f - 0.46f*cosf(k*pi2L);
+        }
+        
+        // Destructor
+        virtual ~HammingWindow() {}
+        
+        // Windowing
+        void Execute(const float x[], float y[])
+        {
+            for (int n=0; n<N_; n++) y[n] = x[n]*w_[n];
+            for (int n=N_; n<NFFT_; n++) y[n] = 0;
+        }
+
+    private:
+        const int N_;
+        const int NFFT_;
+                
+        Array<float> w_;
+
+        // disallow copy constructor and assignment operator
+        HammingWindow(const HammingWindow& );
+        HammingWindow& operator=(const HammingWindow& );
+    };
+}
+#endif  // HAMMING_WINDOW_HPP
diff -r 000000000000 -r e608fc311e4e MySpectrogram/MethodCollection.hpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MySpectrogram/MethodCollection.hpp	Sun Feb 05 07:49:54 2017 +0000
@@ -0,0 +1,104 @@
+//--------------------------------------------------------------
+//  スペクトログラムで使う大域関数
+//
+//  2016/08/11, Copyright (c) 2016 MIKAMI, Naoki
+//--------------------------------------------------------------
+
+#ifndef METHOD_COLLECTION_HPP
+#define METHOD_COLLECTION_HPP
+
+#include "mbed.h"
+#include "NumericLabel.hpp"
+#include "Matrix.hpp"
+#include "FFT_Analysis.hpp"
+
+namespace Mikami
+{
+    // 色相の違いで表示
+    //      0.0 <= x <= 1.0
+    uint32_t HueScale(float x)
+    {
+        if (x >= 1) return LCD_COLOR_WHITE;
+        int r = 0;
+        int b = 0;
+
+        if (x<0.5f) b = (x<0.33f) ? 255 : -(int)(1500.0f*x) + 750;
+        else        r = (0.67f<x) ? 255 :  (int)(1500.0f*x) - 750;
+        int g = 255 - (int)(1020.0f*(x - 0.5f)*(x - 0.5f));
+
+        return 0xFF000000 | (((r << 8) | g) << 8) | b;
+    }
+
+    // 座標軸
+    void DrawAxis(int x0, int y0, int w0, int h0, uint32_t axisColor,
+                  uint16_t ms100, uint16_t px1kHz, LCD_DISCO_F746NG *lcd)
+    {
+        const uint16_t TICK = 5;    // 目盛線の長さ
+        // 横標軸
+        lcd->SetTextColor(axisColor);
+        lcd->DrawHLine(x0, y0+TICK, w0);
+        for (int n=0; n<=w0/ms100; n++)
+            if ((n % 10)== 0) lcd->DrawVLine(x0+n*ms100, y0, 5);
+            else              lcd->DrawVLine(x0+n*ms100, y0+3, 2);
+        for (int n=0; n<=w0/ms100; n+=10)
+            NumericLabel<int> num(x0+n*ms100, y0+TICK+3,
+                                  "%1d", (int)(n*0.1f), Label::CENTER);
+        Label time(x0+w0/2, y0+22, "TIME [s]", Label::CENTER);
+    
+        // 縦標軸
+        lcd->SetTextColor(axisColor);
+        lcd->DrawVLine(x0-TICK, y0-h0, h0);
+        for (int n=0; n<=h0/px1kHz; n++)
+            lcd->DrawHLine(x0-TICK, y0-n*px1kHz, TICK);
+        for (int n=0; n<=h0/px1kHz; n++)
+            NumericLabel<int> num(x0-TICK-12, y0-n*px1kHz-5, "%1d", n);
+        Label hz(x0-32, y0-5*px1kHz-20, "[kHz]");
+    }
+
+    // 色と dB の関係の表示
+    void ColorDb(int y0, uint32_t axisColor, LCD_DISCO_F746NG *lcd)
+    {
+        lcd->SetTextColor(axisColor);
+        lcd->DrawVLine(455, y0-100, 100);
+        for (int n=0; n<=8; n++)
+            lcd->DrawHLine(455, y0-(n*100)/8, 4);
+        for (int n=0; n<=4; n++)
+            NumericLabel<int> num(440, y0-(n*100)/4-5, "%2d", n*20);
+        Label dB(432, y0-120, "[dB]");
+
+        for (int n=0; n<=100; n++)
+        {
+            lcd->SetTextColor(HueScale(n/100.0f));
+            lcd->DrawHLine(460, y0-n, 16);
+        }
+    }
+
+    // スペクトルの更新
+    void SpectrumUpdate(Matrix<uint32_t> &x, FftAnalyzer &analyzer,
+                        const Array<float> &sn, const Array<float> &db)
+    {
+        // 過去のスペクトルを一つずらす
+        for (int n=0; n<x.Rows()-1; n++)
+            for (int k=0; k<x.Cols(); k++)
+                x[n][k] = x[n+1][k];
+
+        // 新しいスペクトル
+        analyzer.Execute(sn, db);
+        const float FACTOR = 1.0f/80.0f;    // 表示範囲: 0 ~ 80 dB
+        for (int k=0; k<=x.Cols(); k++)
+            x[x.Rows()-1][k] = HueScale(FACTOR*((db[k] > 20) ? db[k]-20 : 0));
+    }
+
+    // スペクトルの表示
+    void DisplaySpectrum(const Matrix<uint32_t> &x, int x0, int y0,
+                         int hBar, LCD_DISCO_F746NG *lcd)
+    {
+        for (int n=0; n<x.Rows(); n++)
+            for (int k=0; k<x.Cols(); k++)
+            {
+                lcd->SetTextColor(x[n][k]);
+                lcd->DrawHLine(x0+n*hBar, y0-k, hBar);
+            }
+    }
+}
+#endif  // METHOD_COLLECTION_HPP
diff -r 000000000000 -r e608fc311e4e TS_DISCO_F746NG.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TS_DISCO_F746NG.lib	Sun Feb 05 07:49:54 2017 +0000
@@ -0,0 +1,1 @@
+https://developer.mbed.org/teams/ST/code/TS_DISCO_F746NG/#fe0cf5e2960f
diff -r 000000000000 -r e608fc311e4e UIT_FFT_Real.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/UIT_FFT_Real.lib	Sun Feb 05 07:49:54 2017 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/MikamiUitOpen/code/UIT_FFT_Real/#9649d0e2bb4a
diff -r 000000000000 -r e608fc311e4e main.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Sun Feb 05 07:49:54 2017 +0000
@@ -0,0 +1,564 @@
+/*
+ * mbed program / cwdecoder using the FFT Algorithm
+ *   tested on DISCO-F746G mbed board
+ *
+ *  Modified by Kenji Arai
+ *      http://www.page.sannet.ne.jp/kenjia/index.html
+ *      http://mbed.org/users/kenjiArai/
+ *
+ *      Started:  January  28th, 2017
+ *      Revised:  Feburary  5th, 2017
+ *
+ *  Reference program:
+ *  1)  2016/10/02, Copyright (c) 2016 MIKAMI, Naoki
+ *      https://developer.mbed.org/users/MikamiUitOpen/code/F746_Spectrogram/
+ *  2)  http://skovholm.com/cwdecoder
+ *      by Hjalmar Skovholm Hansen OZ1JHM
+ */
+ 
+//  Include --------------------------------------------------------------------
+#include "mbed.h"
+#include "SAI_InOut.hpp"
+#include "F746_GUI.hpp"
+#include "Matrix.hpp"
+#include "NumericLabel.hpp"
+#include "FFT_Analysis.hpp"
+#include "MethodCollection.hpp"
+
+#warning "If you would like to run this program, you need modify mbed revision."
+#warning "Please set mbed revision 131 (dated on Dec. 15, 2016)"
+
+//  Definition -----------------------------------------------------------------
+//#define METHOD_COLLECTION_HPP   // MethodCollection.hpp will NOT use
+
+#define HIGH            1
+#define LOW             0
+#define MILLIS()        t.read_ms()
+
+#define ONE_LINE        34
+#define LINES           11
+#define WORK_LINE       LINES
+#define TOTAL_CHAR      (ONE_LINE * LINES)
+
+#define USE_COM
+//#define USE_DEBUG
+
+#ifdef USE_COM
+#define BAUD(x)         pc.baud(x)
+#define GETC(x)         pc.getc(x)
+#define PUTC(x)         pc.putc(x)
+#define PRINTF(...)     pc.printf(__VA_ARGS__)
+#define READABLE(x)     pc.readable(x)
+#else
+#define BAUD(x)         {;}
+#define GETC(x)         {;}
+#define PUTC(x)         {;}
+#define PRINTF(...)     {;}
+#define READABLE(x)     {;}
+#endif
+
+#ifdef USE_DEBUG
+#define DEBUG(...)      pc.printf(__VA_ARGS__)
+#else
+#define DEBUG(...)      {;}
+#endif
+
+using namespace Mikami;
+
+//  ROM / Constant data --------------------------------------------------------
+const int FS     = I2S_AUDIOFREQ_32K;
+const int N_FFT  = 512;
+#define SLOT_750HZ 12       // 32KHz /512 * 12 = 750Hz
+
+char *const open_msg[] = {
+    "Center freq.:       750 Hz",
+    "Sampling freq.       32 kHz",   
+    "FFT / # of points:  512",
+    "Two modes ",
+    "(1) CW / MORSE Decoder",
+    "(2) Show Spectram"
+};
+
+//  RAM ------------------------------------------------------------------------
+float       magnitude ;
+int16_t     magnitudelimit      = 100;
+int16_t     magnitudelimit_low  = 100;
+int16_t     realstate = LOW;
+int16_t     realstatebefore     = LOW;
+int16_t     filteredstate       = LOW;
+int16_t     filteredstatebefore = LOW;
+int16_t     nbtime              = 2;         // ms noise blanker         
+int32_t     starttimehigh;
+int32_t     highduration;
+int32_t     lasthighduration;
+int32_t     hightimesavg;
+int32_t     lowtimesavg;
+int32_t     startttimelow;
+int32_t     lowduration;
+int32_t     laststarttime       = 0;
+char        code[32];
+int16_t     stop                = LOW;
+int16_t     wpm;
+uint32_t    cycle               = 0;
+uint8_t     msg_lcd[LINES + 1][48];
+uint8_t     num_last_line       = 0;
+Array<float> sn(N_FFT+1);
+Array<float> db(N_FFT/2+1);
+LCD_DISCO_F746NG *lcd = GuiBase::GetLcdPtr();
+
+//  Object ---------------------------------------------------------------------
+Timer       t;
+DigitalOut  myled(LED1);
+DigitalOut  data_in(D5);
+DigitalOut  loop_trg(D6);
+DigitalOut  out_code(D7);
+Serial      pc(USBTX, USBRX);
+SaiIO       mySai(SaiIO::INPUT, N_FFT+1, FS, INPUT_DEVICE_DIGITAL_MICROPHONE_2);
+FftAnalyzer fftAnalyzer(N_FFT+1, N_FFT);
+
+//  Function prototypes --------------------------------------------------------
+void    setup(void);
+void    loop(void);
+void    docode(void);
+void    printascii(char);
+void    adc_convert(void);
+float   SpectrumUpdate(FftAnalyzer &analyzer,
+        const Array<float> &sn, const Array<float> &db);
+void    cw_decoder(void);
+void    spectrogram(void);
+uint8_t mode_slect(void);
+void    spectrum(void);
+//------------------------------------------------------------------------------
+//  Control Program
+//------------------------------------------------------------------------------
+int main()
+{
+    while (true){
+        lcd->Clear(GuiBase::ENUM_BACK);
+        uint8_t n = mode_slect();
+        switch (n){
+            case 0:
+                cw_decoder();
+                break;
+            case 1:
+                spectrum();
+                break;
+            default:
+                break;
+        }
+    }
+}
+
+uint8_t mode_slect()
+{
+    Label obj0(240, 2, "Operationg Mode",
+               Label::CENTER, Font24, LCD_COLOR_LIGHTGREEN);
+    Label obj1(40,  30, open_msg[0], Label::LEFT, Font20);
+    Label obj2(40,  50, open_msg[1], Label::LEFT, Font20);
+    Label obj3(40,  70, open_msg[2], Label::LEFT, Font20);
+    Label obj4(40, 100, open_msg[3], Label::LEFT, Font20, LCD_COLOR_LIGHTGREEN);
+    Label obj5(70, 120, open_msg[4], Label::LEFT, Font20, LCD_COLOR_LIGHTGREEN);
+    Label obj6(70, 140, open_msg[5], Label::LEFT, Font20, LCD_COLOR_LIGHTGREEN);
+    Button button0( 50, 200, 180, 50, "CW/MORSE", Font24);
+    Button button1(260, 200, 180, 50, "SPECTRAM", Font24);
+    while (true){
+        if (button0.Touched()){     return 0UL;}
+        if (button1.Touched()){     return 1UL;}
+        wait(0.02f);
+    }
+}
+
+void spectrogram()
+{
+    lcd->Clear(GuiBase::ENUM_BACK);
+    PRINTF("\r\nFFT Spectroram\r\n");
+    Button button10(380, 240, 80, 30, "MENUE", Font16);
+        spectrum();
+        if (button10.Touched()){     return;}
+}
+
+void cw_decoder()
+{
+    lcd->Clear(GuiBase::ENUM_BACK);
+    PRINTF("\r\nCW Decoder(FFT) by JH1PJL\r\n");
+    Label myLabel1(120, 250, "CW Decoder(FFT) by JH1PJL",
+                    Label::CENTER, Font16);
+    Button button20(380, 240, 80, 30, "MENUE", Font16);
+    printf("Sys=%u\r\n", SystemCoreClock);
+    lcd->SetTextColor(LCD_COLOR_GREEN);
+    lcd->SetFont(&Font20);
+    mySai.RecordIn();
+    t.start();
+    while (true){
+        loop_trg = !loop_trg;
+        data_in = 1;
+        while (mySai.IsCaptured() == false){;}
+        for (int n=0; n<mySai.GetLength(); n++){
+            int16_t xL, xR;
+            mySai.Input(xL, xR);
+            sn[n] = (float)xL;
+        }
+        data_in = 0;
+        //magnitude = SpectrumUpdate(spectra, fftAnalyzer, sn, db);
+        magnitude = SpectrumUpdate(fftAnalyzer, sn, db);
+        //printf("%f\r\n", magnitude);
+        if (magnitude > magnitudelimit_low){ // magnitude limit automatic
+            magnitudelimit =    // moving average filter
+                    (magnitudelimit +((magnitude - magnitudelimit) / 6.0f));
+        }
+        if (magnitudelimit < magnitudelimit_low){
+            magnitudelimit = magnitudelimit_low;
+        }
+        // check for the magnitude
+        if(magnitude > magnitudelimit * 0.9f){ // just to have some space up 
+            realstate = HIGH; 
+        } else {
+            realstate = LOW;
+        }
+        // clean up the state with a noise blanker
+        if (realstate != realstatebefore){
+            laststarttime = MILLIS();
+        }
+        if ((MILLIS()-laststarttime)> nbtime){
+            if (realstate != filteredstate){
+                filteredstate = realstate;
+            }
+        }
+        // durations on high and low
+        if (filteredstate != filteredstatebefore){
+            if (filteredstate == HIGH){
+                starttimehigh = MILLIS();
+                lowduration = (MILLIS() - startttimelow);
+            }
+            if (filteredstate == LOW){
+                startttimelow = MILLIS();
+                highduration = (MILLIS() - starttimehigh);
+                if (highduration < (2.0f *hightimesavg) || hightimesavg == 0.0f){
+                    // now we know avg dit time ( rolling 3 avg)
+                    hightimesavg = (highduration+hightimesavg+hightimesavg) / 3.0f;
+                }
+                if (highduration > (5.0f * hightimesavg) ){
+                    // if speed decrease fast ..
+                    hightimesavg = highduration+hightimesavg;
+                }
+            }
+        }
+        // now we will check which kind of baud we have - dit or dah
+        // and what kind of pause we do have 1 - 3 or 7 pause
+        // we think that hightimeavg = 1 bit
+        if (filteredstate != filteredstatebefore){
+            stop = LOW;
+            if (filteredstate == LOW){  //// we did end a HIGH
+                // 0.6 filter out false dits
+                if (highduration < (hightimesavg * 2.0f)
+                     && highduration > (hightimesavg * 0.6f)){ 
+                    strcat(code,".");
+                    DEBUG(".");
+                }
+                if (highduration > (hightimesavg*2)
+                     && highduration < (hightimesavg * 6.0f)){ 
+                    strcat(code,"-");
+                    DEBUG("-");
+                    wpm = (wpm + (1200/((highduration)/3)))/2;
+                }
+            }
+            if (filteredstate == HIGH){  // we did end a LOW
+                float lacktime = 1;
+                //  when high speeds we have to have a little more pause
+                //  before new letter or new word
+                if(wpm > 25){   lacktime = 1.0f;} 
+                if(wpm > 30){   lacktime = 1.2f;}
+                if(wpm > 35){   lacktime = 1.5f;}
+                if(wpm > 40){   lacktime = 1.7f;}
+                if(wpm > 45){   lacktime = 1.9f;}
+                if(wpm > 50){   lacktime = 2.0f;}
+                if (lowduration > (hightimesavg*(2.0f * lacktime))
+                            && lowduration < hightimesavg*(5.0f * lacktime)){
+                    docode();
+                    code[0] = '\0';
+                    DEBUG("/");
+                }
+                if (lowduration >= hightimesavg*(5.0f * lacktime)){ // word space
+                    docode();
+                    code[0] = '\0';
+                    printascii(' ');
+                    DEBUG("\r\n");
+                }
+            }
+        }
+        // write if no more letters
+        if ((MILLIS() - startttimelow) > (highduration * 6.0f) && stop == LOW){
+            docode();
+            code[0] = '\0';
+            stop = HIGH;
+        }
+        // we will turn on and off the LED
+        // and the speaker
+        if(filteredstate == HIGH){ 
+            myled = HIGH;
+        } else {
+            myled = LOW;
+        }
+        // the end of main loop clean up
+        realstatebefore = realstate;
+        lasthighduration = highduration;
+        filteredstatebefore = filteredstate;
+        DEBUG("%d\r\n", t.read_ms());
+        // return to menue or continue
+        if (button20.Touched()){     return;}
+    }
+}
+
+float SpectrumUpdate(FftAnalyzer &analyzer,
+                    const Array<float> &sn, const Array<float> &db)
+{
+    analyzer.Execute(sn, db);
+    return (db[SLOT_750HZ] - 20) * 2;
+}
+
+// translate cw code to ascii
+void docode()
+{
+    //PRINTF("decording<%s>", code);
+    if (code[0] == '.'){             // .
+        if (code[1] == '.'){         // ..
+            if (code[2] == '.'){     // ...
+                if (code[3] == '.'){ // ....
+                    if (strcmp(code,"...."   ) == 0){ printascii('H'); return;}
+                    if (strcmp(code,"....."  ) == 0){ printascii('5'); return;}
+                    if (strcmp(code,"....-"  ) == 0){ printascii('4'); return;}
+                } else if (code[3] == '-'){     // ...-
+                    if (code[4] == '.'){        // ...-.
+                        if (strcmp(code,"...-."  ) == 0)
+                                                    { printascii(126); return;}
+                        if (strcmp(code,"...-.-" ) == 0)
+                                                    { printascii(62);  return;}
+                        if (strcmp(code,"...-..-") == 0)
+                                                    { printascii(36);  return;}
+                    } else if (code[4] == '-'){ // ...--
+                        if (strcmp(code,"...--"  ) == 0)
+                                                    { printascii('3'); return;}
+                    } else {
+                        if (strcmp(code,"...-"   ) == 0)
+                                                    { printascii('V'); return;} 
+                    }
+                } else {                        // ...
+                    if (strcmp(code,"..."    ) == 0){ printascii('S'); return;}
+                }
+            } else if (code[2] == '-'){ // ..-
+                if (strcmp(code,"..-"    ) == 0){ printascii('U');  return;}
+                if (strcmp(code,"..-."   ) == 0){ printascii('F');  return;}
+                if (strcmp(code,"..---"  ) == 0){ printascii('2');  return;}
+                if (strcmp(code,"..--.." ) == 0){ printascii(63);   return;}
+            } else {                    // ..
+                if (strcmp(code,".."      ) == 0){ printascii('I');  return;}
+            }
+        } else if (code[1] == '-'){         // .-
+            if (code[2] == '.'){            // .-.
+                if (code[3] == '.'){        // .-..
+                    if (strcmp(code,".-.."   ) == 0){ printascii('L'); return;}
+                    if (strcmp(code,".-..."  ) == 0){ printascii(95);  return;}
+                } else if (code[3] == '-'){ // .-.-
+                    if (strcmp(code,".-.-"   ) == 0){ printascii(3);   return;}
+                    if (strcmp(code,".-.-."  ) == 0){ printascii(60);  return;}
+                    if (strcmp(code,".-.-.-" ) == 0){ printascii(46);  return;}
+                } else {                    // .-.
+                    if (strcmp(code,".-."    ) == 0){ printascii('R'); return;}
+                }
+            } else if (code[2] == '-'){     // .--
+                if (code[3] == '.'){        // .--.
+                    if (strcmp(code,".--."   ) == 0){ printascii('P'); return;}
+                    if (strcmp(code,".--.-"  ) == 0){ printascii('-'); return;}
+                    if (strcmp(code,".--.-." ) == 0){ printascii(64);  return;}
+                } else if (code[3] == '-'){ // .---
+                    if (strcmp(code,".---"   ) == 0){ printascii('J'); return;}
+                    if (strcmp(code,".----"  ) == 0){ printascii('1'); return;}
+                } else {                    // .--
+                    if (strcmp(code,".--"    ) == 0){ printascii('W'); return;}
+                }
+            } else {                        // .-
+                if (strcmp(code,".-") == 0){ printascii('A'); return;}
+            }
+        } else {    // .
+            if (strcmp(code,".") == 0){ printascii('E'); return;}
+        }
+    } else if (code[0] == '-'){             // -
+        if (code[1] == '.'){                // -.
+            if (code[2] == '.'){            // -..
+                if (code[3] == '.'){        // -...
+                    if (strcmp(code,"-..."   ) == 0){ printascii('B'); return;}
+                    if (strcmp(code,"-...."  ) == 0){ printascii('6'); return;}
+                    if (strcmp(code,"-....-" ) == 0){ printascii('-'); return;}
+                } else if (code[3] == '-'){ // -..-
+                    if (strcmp(code,"-..-"   ) == 0){ printascii('X'); return;}
+                    if (strcmp(code,"-..-."  ) == 0){ printascii(47);  return;}
+                } else {
+                    if (strcmp(code,"-.."    ) == 0){ printascii('D'); return;}
+                }
+            } else if (code[2] == '-'){     // -.-
+                if (code[3] == '.'){        // -.-.
+                    if (strcmp(code,"-.-."   ) == 0){ printascii('C'); return;}
+                    if (strcmp(code,"-.-.--" ) == 0){ printascii(33);  return;}
+                } else if (code[3] == '-'){ // -.--
+                    if (strcmp(code,"-.--"   ) == 0){ printascii('Y'); return;}
+                    if (strcmp(code,"-.--."  ) == 0){ printascii(40);  return;}
+                    if (strcmp(code,"-.--.-" ) == 0){ printascii(41);  return;}
+                } else {                    // -.-
+                    if (strcmp(code,"-.-"    ) == 0){ printascii('K'); return;}
+                }
+            } else {                        // -.
+                if (strcmp(code,"-.") == 0){ printascii('N'); return;}
+            }
+        } else if (code[1] == '-'){         // -
+            if (code[2] == '.'){            // --.
+                if (strcmp(code,"--."    ) == 0){ printascii('G'); return;}
+                if (strcmp(code,"--.."   ) == 0){ printascii('Z'); return;}
+                if (strcmp(code,"--.-"   ) == 0){ printascii('Q'); return;}
+                if (strcmp(code,"--..."  ) == 0){ printascii('7'); return;}
+                if (strcmp(code,"--..--" ) == 0){ printascii(44);  return;}                                         
+            } else if (code[2] == '-'){     // ---
+                if (code[3] == '.'){        // ---.
+                    if (strcmp(code,"---.."  ) == 0){ printascii('8'); return;}
+                    if (strcmp(code,"---."   ) == 0){ printascii(4);   return;}
+                    if (strcmp(code,"---..." ) == 0){ printascii(58);  return;}
+                } else if (code[3] == '-'){ // ----
+                    if (strcmp(code,"----."  ) == 0){ printascii('9'); return;}
+                    if (strcmp(code,"-----"  ) == 0){ printascii('0'); return;}
+                } else {                    // ---
+                    if (strcmp(code,"---"    ) == 0){ printascii('O'); return;}
+                } 
+            } else {        // --
+                if (strcmp(code,"--") == 0){ printascii('M'); return;}
+            }
+        } else {    // -
+            if (strcmp(code,"-") == 0){ printascii('T'); return;}
+        }
+    }   
+}
+
+void printascii(char c)
+{
+    uint8_t i,j;
+
+    out_code = 1;
+    PRINTF("%c", c);
+    msg_lcd[WORK_LINE][num_last_line++] = c;
+    if (num_last_line == ONE_LINE){
+        for (j = 0; j < LINES; j++){ // scroll one line
+            for (i =0; i < ONE_LINE; i++){
+                msg_lcd[j][i] = msg_lcd[j+1][i];
+            }
+        }
+        for (i =0; i < ONE_LINE; i++){  // Clear last line
+            msg_lcd[WORK_LINE][i] = ' ';
+        }
+        num_last_line = 0;
+        for (i =0; i < (WORK_LINE + 1); i++){
+            lcd->DisplayStringAtLine( i, &msg_lcd[i][0]);
+        }
+    } else {
+        lcd->DisplayStringAtLine(WORK_LINE, &msg_lcd[WORK_LINE][0]);
+    }
+    out_code = 0;
+}
+
+//------------------------------------------------
+//  リアルタイム・スペクトログラム
+//      入力: MEMS マイク
+//
+//  2016/10/02, Copyright (c) 2016 MIKAMI, Naoki
+//  modified by JH1PJL
+//------------------------------------------------
+void spectrum()
+{
+    const int FS = I2S_AUDIOFREQ_16K;   // 標本化周波数: 16 kHz
+    const int N_FFT = 512;              // FFT の点数
+    const float FRAME = (N_FFT/(float)FS)*1000.0f;  // 1 フレームに対応する時間(単位:ms)
+
+    const int X0    = 40;           // 表示領域の x 座標の原点
+    const int Y0    = 200;          // 表示領域の y 座標の原点
+    const int H0    = 160;          // 表示する際の周波数軸の長さ(5 kHz に対応)
+    const uint16_t PX_1KHZ = H0/5;  // 1 kHz に対応するピクセル数
+    const int W0    = 360;          // 横方向の全体の表示の幅(単位:ピクセル)
+    const int H_BAR = 2;            // 表示する際の 1 フレームに対応する横方向のピクセル数
+    const int SIZE_X = W0/H_BAR;
+    const uint16_t MS100 = 100*H_BAR/FRAME; // 100 ms に対応するピクセル数
+    const uint32_t AXIS_COLOR = LCD_COLOR_WHITE;//0xFFCCFFFF;
+    
+    Matrix<uint32_t> spectra(SIZE_X, H0+1, GuiBase::ENUM_BACK);
+
+    SaiIO mySai(SaiIO::INPUT, N_FFT+1, FS,
+                INPUT_DEVICE_DIGITAL_MICROPHONE_2);
+
+    LCD_DISCO_F746NG *lcd = GuiBase::GetLcdPtr();   // LCD 表示器のオブジェクト
+    lcd->Clear(GuiBase::ENUM_BACK);
+    Label myLabel1(240, 2, "Real-time spectrogram", Label::CENTER, Font16);
+
+    // ButtonGroup の設定
+    const uint16_t B_W = 50;
+    const uint16_t B_Y = 242;
+    const uint16_t B_H = 30;
+    const string RUN_STOP[3] = {"MENUE","RUN", "STOP"};
+    ButtonGroup runStop(285, B_Y, B_W, B_H, 3, RUN_STOP, 0, 0, 3, 1);
+    
+    Button clear(430, B_Y, B_W, B_H, "CLEAR");
+    clear.Inactivate();
+    // ButtonGroup の設定(ここまで)
+
+    // 座標軸
+    DrawAxis(X0, Y0, W0, H0, AXIS_COLOR, MS100, PX_1KHZ, lcd);
+
+    Array<float> sn(N_FFT+1);
+    Array<float> db(N_FFT/2+1);
+
+    // 色と dB の関係の表示
+    ColorDb(Y0, AXIS_COLOR, lcd);
+        
+    FftAnalyzer fftAnalyzer(N_FFT+1, N_FFT);
+
+    // ループ内で使う変数の初期化
+    int stop = 1;       // 0: run, 1: stop
+
+    while(!runStop.GetTouchedNumber(stop)) {}
+    // データ読み込み開始
+    mySai.RecordIn();
+  
+    while (true)
+    {
+        runStop.GetTouchedNumber(stop);
+
+        if (stop == 0){
+            NVIC_SystemReset();
+        }
+        else if (stop == 1)
+        {
+            clear.Inactivate();
+            if (mySai.IsCaptured())
+            {
+                // 1フレーム分の信号の入力
+                for (int n=0; n<mySai.GetLength(); n++)
+                {
+                    int16_t xL, xR;
+                    mySai.Input(xL, xR);
+                    sn[n] = (float)xL;
+                }
+                //mySai.ResetCaptured();
+
+                // スペクトルの更新
+                SpectrumUpdate(spectra, fftAnalyzer, sn, db);
+                // スペクトルの表示
+                DisplaySpectrum(spectra, X0, Y0, H_BAR, lcd);
+            }
+        }
+        else if (stop == 2)
+        {
+            if (!clear.IsActive()) clear.Activate();
+            if (clear.Touched())
+            {
+                spectra.Fill(GuiBase::ENUM_BACK);   // スペクトルの表示をクリア
+                DisplaySpectrum(spectra, X0, Y0, H_BAR, lcd);
+                clear.Draw();
+            }
+        }
+    }
+}
diff -r 000000000000 -r e608fc311e4e mbed.bld
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Sun Feb 05 07:49:54 2017 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/faff56e089b2
\ No newline at end of file