Month: November 2022

CNN for MCUs, some links

https://github.com/jonnor/ESC-CNN-microcontroller

https://bdtechtalks.com/2022/01/17/mcunetv2-tinyml-deep-learning-microcontrollers/ 

https://eloquentarduino.github.io/2020/11/tinyml-on-arduino-and-stm32-cnn-convolutional-neural-network-example/

MCU with CNN: https://www.maximintegrated.com/en/products/microcontrollers/MAX78000.html

Converting Chinese text from GB18030 to UTF-8

I was trying to convert a text from chinese that was “scrambled” like this:

4£©ÍêÉÆAACœâÂëÒì³£ÎÊÌ⣻
5£©ÍêÉÆBT VOLͬ²œ¹ŠÄÜ£»
6£©ÍêÉÆÀ¶ÑÀžèÇúID3ÐÅÏ¢Òì³£ÎÊÌâ;
7£©ÐÞžŽÀ¶ÑÀ¿ª»ú»ØÁ¬¡¢ÊÖ»úÖ÷¶¯Á¬œÓ£¬·ŽžŽµÄ²Ù×÷£¬»á³öÏÖÒì³£žŽÎ»ÎÊÌ⣻
8£©À¶ÑÀ²¥·ÅìÒ»úÎȶšÐÔÍêÉÆ£»
9£©À¶ÑÀÍš»°Ïà¹ØŒæÈÝÐÔ£¬œ¡×³ÐÔÍêÉÆ£»
10£©ÔöŒÓÊÖ»úÀŽµç²¥·Å±ŸµØÌáÊŸÒôµÄ¹ŠÄÜ£¬ŒûCFG_BT_RING_LOCAL²¿·Ö£»
3.HDMI/ͬÖá/¹âÏËÏà¹ØžüУº
1£©JVC£¬º£ÐÅ,СÃ×Æ·ÅƵçÊÓŒæÈÝÐÔÍêÉÆ£»

Then I used the same strategy from here.

$ uchardet Chinese_Scrambled_Text.txt
GB18030
$ iconv -f GB18030 -t UTF-8//TRANSLIT Chinese_Scrambled_Text -o Chinese_Readable_UTF8.txt

Getting OpenOCD to work with Ai-Thinker VC-01

Continuing my adventure with VC-01 module (powered by Unisound US516P6) I found the OpenOCD used with JTAG programmer (VC_Burner B228) and fixed the configuration to get it working (WIP).

First we need to clone this specific openocd repository:

$ git clone https://github.com/andestech/nds-openocd

Then compile it (I enabled all the programmers supported by OpenOCD, but you just need aice)

$ ./bootstrap
$ ./configure --enable-internal-jimtcl --enable-maintainer-mode --disable-werror --disable-shared --enable-stlink --enable-aice --enable-jlink --enable-rlink --enable-vslink --enable-ti-icdi --enable-remote-bitbang --enable-usb-blaster --enable-presto --enable-osbdm
$ sudo make install

You need this OpenOCD config file:

$ cat openocd_nds32.cfg 
log_output iceman_debug0.log
debug_level 3
gdb_port 9902
telnet_port 9901
tcl_port 6666
source [find interface/nds32-aice.cfg]
source [find board/nds32_xc5.cfg]

gdb_target_description enable
gdb_report_data_abort enable
nds log_file_size 10485760
nds global_stop off
nds reset_halt_as_init on
nds boot_time 5000
nds reset_time 1000

Note: you need to edit /usr/local/share/openocd/scripts/interface/nds32-aice.cfg and use:

adapter_khz 12000

instead of 24000!


$ sudo openocd -f openocd_nds32.cfg -d3
Open On-Chip Debugger 0.10.0+dev-g47292a9c3 (2022-11-14-13:07)
Licensed under GNU GPL v2
For bug reports, read
	http://openocd.org/doc/doxygen/bugs.html
User : 91 1 options.c:60 configuration_output_handler(): debug_level: 3
User : 92 1 options.c:60 configuration_output_handler(): 
Debug: 93 1 options.c:184 add_default_dirs(): bindir=/usr/local/bin
Debug: 94 1 options.c:185 add_default_dirs(): pkgdatadir=/usr/local/share/openocd
Debug: 95 1 options.c:186 add_default_dirs(): exepath=/usr/local/bin
Debug: 96 1 options.c:187 add_default_dirs(): bin2data=../share/openocd
Debug: 97 1 configuration.c:42 add_script_search_dir(): adding /root/.openocd
Debug: 98 1 configuration.c:42 add_script_search_dir(): adding /usr/local/bin/../share/openocd/site
Debug: 99 1 configuration.c:42 add_script_search_dir(): adding /usr/local/bin/../share/openocd/scripts
Debug: 100 1 configuration.c:97 find_file(): found openocd_nds32.cfg
Debug: 101 1 command.c:147 script_debug(): command - log_output log_output iceman_debug0.log
Andes AICE-MINI v2.0.0
There is 1 core in target
JTAG frequency 12 MHz
<-- HW reset-and-hold failed. -->
<-- SW reset-and-hold failed. -->
<-- aice_issue_srst ERROR! -->
The core #0 listens on 9902.
ICEman is ready to use.


