Thursday, June 28, 2018

ESP32 from Espressif Systems

This beast is really awesome.  For about $6 (on eBay), we can get a full functional IoT system using ESP32 application SoC made by a Chinese company called Espressif.  The CPU core is based on XTensa architecture.  XTensa is a CPU/MCU architecture designed by a Silicon Valley-based company named Cadence Tensilica.  Cadence Tensilica, according to Wikipedia, was founded by the former co-founder of the MIPS Technologies (one of the first player in RISC CPU architecture), Chris Rowen.

Espressif bought the IP rights to use in their own SoC products such as in ESP32 series. ESP32 itself is an evolutional product of its predecessor, ESP8266.  A lot of features in this tiny SoC, such as WiFi & Bluetooth,  cryptographic co-processor, Hall sensor, generous amount of ADC inputs (but multiplexed with other GPIOs), 2 DAC outputs, SPI, I2S, I2C,  ultra-low power coprocessor, Ethernet MAC MII interface (but we need to add PHY interface to connect to a medium), temperature sensor, touch sensors, CAN, 4 MB flash, etc.

Another interesting and cool thing is there a bunch of toolkits, SDK etc., including FreeRTOS support.  Configuring the device can be as easy with menu-driven a-la Linux Kernel.

The Extensa ISA is actually a hybrid of RISC and CISC ISA.  As detailed in the documents at Github, about it has about 80 RISC instructions with length 24 or 16-bit (unlike common RISC instructions which uniformly 32 bits).  The architecture let the SoC designers customize it to add several extended CISC instructions to speed up and save memory space.  The CPU endianness is also changeable between Little and Big endian.

The extended instructions, among others, are to support MAC (Multiply-Accumulate) which is common in DSP applications and other media processing operations.  Another thing is the support for coprocessors.

Below is an example to blink the onboard LED (GPIO2) with FreeRTOS:


/* Blink Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "sdkconfig.h"

/* Can run 'make menuconfig' to choose the GPIO to blink,
   or you can edit the following line and set a number here.
*/
#define BLINK_GPIO CONFIG_BLINK_GPIO

void blink_task(void *pvParameter)
{
    /* Configure the IOMUX register for pad BLINK_GPIO (some pads are
       muxed to GPIO on reset already, but some default to other
       functions and need to be switched to GPIO. Consult the
       Technical Reference for a list of pads and their default
       functions.)
    */
    gpio_pad_select_gpio(BLINK_GPIO);
    /* Set the GPIO as a push/pull output */
    gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT);
    while(1) {
        /* Blink off (output low) */
        gpio_set_level(BLINK_GPIO, 0);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
        /* Blink on (output high) */
        gpio_set_level(BLINK_GPIO, 1);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

void app_main()
{
    xTaskCreate(&blink_task, "blink_task", configMINIMAL_STACK_SIZE, NULL, 5, NULL);
}



As described in https://www.freertos.org/a00125.html,  the format of task creation API is:

BaseType_t xTaskCreate( TaskFunction_t pvTaskCode, const char * const pcName, unsigned short usStackDepth, void *pvParameters, UBaseType_t uxPriority, TaskHandle_t *pxCreatedTask )

Each task is assigned a priority from 0 to ( configMAX_PRIORITIES - 1 ), where 0 is the lowest priority and configMAX_PRIORITIES is defined within FreeRTOSConfig.h:

/* This has impact on speed of search for highest priority */
#ifdef SMALL_TEST
#define configMAX_PRIORITIES ( 7 )
#else
#define configMAX_PRIORITIES ( 25 )

#endif

Low priority numbers denote low priority tasks. The idle task has priority zero (tskIDLE_PRIORITY).

Sunday, June 10, 2018

Regular Expression in C++

RegexDemo.h:


#ifndef REGEXDEMO_H
#define REGEXDEMO_H

#include <iostream>
#include <string>
#include <regex>

class RegexDemo
{
    public:
        /** Default constructor */
        RegexDemo(char const *str) : m_str(str), m_matches() {};
        RegexDemo(std::string const & str);
        /** Default destructor */
        virtual ~RegexDemo();

        bool match(std::string const & pattern)
        {
            return match(pattern.c_str());
        }
        bool match(char const * pattern);

        std::cmatch& get_cmatch() { return m_matches; }

        friend std::ostream& operator<<(std::ostream& ios, std::cmatch const & cm);
    protected:

    private:
        std::string     m_str;
        std::cmatch     m_matches;
        std::regex_constants::match_flag_type flag = std::regex_constants::match_any;
};


std::ostream& operator<<(std::ostream& ios, std::cmatch const & cm);

#endif // REGEXDEMO_H


RegexDemo.cpp:


#include "RegexDemo.h"

RegexDemo::RegexDemo(std::string const & str) :
    m_str(str), m_matches()
{
    //ctor
}

RegexDemo::~RegexDemo()
{
    //dtor
}


#if 0
bool RegexDemo::match(std::string const & pattern)
{
    std::regex exp(pattern);
    return std::regex_match(m_str, exp);
}
#endif


bool RegexDemo::match(char const * pattern/*, std::cmatch &cm*/)
{
    std::regex exp(pattern);
    return std::regex_match(m_str.c_str(), m_matches, exp, flag);
}


std::ostream& operator<<(std::ostream& ios, std::cmatch const & cm)
{
    for(unsigned i=0; i< cm.size(); ++i)
    {
        ios << "[" << cm[i] << "] ";
    }

    return ios;
}


main.cpp:

#include <iostream>
#include "RegexDemo.h"

using namespace std;

int main()
{
    RegexDemo reg("Hello, World Ahsan,123Bae!");

    std::cout << "Match1: " << reg.match(".*123!") << std::endl;

    std::cmatch matches;
    if (reg.match("(.*),([0-9]+)(.*)"))
    {
        std::cout << "The matches were: " << reg.get_cmatch() << std::endl;
        std::cout << "The number is " << reg.get_cmatch()[2] << std::endl;
    }
    return 0;
}

The Output


$ ./myregex 
Match1: 0
The matches were: [Hello, World Ahsan,123Bae!] [Hello, World Ahsan] [123] [Bae!] 
The number is 123

Saturday, May 19, 2018

How to build wxWidgets for Windows

For sure we need Visual Studio installed (get the community edition for free).  After we install the source code package (e.g, in B:\WxWidgets-3.0.4)

Steps to build:

  1. Open "x64 Native Tools Command Prompt for VS ..." Command shell (just type in the Cortana search)
  2. Change to the wxWidgets directory
  3. type: 
b:
cd wxWidgets-3.0.4\build\msw

nmake /f makefile.vc

After it finishes, just set WXWIN environment variable to poin to that directory (e.g, B:\WxWidgets-3.0.4)



Thursday, May 10, 2018

How to print ClassName


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#ifndef __CNAME_H__
#define __CNAME_H__

#include <string>


inline std::string className(const std::string& prettyFunction)
{
    size_t colons = prettyFunction.find("::");
    if (colons == std::string::npos)
        return "::";

    size_t begin = prettyFunction.find_last_of("::") + 1;
    return prettyFunction.substr(begin);
}

#ifdef __GNUC__
#define __CLASS_NAME__ className(__PRETTY_FUNCTION__)
#define __FUNCNAME__ __PRETTY_FUNCTION__
#else
#define __CLASS_NAME__ className(__FUNCTION__)
#define __FUNCNAME__ __FUNCTION__
#endif

#endif

Vector of Smart Pointers with Template


#include <iostream>
#include <vector>
#include <memory>
#include <sstream>
#include <string>
#include <typeinfo>


// Require C++ version 14 to compile!

class Base
{
public:
    Base(Base & other);
    Base(Base *);
    Base(char const * const tag, char const * const desc) : m_tag(tag), m_desc(desc) {}
    //Base(std::string const & tag, std::string const & desc) : m_tag(tag), m_desc(desc) {}
    ~Base() = default;

    void print();
    virtual void Process(); 

public:
    std::string m_tag = "";
    std::string m_desc = "";
};



Base::Base(Base & rhs)
{
    m_tag = rhs.m_tag;
    m_desc = rhs.m_desc;
}


Base::Base(Base *pOther)
{
    m_tag = pOther->m_tag;
    m_desc = pOther->m_desc;
}


void Base::print()
{
    std::cout << __FUNCTION__ << "(" << this << "): Base::m_tag = " << m_tag << std::endl 
              << "                  Base::m_desc = " << m_desc << std::endl;
}


void Base::Process()
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}