Testing HMAC MD5 on ESP32

I modified the hello_world example to do same HMAC test I did in the PC:

#define MD5_MAC_LEN 16

extern int md5_vector(size_t num_elem, const uint8_t *addr[], const size_t *len, uint8_t *mac);

int hmac_md5_vector(const uint8_t *key, size_t key_len, size_t num_elem,
                    const uint8_t *addr[], const size_t *len, uint8_t *mac)
{
  uint8_t k_pad[64]; /* padding - key XORd with ipad/opad */
  uint8_t tk[16];
  const uint8_t *_addr[6];
  size_t i, _len[6];
  int res;

  if (num_elem > 5)
    {
      /*
       * Fixed limit on the number of fragments to avoid having to
       * allocate memory (which could fail).
       */

      return -1;
    }

  /* if key is longer than 64 bytes reset it to key = MD5(key) */

  if (key_len > 64)
    {
      if (md5_vector(1, &key, &key_len, tk))
        {
      	  return -1;
        }

      key = tk;
      key_len = 16;
    }

  /* the HMAC_MD5 transform looks like:
   *
   * MD5(K XOR opad, MD5(K XOR ipad, text))
   *
   * where K is an n byte key
   * ipad is the byte 0x36 repeated 64 times
   * opad is the byte 0x5c repeated 64 times
   * and text is the data being protected */

  /* start out by storing key in ipad */

  memset(k_pad, 0, sizeof(k_pad));
  memcpy(k_pad, key, key_len);

  /* XOR key with ipad values */

  for (i = 0; i < 64; i++)
    {
      k_pad[i] ^= 0x36;
    }
     
  /* perform inner MD5 */

  _addr[0] = k_pad;
  _len[0] = 64;

  for (i = 0; i < num_elem; i++)
    {
      _addr[i + 1] = addr[i];
      _len[i + 1] = len[i]; 
    }

  if (md5_vector(1 + num_elem, _addr, _len, mac))
    {
	  return -1;
    }

  memset(k_pad, 0, sizeof(k_pad));
  memcpy(k_pad, key, key_len);

  /* XOR key with opad values */

  for (i = 0; i < 64; i++)
    {
      k_pad[i] ^= 0x5c;
    }

  /* perform outer MD5 */

  _addr[0] = k_pad;
  _len[0] = 64;
  _addr[1] = mac;
  _len[1] = MD5_MAC_LEN;
  res = md5_vector(2, _addr, _len, mac);
  memset(k_pad, 0, sizeof(k_pad));
  memset(tk, 0, sizeof(tk));

  return res;
}

int hmac_md5(const uint8_t *key, size_t key_len, const uint8_t *data, size_t data_len,
             uint8_t *mac)
{
  return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac);
}

int main(int argc, FAR char *argv[])
{
  int i;
  uint8_t key[8] = {'S', '3', 'c', 'r', 'e', 't', 's', '!'};
  const uint8_t msg[16] = {'M', 'y', ' ', 'M', 'e', 's', 's', 'a', 'g', 'e', ' ', 'p', 'l', 'a', 'i', 'n'};
  uint8_t hmac[128];

  memset(hmac, 0x00, 128);

  hmac_md5(key, 8, msg, 16, hmac);

  for (i = 0; i < 16; i++)
    {
      printf("hmac[%d] = %02X\n", i, hmac[i]);
    }

  return 0;
}

The result was the same:

nsh> hello
hmac[0] = 3D
hmac[1] = 32
hmac[2] = 76
hmac[3] = FD
hmac[4] = E3
hmac[5] = FB
hmac[6] = 42
hmac[7] = D8
hmac[8] = F0
hmac[9] = 05
hmac[10] = 53
hmac[11] = CC
hmac[12] = 12
hmac[13] = E7
hmac[14] = C9
hmac[15] = C3
nsh>

Compiling a simples HMAC MD5 test

I was trying do some tests with HMAC:

#include <stdint.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <openssl/hmac.h>
#include <openssl/ossl_typ.h>

static int openssl_hmac_vector(const EVP_MD *type, const uint8_t *key,
			       size_t key_len, size_t num_elem,
			       const uint8_t *addr[], const size_t *len, uint8_t *mac,
			       unsigned int mdlen)
{
	HMAC_CTX *ctx;
	size_t i;
	int res;

	ctx = HMAC_CTX_new();
#if OPENSSL_VERSION_NUMBER < 0x00909000
	HMAC_Init_ex(ctx, key, key_len, type, NULL);
#else /* openssl < 0.9.9 */
	if (HMAC_Init_ex(ctx, key, key_len, type, NULL) != 1)
		return -1;
#endif /* openssl < 0.9.9 */

	for (i = 0; i < num_elem; i++)
		HMAC_Update(ctx, addr[i], len[i]);

#if OPENSSL_VERSION_NUMBER < 0x00909000
	HMAC_Final(ctx, mac, &mdlen);
	res = 1;
#else /* openssl < 0.9.9 */
	res = HMAC_Final(ctx, mac, &mdlen);
#endif /* openssl < 0.9.9 */
	HMAC_CTX_free(ctx);

	return res == 1 ? 0 : -1;
}

int hmac_md5_vector(const uint8_t *key, size_t key_len, size_t num_elem,
		    const uint8_t *addr[], const size_t *len, uint8_t *mac)
{
	return openssl_hmac_vector(EVP_md5(), key ,key_len, num_elem, addr, len,
				   mac, 16);
}

int hmac_md5(const uint8_t *key, size_t key_len, const uint8_t *data, size_t data_len,
	     uint8_t *mac)
{
	return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac);
}

int main(void)
{
  int i;
  uint8_t key[8] = {'S', '3', 'c', 'r', 'e', 't', 's', '!'};
  const uint8_t msg[16] = {'M', 'y', ' ', 'M', 'e', 's', 's', 'a', 'g', 'e', ' ', 'p', 'l', 'a', 'i', 'n'};
  uint8_t hmac[128];

  memset(hmac, 0x00, 128);

  hmac_md5(key, 8, msg, 16, hmac);

  for (i = 0; i < 16; i++)
    {
      printf("hmac[%d] = %02X\n", i, hmac[i]);
    }

  return 0;
}

But it was failing to compile:

$ gcc testhmac.c -o testhmac
/usr/bin/ld: /tmp/cczEFXg9.o: in function `openssl_hmac_vector':
testhmac.c:(.text+0x25): undefined reference to `HMAC_CTX_new'
/usr/bin/ld: testhmac.c:(.text+0x4e): undefined reference to `HMAC_Init_ex'
/usr/bin/ld: testhmac.c:(.text+0xa2): undefined reference to `HMAC_Update'
/usr/bin/ld: testhmac.c:(.text+0xc5): undefined reference to `HMAC_Final'
/usr/bin/ld: testhmac.c:(.text+0xd4): undefined reference to `HMAC_CTX_free'
/usr/bin/ld: /tmp/cczEFXg9.o: in function `hmac_md5_vector':
testhmac.c:(.text+0x111): undefined reference to `EVP_md5'
collect2: error: ld returned 1 exit status

Passing -lssl didn’t solve the issue:

$ gcc testhmac.c -o testhmac -lssl
/usr/bin/ld: /tmp/ccRUYEU0.o: in function `openssl_hmac_vector':
testhmac.c:(.text+0x25): undefined reference to `HMAC_CTX_new'
/usr/bin/ld: testhmac.c:(.text+0x4e): undefined reference to `HMAC_Init_ex'
/usr/bin/ld: testhmac.c:(.text+0xa2): undefined reference to `HMAC_Update'
/usr/bin/ld: testhmac.c:(.text+0xc5): undefined reference to `HMAC_Final'
/usr/bin/ld: testhmac.c:(.text+0xd4): undefined reference to `HMAC_CTX_free'
/usr/bin/ld: /tmp/ccRUYEU0.o: in function `hmac_md5_vector':
testhmac.c:(.text+0x111): undefined reference to `EVP_md5'
collect2: error: ld returned 1 exit status

You need to use -lcrypto (some people suggest -lssl -lcrypto)

$ gcc testhmac.c -o testhmac -lcrypto

Now it compiled fine and I can run it:

$ ./testhmac 
hmac[0] = 3D
hmac[1] = 32
hmac[2] = 76
hmac[3] = FD
hmac[4] = E3
hmac[5] = FB
hmac[6] = 42
hmac[7] = D8
hmac[8] = F0
hmac[9] = 05
hmac[10] = 53
hmac[11] = CC
hmac[12] = 12
hmac[13] = E7
hmac[14] = C9
hmac[15] = C3