template <class CNAME>
Base* createClass(char const *const tag, char const * const desc)
{
    CNAME * pObj  = new CNAME(tag,desc);

    std::cout << "Inside " << __FUNCTION__  << "(): ";
    pObj->Process();
    return dynamic_cast<Base*>(pObj);
}


template <class CNAME>
std::unique_ptr<Base> createUniqueClass(char const *const tag, char const *const desc)
{
    std::unique_ptr<Base> obj(createClass<CNAME>(tag, desc));
    return obj;
}



class KelasA : public Base
{
public:
    KelasA(char const * const tag, char const * const desc) : Base(tag, desc) {}
 static std::string const DefaultKelasName;

    void Process() override;
private:
 std::string m_name = DefaultKelasName;
};

std::string const KelasA::DefaultKelasName = "A";




void KelasA::Process()
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}


class KelasB : public Base
{
public:
    KelasB(char const * const tag, char const * const desc) : Base(tag, desc) {}
 static std::string const DefaultKelasName;
    void Process() override;
private:
 std::string m_name = DefaultKelasName;
};


std::string const KelasB::DefaultKelasName = "B";


void KelasB::Process()
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}


class Container
{
public:
 template <class CNAME>
 void Add(std::string tag = "")
 {
  std::ostringstream sout;
  sout << __FUNCTION__ << ":Entry=" << m_bin.size();
  #define ANAM(x) #x
  m_bin.push_back(createUniqueClass<CNAME>(tag.c_str(), const_cast<char const *>(sout.str().c_str())));
 }

 void Process();


private:
    std::vector<std::unique_ptr<Base>> m_bin;
};



void Container::Process()
{
 for(auto & v : m_bin)
    {
        v->Process();
        v->print();
    }
}


int main()
{
 Container c;

 for(auto i = 0; i<10; ++i)
 {
  c.Add<KelasA>("A");
  c.Add<KelasB>("B");
 }

 c.Process();
 
    return 0;
}

Vector of Smart Pointers (revised)

The previous example doesn't really show the polymorphism. This example shows the coolness of C++ (version 14):





#include <iostream>
#include <vector>
#include <memory>


// Require C++ version 14 to compile!

class Base
{
public:
    Base(Base & other);
    Base(Base *);
    Base(char const * const tag, char const * const desc) : m_tag(tag), m_desc(desc) {}
    ~Base() = default;

    void print();
    virtual void Process(); 

public:
    std::string m_tag = "";
    std::string m_desc = "";
};



Base::Base(Base & rhs)
{
    m_tag = rhs.m_tag;
    m_desc = rhs.m_desc;
}


Base::Base(Base *pOther)
{
    m_tag = pOther->m_tag;
    m_desc = pOther->m_desc;
}


void Base::print()
{
    std::cout << __FUNCTION__ << "(" << this << "): Base::m_tag = " << m_tag << std::endl 
              << "                  Base::m_desc = " << m_desc << std::endl;
}


void Base::Process()
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}



template <class CNAME>
Base* createClass(char const *const tag, char const * const desc)
{
    CNAME * pObj  = new CNAME(tag,desc);

    std::cout << "Inside " << __FUNCTION__  << "(): ";
    pObj->Process();
    return dynamic_cast<Base*>(pObj);
}


template <class CNAME>
std::unique_ptr<Base> createUniqueClass(char const *const tag, char const *const desc)
{
    std::unique_ptr<Base> obj(createClass<CNAME>(tag, desc));
    return obj;
}



class KelasA : public Base
{
public:

    KelasA(char const * const tag, char const * const desc) : Base(tag, desc) {}
    void Process() override;
};


void KelasA::Process()
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}


class KelasB : public Base
{
public:
    KelasB(char const * const tag, char const * const desc) : Base("B", desc) {}
    void Process() override;
};



void KelasB::Process()
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}




int main()
{
    std::vector<std::unique_ptr<Base>> vb;

    vb.push_back(createUniqueClass<KelasA>("A", "Kelase A-1"));

    vb.push_back(createUniqueClass<KelasB>("B", "Kelase B-1"));

    //for(auto v = vb.begin(); v != vb.end(); v++)a
    for(auto & v : vb)
    {
        v->Process();
        v->print();
    }

    return 0;
}